/* Lzma2Enc.c -- LZMA2 Encoder | |
2018-07-04 : Igor Pavlov : Public domain */ | |
#include "Precomp.h" | |
#include <string.h> | |
/* #define _7ZIP_ST */ | |
#include "Lzma2Enc.h" | |
#ifndef _7ZIP_ST | |
#include "MtCoder.h" | |
#else | |
#define MTCODER__THREADS_MAX 1 | |
#endif | |
#define LZMA2_CONTROL_LZMA (1 << 7) | |
#define LZMA2_CONTROL_COPY_NO_RESET 2 | |
#define LZMA2_CONTROL_COPY_RESET_DIC 1 | |
#define LZMA2_CONTROL_EOF 0 | |
#define LZMA2_LCLP_MAX 4 | |
#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) | |
#define LZMA2_PACK_SIZE_MAX (1 << 16) | |
#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX | |
#define LZMA2_UNPACK_SIZE_MAX (1 << 21) | |
#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX | |
#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) | |
#define PRF(x) /* x */ | |
/* ---------- CLimitedSeqInStream ---------- */ | |
typedef struct | |
{ | |
ISeqInStream vt; | |
ISeqInStream *realStream; | |
UInt64 limit; | |
UInt64 processed; | |
int finished; | |
} CLimitedSeqInStream; | |
static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) | |
{ | |
p->limit = (UInt64)(Int64)-1; | |
p->processed = 0; | |
p->finished = 0; | |
} | |
static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | |
{ | |
CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt); | |
size_t size2 = *size; | |
SRes res = SZ_OK; | |
if (p->limit != (UInt64)(Int64)-1) | |
{ | |
UInt64 rem = p->limit - p->processed; | |
if (size2 > rem) | |
size2 = (size_t)rem; | |
} | |
if (size2 != 0) | |
{ | |
res = ISeqInStream_Read(p->realStream, data, &size2); | |
p->finished = (size2 == 0 ? 1 : 0); | |
p->processed += size2; | |
} | |
*size = size2; | |
return res; | |
} | |
/* ---------- CLzma2EncInt ---------- */ | |
typedef struct | |
{ | |
CLzmaEncHandle enc; | |
Byte propsAreSet; | |
Byte propsByte; | |
Byte needInitState; | |
Byte needInitProp; | |
UInt64 srcPos; | |
} CLzma2EncInt; | |
static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) | |
{ | |
if (!p->propsAreSet) | |
{ | |
SizeT propsSize = LZMA_PROPS_SIZE; | |
Byte propsEncoded[LZMA_PROPS_SIZE]; | |
RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); | |
RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); | |
p->propsByte = propsEncoded[0]; | |
p->propsAreSet = True; | |
} | |
return SZ_OK; | |
} | |
static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) | |
{ | |
p->srcPos = 0; | |
p->needInitState = True; | |
p->needInitProp = True; | |
} | |
SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, | |
ISzAllocPtr alloc, ISzAllocPtr allocBig); | |
SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, | |
UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); | |
SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, | |
Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); | |
const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); | |
void LzmaEnc_Finish(CLzmaEncHandle pp); | |
void LzmaEnc_SaveState(CLzmaEncHandle pp); | |
void LzmaEnc_RestoreState(CLzmaEncHandle pp); | |
/* | |
UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp); | |
*/ | |
static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, | |
size_t *packSizeRes, ISeqOutStream *outStream) | |
{ | |
size_t packSizeLimit = *packSizeRes; | |
size_t packSize = packSizeLimit; | |
UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; | |
unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); | |
BoolInt useCopyBlock; | |
SRes res; | |
*packSizeRes = 0; | |
if (packSize < lzHeaderSize) | |
return SZ_ERROR_OUTPUT_EOF; | |
packSize -= lzHeaderSize; | |
LzmaEnc_SaveState(p->enc); | |
res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, | |
outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); | |
PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); | |
if (unpackSize == 0) | |
return res; | |
if (res == SZ_OK) | |
useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); | |
else | |
{ | |
if (res != SZ_ERROR_OUTPUT_EOF) | |
return res; | |
res = SZ_OK; | |
useCopyBlock = True; | |
} | |
if (useCopyBlock) | |
{ | |
size_t destPos = 0; | |
PRF(printf("################# COPY ")); | |
while (unpackSize > 0) | |
{ | |
UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; | |
if (packSizeLimit - destPos < u + 3) | |
return SZ_ERROR_OUTPUT_EOF; | |
outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); | |
outBuf[destPos++] = (Byte)((u - 1) >> 8); | |
outBuf[destPos++] = (Byte)(u - 1); | |
memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); | |
unpackSize -= u; | |
destPos += u; | |
p->srcPos += u; | |
if (outStream) | |
{ | |
*packSizeRes += destPos; | |
if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) | |
return SZ_ERROR_WRITE; | |
destPos = 0; | |
} | |
else | |
*packSizeRes = destPos; | |
/* needInitState = True; */ | |
} | |
LzmaEnc_RestoreState(p->enc); | |
return SZ_OK; | |
} | |
{ | |
size_t destPos = 0; | |
UInt32 u = unpackSize - 1; | |
UInt32 pm = (UInt32)(packSize - 1); | |
unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); | |
PRF(printf(" ")); | |
outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); | |
outBuf[destPos++] = (Byte)(u >> 8); | |
outBuf[destPos++] = (Byte)u; | |
outBuf[destPos++] = (Byte)(pm >> 8); | |
outBuf[destPos++] = (Byte)pm; | |
if (p->needInitProp) | |
outBuf[destPos++] = p->propsByte; | |
p->needInitProp = False; | |
p->needInitState = False; | |
destPos += packSize; | |
p->srcPos += unpackSize; | |
if (outStream) | |
if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) | |
return SZ_ERROR_WRITE; | |
*packSizeRes = destPos; | |
return SZ_OK; | |
} | |
} | |
/* ---------- Lzma2 Props ---------- */ | |
void Lzma2EncProps_Init(CLzma2EncProps *p) | |
{ | |
LzmaEncProps_Init(&p->lzmaProps); | |
p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO; | |
p->numBlockThreads_Reduced = -1; | |
p->numBlockThreads_Max = -1; | |
p->numTotalThreads = -1; | |
} | |
void Lzma2EncProps_Normalize(CLzma2EncProps *p) | |
{ | |
UInt64 fileSize; | |
int t1, t1n, t2, t2r, t3; | |
{ | |
CLzmaEncProps lzmaProps = p->lzmaProps; | |
LzmaEncProps_Normalize(&lzmaProps); | |
t1n = lzmaProps.numThreads; | |
} | |
t1 = p->lzmaProps.numThreads; | |
t2 = p->numBlockThreads_Max; | |
t3 = p->numTotalThreads; | |
if (t2 > MTCODER__THREADS_MAX) | |
t2 = MTCODER__THREADS_MAX; | |
if (t3 <= 0) | |
{ | |
if (t2 <= 0) | |
t2 = 1; | |
t3 = t1n * t2; | |
} | |
else if (t2 <= 0) | |
{ | |
t2 = t3 / t1n; | |
if (t2 == 0) | |
{ | |
t1 = 1; | |
t2 = t3; | |
} | |
if (t2 > MTCODER__THREADS_MAX) | |
t2 = MTCODER__THREADS_MAX; | |
} | |
else if (t1 <= 0) | |
{ | |
t1 = t3 / t2; | |
if (t1 == 0) | |
t1 = 1; | |
} | |
else | |
t3 = t1n * t2; | |
p->lzmaProps.numThreads = t1; | |
t2r = t2; | |
fileSize = p->lzmaProps.reduceSize; | |
if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | |
&& p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO | |
&& (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) | |
p->lzmaProps.reduceSize = p->blockSize; | |
LzmaEncProps_Normalize(&p->lzmaProps); | |
p->lzmaProps.reduceSize = fileSize; | |
t1 = p->lzmaProps.numThreads; | |
if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | |
{ | |
t2r = t2 = 1; | |
t3 = t1; | |
} | |
else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1) | |
{ | |
/* if there is no block multi-threading, we use SOLID block */ | |
p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; | |
} | |
else | |
{ | |
if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | |
{ | |
const UInt32 kMinSize = (UInt32)1 << 20; | |
const UInt32 kMaxSize = (UInt32)1 << 28; | |
const UInt32 dictSize = p->lzmaProps.dictSize; | |
UInt64 blockSize = (UInt64)dictSize << 2; | |
if (blockSize < kMinSize) blockSize = kMinSize; | |
if (blockSize > kMaxSize) blockSize = kMaxSize; | |
if (blockSize < dictSize) blockSize = dictSize; | |
blockSize += (kMinSize - 1); | |
blockSize &= ~(UInt64)(kMinSize - 1); | |
p->blockSize = blockSize; | |
} | |
if (t2 > 1 && fileSize != (UInt64)(Int64)-1) | |
{ | |
UInt64 numBlocks = fileSize / p->blockSize; | |
if (numBlocks * p->blockSize != fileSize) | |
numBlocks++; | |
if (numBlocks < (unsigned)t2) | |
{ | |
t2r = (unsigned)numBlocks; | |
if (t2r == 0) | |
t2r = 1; | |
t3 = t1 * t2r; | |
} | |
} | |
} | |
p->numBlockThreads_Max = t2; | |
p->numBlockThreads_Reduced = t2r; | |
p->numTotalThreads = t3; | |
} | |
static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) | |
{ | |
return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; | |
} | |
/* ---------- Lzma2 ---------- */ | |
typedef struct | |
{ | |
Byte propEncoded; | |
CLzma2EncProps props; | |
UInt64 expectedDataSize; | |
Byte *tempBufLzma; | |
ISzAllocPtr alloc; | |
ISzAllocPtr allocBig; | |
CLzma2EncInt coders[MTCODER__THREADS_MAX]; | |
#ifndef _7ZIP_ST | |
ISeqOutStream *outStream; | |
Byte *outBuf; | |
size_t outBuf_Rem; /* remainder in outBuf */ | |
size_t outBufSize; /* size of allocated outBufs[i] */ | |
size_t outBufsDataSizes[MTCODER__BLOCKS_MAX]; | |
BoolInt mtCoder_WasConstructed; | |
CMtCoder mtCoder; | |
Byte *outBufs[MTCODER__BLOCKS_MAX]; | |
#endif | |
} CLzma2Enc; | |
CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) | |
{ | |
CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); | |
if (!p) | |
return NULL; | |
Lzma2EncProps_Init(&p->props); | |
Lzma2EncProps_Normalize(&p->props); | |
p->expectedDataSize = (UInt64)(Int64)-1; | |
p->tempBufLzma = NULL; | |
p->alloc = alloc; | |
p->allocBig = allocBig; | |
{ | |
unsigned i; | |
for (i = 0; i < MTCODER__THREADS_MAX; i++) | |
p->coders[i].enc = NULL; | |
} | |
#ifndef _7ZIP_ST | |
p->mtCoder_WasConstructed = False; | |
{ | |
unsigned i; | |
for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | |
p->outBufs[i] = NULL; | |
p->outBufSize = 0; | |
} | |
#endif | |
return p; | |
} | |
#ifndef _7ZIP_ST | |
static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) | |
{ | |
unsigned i; | |
for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | |
if (p->outBufs[i]) | |
{ | |
ISzAlloc_Free(p->alloc, p->outBufs[i]); | |
p->outBufs[i] = NULL; | |
} | |
p->outBufSize = 0; | |
} | |
#endif | |
void Lzma2Enc_Destroy(CLzma2EncHandle pp) | |
{ | |
CLzma2Enc *p = (CLzma2Enc *)pp; | |
unsigned i; | |
for (i = 0; i < MTCODER__THREADS_MAX; i++) | |
{ | |
CLzma2EncInt *t = &p->coders[i]; | |
if (t->enc) | |
{ | |
LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); | |
t->enc = NULL; | |
} | |
} | |
#ifndef _7ZIP_ST | |
if (p->mtCoder_WasConstructed) | |
{ | |
MtCoder_Destruct(&p->mtCoder); | |
p->mtCoder_WasConstructed = False; | |
} | |
Lzma2Enc_FreeOutBufs(p); | |
#endif | |
ISzAlloc_Free(p->alloc, p->tempBufLzma); | |
p->tempBufLzma = NULL; | |
ISzAlloc_Free(p->alloc, pp); | |
} | |
SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) | |
{ | |
CLzma2Enc *p = (CLzma2Enc *)pp; | |
CLzmaEncProps lzmaProps = props->lzmaProps; | |
LzmaEncProps_Normalize(&lzmaProps); | |
if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) | |
return SZ_ERROR_PARAM; | |
p->props = *props; | |
Lzma2EncProps_Normalize(&p->props); | |
return SZ_OK; | |
} | |
void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) | |
{ | |
CLzma2Enc *p = (CLzma2Enc *)pp; | |
p->expectedDataSize = expectedDataSiize; | |
} | |
Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) | |
{ | |
CLzma2Enc *p = (CLzma2Enc *)pp; | |
unsigned i; | |
UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); | |
for (i = 0; i < 40; i++) | |
if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) | |
break; | |
return (Byte)i; | |
} | |
static SRes Lzma2Enc_EncodeMt1( | |
CLzma2Enc *me, | |
CLzma2EncInt *p, | |
ISeqOutStream *outStream, | |
Byte *outBuf, size_t *outBufSize, | |
ISeqInStream *inStream, | |
const Byte *inData, size_t inDataSize, | |
int finished, | |
ICompressProgress *progress) | |
{ | |
UInt64 unpackTotal = 0; | |
UInt64 packTotal = 0; | |
size_t outLim = 0; | |
CLimitedSeqInStream limitedInStream; | |
if (outBuf) | |
{ | |
outLim = *outBufSize; | |
*outBufSize = 0; | |
} | |
if (!p->enc) | |
{ | |
p->propsAreSet = False; | |
p->enc = LzmaEnc_Create(me->alloc); | |
if (!p->enc) | |
return SZ_ERROR_MEM; | |
} | |
limitedInStream.realStream = inStream; | |
if (inStream) | |
{ | |
limitedInStream.vt.Read = LimitedSeqInStream_Read; | |
} | |
if (!outBuf) | |
{ | |
// outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma | |
if (!me->tempBufLzma) | |
{ | |
me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); | |
if (!me->tempBufLzma) | |
return SZ_ERROR_MEM; | |
} | |
} | |
RINOK(Lzma2EncInt_InitStream(p, &me->props)); | |
for (;;) | |
{ | |
SRes res = SZ_OK; | |
size_t inSizeCur = 0; | |
Lzma2EncInt_InitBlock(p); | |
LimitedSeqInStream_Init(&limitedInStream); | |
limitedInStream.limit = me->props.blockSize; | |
if (inStream) | |
{ | |
UInt64 expected = (UInt64)(Int64)-1; | |
// inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize | |
if (me->expectedDataSize != (UInt64)(Int64)-1 | |
&& me->expectedDataSize >= unpackTotal) | |
expected = me->expectedDataSize - unpackTotal; | |
if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | |
&& expected > me->props.blockSize) | |
expected = (size_t)me->props.blockSize; | |
LzmaEnc_SetDataSize(p->enc, expected); | |
RINOK(LzmaEnc_PrepareForLzma2(p->enc, | |
&limitedInStream.vt, | |
LZMA2_KEEP_WINDOW_SIZE, | |
me->alloc, | |
me->allocBig)); | |
} | |
else | |
{ | |
inSizeCur = inDataSize - (size_t)unpackTotal; | |
if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | |
&& inSizeCur > me->props.blockSize) | |
inSizeCur = (size_t)me->props.blockSize; | |
// LzmaEnc_SetDataSize(p->enc, inSizeCur); | |
RINOK(LzmaEnc_MemPrepare(p->enc, | |
inData + (size_t)unpackTotal, inSizeCur, | |
LZMA2_KEEP_WINDOW_SIZE, | |
me->alloc, | |
me->allocBig)); | |
} | |
for (;;) | |
{ | |
size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; | |
if (outBuf) | |
packSize = outLim - (size_t)packTotal; | |
res = Lzma2EncInt_EncodeSubblock(p, | |
outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, | |
outBuf ? NULL : outStream); | |
if (res != SZ_OK) | |
break; | |
packTotal += packSize; | |
if (outBuf) | |
*outBufSize = (size_t)packTotal; | |
res = Progress(progress, unpackTotal + p->srcPos, packTotal); | |
if (res != SZ_OK) | |
break; | |
/* | |
if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) | |
break; | |
*/ | |
if (packSize == 0) | |
break; | |
} | |
LzmaEnc_Finish(p->enc); | |
unpackTotal += p->srcPos; | |
RINOK(res); | |
if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) | |
return SZ_ERROR_FAIL; | |
if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) | |
{ | |
if (finished) | |
{ | |
if (outBuf) | |
{ | |
size_t destPos = *outBufSize; | |
if (destPos >= outLim) | |
return SZ_ERROR_OUTPUT_EOF; | |
outBuf[destPos] = 0; | |
*outBufSize = destPos + 1; | |
} | |
else | |
{ | |
Byte b = 0; | |
if (ISeqOutStream_Write(outStream, &b, 1) != 1) | |
return SZ_ERROR_WRITE; | |
} | |
} | |
return SZ_OK; | |
} | |
} | |
} | |
#ifndef _7ZIP_ST | |
static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, | |
const Byte *src, size_t srcSize, int finished) | |
{ | |
CLzma2Enc *me = (CLzma2Enc *)pp; | |
size_t destSize = me->outBufSize; | |
SRes res; | |
CMtProgressThunk progressThunk; | |
Byte *dest = me->outBufs[outBufIndex]; | |
me->outBufsDataSizes[outBufIndex] = 0; | |
if (!dest) | |
{ | |
dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); | |
if (!dest) | |
return SZ_ERROR_MEM; | |
me->outBufs[outBufIndex] = dest; | |
} | |
MtProgressThunk_CreateVTable(&progressThunk); | |
progressThunk.mtProgress = &me->mtCoder.mtProgress; | |
progressThunk.inSize = 0; | |
progressThunk.outSize = 0; | |
res = Lzma2Enc_EncodeMt1(me, | |
&me->coders[coderIndex], | |
NULL, dest, &destSize, | |
NULL, src, srcSize, | |
finished, | |
&progressThunk.vt); | |
me->outBufsDataSizes[outBufIndex] = destSize; | |
return res; | |
} | |
static SRes Lzma2Enc_MtCallback_Write(void *pp, unsigned outBufIndex) | |
{ | |
CLzma2Enc *me = (CLzma2Enc *)pp; | |
size_t size = me->outBufsDataSizes[outBufIndex]; | |
const Byte *data = me->outBufs[outBufIndex]; | |
if (me->outStream) | |
return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; | |
if (size > me->outBuf_Rem) | |
return SZ_ERROR_OUTPUT_EOF; | |
memcpy(me->outBuf, data, size); | |
me->outBuf_Rem -= size; | |
me->outBuf += size; | |
return SZ_OK; | |
} | |
#endif | |
SRes Lzma2Enc_Encode2(CLzma2EncHandle pp, | |
ISeqOutStream *outStream, | |
Byte *outBuf, size_t *outBufSize, | |
ISeqInStream *inStream, | |
const Byte *inData, size_t inDataSize, | |
ICompressProgress *progress) | |
{ | |
CLzma2Enc *p = (CLzma2Enc *)pp; | |
if (inStream && inData) | |
return SZ_ERROR_PARAM; | |
if (outStream && outBuf) | |
return SZ_ERROR_PARAM; | |
{ | |
unsigned i; | |
for (i = 0; i < MTCODER__THREADS_MAX; i++) | |
p->coders[i].propsAreSet = False; | |
} | |
#ifndef _7ZIP_ST | |
if (p->props.numBlockThreads_Reduced > 1) | |
{ | |
IMtCoderCallback2 vt; | |
if (!p->mtCoder_WasConstructed) | |
{ | |
p->mtCoder_WasConstructed = True; | |
MtCoder_Construct(&p->mtCoder); | |
} | |
vt.Code = Lzma2Enc_MtCallback_Code; | |
vt.Write = Lzma2Enc_MtCallback_Write; | |
p->outStream = outStream; | |
p->outBuf = NULL; | |
p->outBuf_Rem = 0; | |
if (!outStream) | |
{ | |
p->outBuf = outBuf; | |
p->outBuf_Rem = *outBufSize; | |
*outBufSize = 0; | |
} | |
p->mtCoder.allocBig = p->allocBig; | |
p->mtCoder.progress = progress; | |
p->mtCoder.inStream = inStream; | |
p->mtCoder.inData = inData; | |
p->mtCoder.inDataSize = inDataSize; | |
p->mtCoder.mtCallback = &vt; | |
p->mtCoder.mtCallbackObject = p; | |
p->mtCoder.blockSize = (size_t)p->props.blockSize; | |
if (p->mtCoder.blockSize != p->props.blockSize) | |
return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ | |
{ | |
size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; | |
if (destBlockSize < p->mtCoder.blockSize) | |
return SZ_ERROR_PARAM; | |
if (p->outBufSize != destBlockSize) | |
Lzma2Enc_FreeOutBufs(p); | |
p->outBufSize = destBlockSize; | |
} | |
p->mtCoder.numThreadsMax = p->props.numBlockThreads_Max; | |
p->mtCoder.expectedDataSize = p->expectedDataSize; | |
{ | |
SRes res = MtCoder_Code(&p->mtCoder); | |
if (!outStream) | |
*outBufSize = p->outBuf - outBuf; | |
return res; | |
} | |
} | |
#endif | |
return Lzma2Enc_EncodeMt1(p, | |
&p->coders[0], | |
outStream, outBuf, outBufSize, | |
inStream, inData, inDataSize, | |
True, /* finished */ | |
progress); | |
} |