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