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