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