1325 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			1325 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* XzEnc.c -- Xz Encode
 | ||
|  | 2017-08-25 : Igor Pavlov : Public domain */ | ||
|  | 
 | ||
|  | #include "Precomp.h"
 | ||
|  | 
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <string.h>
 | ||
|  | 
 | ||
|  | #include "7zCrc.h"
 | ||
|  | #include "Bra.h"
 | ||
|  | #include "CpuArch.h"
 | ||
|  | 
 | ||
|  | #ifdef USE_SUBBLOCK
 | ||
|  | #include "Bcj3Enc.c"
 | ||
|  | #include "SbFind.c"
 | ||
|  | #include "SbEnc.c"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include "XzEnc.h"
 | ||
|  | 
 | ||
|  | // #define _7ZIP_ST
 | ||
|  | 
 | ||
|  | #ifndef _7ZIP_ST
 | ||
|  | #include "MtCoder.h"
 | ||
|  | #else
 | ||
|  | #define MTCODER__THREADS_MAX 1
 | ||
|  | #define MTCODER__BLOCKS_MAX 1
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3)
 | ||
|  | 
 | ||
|  | /* max pack size for LZMA2 block + check-64bytrs: */ | ||
|  | #define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)
 | ||
|  | 
 | ||
|  | #define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize))
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #define XzBlock_ClearFlags(p)       (p)->flags = 0;
 | ||
|  | #define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);
 | ||
|  | #define XzBlock_SetHasPackSize(p)   (p)->flags |= XZ_BF_PACK_SIZE;
 | ||
|  | #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
 | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size) | ||
|  | { | ||
|  |   return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; | ||
|  | } | ||
|  | 
 | ||
|  | static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc) | ||
|  | { | ||
|  |   *crc = CrcUpdate(*crc, buf, size); | ||
|  |   return WriteBytes(s, buf, size); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) | ||
|  | { | ||
|  |   UInt32 crc; | ||
|  |   Byte header[XZ_STREAM_HEADER_SIZE]; | ||
|  |   memcpy(header, XZ_SIG, XZ_SIG_SIZE); | ||
|  |   header[XZ_SIG_SIZE] = (Byte)(f >> 8); | ||
|  |   header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); | ||
|  |   crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); | ||
|  |   SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); | ||
|  |   return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) | ||
|  | { | ||
|  |   Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; | ||
|  | 
 | ||
|  |   unsigned pos = 1; | ||
|  |   unsigned numFilters, i; | ||
|  |   header[pos++] = p->flags; | ||
|  | 
 | ||
|  |   if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); | ||
|  |   if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); | ||
|  |   numFilters = XzBlock_GetNumFilters(p); | ||
|  |    | ||
|  |   for (i = 0; i < numFilters; i++) | ||
|  |   { | ||
|  |     const CXzFilter *f = &p->filters[i]; | ||
|  |     pos += Xz_WriteVarInt(header + pos, f->id); | ||
|  |     pos += Xz_WriteVarInt(header + pos, f->propsSize); | ||
|  |     memcpy(header + pos, f->props, f->propsSize); | ||
|  |     pos += f->propsSize; | ||
|  |   } | ||
|  | 
 | ||
|  |   while ((pos & 3) != 0) | ||
|  |     header[pos++] = 0; | ||
|  | 
 | ||
|  |   header[0] = (Byte)(pos >> 2); | ||
|  |   SetUi32(header + pos, CrcCalc(header, pos)); | ||
|  |   return WriteBytes(s, header, pos + 4); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   size_t numBlocks; | ||
|  |   size_t size; | ||
|  |   size_t allocated; | ||
|  |   Byte *blocks; | ||
|  | } CXzEncIndex; | ||
|  | 
 | ||
|  | 
 | ||
|  | static void XzEncIndex_Construct(CXzEncIndex *p) | ||
|  | { | ||
|  |   p->numBlocks = 0; | ||
|  |   p->size = 0; | ||
|  |   p->allocated = 0; | ||
|  |   p->blocks = NULL; | ||
|  | } | ||
|  | 
 | ||
|  | static void XzEncIndex_Init(CXzEncIndex *p) | ||
|  | { | ||
|  |   p->numBlocks = 0; | ||
|  |   p->size = 0; | ||
|  | } | ||
|  | 
 | ||
