Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/lzma/src/XzEnc.c
4253 views
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
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
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
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
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
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
119
static void XzEncIndex_Init(CXzEncIndex *p)
120
{
121
p->numBlocks = 0;
122
p->size = 0;
123
}
124
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
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
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
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
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
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
250
static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
251
{
252
XzCheck_Final(&p->check, digest);
253
}
254
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
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
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
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
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
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
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
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
476
void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
477
{
478
SbEnc_Construct(&p->enc, alloc);
479
p->vt.Read = SbEncInStream_Read;
480
}
481
482
SRes SbEncInStream_Init(CSbEncInStream *p)
483
{
484
return SbEnc_Init(&p->enc);
485
}
486
487
void SbEncInStream_Free(CSbEncInStream *p)
488
{
489
SbEnc_Free(&p->enc);
490
}
491
492
#endif
493
494
495
496
/* ---------- CXzProps ---------- */
497
498
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1370