1 /* XzEnc.c -- Xz Encode
2 2021-04-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 _7ZIP_ST
22 
23 #ifndef _7ZIP_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_SetNumFilters(p, n) (p)->flags = (Byte)((p)->flags | ((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(ISeqOutStream * s,const void * buf,size_t size)44 static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size)
45 {
46   return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
47 }
48 
WriteBytesUpdateCrc(ISeqOutStream * s,const void * buf,size_t size,UInt32 * crc)49 static SRes WriteBytesUpdateCrc(ISeqOutStream *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,ISeqOutStream * s)56 static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *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,ISeqOutStream * s)69 static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *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,ISeqOutStream * s)194 static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *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(WriteBytesUpdateCrc(s, buf, pos, &crc));
204   RINOK(WriteBytesUpdateCrc(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   ISeqInStream *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(const ISeqInStream * pp,void * data,size_t * size)254 static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
255 {
256   CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt);
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   ISeqOutStream *realStream;
289   Byte *outBuf;
290   size_t outBufLimit;
291   UInt64 processed;
292 } CSeqSizeOutStream;
293 
SeqSizeOutStream_Write(const ISeqOutStream * pp,const void * data,size_t size)294 static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size)
295 {
296   CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt);
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 p;
317   ISeqInStream *realStream;
318   IStateCoder StateCoder;
319   Byte *buf;
320   size_t curPos;
321   size_t endPos;
322   int srcWasFinished;
323 } CSeqInFilter;
324 
325 
326 SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);
327 
SeqInFilter_Init(CSeqInFilter * p,const CXzFilter * props,ISzAllocPtr alloc)328 static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc)
329 {
330   if (!p->buf)
331   {
332     p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE);
333     if (!p->buf)
334       return SZ_ERROR_MEM;
335   }
336   p->curPos = p->endPos = 0;
337   p->srcWasFinished = 0;
338   RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc));
339   RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc));
340   p->StateCoder.Init(p->StateCoder.p);
341   return SZ_OK;
342 }
343 
344 
SeqInFilter_Read(const ISeqInStream * pp,void * data,size_t * size)345 static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size)
346 {
347   CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p);
348   size_t sizeOriginal = *size;
349   if (sizeOriginal == 0)
350     return SZ_OK;
351   *size = 0;
352 
353   for (;;)
354   {
355     if (!p->srcWasFinished && p->curPos == p->endPos)
356     {
357       p->curPos = 0;
358       p->endPos = FILTER_BUF_SIZE;
359       RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos));
360       if (p->endPos == 0)
361         p->srcWasFinished = 1;
362     }
363     {
364       SizeT srcLen = p->endPos - p->curPos;
365       ECoderStatus status;
366       SRes res;
367       *size = sizeOriginal;
368       res = p->StateCoder.Code2(p->StateCoder.p,
369           (Byte *)data, size,
370           p->buf + p->curPos, &srcLen,
371           p->srcWasFinished, CODER_FINISH_ANY,
372           &status);
373       p->curPos += srcLen;
374       if (*size != 0 || srcLen == 0 || res != SZ_OK)
375         return res;
376     }
377   }
378 }
379 
SeqInFilter_Construct(CSeqInFilter * p)380 static void SeqInFilter_Construct(CSeqInFilter *p)
381 {
382   p->buf = NULL;
383   p->StateCoder.p = NULL;
384   p->p.Read = SeqInFilter_Read;
385 }
386 
SeqInFilter_Free(CSeqInFilter * p,ISzAllocPtr alloc)387 static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
388 {
389   if (p->StateCoder.p)
390   {
391     p->StateCoder.Free(p->StateCoder.p, alloc);
392     p->StateCoder.p = NULL;
393   }
394   if (p->buf)
395   {
396     ISzAlloc_Free(alloc, p->buf);
397     p->buf = NULL;
398   }
399 }
400 
401 
402 /* ---------- CSbEncInStream ---------- */
403 
404 #ifdef USE_SUBBLOCK
405 
406 typedef struct
407 {
408   ISeqInStream vt;
409   ISeqInStream *inStream;
410   CSbEnc enc;
411 } CSbEncInStream;
412 
SbEncInStream_Read(const ISeqInStream * pp,void * data,size_t * size)413 static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
414 {
415   CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt);
416   size_t sizeOriginal = *size;
417   if (sizeOriginal == 0)
418     return SZ_OK;
419 
420   for (;;)
421   {
422     if (p->enc.needRead && !p->enc.readWasFinished)
423     {
424       size_t processed = p->enc.needReadSizeMax;
425       RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed));
426       p->enc.readPos += processed;
427       if (processed == 0)
428       {
429         p->enc.readWasFinished = True;
430         p->enc.isFinalFinished = True;
431       }
432       p->enc.needRead = False;
433     }
434 
435     *size = sizeOriginal;
436     RINOK(SbEnc_Read(&p->enc, data, size));
437     if (*size != 0 || !p->enc.needRead)
438       return SZ_OK;
439   }
440 }
441 
SbEncInStream_Construct(CSbEncInStream * p,ISzAllocPtr alloc)442 void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
443 {
444   SbEnc_Construct(&p->enc, alloc);
445   p->vt.Read = SbEncInStream_Read;
446 }
447 
SbEncInStream_Init(CSbEncInStream * p)448 SRes SbEncInStream_Init(CSbEncInStream *p)
449 {
450   return SbEnc_Init(&p->enc);
451 }
452 
SbEncInStream_Free(CSbEncInStream * p)453 void SbEncInStream_Free(CSbEncInStream *p)
454 {
455   SbEnc_Free(&p->enc);
456 }
457 
458 #endif
459 
460 
461 
462 /* ---------- CXzProps ---------- */
463 
464 
XzFilterProps_Init(CXzFilterProps * p)465 void XzFilterProps_Init(CXzFilterProps *p)
466 {
467   p->id = 0;
468   p->delta = 0;
469   p->ip = 0;
470   p->ipDefined = False;
471 }
472 
XzProps_Init(CXzProps * p)473 void XzProps_Init(CXzProps *p)
474 {
475   p->checkId = XZ_CHECK_CRC32;
476   p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO;
477   p->numBlockThreads_Reduced = -1;
478   p->numBlockThreads_Max = -1;
479   p->numTotalThreads = -1;
480   p->reduceSize = (UInt64)(Int64)-1;
481   p->forceWriteSizesInHeader = 0;
482   // p->forceWriteSizesInHeader = 1;
483 
484   XzFilterProps_Init(&p->filterProps);
485   Lzma2EncProps_Init(&p->lzma2Props);
486 }
487 
488 
XzEncProps_Normalize_Fixed(CXzProps * p)489 static void XzEncProps_Normalize_Fixed(CXzProps *p)
490 {
491   UInt64 fileSize;
492   int t1, t1n, t2, t2r, t3;
493   {
494     CLzma2EncProps tp = p->lzma2Props;
495     if (tp.numTotalThreads <= 0)
496       tp.numTotalThreads = p->numTotalThreads;
497     Lzma2EncProps_Normalize(&tp);
498     t1n = tp.numTotalThreads;
499   }
500 
501   t1 = p->lzma2Props.numTotalThreads;
502   t2 = p->numBlockThreads_Max;
503   t3 = p->numTotalThreads;
504 
505   if (t2 > MTCODER__THREADS_MAX)
506     t2 = MTCODER__THREADS_MAX;
507 
508   if (t3 <= 0)
509   {
510     if (t2 <= 0)
511       t2 = 1;
512     t3 = t1n * t2;
513   }
514   else if (t2 <= 0)
515   {
516     t2 = t3 / t1n;
517     if (t2 == 0)
518     {
519       t1 = 1;
520       t2 = t3;
521     }
522     if (t2 > MTCODER__THREADS_MAX)
523       t2 = MTCODER__THREADS_MAX;
524   }
525   else if (t1 <= 0)
526   {
527     t1 = t3 / t2;
528     if (t1 == 0)
529       t1 = 1;
530   }
531   else
532     t3 = t1n * t2;
533 
534   p->lzma2Props.numTotalThreads = t1;
535 
536   t2r = t2;
537 
538   fileSize = p->reduceSize;
539 
540   if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
541     p->lzma2Props.lzmaProps.reduceSize = p->blockSize;
542 
543   Lzma2EncProps_Normalize(&p->lzma2Props);
544 
545   t1 = p->lzma2Props.numTotalThreads;
546 
547   {
548     if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
549     {
550       UInt64 numBlocks = fileSize / p->blockSize;
551       if (numBlocks * p->blockSize != fileSize)
552         numBlocks++;
553       if (numBlocks < (unsigned)t2)
554       {
555         t2r = (int)numBlocks;
556         if (t2r == 0)
557           t2r = 1;
558         t3 = t1 * t2r;
559       }
560     }
561   }
562 
563   p->numBlockThreads_Max = t2;
564   p->numBlockThreads_Reduced = t2r;
565   p->numTotalThreads = t3;
566 }
567 
568 
XzProps_Normalize(CXzProps * p)569 static void XzProps_Normalize(CXzProps *p)
570 {
571   /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
572      Lzma2Enc_SetProps() will normalize lzma2Props later. */
573 
574   if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID)
575   {
576     p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
577     p->numBlockThreads_Reduced = 1;
578     p->numBlockThreads_Max = 1;
579     if (p->lzma2Props.numTotalThreads <= 0)
580       p->lzma2Props.numTotalThreads = p->numTotalThreads;
581     return;
582   }
583   else
584   {
585     CLzma2EncProps *lzma2 = &p->lzma2Props;
586     if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
587     {
588       // xz-auto
589       p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
590 
591       if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
592       {
593         // if (xz-auto && lzma2-solid) - we use solid for both
594         p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID;
595         p->numBlockThreads_Reduced = 1;
596         p->numBlockThreads_Max = 1;
597         if (p->lzma2Props.numTotalThreads <= 0)
598           p->lzma2Props.numTotalThreads = p->numTotalThreads;
599       }
600       else
601       {
602         // if (xz-auto && (lzma2-auto || lzma2-fixed_)
603         //   we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block
604         CLzma2EncProps tp = p->lzma2Props;
605         if (tp.numTotalThreads <= 0)
606           tp.numTotalThreads = p->numTotalThreads;
607 
608         Lzma2EncProps_Normalize(&tp);
609 
610         p->blockSize = tp.blockSize; // fixed or solid
611         p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced;
612         p->numBlockThreads_Max = tp.numBlockThreads_Max;
613         if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
614           lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
615         if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
616           lzma2->lzmaProps.reduceSize = tp.blockSize;
617         lzma2->numBlockThreads_Reduced = 1;
618         lzma2->numBlockThreads_Max = 1;
619         return;
620       }
621     }
622     else
623     {
624       // xz-fixed
625       // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize
626 
627       p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
628       {
629         UInt64 r = p->reduceSize;
630         if (r > p->blockSize || r == (UInt64)(Int64)-1)
631           r = p->blockSize;
632         lzma2->lzmaProps.reduceSize = r;
633       }
634       if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
635         lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
636       else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
637         lzma2->blockSize = p->blockSize;
638 
639       XzEncProps_Normalize_Fixed(p);
640     }
641   }
642 }
643 
644 
645 /* ---------- CLzma2WithFilters ---------- */
646 
647 typedef struct
648 {
649   CLzma2EncHandle lzma2;
650   CSeqInFilter filter;
651 
652   #ifdef USE_SUBBLOCK
653   CSbEncInStream sb;
654   #endif
655 } CLzma2WithFilters;
656 
657 
Lzma2WithFilters_Construct(CLzma2WithFilters * p)658 static void Lzma2WithFilters_Construct(CLzma2WithFilters *p)
659 {
660   p->lzma2 = NULL;
661   SeqInFilter_Construct(&p->filter);
662 
663   #ifdef USE_SUBBLOCK
664   SbEncInStream_Construct(&p->sb, alloc);
665   #endif
666 }
667 
668 
Lzma2WithFilters_Create(CLzma2WithFilters * p,ISzAllocPtr alloc,ISzAllocPtr bigAlloc)669 static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc)
670 {
671   if (!p->lzma2)
672   {
673     p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc);
674     if (!p->lzma2)
675       return SZ_ERROR_MEM;
676   }
677   return SZ_OK;
678 }
679 
680 
Lzma2WithFilters_Free(CLzma2WithFilters * p,ISzAllocPtr alloc)681 static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
682 {
683   #ifdef USE_SUBBLOCK
684   SbEncInStream_Free(&p->sb);
685   #endif
686 
687   SeqInFilter_Free(&p->filter, alloc);
688   if (p->lzma2)
689   {
690     Lzma2Enc_Destroy(p->lzma2);
691     p->lzma2 = NULL;
692   }
693 }
694 
695 
696 typedef struct
697 {
698   UInt64 unpackSize;
699   UInt64 totalSize;
700   size_t headerSize;
701 } CXzEncBlockInfo;
702 
703 
Xz_CompressBlock(CLzma2WithFilters * lzmaf,ISeqOutStream * outStream,Byte * outBufHeader,Byte * outBufData,size_t outBufDataLimit,ISeqInStream * inStream,const Byte * inBuf,size_t inBufSize,const CXzProps * props,ICompressProgress * progress,int * inStreamFinished,CXzEncBlockInfo * blockSizes,ISzAllocPtr alloc,ISzAllocPtr allocBig)704 static SRes Xz_CompressBlock(
705     CLzma2WithFilters *lzmaf,
706 
707     ISeqOutStream *outStream,
708     Byte *outBufHeader,
709     Byte *outBufData, size_t outBufDataLimit,
710 
711     ISeqInStream *inStream,
712     // UInt64 expectedSize,
713     const Byte *inBuf, // used if (!inStream)
714     size_t inBufSize,  // used if (!inStream), it's block size, props->blockSize is ignored
715 
716     const CXzProps *props,
717     ICompressProgress *progress,
718     int *inStreamFinished,  /* only for inStream version */
719     CXzEncBlockInfo *blockSizes,
720     ISzAllocPtr alloc,
721     ISzAllocPtr allocBig)
722 {
723   CSeqCheckInStream checkInStream;
724   CSeqSizeOutStream seqSizeOutStream;
725   CXzBlock block;
726   unsigned filterIndex = 0;
727   CXzFilter *filter = NULL;
728   const CXzFilterProps *fp = &props->filterProps;
729   if (fp->id == 0)
730     fp = NULL;
731 
732   *inStreamFinished = False;
733 
734   RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig));
735 
736   RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props));
737 
738   XzBlock_ClearFlags(&block);
739   XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0));
740 
741   if (fp)
742   {
743     filter = &block.filters[filterIndex++];
744     filter->id = fp->id;
745     filter->propsSize = 0;
746 
747     if (fp->id == XZ_ID_Delta)
748     {
749       filter->props[0] = (Byte)(fp->delta - 1);
750       filter->propsSize = 1;
751     }
752     else if (fp->ipDefined)
753     {
754       Byte *ptr = filter->props;
755       SetUi32(ptr, fp->ip);
756       filter->propsSize = 4;
757     }
758   }
759 
760   {
761     CXzFilter *f = &block.filters[filterIndex++];
762     f->id = XZ_ID_LZMA2;
763     f->propsSize = 1;
764     f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
765   }
766 
767   seqSizeOutStream.vt.Write = SeqSizeOutStream_Write;
768   seqSizeOutStream.realStream = outStream;
769   seqSizeOutStream.outBuf = outBufData;
770   seqSizeOutStream.outBufLimit = outBufDataLimit;
771   seqSizeOutStream.processed = 0;
772 
773   /*
774   if (expectedSize != (UInt64)(Int64)-1)
775   {
776     block.unpackSize = expectedSize;
777     if (props->blockSize != (UInt64)(Int64)-1)
778       if (expectedSize > props->blockSize)
779         block.unpackSize = props->blockSize;
780     XzBlock_SetHasUnpackSize(&block);
781   }
782   */
783 
784   if (outStream)
785   {
786     RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
787   }
788 
789   checkInStream.vt.Read = SeqCheckInStream_Read;
790   SeqCheckInStream_Init(&checkInStream, props->checkId);
791 
792   checkInStream.realStream = inStream;
793   checkInStream.data = inBuf;
794   checkInStream.limit = props->blockSize;
795   if (!inStream)
796     checkInStream.limit = inBufSize;
797 
798   if (fp)
799   {
800     #ifdef USE_SUBBLOCK
801     if (fp->id == XZ_ID_Subblock)
802     {
803       lzmaf->sb.inStream = &checkInStream.vt;
804       RINOK(SbEncInStream_Init(&lzmaf->sb));
805     }
806     else
807     #endif
808     {
809       lzmaf->filter.realStream = &checkInStream.vt;
810       RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc));
811     }
812   }
813 
814   {
815     SRes res;
816     Byte *outBuf = NULL;
817     size_t outSize = 0;
818     BoolInt useStream = (fp || inStream);
819     // useStream = True;
820 
821     if (!useStream)
822     {
823       XzCheck_Update(&checkInStream.check, inBuf, inBufSize);
824       checkInStream.processed = inBufSize;
825     }
826 
827     if (!outStream)
828     {
829       outBuf = seqSizeOutStream.outBuf; //  + (size_t)seqSizeOutStream.processed;
830       outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed;
831     }
832 
833     res = Lzma2Enc_Encode2(lzmaf->lzma2,
834         outBuf ? NULL : &seqSizeOutStream.vt,
835         outBuf,
836         outBuf ? &outSize : NULL,
837 
838         useStream ?
839           (fp ?
840             (
841             #ifdef USE_SUBBLOCK
842             (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt:
843             #endif
844             &lzmaf->filter.p) :
845             &checkInStream.vt) : NULL,
846 
847         useStream ? NULL : inBuf,
848         useStream ? 0 : inBufSize,
849 
850         progress);
851 
852     if (outBuf)
853       seqSizeOutStream.processed += outSize;
854 
855     RINOK(res);
856     blockSizes->unpackSize = checkInStream.processed;
857   }
858   {
859     Byte buf[4 + 64];
860     unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
861     UInt64 packSize = seqSizeOutStream.processed;
862 
863     buf[0] = 0;
864     buf[1] = 0;
865     buf[2] = 0;
866     buf[3] = 0;
867 
868     SeqCheckInStream_GetDigest(&checkInStream, buf + 4);
869     RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId)));
870 
871     blockSizes->totalSize = seqSizeOutStream.processed - padSize;
872 
873     if (!outStream)
874     {
875       seqSizeOutStream.outBuf = outBufHeader;
876       seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX;
877       seqSizeOutStream.processed = 0;
878 
879       block.unpackSize = blockSizes->unpackSize;
880       XzBlock_SetHasUnpackSize(&block);
881 
882       block.packSize = packSize;
883       XzBlock_SetHasPackSize(&block);
884 
885       RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
886 
887       blockSizes->headerSize = (size_t)seqSizeOutStream.processed;
888       blockSizes->totalSize += seqSizeOutStream.processed;
889     }
890   }
891 
892   if (inStream)
893     *inStreamFinished = checkInStream.realStreamFinished;
894   else
895   {
896     *inStreamFinished = False;
897     if (checkInStream.processed != inBufSize)
898       return SZ_ERROR_FAIL;
899   }
900 
901   return SZ_OK;
902 }
903 
904 
905 
906 typedef struct
907 {
908   ICompressProgress vt;
909   ICompressProgress *progress;
910   UInt64 inOffset;
911   UInt64 outOffset;
912 } CCompressProgress_XzEncOffset;
913 
914 
CompressProgress_XzEncOffset_Progress(const ICompressProgress * pp,UInt64 inSize,UInt64 outSize)915 static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize)
916 {
917   const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt);
918   inSize += p->inOffset;
919   outSize += p->outOffset;
920   return ICompressProgress_Progress(p->progress, inSize, outSize);
921 }
922 
923 
924 
925 
926 typedef struct
927 {
928   ISzAllocPtr alloc;
929   ISzAllocPtr allocBig;
930 
931   CXzProps xzProps;
932   UInt64 expectedDataSize;
933 
934   CXzEncIndex xzIndex;
935 
936   CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX];
937 
938   size_t outBufSize;       /* size of allocated outBufs[i] */
939   Byte *outBufs[MTCODER__BLOCKS_MAX];
940 
941   #ifndef _7ZIP_ST
942   unsigned checkType;
943   ISeqOutStream *outStream;
944   BoolInt mtCoder_WasConstructed;
945   CMtCoder mtCoder;
946   CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX];
947   #endif
948 
949 } CXzEnc;
950 
951 
XzEnc_Construct(CXzEnc * p)952 static void XzEnc_Construct(CXzEnc *p)
953 {
954   unsigned i;
955 
956   XzEncIndex_Construct(&p->xzIndex);
957 
958   for (i = 0; i < MTCODER__THREADS_MAX; i++)
959     Lzma2WithFilters_Construct(&p->lzmaf_Items[i]);
960 
961   #ifndef _7ZIP_ST
962   p->mtCoder_WasConstructed = False;
963   {
964     for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
965       p->outBufs[i] = NULL;
966     p->outBufSize = 0;
967   }
968   #endif
969 }
970 
971 
XzEnc_FreeOutBufs(CXzEnc * p)972 static void XzEnc_FreeOutBufs(CXzEnc *p)
973 {
974   unsigned i;
975   for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
976     if (p->outBufs[i])
977     {
978       ISzAlloc_Free(p->alloc, p->outBufs[i]);
979       p->outBufs[i] = NULL;
980     }
981   p->outBufSize = 0;
982 }
983 
984 
XzEnc_Free(CXzEnc * p,ISzAllocPtr alloc)985 static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc)
986 {
987   unsigned i;
988 
989   XzEncIndex_Free(&p->xzIndex, alloc);
990 
991   for (i = 0; i < MTCODER__THREADS_MAX; i++)
992     Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc);
993 
994   #ifndef _7ZIP_ST
995   if (p->mtCoder_WasConstructed)
996   {
997     MtCoder_Destruct(&p->mtCoder);
998     p->mtCoder_WasConstructed = False;
999   }
1000   XzEnc_FreeOutBufs(p);
1001   #endif
1002 }
1003 
1004 
XzEnc_Create(ISzAllocPtr alloc,ISzAllocPtr allocBig)1005 CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
1006 {
1007   CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc));
1008   if (!p)
1009     return NULL;
1010   XzEnc_Construct(p);
1011   XzProps_Init(&p->xzProps);
1012   XzProps_Normalize(&p->xzProps);
1013   p->expectedDataSize = (UInt64)(Int64)-1;
1014   p->alloc = alloc;
1015   p->allocBig = allocBig;
1016   return p;
1017 }
1018 
1019 
XzEnc_Destroy(CXzEncHandle pp)1020 void XzEnc_Destroy(CXzEncHandle pp)
1021 {
1022   CXzEnc *p = (CXzEnc *)pp;
1023   XzEnc_Free(p, p->alloc);
1024   ISzAlloc_Free(p->alloc, p);
1025 }
1026 
1027 
XzEnc_SetProps(CXzEncHandle pp,const CXzProps * props)1028 SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props)
1029 {
1030   CXzEnc *p = (CXzEnc *)pp;
1031   p->xzProps = *props;
1032   XzProps_Normalize(&p->xzProps);
1033   return SZ_OK;
1034 }
1035 
1036 
XzEnc_SetDataSize(CXzEncHandle pp,UInt64 expectedDataSiize)1037 void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize)
1038 {
1039   CXzEnc *p = (CXzEnc *)pp;
1040   p->expectedDataSize = expectedDataSiize;
1041 }
1042 
1043 
1044 
1045 
1046 #ifndef _7ZIP_ST
1047 
XzEnc_MtCallback_Code(void * pp,unsigned coderIndex,unsigned outBufIndex,const Byte * src,size_t srcSize,int finished)1048 static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex,
1049     const Byte *src, size_t srcSize, int finished)
1050 {
1051   CXzEnc *me = (CXzEnc *)pp;
1052   SRes res;
1053   CMtProgressThunk progressThunk;
1054 
1055   Byte *dest = me->outBufs[outBufIndex];
1056 
1057   UNUSED_VAR(finished)
1058 
1059   {
1060     CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
1061     bInfo->totalSize = 0;
1062     bInfo->unpackSize = 0;
1063     bInfo->headerSize = 0;
1064   }
1065 
1066   if (!dest)
1067   {
1068     dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize);
1069     if (!dest)
1070       return SZ_ERROR_MEM;
1071     me->outBufs[outBufIndex] = dest;
1072   }
1073 
1074   MtProgressThunk_CreateVTable(&progressThunk);
1075   progressThunk.mtProgress = &me->mtCoder.mtProgress;
1076   MtProgressThunk_Init(&progressThunk);
1077 
1078   {
1079     CXzEncBlockInfo blockSizes;
1080     int inStreamFinished;
1081 
1082     res = Xz_CompressBlock(
1083         &me->lzmaf_Items[coderIndex],
1084 
1085         NULL,
1086         dest,
1087         dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX,
1088 
1089         NULL,
1090         // srcSize, // expectedSize
1091         src, srcSize,
1092 
1093         &me->xzProps,
1094         &progressThunk.vt,
1095         &inStreamFinished,
1096         &blockSizes,
1097         me->alloc,
1098         me->allocBig);
1099 
1100     if (res == SZ_OK)
1101       me->EncBlocks[outBufIndex] = blockSizes;
1102 
1103     return res;
1104   }
1105 }
1106 
1107 
XzEnc_MtCallback_Write(void * pp,unsigned outBufIndex)1108 static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex)
1109 {
1110   CXzEnc *me = (CXzEnc *)pp;
1111 
1112   const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
1113   const Byte *data = me->outBufs[outBufIndex];
1114 
1115   RINOK(WriteBytes(me->outStream, data, bInfo->headerSize));
1116 
1117   {
1118     UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize);
1119     RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize));
1120   }
1121 
1122   return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc);
1123 }
1124 
1125 #endif
1126 
1127 
1128 
XzEnc_Encode(CXzEncHandle pp,ISeqOutStream * outStream,ISeqInStream * inStream,ICompressProgress * progress)1129 SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
1130 {
1131   CXzEnc *p = (CXzEnc *)pp;
1132 
1133   const CXzProps *props = &p->xzProps;
1134 
1135   XzEncIndex_Init(&p->xzIndex);
1136   {
1137     UInt64 numBlocks = 1;
1138     UInt64 blockSize = props->blockSize;
1139 
1140     if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID
1141         && props->reduceSize != (UInt64)(Int64)-1)
1142     {
1143       numBlocks = props->reduceSize / blockSize;
1144       if (numBlocks * blockSize != props->reduceSize)
1145         numBlocks++;
1146     }
1147     else
1148       blockSize = (UInt64)1 << 62;
1149 
1150     RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc));
1151   }
1152 
1153   RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream));
1154 
1155 
1156   #ifndef _7ZIP_ST
1157   if (props->numBlockThreads_Reduced > 1)
1158   {
1159     IMtCoderCallback2 vt;
1160 
1161     if (!p->mtCoder_WasConstructed)
1162     {
1163       p->mtCoder_WasConstructed = True;
1164       MtCoder_Construct(&p->mtCoder);
1165     }
1166 
1167     vt.Code = XzEnc_MtCallback_Code;
1168     vt.Write = XzEnc_MtCallback_Write;
1169 
1170     p->checkType = props->checkId;
1171     p->xzProps = *props;
1172 
1173     p->outStream = outStream;
1174 
1175     p->mtCoder.allocBig = p->allocBig;
1176     p->mtCoder.progress = progress;
1177     p->mtCoder.inStream = inStream;
1178     p->mtCoder.inData = NULL;
1179     p->mtCoder.inDataSize = 0;
1180     p->mtCoder.mtCallback = &vt;
1181     p->mtCoder.mtCallbackObject = p;
1182 
1183     if (   props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID
1184         || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO)
1185       return SZ_ERROR_FAIL;
1186 
1187     p->mtCoder.blockSize = (size_t)props->blockSize;
1188     if (p->mtCoder.blockSize != props->blockSize)
1189       return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */
1190 
1191     {
1192       size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize);
1193       if (destBlockSize < p->mtCoder.blockSize)
1194         return SZ_ERROR_PARAM;
1195       if (p->outBufSize != destBlockSize)
1196         XzEnc_FreeOutBufs(p);
1197       p->outBufSize = destBlockSize;
1198     }
1199 
1200     p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max;
1201     p->mtCoder.expectedDataSize = p->expectedDataSize;
1202 
1203     RINOK(MtCoder_Code(&p->mtCoder));
1204   }
1205   else
1206   #endif
1207   {
1208     int writeStartSizes;
1209     CCompressProgress_XzEncOffset progress2;
1210     Byte *bufData = NULL;
1211     size_t bufSize = 0;
1212 
1213     progress2.vt.Progress = CompressProgress_XzEncOffset_Progress;
1214     progress2.inOffset = 0;
1215     progress2.outOffset = 0;
1216     progress2.progress = progress;
1217 
1218     writeStartSizes = 0;
1219 
1220     if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID)
1221     {
1222       writeStartSizes = (props->forceWriteSizesInHeader > 0);
1223 
1224       if (writeStartSizes)
1225       {
1226         size_t t2;
1227         size_t t = (size_t)props->blockSize;
1228         if (t != props->blockSize)
1229           return SZ_ERROR_PARAM;
1230         t = XZ_GET_MAX_BLOCK_PACK_SIZE(t);
1231         if (t < props->blockSize)
1232           return SZ_ERROR_PARAM;
1233         t2 = XZ_BLOCK_HEADER_SIZE_MAX + t;
1234         if (!p->outBufs[0] || t2 != p->outBufSize)
1235         {
1236           XzEnc_FreeOutBufs(p);
1237           p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2);
1238           if (!p->outBufs[0])
1239             return SZ_ERROR_MEM;
1240           p->outBufSize = t2;
1241         }
1242         bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX;
1243         bufSize = t;
1244       }
1245     }
1246 
1247     for (;;)
1248     {
1249       CXzEncBlockInfo blockSizes;
1250       int inStreamFinished;
1251 
1252       /*
1253       UInt64 rem = (UInt64)(Int64)-1;
1254       if (props->reduceSize != (UInt64)(Int64)-1
1255           && props->reduceSize >= progress2.inOffset)
1256         rem = props->reduceSize - progress2.inOffset;
1257       */
1258 
1259       blockSizes.headerSize = 0; // for GCC
1260 
1261       RINOK(Xz_CompressBlock(
1262           &p->lzmaf_Items[0],
1263 
1264           writeStartSizes ? NULL : outStream,
1265           writeStartSizes ? p->outBufs[0] : NULL,
1266           bufData, bufSize,
1267 
1268           inStream,
1269           // rem,
1270           NULL, 0,
1271 
1272           props,
1273           progress ? &progress2.vt : NULL,
1274           &inStreamFinished,
1275           &blockSizes,
1276           p->alloc,
1277           p->allocBig));
1278 
1279       {
1280         UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize);
1281 
1282         if (writeStartSizes)
1283         {
1284           RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize));
1285           RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize));
1286         }
1287 
1288         RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc));
1289 
1290         progress2.inOffset += blockSizes.unpackSize;
1291         progress2.outOffset += totalPackFull;
1292       }
1293 
1294       if (inStreamFinished)
1295         break;
1296     }
1297   }
1298 
1299   return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream);
1300 }
1301 
1302 
1303 #include "Alloc.h"
1304 
Xz_Encode(ISeqOutStream * outStream,ISeqInStream * inStream,const CXzProps * props,ICompressProgress * progress)1305 SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
1306     const CXzProps *props, ICompressProgress *progress)
1307 {
1308   SRes res;
1309   CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc);
1310   if (!xz)
1311     return SZ_ERROR_MEM;
1312   res = XzEnc_SetProps(xz, props);
1313   if (res == SZ_OK)
1314     res = XzEnc_Encode(xz, outStream, inStream, progress);
1315   XzEnc_Destroy(xz);
1316   return res;
1317 }
1318 
1319 
Xz_EncodeEmpty(ISeqOutStream * outStream)1320 SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
1321 {
1322   SRes res;
1323   CXzEncIndex xzIndex;
1324   XzEncIndex_Construct(&xzIndex);
1325   res = Xz_WriteHeader((CXzStreamFlags)0, outStream);
1326   if (res == SZ_OK)
1327     res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream);
1328   XzEncIndex_Free(&xzIndex, NULL); // g_Alloc
1329   return res;
1330 }
1331