|  | static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   if (p->blocks) | ||
|  |   { | ||
|  |     ISzAlloc_Free(alloc, p->blocks); | ||
|  |     p->blocks = NULL; | ||
|  |   } | ||
|  |   p->numBlocks = 0; | ||
|  |   p->size = 0; | ||
|  |   p->allocated = 0; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   Byte *blocks = ISzAlloc_Alloc(alloc, newSize); | ||
|  |   if (!blocks) | ||
|  |     return SZ_ERROR_MEM; | ||
|  |   if (p->size != 0) | ||
|  |     memcpy(blocks, p->blocks, p->size); | ||
|  |   if (p->blocks) | ||
|  |     ISzAlloc_Free(alloc, p->blocks); | ||
|  |   p->blocks = blocks; | ||
|  |   p->allocated = newSize; | ||
|  |   return SZ_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   UInt64 pos; | ||
|  |   { | ||
|  |     Byte buf[32]; | ||
|  |     unsigned pos2 = Xz_WriteVarInt(buf, totalSize); | ||
|  |     pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); | ||
|  |     pos = numBlocks * pos2; | ||
|  |   } | ||
|  |    | ||
|  |   if (pos <= p->allocated - p->size) | ||
|  |     return SZ_OK; | ||
|  |   { | ||
|  |     UInt64 newSize64 = p->size + pos; | ||
|  |     size_t newSize = (size_t)newSize64; | ||
|  |     if (newSize != newSize64) | ||
|  |       return SZ_ERROR_MEM; | ||
|  |     return XzEncIndex_ReAlloc(p, newSize, alloc); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   Byte buf[32]; | ||
|  |   unsigned pos = Xz_WriteVarInt(buf, totalSize); | ||
|  |   pos += Xz_WriteVarInt(buf + pos, unpackSize); | ||
|  | 
 | ||
|  |   if (pos > p->allocated - p->size) | ||
|  |   { | ||
|  |     size_t newSize = p->allocated * 2 + 16 * 2; | ||
|  |     if (newSize < p->size + pos) | ||
|  |       return SZ_ERROR_MEM; | ||
|  |     RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)); | ||
|  |   } | ||
|  |   memcpy(p->blocks + p->size, buf, pos); | ||
|  |   p->size += pos; | ||
|  |   p->numBlocks++; | ||
|  |   return SZ_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s) | ||
|  | { | ||
|  |   Byte buf[32]; | ||
|  |   UInt64 globalPos; | ||
|  |   UInt32 crc = CRC_INIT_VAL; | ||
|  |   unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); | ||
|  |    | ||
|  |   globalPos = pos; | ||
|  |   buf[0] = 0; | ||
|  |   RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc)); | ||
|  |   RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc)); | ||
|  |   globalPos += p->size; | ||
|  |    | ||
|  |   pos = XZ_GET_PAD_SIZE(globalPos); | ||
|  |   buf[1] = 0; | ||
|  |   buf[2] = 0; | ||
|  |   buf[3] = 0; | ||
|  |   globalPos += pos; | ||
|  |    | ||
|  |   crc = CrcUpdate(crc, buf + 4 - pos, pos); | ||
|  |   SetUi32(buf + 4, CRC_GET_DIGEST(crc)); | ||
|  |    | ||
|  |   SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)); | ||
|  |   buf[8 + 8] = (Byte)(flags >> 8); | ||
|  |   buf[8 + 9] = (Byte)(flags & 0xFF); | ||
|  |   SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)); | ||
|  |   buf[8 + 10] = XZ_FOOTER_SIG_0; | ||
|  |   buf[8 + 11] = XZ_FOOTER_SIG_1; | ||
|  |    | ||
|  |   return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------- CSeqCheckInStream ---------- */ | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ISeqInStream vt; | ||
|  |   ISeqInStream *realStream; | ||
|  |   const Byte *data; | ||
|  |   UInt64 limit; | ||
|  |   UInt64 processed; | ||
|  |   int realStreamFinished; | ||
|  |   CXzCheck check; | ||
|  | } CSeqCheckInStream; | ||
|  | 
 | ||
|  | static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) | ||
|  | { | ||
|  |   p->limit = (UInt64)(Int64)-1; | ||
|  |   p->processed = 0; | ||
|  |   p->realStreamFinished = 0; | ||
|  |   XzCheck_Init(&p->check, checkMode); | ||
|  | } | ||
|  | 
 | ||
|  | static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) | ||
|  | { | ||
|  |   XzCheck_Final(&p->check, digest); | ||
|  | } | ||
|  | 
 | ||
|  | static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
|  | { | ||
|  |   CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, 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) | ||
|  |   { | ||
|  |     if (p->realStream) | ||
|  |     { | ||
|  |       res = ISeqInStream_Read(p->realStream, data, &size2); | ||
|  |       p->realStreamFinished = (size2 == 0) ? 1 : 0; | ||
|  |     } | ||
|  |     else | ||
|  |       memcpy(data, p->data + (size_t)p->processed, size2); | ||
|  |     XzCheck_Update(&p->check, data, size2); | ||
|  |     p->processed += size2; | ||
|  |   } | ||
|  |   *size = size2; | ||
|  |   return res; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------- CSeqSizeOutStream ---------- */ | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ISeqOutStream vt; | ||
|  |   ISeqOutStream *realStream; | ||
|  |   Byte *outBuf; | ||
|  |   size_t outBufLimit; | ||
|  |   UInt64 processed; | ||
|  | } CSeqSizeOutStream; | ||
|  | 
 | ||
|  | static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) | ||
|  | { | ||
|  |   CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt); | ||
|  |   if (p->realStream) | ||
|  |     size = ISeqOutStream_Write(p->realStream, data, size); | ||
|  |   else | ||
|  |   { | ||
|  |     if (size > p->outBufLimit - (size_t)p->processed) | ||
|  |       return 0; | ||
|  |     memcpy(p->outBuf + (size_t)p->processed, data, size); | ||
|  |   } | ||
|  |   p->processed += size; | ||
|  |   return size; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------- CSeqInFilter ---------- */ | ||
|  | 
 | ||
|  | #define FILTER_BUF_SIZE (1 << 20)
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ISeqInStream p; | ||
|  |   ISeqInStream *realStream; | ||
|  |   IStateCoder StateCoder; | ||
|  |   Byte *buf; | ||
|  |   size_t curPos; | ||
|  |   size_t endPos; | ||
|  |   int srcWasFinished; | ||
|  | } CSeqInFilter; | ||
|  | 
 | ||
|  | 
 | ||
|  | SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc); | ||
|  | 
 | ||
