801 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			801 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* Lzma2Enc.c -- LZMA2 Encoder
 | ||
|  | 2017-08-28 : 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, Bool 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); | ||
|  |   Bool 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 outBufSize; | ||
|  |   size_t outBufsDataSizes[MTCODER__BLOCKS_MAX]; | ||
|  |   Bool 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 = 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.index = coderIndex; | ||
|  | 
 | ||
|  |   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->outBufSize) | ||
|  |     return SZ_ERROR_OUTPUT_EOF; | ||
|  |   memcpy(me->outBuf, data, size); | ||
|  |   me->outBufSize -= 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 E_INVALIDARG; | ||
|  | 
 | ||
|  |   if (outStream && outBuf) | ||
|  |     return E_INVALIDARG; | ||
|  | 
 | ||
|  |   { | ||
|  |     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->outBufSize = 0; | ||
|  |     if (!outStream) | ||
|  |     { | ||
|  |       p->outBuf = outBuf; | ||
|  |       p->outBufSize = *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); | ||
|  | } |