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