|  | static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   if (!p->buf) | ||
|  |   { | ||
|  |     p->buf = ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); | ||
|  |     if (!p->buf) | ||
|  |       return SZ_ERROR_MEM; | ||
|  |   } | ||
|  |   p->curPos = p->endPos = 0; | ||
|  |   p->srcWasFinished = 0; | ||
|  |   RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc)); | ||
|  |   RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)); | ||
|  |   p->StateCoder.Init(p->StateCoder.p); | ||
|  |   return SZ_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
|  | { | ||
|  |   CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p); | ||
|  |   size_t sizeOriginal = *size; | ||
|  |   if (sizeOriginal == 0) | ||
|  |     return SZ_OK; | ||
|  |   *size = 0; | ||
|  |    | ||
|  |   for (;;) | ||
|  |   { | ||
|  |     if (!p->srcWasFinished && p->curPos == p->endPos) | ||
|  |     { | ||
|  |       p->curPos = 0; | ||
|  |       p->endPos = FILTER_BUF_SIZE; | ||
|  |       RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)); | ||
|  |       if (p->endPos == 0) | ||
|  |         p->srcWasFinished = 1; | ||
|  |     } | ||
|  |     { | ||
|  |       SizeT srcLen = p->endPos - p->curPos; | ||
|  |       int wasFinished; | ||
|  |       SRes res; | ||
|  |       *size = sizeOriginal; | ||
|  |       res = p->StateCoder.Code(p->StateCoder.p, data, size, p->buf + p->curPos, &srcLen, | ||
|  |         p->srcWasFinished, CODER_FINISH_ANY, &wasFinished); | ||
|  |       p->curPos += srcLen; | ||
|  |       if (*size != 0 || srcLen == 0 || res != 0) | ||
|  |         return res; | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | static void SeqInFilter_Construct(CSeqInFilter *p) | ||
|  | { | ||
|  |   p->buf = NULL; | ||
|  |   p->StateCoder.p = NULL; | ||
|  |   p->p.Read = SeqInFilter_Read; | ||
|  | } | ||
|  | 
 | ||
|  | static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   if (p->StateCoder.p) | ||
|  |   { | ||
|  |     p->StateCoder.Free(p->StateCoder.p, alloc); | ||
|  |     p->StateCoder.p = NULL; | ||
|  |   } | ||
|  |   if (p->buf) | ||
|  |   { | ||
|  |     ISzAlloc_Free(alloc, p->buf); | ||
|  |     p->buf = NULL; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------- CSbEncInStream ---------- */ | ||
|  | 
 | ||
|  | #ifdef USE_SUBBLOCK
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ISeqInStream vt; | ||
|  |   ISeqInStream *inStream; | ||
|  |   CSbEnc enc; | ||
|  | } CSbEncInStream; | ||
|  | 
 | ||
|  | static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
|  | { | ||
|  |   CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); | ||
|  |   size_t sizeOriginal = *size; | ||
|  |   if (sizeOriginal == 0) | ||
|  |     return SZ_OK; | ||
|  |    | ||
|  |   for (;;) | ||
|  |   { | ||
|  |     if (p->enc.needRead && !p->enc.readWasFinished) | ||
|  |     { | ||
|  |       size_t processed = p->enc.needReadSizeMax; | ||
|  |       RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); | ||
|  |       p->enc.readPos += processed; | ||
|  |       if (processed == 0) | ||
|  |       { | ||
|  |         p->enc.readWasFinished = True; | ||
|  |         p->enc.isFinalFinished = True; | ||
|  |       } | ||
|  |       p->enc.needRead = False; | ||
|  |     } | ||
|  |    | ||
|  |     *size = sizeOriginal; | ||
|  |     RINOK(SbEnc_Read(&p->enc, data, size)); | ||
|  |     if (*size != 0 || !p->enc.needRead) | ||
|  |       return SZ_OK; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   SbEnc_Construct(&p->enc, alloc); | ||
|  |   p->vt.Read = SbEncInStream_Read; | ||
|  | } | ||
|  | 
 | ||
|  | SRes SbEncInStream_Init(CSbEncInStream *p) | ||
|  | { | ||
|  |   return SbEnc_Init(&p->enc); | ||
|  | } | ||
|  | 
 | ||
|  | void SbEncInStream_Free(CSbEncInStream *p) | ||
|  | { | ||
|  |   SbEnc_Free(&p->enc); | ||
|  | } | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------- CXzProps ---------- */ | ||
|  | 
 | ||
|  | 
 | ||
|  | void XzFilterProps_Init(CXzFilterProps *p) | ||
|  | { | ||
|  |   p->id = 0; | ||
|  |   p->delta = 0; | ||
|  |   p->ip = 0; | ||
|  |   p->ipDefined = False; | ||
|  | } | ||
|  | 
 | ||
