Coverage Report

Created: 2025-07-11 06:29

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