• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* XzEnc.c -- Xz Encode
2 2023-04-13 : Igor Pavlov : Public domain */
3 
4 #include "Precomp.h"
5 
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "7zCrc.h"
10 #include "Bra.h"
11 #include "CpuArch.h"
12 
13 #ifdef USE_SUBBLOCK
14 #include "Bcj3Enc.c"
15 #include "SbFind.c"
16 #include "SbEnc.c"
17 #endif
18 
19 #include "XzEnc.h"
20 
21 // #define Z7_ST
22 
23 #ifndef Z7_ST
24 #include "MtCoder.h"
25 #else
26 #define MTCODER_THREADS_MAX 1
27 #define MTCODER_BLOCKS_MAX 1
28 #endif
29 
30 #define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3)
31 
32 /* max pack size for LZMA2 block + check-64bytrs: */
33 #define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)
34 
35 #define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize))
36 
37 
38 // #define XzBlock_ClearFlags(p)       (p)->flags = 0;
39 #define XzBlock_ClearFlags_SetNumFilters(p, n) (p)->flags = (Byte)((n) - 1);
40 #define XzBlock_SetHasPackSize(p)   (p)->flags |= XZ_BF_PACK_SIZE;
41 #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
42 
43 
WriteBytes(ISeqOutStreamPtr s,const void * buf,size_t size)44 static SRes WriteBytes(ISeqOutStreamPtr s, const void *buf, size_t size)
45 {
46   return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
47 }
48 
WriteBytes_UpdateCrc(ISeqOutStreamPtr s,const void * buf,size_t size,UInt32 * crc)49 static SRes WriteBytes_UpdateCrc(ISeqOutStreamPtr s, const void *buf, size_t size, UInt32 *crc)
50 {
51   *crc = CrcUpdate(*crc, buf, size);
52   return WriteBytes(s, buf, size);
53 }
54 
55 
Xz_WriteHeader(CXzStreamFlags f,ISeqOutStreamPtr s)56 static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStreamPtr s)
57 {
58   UInt32 crc;
59   Byte header[XZ_STREAM_HEADER_SIZE];
60   memcpy(header, XZ_SIG, XZ_SIG_SIZE);
61   header[XZ_SIG_SIZE] = (Byte)(f >> 8);
62   header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
63   crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
64   SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc)
65   return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
66 }
67 
68 
XzBlock_WriteHeader(const CXzBlock * p,ISeqOutStreamPtr s)69 static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStreamPtr s)
70 {
71   Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
72 
73   unsigned pos = 1;
74   unsigned numFilters, i;
75   header[pos++] = p->flags;
76 
77   if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
78   if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
79   numFilters = XzBlock_GetNumFilters(p);
80 
81   for (i = 0; i < numFilters; i++)
82   {
83     const CXzFilter *f = &p->filters[i];
84     pos += Xz_WriteVarInt(header + pos, f->id);
85     pos += Xz_WriteVarInt(header + pos, f->propsSize);
86     memcpy(header + pos, f->props, f->propsSize);
87     pos += f->propsSize;
88   }
89 
90   while ((pos & 3) != 0)
91     header[pos++] = 0;
92 
93   header[0] = (Byte)(pos >> 2);
94   SetUi32(header + pos, CrcCalc(header, pos))
95   return WriteBytes(s, header, pos + 4);
96 }
97 
98 
99 
100 
101 typedef struct
102 {
103   size_t numBlocks;
104   size_t size;
105   size_t allocated;
106   Byte *blocks;
107 } CXzEncIndex;
108 
109 
XzEncIndex_Construct(CXzEncIndex * p)110 static void XzEncIndex_Construct(CXzEncIndex *p)
111 {
112   p->numBlocks = 0;
113   p->size = 0;
114   p->allocated = 0;
115   p->blocks = NULL;
116 }
117 
XzEncIndex_Init(CXzEncIndex * p)118 static void XzEncIndex_Init(CXzEncIndex *p)
119 {
120   p->numBlocks = 0;
121   p->size = 0;
122 }
123 
XzEncIndex_Free(CXzEncIndex * p,ISzAllocPtr alloc)124 static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc)
125 {
126   if (p->blocks)
127   {
128     ISzAlloc_Free(alloc, p->blocks);
129     p->blocks = NULL;
130   }
131   p->numBlocks = 0;
132   p->size = 0;
133   p->allocated = 0;
134 }
135 
136 
XzEncIndex_ReAlloc(CXzEncIndex * p,size_t newSize,ISzAllocPtr alloc)137 static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc)
138 {
139   Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize);
140   if (!blocks)
141     return SZ_ERROR_MEM;
142   if (p->size != 0)
143     memcpy(blocks, p->blocks, p->size);
144   if (p->blocks)
145     ISzAlloc_Free(alloc, p->blocks);
146   p->blocks = blocks;
147   p->allocated = newSize;
148   return SZ_OK;
149 }
150 
151 
XzEncIndex_PreAlloc(CXzEncIndex * p,UInt64 numBlocks,UInt64 unpackSize,UInt64 totalSize,ISzAllocPtr alloc)152 static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
153 {
154   UInt64 pos;
155   {
156     Byte buf[32];
157     unsigned pos2 = Xz_WriteVarInt(buf, totalSize);
158     pos2 += Xz_WriteVarInt(buf + pos2, unpackSize);
159     pos = numBlocks * pos2;
160   }
161 
162   if (pos <= p->allocated - p->size)
163     return SZ_OK;
164   {
165     UInt64 newSize64 = p->size + pos;
166     size_t newSize = (size_t)newSize64;
167     if (newSize != newSize64)
168       return SZ_ERROR_MEM;
169     return XzEncIndex_ReAlloc(p, newSize, alloc);
170   }
171 }
172 
173 
XzEncIndex_AddIndexRecord(CXzEncIndex * p,UInt64 unpackSize,UInt64 totalSize,ISzAllocPtr alloc)174 static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
175 {
176   Byte buf[32];
177   unsigned pos = Xz_WriteVarInt(buf, totalSize);
178   pos += Xz_WriteVarInt(buf + pos, unpackSize);
179 
180   if (pos > p->allocated - p->size)
181   {
182     size_t newSize = p->allocated * 2 + 16 * 2;
183     if (newSize < p->size + pos)
184       return SZ_ERROR_MEM;
185     RINOK(XzEncIndex_ReAlloc(p, newSize, alloc))
186   }
187   memcpy(p->blocks + p->size, buf, pos);
188   p->size += pos;
189   p->numBlocks++;
190   return SZ_OK;
191 }
192 
193 
XzEncIndex_WriteFooter(const CXzEncIndex * p,CXzStreamFlags flags,ISeqOutStreamPtr s)194 static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStreamPtr s)
195 {
196   Byte buf[32];
197   UInt64 globalPos;
198   UInt32 crc = CRC_INIT_VAL;
199   unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
200 
201   globalPos = pos;
202   buf[0] = 0;
203   RINOK(WriteBytes_UpdateCrc(s, buf, pos, &crc))
204   RINOK(WriteBytes_UpdateCrc(s, p->blocks, p->size, &crc))
205   globalPos += p->size;
206 
207   pos = XZ_GET_PAD_SIZE(globalPos);
208   buf[1] = 0;
209   buf[2] = 0;
210   buf[3] = 0;
211   globalPos += pos;
212 
213   crc = CrcUpdate(crc, buf + 4 - pos, pos);
214   SetUi32(buf + 4, CRC_GET_DIGEST(crc))
215 
216   SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2))
217   buf[8 + 8] = (Byte)(flags >> 8);
218   buf[8 + 9] = (Byte)(flags & 0xFF);
219   SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6))
220   buf[8 + 10] = XZ_FOOTER_SIG_0;
221   buf[8 + 11] = XZ_FOOTER_SIG_1;
222 
223   return WriteBytes(s, buf + 4 - pos, pos + 4 + 12);
224 }
225 
226 
227 
228 /* ---------- CSeqCheckInStream ---------- */
229 
230 typedef struct
231 {
232   ISeqInStream vt;
233   ISeqInStreamPtr realStream;
234   const Byte *data;
235   UInt64 limit;
236   UInt64 processed;
237   int realStreamFinished;
238   CXzCheck check;
239 } CSeqCheckInStream;
240 
SeqCheckInStream_Init(CSeqCheckInStream * p,unsigned checkMode)241 static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode)
242 {
243   p->limit = (UInt64)(Int64)-1;
244   p->processed = 0;
245   p->realStreamFinished = 0;
246   XzCheck_Init(&p->check, checkMode);
247 }
248 
SeqCheckInStream_GetDigest(CSeqCheckInStream * p,Byte * digest)249 static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
250 {
251   XzCheck_Final(&p->check, digest);
252 }
253 
SeqCheckInStream_Read(ISeqInStreamPtr pp,void * data,size_t * size)254 static SRes SeqCheckInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size)
255 {
256   Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqCheckInStream)
257   size_t size2 = *size;
258   SRes res = SZ_OK;
259 
260   if (p->limit != (UInt64)(Int64)-1)
261   {
262     UInt64 rem = p->limit - p->processed;
263     if (size2 > rem)
264       size2 = (size_t)rem;
265   }
266   if (size2 != 0)
267   {
268     if (p->realStream)
269     {
270       res = ISeqInStream_Read(p->realStream, data, &size2);
271       p->realStreamFinished = (size2 == 0) ? 1 : 0;
272     }
273     else
274       memcpy(data, p->data + (size_t)p->processed, size2);
275     XzCheck_Update(&p->check, data, size2);
276     p->processed += size2;
277   }
278   *size = size2;
279   return res;
280 }
281 
282 
283 /* ---------- CSeqSizeOutStream ---------- */
284 
285 typedef struct
286 {
287   ISeqOutStream vt;
288   ISeqOutStreamPtr realStream;
289   Byte *outBuf;
290   size_t outBufLimit;
291   UInt64 processed;
292 } CSeqSizeOutStream;
293 
SeqSizeOutStream_Write(ISeqOutStreamPtr pp,const void * data,size_t size)294 static size_t SeqSizeOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
295 {
296   Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqSizeOutStream)
297   if (p->realStream)
298     size = ISeqOutStream_Write(p->realStream, data, size);
299   else
300   {
301     if (size > p->outBufLimit - (size_t)p->processed)
302       return 0;
303     memcpy(p->outBuf + (size_t)p->processed, data, size);
304   }
305   p->processed += size;
306   return size;
307 }
308 
309 
310 /* ---------- CSeqInFilter ---------- */
311 
312 #define FILTER_BUF_SIZE (1 << 20)
313 
314 typedef struct
315 {
316   ISeqInStream vt;
317   ISeqInStreamPtr realStream;
318   IStateCoder StateCoder;
319   Byte *buf;
320   size_t curPos;
321   size_t endPos;
322   int srcWasFinished;
323 } CSeqInFilter;
324 
325 
326 static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Enc[] =
327 {
328   Z7_BRANCH_CONV_ENC(PPC),
329   Z7_BRANCH_CONV_ENC(IA64),
330   Z7_BRANCH_CONV_ENC(ARM),
331   Z7_BRANCH_CONV_ENC(ARMT),
332   Z7_BRANCH_CONV_ENC(SPARC),
333   Z7_BRANCH_CONV_ENC(ARM64)
334 };
335 
XzBcFilterStateBase_Filter_Enc(CXzBcFilterStateBase * p,Byte * data,SizeT size)336 static SizeT XzBcFilterStateBase_Filter_Enc(CXzBcFilterStateBase *p, Byte *data, SizeT size)
337 {
338   switch (p->methodId)
339   {
340     case XZ_ID_Delta:
341       Delta_Encode(p->delta_State, p->delta, data, size);
342       break;
343     case XZ_ID_X86:
344       size = (SizeT)(z7_BranchConvSt_X86_Enc(data, size, p->ip, &p->X86_State) - data);
345       break;
346     default:
347       if (p->methodId >= XZ_ID_PPC)
348       {
349         const UInt32 i = p->methodId - XZ_ID_PPC;
350         if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Enc))
351           size = (SizeT)(g_Funcs_BranchConv_RISC_Enc[i](data, size, p->ip) - data);
352       }
353       break;
354   }
355   p->ip += (UInt32)size;
356   return size;
357 }
358 
359 
SeqInFilter_Init(CSeqInFilter * p,const CXzFilter * props,ISzAllocPtr alloc)360 static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc)
361 {
362   if (!p->buf)
363   {
364     p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE);
365     if (!p->buf)
366       return SZ_ERROR_MEM;
367   }
368   p->curPos = p->endPos = 0;
369   p->srcWasFinished = 0;
370   RINOK(Xz_StateCoder_Bc_SetFromMethod_Func(&p->StateCoder, props->id, XzBcFilterStateBase_Filter_Enc, alloc))
371   RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc))
372   p->StateCoder.Init(p->StateCoder.p);
373   return SZ_OK;
374 }
375 
376 
SeqInFilter_Read(ISeqInStreamPtr pp,void * data,size_t * size)377 static SRes SeqInFilter_Read(ISeqInStreamPtr pp, void *data, size_t *size)
378 {
379   Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInFilter)
380   const size_t sizeOriginal = *size;
381   if (sizeOriginal == 0)
382     return SZ_OK;
383   *size = 0;
384 
385   for (;;)
386   {
387     if (!p->srcWasFinished && p->curPos == p->endPos)
388     {
389       p->curPos = 0;
390       p->endPos = FILTER_BUF_SIZE;
391       RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos))
392       if (p->endPos == 0)
393         p->srcWasFinished = 1;
394     }
395     {
396       SizeT srcLen = p->endPos - p->curPos;
397       ECoderStatus status;
398       SRes res;
399       *size = sizeOriginal;
400       res = p->StateCoder.Code2(p->StateCoder.p,
401           (Byte *)data, size,
402           p->buf + p->curPos, &srcLen,
403           p->srcWasFinished, CODER_FINISH_ANY,
404           &status);
405       p->curPos += srcLen;
406       if (*size != 0 || srcLen == 0 || res != SZ_OK)
407         return res;
408     }
409   }
410 }
411 
SeqInFilter_Construct(CSeqInFilter * p)412 static void SeqInFilter_Construct(CSeqInFilter *p)
413 {
414   p->buf = NULL;
415   p->StateCoder.p = NULL;
416   p->vt.Read = SeqInFilter_Read;
417 }
418 
SeqInFilter_Free(CSeqInFilter * p,ISzAllocPtr alloc)419 static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
420 {
421   if (p->StateCoder.p)
422   {
423     p->StateCoder.Free(p->StateCoder.p, alloc);
424     p->StateCoder.p = NULL;
425   }
426   if (p->buf)
427   {
428     ISzAlloc_Free(alloc, p->buf);
429     p->buf = NULL;
430   }
431 }
432 
433 
434 /* ---------- CSbEncInStream ---------- */
435 
436 #ifdef USE_SUBBLOCK
437 
438 typedef struct
439 {
440   ISeqInStream vt;
441   ISeqInStreamPtr inStream;
442   CSbEnc enc;
443 } CSbEncInStream;
444 
SbEncInStream_Read(ISeqInStreamPtr pp,void * data,size_t * size)445 static SRes SbEncInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size)
446 {
447   CSbEncInStream *p = Z7_CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt);
448   size_t sizeOriginal = *size;
449   if (sizeOriginal == 0)
450     return SZ_OK;
451 
452   for (;;)
453   {
454     if (p->enc.needRead && !p->enc.readWasFinished)
455     {
456       size_t processed = p->enc.needReadSizeMax;
457       RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed))
458       p->enc.readPos += processed;
459       if (processed == 0)
460       {
461         p->enc.readWasFinished = True;
462         p->enc.isFinalFinished = True;
463       }
464       p->enc.needRead = False;
465     }
466 
467     *size = sizeOriginal;
468     RINOK(SbEnc_Read(&p->enc, data, size))
469     if (*size != 0 || !p->enc.needRead)
470       return SZ_OK;
471   }
472 }
473 
SbEncInStream_Construct(CSbEncInStream * p,ISzAllocPtr alloc)474 void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
475 {
476   SbEnc_Construct(&p->enc, alloc);
477   p->vt.Read = SbEncInStream_Read;
478 }
479 
SbEncInStream_Init(CSbEncInStream * p)480 SRes SbEncInStream_Init(CSbEncInStream *p)
481 {
482   return SbEnc_Init(&p->enc);
483 }
484 
SbEncInStream_Free(CSbEncInStream * p)485 void SbEncInStream_Free(CSbEncInStream *p)
486 {
487   SbEnc_Free(&p->enc);
488 }
489 
490 #endif
491 
492 
493 
494 /* ---------- CXzProps ---------- */
495 
496 
XzFilterProps_Init(CXzFilterProps * p)497 void XzFilterProps_Init(CXzFilterProps *p)
498 {
499   p->id = 0;
500   p->delta = 0;
501   p->ip = 0;
502   p->ipDefined = False;
503 }
504 
XzProps_Init(CXzProps * p)505 void XzProps_Init(CXzProps *p)
506 {
507   p->checkId = XZ_CHECK_CRC32;
508   p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO;
509   p->numBlockThreads_Reduced = -1;
510   p->numBlockThreads_Max = -1;
511   p->numTotalThreads = -1;
512   p->reduceSize = (UInt64)(Int64)-1;
513   p->forceWriteSizesInHeader = 0;
514   // p->forceWriteSizesInHeader = 1;
515 
516   XzFilterProps_Init(&p->filterProps);
517   Lzma2EncProps_Init(&p->lzma2Props);
518 }
519 
520 
XzEncProps_Normalize_Fixed(CXzProps * p)521 static void XzEncProps_Normalize_Fixed(CXzProps *p)
522 {
523   UInt64 fileSize;
524   int t1, t1n, t2, t2r, t3;
525   {
526     CLzma2EncProps tp = p->lzma2Props;
527     if (tp.numTotalThreads <= 0)
528       tp.numTotalThreads = p->numTotalThreads;
529     Lzma2EncProps_Normalize(&tp);
530     t1n = tp.numTotalThreads;
531   }
532 
533   t1 = p->lzma2Props.numTotalThreads;
534   t2 = p->numBlockThreads_Max;
535   t3 = p->numTotalThreads;
536 
537   if (t2 > MTCODER_THREADS_MAX)
538     t2 = MTCODER_THREADS_MAX;
539 
540   if (t3 <= 0)
541   {
542     if (t2 <= 0)
543       t2 = 1;
544     t3 = t1n * t2;
545   }
546   else if (t2 <= 0)
547   {
548     t2 = t3 / t1n;
549     if (t2 == 0)
550     {
551       t1 = 1;
552       t2 = t3;
553     }
554     if (t2 > MTCODER_THREADS_MAX)
555       t2 = MTCODER_THREADS_MAX;
556   }
557   else if (t1 <= 0)
558   {
559     t1 = t3 / t2;
560     if (t1 == 0)
561       t1 = 1;
562   }
563   else
564     t3 = t1n * t2;
565 
566   p->lzma2Props.numTotalThreads = t1;
567 
568   t2r = t2;
569 
570   fileSize = p->reduceSize;
571 
572   if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
573     p->lzma2Props.lzmaProps.reduceSize = p->blockSize;
574 
575   Lzma2EncProps_Normalize(&p->lzma2Props);
576 
577   t1 = p->lzma2Props.numTotalThreads;
578 
579   {
580     if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
581     {
582       UInt64 numBlocks = fileSize / p->blockSize;
583       if (numBlocks * p->blockSize != fileSize)
584         numBlocks++;
585       if (numBlocks < (unsigned)t2)
586       {
587         t2r = (int)numBlocks;
588         if (t2r == 0)
589           t2r = 1;
590         t3 = t1 * t2r;
591       }
592     }
593   }
594 
595   p->numBlockThreads_Max = t2;
596   p->numBlockThreads_Reduced = t2r;
597   p->numTotalThreads = t3;
598 }
599 
600 
XzProps_Normalize(CXzProps * p)601 static void XzProps_Normalize(CXzProps *p)
602 {
603   /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
604      Lzma2Enc_SetProps() will normalize lzma2Props later. */
605 
606   if (p->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID)
607   {
608     p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
609     p->numBlockThreads_Reduced = 1;
610     p->numBlockThreads_Max = 1;
611     if (p->lzma2Props.numTotalThreads <= 0)
612       p->lzma2Props.numTotalThreads = p->numTotalThreads;
613     return;
614   }
615   else
616   {
617     CLzma2EncProps *lzma2 = &p->lzma2Props;
618     if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
619     {
620       // xz-auto
621       p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
622 
623       if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
624       {
625         // if (xz-auto && lzma2-solid) - we use solid for both
626         p->blockSize = XZ_PROPS_BLOCK_SIZE_SOLID;
627         p->numBlockThreads_Reduced = 1;
628         p->numBlockThreads_Max = 1;
629         if (p->lzma2Props.numTotalThreads <= 0)
630           p->lzma2Props.numTotalThreads = p->numTotalThreads;
631       }
632       else
633       {
634         // if (xz-auto && (lzma2-auto || lzma2-fixed_)
635         //   we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block
636         CLzma2EncProps tp = p->lzma2Props;
637         if (tp.numTotalThreads <= 0)
638           tp.numTotalThreads = p->numTotalThreads;
639 
640         Lzma2EncProps_Normalize(&tp);
641 
642         p->blockSize = tp.blockSize; // fixed or solid
643         p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced;
644         p->numBlockThreads_Max = tp.numBlockThreads_Max;
645         if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
646           lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
647         if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
648           lzma2->lzmaProps.reduceSize = tp.blockSize;
649         lzma2->numBlockThreads_Reduced = 1;
650         lzma2->numBlockThreads_Max = 1;
651         return;
652       }
653     }
654     else
655     {
656       // xz-fixed
657       // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize
658 
659       p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
660       {
661         UInt64 r = p->reduceSize;
662         if (r > p->blockSize || r == (UInt64)(Int64)-1)
663           r = p->blockSize;
664         lzma2->lzmaProps.reduceSize = r;
665       }
666       if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
667         lzma2->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID;
668       else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
669         lzma2->blockSize = p->blockSize;
670 
671       XzEncProps_Normalize_Fixed(p);
672     }
673   }
674 }
675 
676 
677 /* ---------- CLzma2WithFilters ---------- */
678 
679 typedef struct
680 {
681   CLzma2EncHandle lzma2;
682   CSeqInFilter filter;
683 
684   #ifdef USE_SUBBLOCK
685   CSbEncInStream sb;
686   #endif
687 } CLzma2WithFilters;
688 
689 
Lzma2WithFilters_Construct(CLzma2WithFilters * p)690 static void Lzma2WithFilters_Construct(CLzma2WithFilters *p)
691 {
692   p->lzma2 = NULL;
693   SeqInFilter_Construct(&p->filter);
694 
695   #ifdef USE_SUBBLOCK
696   SbEncInStream_Construct(&p->sb, alloc);
697   #endif
698 }
699 
700 
Lzma2WithFilters_Create(CLzma2WithFilters * p,ISzAllocPtr alloc,ISzAllocPtr bigAlloc)701 static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc)
702 {
703   if (!p->lzma2)
704   {
705     p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc);
706     if (!p->lzma2)
707       return SZ_ERROR_MEM;
708   }
709   return SZ_OK;
710 }
711 
712 
Lzma2WithFilters_Free(CLzma2WithFilters * p,ISzAllocPtr alloc)713 static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
714 {
715   #ifdef USE_SUBBLOCK
716   SbEncInStream_Free(&p->sb);
717   #endif
718 
719   SeqInFilter_Free(&p->filter, alloc);
720   if (p->lzma2)
721   {
722     Lzma2Enc_Destroy(p->lzma2);
723     p->lzma2 = NULL;
724   }
725 }
726 
727 
728 typedef struct
729 {
730   UInt64 unpackSize;
731   UInt64 totalSize;
732   size_t headerSize;
733 } CXzEncBlockInfo;
734 
735 
Xz_CompressBlock(CLzma2WithFilters * lzmaf,ISeqOutStreamPtr outStream,Byte * outBufHeader,Byte * outBufData,size_t outBufDataLimit,ISeqInStreamPtr inStream,const Byte * inBuf,size_t inBufSize,const CXzProps * props,ICompressProgressPtr progress,int * inStreamFinished,CXzEncBlockInfo * blockSizes,ISzAllocPtr alloc,ISzAllocPtr allocBig)736 static SRes Xz_CompressBlock(
737     CLzma2WithFilters *lzmaf,
738 
739     ISeqOutStreamPtr outStream,
740     Byte *outBufHeader,
741     Byte *outBufData, size_t outBufDataLimit,
742 
743     ISeqInStreamPtr inStream,
744     // UInt64 expectedSize,
745     const Byte *inBuf, // used if (!inStream)
746     size_t inBufSize,  // used if (!inStream), it's block size, props->blockSize is ignored
747 
748     const CXzProps *props,
749     ICompressProgressPtr progress,
750     int *inStreamFinished,  /* only for inStream version */
751     CXzEncBlockInfo *blockSizes,
752     ISzAllocPtr alloc,
753     ISzAllocPtr allocBig)
754 {
755   CSeqCheckInStream checkInStream;
756   CSeqSizeOutStream seqSizeOutStream;
757   CXzBlock block;
758   unsigned filterIndex = 0;
759   CXzFilter *filter = NULL;
760   const CXzFilterProps *fp = &props->filterProps;
761   if (fp->id == 0)
762     fp = NULL;
763 
764   *inStreamFinished = False;
765 
766   RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig))
767 
768   RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props))
769 
770   // XzBlock_ClearFlags(&block)
771   XzBlock_ClearFlags_SetNumFilters(&block, 1 + (fp ? 1 : 0))
772 
773   if (fp)
774   {
775     filter = &block.filters[filterIndex++];
776     filter->id = fp->id;
777     filter->propsSize = 0;
778 
779     if (fp->id == XZ_ID_Delta)
780     {
781       filter->props[0] = (Byte)(fp->delta - 1);
782       filter->propsSize = 1;
783     }
784     else if (fp->ipDefined)
785     {
786       Byte *ptr = filter->props;
787       SetUi32(ptr, fp->ip)
788       filter->propsSize = 4;
789     }
790   }
791 
792   {
793     CXzFilter *f = &block.filters[filterIndex++];
794     f->id = XZ_ID_LZMA2;
795     f->propsSize = 1;
796     f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
797   }
798 
799   seqSizeOutStream.vt.Write = SeqSizeOutStream_Write;
800   seqSizeOutStream.realStream = outStream;
801   seqSizeOutStream.outBuf = outBufData;
802   seqSizeOutStream.outBufLimit = outBufDataLimit;
803   seqSizeOutStream.processed = 0;
804 
805   /*
806   if (expectedSize != (UInt64)(Int64)-1)
807   {
808     block.unpackSize = expectedSize;
809     if (props->blockSize != (UInt64)(Int64)-1)
810       if (expectedSize > props->blockSize)
811         block.unpackSize = props->blockSize;
812     XzBlock_SetHasUnpackSize(&block)
813   }
814   */
815 
816   if (outStream)
817   {
818     RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt))
819   }
820 
821   checkInStream.vt.Read = SeqCheckInStream_Read;
822   SeqCheckInStream_Init(&checkInStream, props->checkId);
823 
824   checkInStream.realStream = inStream;
825   checkInStream.data = inBuf;
826   checkInStream.limit = props->blockSize;
827   if (!inStream)
828     checkInStream.limit = inBufSize;
829 
830   if (fp)
831   {
832     #ifdef USE_SUBBLOCK
833     if (fp->id == XZ_ID_Subblock)
834     {
835       lzmaf->sb.inStream = &checkInStream.vt;
836       RINOK(SbEncInStream_Init(&lzmaf->sb))
837     }
838     else
839     #endif
840     {
841       lzmaf->filter.realStream = &checkInStream.vt;
842       RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc))
843     }
844   }
845 
846   {
847     SRes res;
848     Byte *outBuf = NULL;
849     size_t outSize = 0;
850     BoolInt useStream = (fp || inStream);
851     // useStream = True;
852 
853     if (!useStream)
854     {
855       XzCheck_Update(&checkInStream.check, inBuf, inBufSize);
856       checkInStream.processed = inBufSize;
857     }
858 
859     if (!outStream)
860     {
861       outBuf = seqSizeOutStream.outBuf; //  + (size_t)seqSizeOutStream.processed;
862       outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed;
863     }
864 
865     res = Lzma2Enc_Encode2(lzmaf->lzma2,
866         outBuf ? NULL : &seqSizeOutStream.vt,
867         outBuf,
868         outBuf ? &outSize : NULL,
869 
870         useStream ?
871           (fp ?
872             (
873             #ifdef USE_SUBBLOCK
874             (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt:
875             #endif
876             &lzmaf->filter.vt) :
877             &checkInStream.vt) : NULL,
878 
879         useStream ? NULL : inBuf,
880         useStream ? 0 : inBufSize,
881 
882         progress);
883 
884     if (outBuf)
885       seqSizeOutStream.processed += outSize;
886 
887     RINOK(res)
888     blockSizes->unpackSize = checkInStream.processed;
889   }
890   {
891     Byte buf[4 + 64];
892     unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
893     UInt64 packSize = seqSizeOutStream.processed;
894 
895     buf[0] = 0;
896     buf[1] = 0;
897     buf[2] = 0;
898     buf[3] = 0;
899 
900     SeqCheckInStream_GetDigest(&checkInStream, buf + 4);
901     RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId)))
902 
903     blockSizes->totalSize = seqSizeOutStream.processed - padSize;
904 
905     if (!outStream)
906     {
907       seqSizeOutStream.outBuf = outBufHeader;
908       seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX;
909       seqSizeOutStream.processed = 0;
910 
911       block.unpackSize = blockSizes->unpackSize;
912       XzBlock_SetHasUnpackSize(&block)
913 
914       block.packSize = packSize;
915       XzBlock_SetHasPackSize(&block)
916 
917       RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt))
918 
919       blockSizes->headerSize = (size_t)seqSizeOutStream.processed;
920       blockSizes->totalSize += seqSizeOutStream.processed;
921     }
922   }
923 
924   if (inStream)
925     *inStreamFinished = checkInStream.realStreamFinished;
926   else
927   {
928     *inStreamFinished = False;
929     if (checkInStream.processed != inBufSize)
930       return SZ_ERROR_FAIL;
931   }
932 
933   return SZ_OK;
934 }
935 
936 
937 
938 typedef struct
939 {
940   ICompressProgress vt;
941   ICompressProgressPtr progress;
942   UInt64 inOffset;
943   UInt64 outOffset;
944 } CCompressProgress_XzEncOffset;
945 
946 
CompressProgress_XzEncOffset_Progress(ICompressProgressPtr pp,UInt64 inSize,UInt64 outSize)947 static SRes CompressProgress_XzEncOffset_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize)
948 {
949   const CCompressProgress_XzEncOffset *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CCompressProgress_XzEncOffset, vt);
950   inSize += p->inOffset;
951   outSize += p->outOffset;
952   return ICompressProgress_Progress(p->progress, inSize, outSize);
953 }
954 
955 
956 
957 
958 struct CXzEnc
959 {
960   ISzAllocPtr alloc;
961   ISzAllocPtr allocBig;
962 
963   CXzProps xzProps;
964   UInt64 expectedDataSize;
965 
966   CXzEncIndex xzIndex;
967 
968   CLzma2WithFilters lzmaf_Items[MTCODER_THREADS_MAX];
969 
970   size_t outBufSize;       /* size of allocated outBufs[i] */
971   Byte *outBufs[MTCODER_BLOCKS_MAX];
972 
973   #ifndef Z7_ST
974   unsigned checkType;
975   ISeqOutStreamPtr outStream;
976   BoolInt mtCoder_WasConstructed;
977   CMtCoder mtCoder;
978   CXzEncBlockInfo EncBlocks[MTCODER_BLOCKS_MAX];
979   #endif
980 };
981 
982 
XzEnc_Construct(CXzEnc * p)983 static void XzEnc_Construct(CXzEnc *p)
984 {
985   unsigned i;
986 
987   XzEncIndex_Construct(&p->xzIndex);
988 
989   for (i = 0; i < MTCODER_THREADS_MAX; i++)
990     Lzma2WithFilters_Construct(&p->lzmaf_Items[i]);
991 
992   #ifndef Z7_ST
993   p->mtCoder_WasConstructed = False;
994   {
995     for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
996       p->outBufs[i] = NULL;
997     p->outBufSize = 0;
998   }
999   #endif
1000 }
1001 
1002 
XzEnc_FreeOutBufs(CXzEnc * p)1003 static void XzEnc_FreeOutBufs(CXzEnc *p)
1004 {
1005   unsigned i;
1006   for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
1007     if (p->outBufs[i])
1008     {
1009       ISzAlloc_Free(p->alloc, p->outBufs[i]);
1010       p->outBufs[i] = NULL;
1011     }
1012   p->outBufSize = 0;
1013 }
1014 
1015 
XzEnc_Free(CXzEnc * p,ISzAllocPtr alloc)1016 static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc)
1017 {
1018   unsigned i;
1019 
1020   XzEncIndex_Free(&p->xzIndex, alloc);
1021 
1022   for (i = 0; i < MTCODER_THREADS_MAX; i++)
1023     Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc);
1024 
1025   #ifndef Z7_ST
1026   if (p->mtCoder_WasConstructed)
1027   {
1028     MtCoder_Destruct(&p->mtCoder);
1029     p->mtCoder_WasConstructed = False;
1030   }
1031   XzEnc_FreeOutBufs(p);
1032   #endif
1033 }
1034 
1035 
XzEnc_Create(ISzAllocPtr alloc,ISzAllocPtr allocBig)1036 CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
1037 {
1038   CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc));
1039   if (!p)
1040     return NULL;
1041   XzEnc_Construct(p);
1042   XzProps_Init(&p->xzProps);
1043   XzProps_Normalize(&p->xzProps);
1044   p->expectedDataSize = (UInt64)(Int64)-1;
1045   p->alloc = alloc;
1046   p->allocBig = allocBig;
1047   return (CXzEncHandle)p;
1048 }
1049 
1050 // #define GET_CXzEnc_p  CXzEnc *p = (CXzEnc *)(void *)pp;
1051 
XzEnc_Destroy(CXzEncHandle p)1052 void XzEnc_Destroy(CXzEncHandle p)
1053 {
1054   // GET_CXzEnc_p
1055   XzEnc_Free(p, p->alloc);
1056   ISzAlloc_Free(p->alloc, p);
1057 }
1058 
1059 
XzEnc_SetProps(CXzEncHandle p,const CXzProps * props)1060 SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props)
1061 {
1062   // GET_CXzEnc_p
1063   p->xzProps = *props;
1064   XzProps_Normalize(&p->xzProps);
1065   return SZ_OK;
1066 }
1067 
1068 
XzEnc_SetDataSize(CXzEncHandle p,UInt64 expectedDataSiize)1069 void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize)
1070 {
1071   // GET_CXzEnc_p
1072   p->expectedDataSize = expectedDataSiize;
1073 }
1074 
1075 
1076 
1077 
1078 #ifndef Z7_ST
1079 
XzEnc_MtCallback_Code(void * pp,unsigned coderIndex,unsigned outBufIndex,const Byte * src,size_t srcSize,int finished)1080 static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex,
1081     const Byte *src, size_t srcSize, int finished)
1082 {
1083   CXzEnc *me = (CXzEnc *)pp;
1084   SRes res;
1085   CMtProgressThunk progressThunk;
1086 
1087   Byte *dest = me->outBufs[outBufIndex];
1088 
1089   UNUSED_VAR(finished)
1090 
1091   {
1092     CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
1093     bInfo->totalSize = 0;
1094     bInfo->unpackSize = 0;
1095     bInfo->headerSize = 0;
1096   }
1097 
1098   if (!dest)
1099   {
1100     dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize);
1101     if (!dest)
1102       return SZ_ERROR_MEM;
1103     me->outBufs[outBufIndex] = dest;
1104   }
1105 
1106   MtProgressThunk_CreateVTable(&progressThunk);
1107   progressThunk.mtProgress = &me->mtCoder.mtProgress;
1108   MtProgressThunk_INIT(&progressThunk)
1109 
1110   {
1111     CXzEncBlockInfo blockSizes;
1112     int inStreamFinished;
1113 
1114     res = Xz_CompressBlock(
1115         &me->lzmaf_Items[coderIndex],
1116 
1117         NULL,
1118         dest,
1119         dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX,
1120 
1121         NULL,
1122         // srcSize, // expectedSize
1123         src, srcSize,
1124 
1125         &me->xzProps,
1126         &progressThunk.vt,
1127         &inStreamFinished,
1128         &blockSizes,
1129         me->alloc,
1130         me->allocBig);
1131 
1132     if (res == SZ_OK)
1133       me->EncBlocks[outBufIndex] = blockSizes;
1134 
1135     return res;
1136   }
1137 }
1138 
1139 
XzEnc_MtCallback_Write(void * pp,unsigned outBufIndex)1140 static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex)
1141 {
1142   CXzEnc *me = (CXzEnc *)pp;
1143 
1144   const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
1145   const Byte *data = me->outBufs[outBufIndex];
1146 
1147   RINOK(WriteBytes(me->outStream, data, bInfo->headerSize))
1148 
1149   {
1150     UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize);
1151     RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize))
1152   }
1153 
1154   return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc);
1155 }
1156 
1157 #endif
1158 
1159 
1160 
XzEnc_Encode(CXzEncHandle p,ISeqOutStreamPtr outStream,ISeqInStreamPtr inStream,ICompressProgressPtr progress)1161 SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress)
1162 {
1163   // GET_CXzEnc_p
1164 
1165   const CXzProps *props = &p->xzProps;
1166 
1167   XzEncIndex_Init(&p->xzIndex);
1168   {
1169     UInt64 numBlocks = 1;
1170     UInt64 blockSize = props->blockSize;
1171 
1172     if (blockSize != XZ_PROPS_BLOCK_SIZE_SOLID
1173         && props->reduceSize != (UInt64)(Int64)-1)
1174     {
1175       numBlocks = props->reduceSize / blockSize;
1176       if (numBlocks * blockSize != props->reduceSize)
1177         numBlocks++;
1178     }
1179     else
1180       blockSize = (UInt64)1 << 62;
1181 
1182     RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc))
1183   }
1184 
1185   RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream))
1186 
1187 
1188   #ifndef Z7_ST
1189   if (props->numBlockThreads_Reduced > 1)
1190   {
1191     IMtCoderCallback2 vt;
1192 
1193     if (!p->mtCoder_WasConstructed)
1194     {
1195       p->mtCoder_WasConstructed = True;
1196       MtCoder_Construct(&p->mtCoder);
1197     }
1198 
1199     vt.Code = XzEnc_MtCallback_Code;
1200     vt.Write = XzEnc_MtCallback_Write;
1201 
1202     p->checkType = props->checkId;
1203     p->xzProps = *props;
1204 
1205     p->outStream = outStream;
1206 
1207     p->mtCoder.allocBig = p->allocBig;
1208     p->mtCoder.progress = progress;
1209     p->mtCoder.inStream = inStream;
1210     p->mtCoder.inData = NULL;
1211     p->mtCoder.inDataSize = 0;
1212     p->mtCoder.mtCallback = &vt;
1213     p->mtCoder.mtCallbackObject = p;
1214 
1215     if (   props->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID
1216         || props->blockSize == XZ_PROPS_BLOCK_SIZE_AUTO)
1217       return SZ_ERROR_FAIL;
1218 
1219     p->mtCoder.blockSize = (size_t)props->blockSize;
1220     if (p->mtCoder.blockSize != props->blockSize)
1221       return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */
1222 
1223     {
1224       size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize);
1225       if (destBlockSize < p->mtCoder.blockSize)
1226         return SZ_ERROR_PARAM;
1227       if (p->outBufSize != destBlockSize)
1228         XzEnc_FreeOutBufs(p);
1229       p->outBufSize = destBlockSize;
1230     }
1231 
1232     p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max;
1233     p->mtCoder.expectedDataSize = p->expectedDataSize;
1234 
1235     RINOK(MtCoder_Code(&p->mtCoder))
1236   }
1237   else
1238   #endif
1239   {
1240     int writeStartSizes;
1241     CCompressProgress_XzEncOffset progress2;
1242     Byte *bufData = NULL;
1243     size_t bufSize = 0;
1244 
1245     progress2.vt.Progress = CompressProgress_XzEncOffset_Progress;
1246     progress2.inOffset = 0;
1247     progress2.outOffset = 0;
1248     progress2.progress = progress;
1249 
1250     writeStartSizes = 0;
1251 
1252     if (props->blockSize != XZ_PROPS_BLOCK_SIZE_SOLID)
1253     {
1254       writeStartSizes = (props->forceWriteSizesInHeader > 0);
1255 
1256       if (writeStartSizes)
1257       {
1258         size_t t2;
1259         size_t t = (size_t)props->blockSize;
1260         if (t != props->blockSize)
1261           return SZ_ERROR_PARAM;
1262         t = XZ_GET_MAX_BLOCK_PACK_SIZE(t);
1263         if (t < props->blockSize)
1264           return SZ_ERROR_PARAM;
1265         t2 = XZ_BLOCK_HEADER_SIZE_MAX + t;
1266         if (!p->outBufs[0] || t2 != p->outBufSize)
1267         {
1268           XzEnc_FreeOutBufs(p);
1269           p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2);
1270           if (!p->outBufs[0])
1271             return SZ_ERROR_MEM;
1272           p->outBufSize = t2;
1273         }
1274         bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX;
1275         bufSize = t;
1276       }
1277     }
1278 
1279     for (;;)
1280     {
1281       CXzEncBlockInfo blockSizes;
1282       int inStreamFinished;
1283 
1284       /*
1285       UInt64 rem = (UInt64)(Int64)-1;
1286       if (props->reduceSize != (UInt64)(Int64)-1
1287           && props->reduceSize >= progress2.inOffset)
1288         rem = props->reduceSize - progress2.inOffset;
1289       */
1290 
1291       blockSizes.headerSize = 0; // for GCC
1292 
1293       RINOK(Xz_CompressBlock(
1294           &p->lzmaf_Items[0],
1295 
1296           writeStartSizes ? NULL : outStream,
1297           writeStartSizes ? p->outBufs[0] : NULL,
1298           bufData, bufSize,
1299 
1300           inStream,
1301           // rem,
1302           NULL, 0,
1303 
1304           props,
1305           progress ? &progress2.vt : NULL,
1306           &inStreamFinished,
1307           &blockSizes,
1308           p->alloc,
1309           p->allocBig))
1310 
1311       {
1312         UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize);
1313 
1314         if (writeStartSizes)
1315         {
1316           RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize))
1317           RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize))
1318         }
1319 
1320         RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc))
1321 
1322         progress2.inOffset += blockSizes.unpackSize;
1323         progress2.outOffset += totalPackFull;
1324       }
1325 
1326       if (inStreamFinished)
1327         break;
1328     }
1329   }
1330 
1331   return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream);
1332 }
1333 
1334 
1335 #include "Alloc.h"
1336 
Xz_Encode(ISeqOutStreamPtr outStream,ISeqInStreamPtr inStream,const CXzProps * props,ICompressProgressPtr progress)1337 SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
1338     const CXzProps *props, ICompressProgressPtr progress)
1339 {
1340   SRes res;
1341   CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc);
1342   if (!xz)
1343     return SZ_ERROR_MEM;
1344   res = XzEnc_SetProps(xz, props);
1345   if (res == SZ_OK)
1346     res = XzEnc_Encode(xz, outStream, inStream, progress);
1347   XzEnc_Destroy(xz);
1348   return res;
1349 }
1350 
1351 
Xz_EncodeEmpty(ISeqOutStreamPtr outStream)1352 SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream)
1353 {
1354   SRes res;
1355   CXzEncIndex xzIndex;
1356   XzEncIndex_Construct(&xzIndex);
1357   res = Xz_WriteHeader((CXzStreamFlags)0, outStream);
1358   if (res == SZ_OK)
1359     res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream);
1360   XzEncIndex_Free(&xzIndex, NULL); // g_Alloc
1361   return res;
1362 }
1363