|  | void XzProps_Init(CXzProps *p) | ||
|  | { | ||
|  |   p->checkId = XZ_CHECK_CRC32; | ||
|  |   p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO; | ||
|  |   p->numBlockThreads_Reduced = -1; | ||
|  |   p->numBlockThreads_Max = -1; | ||
|  |   p->numTotalThreads = -1; | ||
|  |   p->reduceSize = (UInt64)(Int64)-1; | ||
|  |   p->forceWriteSizesInHeader = 0; | ||
|  |   // p->forceWriteSizesInHeader = 1;
 | ||
|  | 
 | ||
|  |   XzFilterProps_Init(&p->filterProps); | ||
|  |   Lzma2EncProps_Init(&p->lzma2Props); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static void XzEncProps_Normalize_Fixed(CXzProps *p) | ||
|  | { | ||
|  |   UInt64 fileSize; | ||
|  |   int t1, t1n, t2, t2r, t3; | ||
|  |   { | ||
|  |     CLzma2EncProps tp = p->lzma2Props; | ||
|  |     if (tp.numTotalThreads <= 0) | ||
|  |       tp.numTotalThreads = p->numTotalThreads; | ||
|  |     Lzma2EncProps_Normalize(&tp); | ||
|  |     t1n = tp.numTotalThreads; | ||
|  |   } | ||
|  | 
 | ||
|  |   t1 = p->lzma2Props.numTotalThreads; | ||
|  |   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->lzma2Props.numTotalThreads = t1; | ||
|  | 
 | ||
|  |   t2r = t2; | ||
|  | 
 | ||
|  |   fileSize = p->reduceSize; | ||
|  | 
 | ||
|  |   if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) | ||
|  |     p->lzma2Props.lzmaProps.reduceSize = p->blockSize; | ||
|  | 
 | ||
|  |   Lzma2EncProps_Normalize(&p->lzma2Props); | ||
|  | 
 | ||
|  |   t1 = p->lzma2Props.numTotalThreads; | ||
|  | 
 | ||
|  |   { | ||
|  |     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 void XzProps_Normalize(CXzProps *p) | ||
|  | { | ||
|  |   /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
 | ||
|  |      Lzma2Enc_SetProps() will normalize lzma2Props later. */ | ||
|  |    | ||
|  |   if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID) | ||
|  |   { | ||
|  |     p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
|  |     p->numBlockThreads_Reduced = 1; | ||
|  |     p->numBlockThreads_Max = 1; | ||
|  |     if (p->lzma2Props.numTotalThreads <= 0) | ||
|  |       p->lzma2Props.numTotalThreads = p->numTotalThreads; | ||
|  |     return; | ||
|  |   } | ||
|  |   else | ||
|  |   { | ||
|  |     CLzma2EncProps *lzma2 = &p->lzma2Props; | ||
|  |     if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
|  |     { | ||
|  |       // xz-auto
 | ||
|  |       p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
|  | 
 | ||
|  |       if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
|  |       { | ||
|  |         // if (xz-auto && lzma2-solid) - we use solid for both
 | ||
|  |         p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID; | ||
|  |         p->numBlockThreads_Reduced = 1; | ||
|  |         p->numBlockThreads_Max = 1; | ||
|  |         if (p->lzma2Props.numTotalThreads <= 0) | ||
|  |           p->lzma2Props.numTotalThreads = p->numTotalThreads; | ||
|  |       } | ||
|  |       else | ||
|  |       { | ||
|  |         // if (xz-auto && (lzma2-auto || lzma2-fixed_)
 | ||
|  |         //   we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block
 | ||
|  |         CLzma2EncProps tp = p->lzma2Props; | ||
|  |         if (tp.numTotalThreads <= 0) | ||
|  |           tp.numTotalThreads = p->numTotalThreads; | ||
|  |          | ||
|  |         Lzma2EncProps_Normalize(&tp); | ||
|  |          | ||
|  |         p->blockSize = tp.blockSize; // fixed or solid
 | ||
|  |         p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; | ||
|  |         p->numBlockThreads_Max = tp.numBlockThreads_Max; | ||
|  |         if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
|  |           lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
 | ||
|  |         if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
|  |           lzma2->lzmaProps.reduceSize = tp.blockSize; | ||
|  |         lzma2->numBlockThreads_Reduced = 1; | ||
|  |         lzma2->numBlockThreads_Max = 1; | ||
|  |         return; | ||
|  |       } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |       // xz-fixed
 | ||
|  |       // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize
 | ||
|  |        | ||
|  |       p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
|  |       { | ||
|  |         UInt64 r = p->reduceSize; | ||
|  |         if (r > p->blockSize || r == (UInt64)(Int64)-1) | ||
|  |           r = p->blockSize; | ||
|  |         lzma2->lzmaProps.reduceSize = r; | ||
|  |       } | ||
|  |       if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
|  |         lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; | ||
|  |       else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
|  |         lzma2->blockSize = p->blockSize; | ||
|  |        | ||
|  |       XzEncProps_Normalize_Fixed(p); | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------- CLzma2WithFilters ---------- */ | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   CLzma2EncHandle lzma2; | ||
|  |   CSeqInFilter filter; | ||
|  | 
 | ||
|  |   #ifdef USE_SUBBLOCK
 | ||
|  |   CSbEncInStream sb; | ||
|  |   #endif
 | ||
|  | } CLzma2WithFilters; | ||
|  | 
 | ||
|  | 
 | ||
|  | static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) | ||
|  | { | ||
|  |   p->lzma2 = NULL; | ||
|  |   SeqInFilter_Construct(&p->filter); | ||
|  | 
 | ||
|  |   #ifdef USE_SUBBLOCK
 | ||
|  |   SbEncInStream_Construct(&p->sb, alloc); | ||
|  |   #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) | ||
|  | { | ||
|  |   if (!p->lzma2) | ||
|  |   { | ||
|  |     p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); | ||
|  |     if (!p->lzma2) | ||
|  |       return SZ_ERROR_MEM; | ||
|  |   } | ||
|  |   return SZ_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   #ifdef USE_SUBBLOCK
 | ||
|  |   SbEncInStream_Free(&p->sb); | ||
|  |   #endif
 | ||
|  | 
 | ||
|  |   SeqInFilter_Free(&p->filter, alloc); | ||
|  |   if (p->lzma2) | ||
|  |   { | ||
|  |     Lzma2Enc_Destroy(p->lzma2); | ||
|  |     p->lzma2 = NULL; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   UInt64 unpackSize; | ||
|  |   UInt64 totalSize; | ||
|  |   size_t headerSize; | ||
|  | } CXzEncBlockInfo; | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes Xz_CompressBlock( | ||
|  |     CLzma2WithFilters *lzmaf, | ||
|  |      | ||
|  |     ISeqOutStream *outStream, | ||
|  |     Byte *outBufHeader, | ||
|  |     Byte *outBufData, size_t outBufDataLimit, | ||
|  | 
 | ||
|  |     ISeqInStream *inStream, | ||
|  |     // UInt64 expectedSize,
 | ||
|  |     const Byte *inBuf, // used if (!inStream)
 | ||
|  |     size_t inBufSize,  // used if (!inStream), it's block size, props->blockSize is ignored
 | ||
|  | 
 | ||
|  |     const CXzProps *props, | ||
|  |     ICompressProgress *progress, | ||
|  |     int *inStreamFinished,  /* only for inStream version */ | ||
|  |     CXzEncBlockInfo *blockSizes, | ||
|  |     ISzAllocPtr alloc, | ||
|  |     ISzAllocPtr allocBig) | ||
|  | { | ||
|  |   CSeqCheckInStream checkInStream; | ||
|  |   CSeqSizeOutStream seqSizeOutStream; | ||
|  |   CXzBlock block; | ||
|  |   unsigned filterIndex = 0; | ||
|  |   CXzFilter *filter = NULL; | ||
|  |   const CXzFilterProps *fp = &props->filterProps; | ||
|  |   if (fp->id == 0) | ||
|  |     fp = NULL; | ||
|  |    | ||
|  |   *inStreamFinished = False; | ||
|  |    | ||
|  |   RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)); | ||
|  |    | ||
|  |   RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)); | ||
|  |    | ||
|  |   XzBlock_ClearFlags(&block); | ||
|  |   XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); | ||
|  |    | ||
|  |   if (fp) | ||
|  |   { | ||
|  |     filter = &block.filters[filterIndex++]; | ||
|  |     filter->id = fp->id; | ||
|  |     filter->propsSize = 0; | ||
|  |      | ||
|  |     if (fp->id == XZ_ID_Delta) | ||
|  |     { | ||
|  |       filter->props[0] = (Byte)(fp->delta - 1); | ||
|  |       filter->propsSize = 1; | ||
|  |     } | ||
|  |     else if (fp->ipDefined) | ||
|  |     { | ||
|  |       SetUi32(filter->props, fp->ip); | ||
|  |       filter->propsSize = 4; | ||
|  |     } | ||
|  |   } | ||
|  |    | ||
|  |   { | ||
|  |     CXzFilter *f = &block.filters[filterIndex++]; | ||
|  |     f->id = XZ_ID_LZMA2; | ||
|  |     f->propsSize = 1; | ||
|  |     f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); | ||
|  |   } | ||
|  |    | ||
|  |   seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; | ||
|  |   seqSizeOutStream.realStream = outStream; | ||
|  |   seqSizeOutStream.outBuf = outBufData; | ||
|  |   seqSizeOutStream.outBufLimit = outBufDataLimit; | ||
|  |   seqSizeOutStream.processed = 0; | ||
|  |      | ||
|  |   /*
 | ||
|  |   if (expectedSize != (UInt64)(Int64)-1) | ||
|  |   { | ||
|  |     block.unpackSize = expectedSize; | ||
|  |     if (props->blockSize != (UInt64)(Int64)-1) | ||
|  |       if (expectedSize > props->blockSize) | ||
|  |         block.unpackSize = props->blockSize; | ||
|  |     XzBlock_SetHasUnpackSize(&block); | ||
|  |   } | ||
|  |   */ | ||
|  | 
 | ||
|  |   if (outStream) | ||
|  |   { | ||
|  |     RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); | ||
|  |   } | ||
|  |    | ||
|  |   checkInStream.vt.Read = SeqCheckInStream_Read; | ||
|  |   SeqCheckInStream_Init(&checkInStream, props->checkId); | ||
|  |    | ||
|  |   checkInStream.realStream = inStream; | ||
|  |   checkInStream.data = inBuf; | ||
|  |   checkInStream.limit = props->blockSize; | ||
|  |   if (!inStream) | ||
|  |     checkInStream.limit = inBufSize; | ||
|  | 
 | ||
|  |   if (fp) | ||
|  |   { | ||
|  |     #ifdef USE_SUBBLOCK
 | ||
|  |     if (fp->id == XZ_ID_Subblock) | ||
|  |     { | ||
|  |       lzmaf->sb.inStream = &checkInStream.vt; | ||
|  |       RINOK(SbEncInStream_Init(&lzmaf->sb)); | ||
|  |     } | ||
|  |     else | ||
|  |     #endif
 | ||
|  |     { | ||
|  |       lzmaf->filter.realStream = &checkInStream.vt; | ||
|  |       RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   { | ||
|  |     SRes res; | ||
|  |     Byte *outBuf = NULL; | ||
|  |     size_t outSize = 0; | ||
|  |     Bool useStream = (fp || inStream); | ||
|  |     // useStream = True;
 | ||
|  |      | ||
|  |     if (!useStream) | ||
|  |     { | ||
|  |       XzCheck_Update(&checkInStream.check, inBuf, inBufSize); | ||
|  |       checkInStream.processed = inBufSize; | ||
|  |     } | ||
|  |      | ||
|  |     if (!outStream) | ||
|  |     { | ||
|  |       outBuf = seqSizeOutStream.outBuf; //  + (size_t)seqSizeOutStream.processed;
 | ||
|  |       outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed;
 | ||
|  |     } | ||
|  |      | ||
|  |     res = Lzma2Enc_Encode2(lzmaf->lzma2, | ||
|  |         outBuf ? NULL : &seqSizeOutStream.vt, | ||
|  |         outBuf, | ||
|  |         outBuf ? &outSize : NULL, | ||
|  |        | ||
|  |         useStream ? | ||
|  |           (fp ? | ||
|  |             ( | ||
|  |             #ifdef USE_SUBBLOCK
 | ||
|  |             (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: | ||
|  |             #endif
 | ||
|  |             &lzmaf->filter.p) : | ||
|  |             &checkInStream.vt) : NULL, | ||
|  |        | ||
|  |         useStream ? NULL : inBuf, | ||
|  |         useStream ? 0 : inBufSize, | ||
|  |          | ||
|  |         progress); | ||
|  |      | ||
|  |     if (outBuf) | ||
|  |       seqSizeOutStream.processed += outSize; | ||
|  |      | ||
|  |     RINOK(res); | ||
|  |     blockSizes->unpackSize = checkInStream.processed; | ||
|  |   } | ||
|  |   { | ||
|  |     Byte buf[4 + 64]; | ||
|  |     unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); | ||
|  |     UInt64 packSize = seqSizeOutStream.processed; | ||
|  |      | ||
|  |     buf[0] = 0; | ||
|  |     buf[1] = 0; | ||
|  |     buf[2] = 0; | ||
|  |     buf[3] = 0; | ||
|  |      | ||
|  |     SeqCheckInStream_GetDigest(&checkInStream, buf + 4); | ||
|  |     RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))); | ||
|  |      | ||
|  |     blockSizes->totalSize = seqSizeOutStream.processed - padSize; | ||
|  |      | ||
|  |     if (!outStream) | ||
|  |     { | ||
|  |       seqSizeOutStream.outBuf = outBufHeader; | ||
|  |       seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; | ||
|  |       seqSizeOutStream.processed = 0; | ||
|  |        | ||
|  |       block.unpackSize = blockSizes->unpackSize; | ||
|  |       XzBlock_SetHasUnpackSize(&block); | ||
|  |        | ||
|  |       block.packSize = packSize; | ||
|  |       XzBlock_SetHasPackSize(&block); | ||
|  |        | ||
|  |       RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); | ||
|  |        | ||
|  |       blockSizes->headerSize = (size_t)seqSizeOutStream.processed; | ||
|  |       blockSizes->totalSize += seqSizeOutStream.processed; | ||
|  |     } | ||
|  |   } | ||
|  |    | ||
|  |   if (inStream) | ||
|  |     *inStreamFinished = checkInStream.realStreamFinished; | ||
|  |   else | ||
|  |   { | ||
|  |     *inStreamFinished = False; | ||
|  |     if (checkInStream.processed != inBufSize) | ||
|  |       return SZ_ERROR_FAIL; | ||
|  |   } | ||
|  | 
 | ||
|  |   return SZ_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ICompressProgress vt; | ||
|  |   ICompressProgress *progress; | ||
|  |   UInt64 inOffset; | ||
|  |   UInt64 outOffset; | ||
|  | } CCompressProgress_XzEncOffset; | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) | ||
|  | { | ||
|  |   const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt); | ||
|  |   inSize += p->inOffset; | ||
|  |   outSize += p->outOffset; | ||
|  |   return ICompressProgress_Progress(p->progress, inSize, outSize); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ISzAllocPtr alloc; | ||
|  |   ISzAllocPtr allocBig; | ||
|  | 
 | ||
|  |   CXzProps xzProps; | ||
|  |   UInt64 expectedDataSize; | ||
|  | 
 | ||
|  |   CXzEncIndex xzIndex; | ||
|  | 
 | ||
|  |   CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX]; | ||
|  |    | ||
|  |   size_t outBufSize;       /* size of allocated outBufs[i] */ | ||
|  |   Byte *outBufs[MTCODER__BLOCKS_MAX]; | ||
|  | 
 | ||
|  |   #ifndef _7ZIP_ST
 | ||
|  |   unsigned checkType; | ||
|  |   ISeqOutStream *outStream; | ||
|  |   Bool mtCoder_WasConstructed; | ||
|  |   CMtCoder mtCoder; | ||
|  |   CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX]; | ||
|  |   #endif
 | ||
|  | 
 | ||
|  | } CXzEnc; | ||
|  | 
 | ||
|  | 
 | ||
|  | static void XzEnc_Construct(CXzEnc *p) | ||
|  | { | ||
|  |   unsigned i; | ||
|  | 
 | ||
|  |   XzEncIndex_Construct(&p->xzIndex); | ||
|  | 
 | ||
|  |   for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
|  |     Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); | ||
|  | 
 | ||
|  |   #ifndef _7ZIP_ST
 | ||
|  |   p->mtCoder_WasConstructed = False; | ||
|  |   { | ||
|  |     for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
|  |       p->outBufs[i] = NULL; | ||
|  |     p->outBufSize = 0; | ||
|  |   } | ||
|  |   #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static void XzEnc_FreeOutBufs(CXzEnc *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; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) | ||
|  | { | ||
|  |   unsigned i; | ||
|  | 
 | ||
|  |   XzEncIndex_Free(&p->xzIndex, alloc); | ||
|  | 
 | ||
|  |   for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
|  |     Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); | ||
|  |    | ||
|  |   #ifndef _7ZIP_ST
 | ||
|  |   if (p->mtCoder_WasConstructed) | ||
|  |   { | ||
|  |     MtCoder_Destruct(&p->mtCoder); | ||
|  |     p->mtCoder_WasConstructed = False; | ||
|  |   } | ||
|  |   XzEnc_FreeOutBufs(p); | ||
|  |   #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
|  | { | ||
|  |   CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); | ||
|  |   if (!p) | ||
|  |     return NULL; | ||
|  |   XzEnc_Construct(p); | ||
|  |   XzProps_Init(&p->xzProps); | ||
|  |   XzProps_Normalize(&p->xzProps); | ||
|  |   p->expectedDataSize = (UInt64)(Int64)-1; | ||
|  |   p->alloc = alloc; | ||
|  |   p->allocBig = allocBig; | ||
|  |   return p; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void XzEnc_Destroy(CXzEncHandle pp) | ||
|  | { | ||
|  |   CXzEnc *p = (CXzEnc *)pp; | ||
|  |   XzEnc_Free(p, p->alloc); | ||
|  |   ISzAlloc_Free(p->alloc, p); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props) | ||
|  | { | ||
|  |   CXzEnc *p = (CXzEnc *)pp; | ||
|  |   p->xzProps = *props; | ||
|  |   XzProps_Normalize(&p->xzProps); | ||
|  |   return SZ_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize) | ||
|  | { | ||
|  |   CXzEnc *p = (CXzEnc *)pp; | ||
|  |   p->expectedDataSize = expectedDataSiize; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifndef _7ZIP_ST
 | ||
|  | 
 | ||
|  | static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, | ||
|  |     const Byte *src, size_t srcSize, int finished) | ||
|  | { | ||
|  |   CXzEnc *me = (CXzEnc *)pp; | ||
|  |   SRes res; | ||
|  |   CMtProgressThunk progressThunk; | ||
|  | 
 | ||
|  |   Byte *dest = me->outBufs[outBufIndex]; | ||
|  | 
 | ||
|  |   UNUSED_VAR(finished) | ||
|  | 
 | ||
|  |   { | ||
|  |     CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; | ||
|  |     bInfo->totalSize = 0; | ||
|  |     bInfo->unpackSize = 0; | ||
|  |     bInfo->headerSize = 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; | ||
|  | 
 | ||
|  |   { | ||
|  |     CXzEncBlockInfo blockSizes; | ||
|  |     int inStreamFinished; | ||
|  | 
 | ||
|  |     res = Xz_CompressBlock( | ||
|  |         &me->lzmaf_Items[coderIndex], | ||
|  |          | ||
|  |         NULL, | ||
|  |         dest, | ||
|  |         dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, | ||
|  | 
 | ||
|  |         NULL, | ||
|  |         // srcSize, // expectedSize
 | ||
|  |         src, srcSize, | ||
|  | 
 | ||
|  |         &me->xzProps, | ||
|  |         &progressThunk.vt, | ||
|  |         &inStreamFinished, | ||
|  |         &blockSizes, | ||
|  |         me->alloc, | ||
|  |         me->allocBig); | ||
|  |      | ||
|  |     if (res == SZ_OK) | ||
|  |       me->EncBlocks[outBufIndex] = blockSizes; | ||
|  | 
 | ||
|  |     return res; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) | ||
|  | { | ||
|  |   CXzEnc *me = (CXzEnc *)pp; | ||
|  | 
 | ||
|  |   const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; | ||
|  |   const Byte *data = me->outBufs[outBufIndex]; | ||
|  | 
 | ||
|  |   RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)); | ||
|  | 
 | ||
|  |   { | ||
|  |     UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); | ||
|  |     RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)); | ||
|  |   } | ||
|  | 
 | ||
|  |   return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); | ||
|  | } | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) | ||
|  | { | ||
|  |   CXzEnc *p = (CXzEnc *)pp; | ||
|  | 
 | ||
|  |   const CXzProps *props = &p->xzProps; | ||
|  | 
 | ||
|  |   XzEncIndex_Init(&p->xzIndex); | ||
|  |   { | ||
|  |     UInt64 numBlocks = 1; | ||
|  |     UInt64 blockSize = props->blockSize; | ||
|  |      | ||
|  |     if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID | ||
|  |         && props->reduceSize != (UInt64)(Int64)-1) | ||
|  |     { | ||
|  |       numBlocks = props->reduceSize / blockSize; | ||
|  |       if (numBlocks * blockSize != props->reduceSize) | ||
|  |         numBlocks++; | ||
|  |     } | ||
|  |     else | ||
|  |       blockSize = (UInt64)1 << 62; | ||
|  |      | ||
|  |     RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)); | ||
|  |   } | ||
|  | 
 | ||
|  |   RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)); | ||
|  | 
 | ||
|  | 
 | ||
|  |   #ifndef _7ZIP_ST
 | ||
|  |   if (props->numBlockThreads_Reduced > 1) | ||
|  |   { | ||
|  |     IMtCoderCallback2 vt; | ||
|  | 
 | ||
|  |     if (!p->mtCoder_WasConstructed) | ||
|  |     { | ||
|  |       p->mtCoder_WasConstructed = True; | ||
|  |       MtCoder_Construct(&p->mtCoder); | ||
|  |     } | ||
|  | 
 | ||
|  |     vt.Code = XzEnc_MtCallback_Code; | ||
|  |     vt.Write = XzEnc_MtCallback_Write; | ||
|  | 
 | ||
|  |     p->checkType = props->checkId; | ||
|  |     p->xzProps = *props; | ||
|  |      | ||
|  |     p->outStream = outStream; | ||
|  | 
 | ||
|  |     p->mtCoder.allocBig = p->allocBig; | ||
|  |     p->mtCoder.progress = progress; | ||
|  |     p->mtCoder.inStream = inStream; | ||
|  |     p->mtCoder.inData = NULL; | ||
|  |     p->mtCoder.inDataSize = 0; | ||
|  |     p->mtCoder.mtCallback = &vt; | ||
|  |     p->mtCoder.mtCallbackObject = p; | ||
|  | 
 | ||
|  |     if (   props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID | ||
|  |         || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO) | ||
|  |       return SZ_ERROR_FAIL; | ||
|  | 
 | ||
|  |     p->mtCoder.blockSize = (size_t)props->blockSize; | ||
|  |     if (p->mtCoder.blockSize != props->blockSize) | ||
|  |       return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ | ||
|  | 
 | ||
|  |     { | ||
|  |       size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); | ||
|  |       if (destBlockSize < p->mtCoder.blockSize) | ||
|  |         return SZ_ERROR_PARAM; | ||
|  |       if (p->outBufSize != destBlockSize) | ||
|  |         XzEnc_FreeOutBufs(p); | ||
|  |       p->outBufSize = destBlockSize; | ||
|  |     } | ||
|  | 
 | ||
|  |     p->mtCoder.numThreadsMax = props->numBlockThreads_Max; | ||
|  |     p->mtCoder.expectedDataSize = p->expectedDataSize; | ||
|  |      | ||
|  |     RINOK(MtCoder_Code(&p->mtCoder)); | ||
|  |   } | ||
|  |   else | ||
|  |   #endif
 | ||
|  |   { | ||
|  |     int writeStartSizes; | ||
|  |     CCompressProgress_XzEncOffset progress2; | ||
|  |     Byte *bufData = NULL; | ||
|  |     size_t bufSize = 0; | ||
|  | 
 | ||
|  |     progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; | ||
|  |     progress2.inOffset = 0; | ||
|  |     progress2.outOffset = 0; | ||
|  |     progress2.progress = progress; | ||
|  |      | ||
|  |     writeStartSizes = 0; | ||
|  |      | ||
|  |     if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID) | ||
|  |     { | ||
|  |       writeStartSizes = (props->forceWriteSizesInHeader > 0); | ||
|  |        | ||
|  |       if (writeStartSizes) | ||
|  |       { | ||
|  |         size_t t2; | ||
|  |         size_t t = (size_t)props->blockSize; | ||
|  |         if (t != props->blockSize) | ||
|  |           return SZ_ERROR_PARAM; | ||
|  |         t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); | ||
|  |         if (t < props->blockSize) | ||
|  |           return SZ_ERROR_PARAM; | ||
|  |         t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; | ||
|  |         if (!p->outBufs[0] || t2 != p->outBufSize) | ||
|  |         { | ||
|  |           XzEnc_FreeOutBufs(p); | ||
|  |           p->outBufs[0] = ISzAlloc_Alloc(p->alloc, t2); | ||
|  |           if (!p->outBufs[0]) | ||
|  |             return SZ_ERROR_MEM; | ||
|  |           p->outBufSize = t2; | ||
|  |         } | ||
|  |         bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; | ||
|  |         bufSize = t; | ||
|  |       } | ||
|  |     } | ||
|  |      | ||
|  |     for (;;) | ||
|  |     { | ||
|  |       CXzEncBlockInfo blockSizes; | ||
|  |       int inStreamFinished; | ||
|  |        | ||
|  |       /*
 | ||
|  |       UInt64 rem = (UInt64)(Int64)-1; | ||
|  |       if (props->reduceSize != (UInt64)(Int64)-1 | ||
|  |           && props->reduceSize >= progress2.inOffset) | ||
|  |         rem = props->reduceSize - progress2.inOffset; | ||
|  |       */ | ||
|  |        | ||
|  |       RINOK(Xz_CompressBlock( | ||
|  |           &p->lzmaf_Items[0], | ||
|  |            | ||
|  |           writeStartSizes ? NULL : outStream, | ||
|  |           writeStartSizes ? p->outBufs[0] : NULL, | ||
|  |           bufData, bufSize, | ||
|  |            | ||
|  |           inStream, | ||
|  |           // rem,
 | ||
|  |           NULL, 0, | ||
|  |            | ||
|  |           props, | ||
|  |           progress ? &progress2.vt : NULL, | ||
|  |           &inStreamFinished, | ||
|  |           &blockSizes, | ||
|  |           p->alloc, | ||
|  |           p->allocBig)); | ||
|  | 
 | ||
|  |       { | ||
|  |         UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); | ||
|  |        | ||
|  |         if (writeStartSizes) | ||
|  |         { | ||
|  |           RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)); | ||
|  |           RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)); | ||
|  |         } | ||
|  |          | ||
|  |         RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)); | ||
|  |          | ||
|  |         progress2.inOffset += blockSizes.unpackSize; | ||
|  |         progress2.outOffset += totalPackFull; | ||
|  |       } | ||
|  |          | ||
|  |       if (inStreamFinished) | ||
|  |         break; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #include "Alloc.h"
 | ||
|  | 
 | ||
|  | SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, | ||
|  |     const CXzProps *props, ICompressProgress *progress) | ||
|  | { | ||
|  |   SRes res; | ||
|  |   CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); | ||
|  |   if (!xz) | ||
|  |     return SZ_ERROR_MEM; | ||
|  |   res = XzEnc_SetProps(xz, props); | ||
|  |   if (res == SZ_OK) | ||
|  |     res = XzEnc_Encode(xz, outStream, inStream, progress); | ||
|  |   XzEnc_Destroy(xz); | ||
|  |   return res; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | SRes Xz_EncodeEmpty(ISeqOutStream *outStream) | ||
|  | { | ||
|  |   SRes res; | ||
|  |   CXzEncIndex xzIndex; | ||
|  |   XzEncIndex_Construct(&xzIndex); | ||
|  |   res = Xz_WriteHeader((CXzStreamFlags)0, outStream); | ||
|  |   if (res == SZ_OK) | ||
|  |     res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); | ||
|  |   XzEncIndex_Free(&xzIndex, NULL); // g_Alloc
 | ||
|  |   return res; | ||
|  | } |