Coverage Report

Created: 2024-06-17 06:08

/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
31.1k
#define MTCODER__THREADS_MAX 1
27
0
#define MTCODER__BLOCKS_MAX 1
28
#endif
29
30
23.3k
#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
7.79k
#define XzBlock_ClearFlags(p)       (p)->flags = 0;
39
15.5k
#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
46.7k
{
46
46.7k
  return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
47
46.7k
}
48
49
static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc)
50
15.5k
{
51
15.5k
  *crc = CrcUpdate(*crc, buf, size);
52
15.5k
  return WriteBytes(s, buf, size);
53
15.5k
}
54
55
56
static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
57
7.79k
{
58
7.79k
  UInt32 crc;
59
7.79k
  Byte header[XZ_STREAM_HEADER_SIZE];
60
7.79k
  memcpy(header, XZ_SIG, XZ_SIG_SIZE);
61
7.79k
  header[XZ_SIG_SIZE] = (Byte)(f >> 8);
62
7.79k
  header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
63
7.79k
  crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
64
7.79k
  SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
65
7.79k
  return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
66
7.79k
}
67
68
69
static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
70
7.79k
{
71
7.79k
  Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
72
73
7.79k
  unsigned pos = 1;
74
7.79k
  unsigned numFilters, i;
75
7.79k
  header[pos++] = p->flags;
76
77
7.79k
  if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
78
7.79k
  if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
79
7.79k
  numFilters = XzBlock_GetNumFilters(p);
80
  
81
18.8k
  for (i = 0; i < numFilters; i++)
82
11.0k
  {
83
11.0k
    const CXzFilter *f = &p->filters[i];
84
11.0k
    pos += Xz_WriteVarInt(header + pos, f->id);
85
11.0k
    pos += Xz_WriteVarInt(header + pos, f->propsSize);
86
11.0k
    memcpy(header + pos, f->props, f->propsSize);
87
11.0k
    pos += f->propsSize;
88
11.0k
  }
89
90
24.0k
  while ((pos & 3) != 0)
91
16.2k
    header[pos++] = 0;
92
93
7.79k
  header[0] = (Byte)(pos >> 2);
94
7.79k
  SetUi32(header + pos, CrcCalc(header, pos));
95
7.79k
  return WriteBytes(s, header, pos + 4);
96
7.79k
}
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
7.79k
{
112
7.79k
  p->numBlocks = 0;
113
7.79k
  p->size = 0;
114
7.79k
  p->allocated = 0;
115
7.79k
  p->blocks = NULL;
116
7.79k
}
117
118
static void XzEncIndex_Init(CXzEncIndex *p)
119
7.79k
{
120
7.79k
  p->numBlocks = 0;
121
7.79k
  p->size = 0;
122
7.79k
}
123
124
static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc)
125
7.79k
{
126
7.79k
  if (p->blocks)
127
7.79k
  {
128
7.79k
    ISzAlloc_Free(alloc, p->blocks);
129
7.79k
    p->blocks = NULL;
130
7.79k
  }
131
7.79k
  p->numBlocks = 0;
132
7.79k
  p->size = 0;
133
7.79k
  p->allocated = 0;
134
7.79k
}
135
136
137
static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc)
138
7.79k
{
139
7.79k
  Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize);
140
7.79k
  if (!blocks)
141
0
    return SZ_ERROR_MEM;
142
7.79k
  if (p->size != 0)
143
0
    memcpy(blocks, p->blocks, p->size);
144
7.79k
  if (p->blocks)
145
0
    ISzAlloc_Free(alloc, p->blocks);
146
7.79k
  p->blocks = blocks;
147
7.79k
  p->allocated = newSize;
148
7.79k
  return SZ_OK;
149
7.79k
}
150
151
152
static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
153
7.79k
{
154
7.79k
  UInt64 pos;
155
7.79k
  {
156
7.79k
    Byte buf[32];
157
7.79k
    unsigned pos2 = Xz_WriteVarInt(buf, totalSize);
158
7.79k
    pos2 += Xz_WriteVarInt(buf + pos2, unpackSize);
159
7.79k
    pos = numBlocks * pos2;
160
7.79k
  }
161
  
162
7.79k
  if (pos <= p->allocated - p->size)
163
0
    return SZ_OK;
164
7.79k
  {
165
7.79k
    UInt64 newSize64 = p->size + pos;
166
7.79k
    size_t newSize = (size_t)newSize64;
167
7.79k
    if (newSize != newSize64)
168
0
      return SZ_ERROR_MEM;
169
7.79k
    return XzEncIndex_ReAlloc(p, newSize, alloc);
170
7.79k
  }
171
7.79k
}
172
173
174
static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
175
7.79k
{
176
7.79k
  Byte buf[32];
177
7.79k
  unsigned pos = Xz_WriteVarInt(buf, totalSize);
178
7.79k
  pos += Xz_WriteVarInt(buf + pos, unpackSize);
179
180
7.79k
  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
7.79k
  memcpy(p->blocks + p->size, buf, pos);
188
7.79k
  p->size += pos;
189
7.79k
  p->numBlocks++;
190
7.79k
  return SZ_OK;
191
7.79k
}
192
193
194
static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s)
195
7.79k
{
196
7.79k
  Byte buf[32];
197
7.79k
  UInt64 globalPos;
198
7.79k
  UInt32 crc = CRC_INIT_VAL;
199
7.79k
  unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
200
  
201
7.79k
  globalPos = pos;
202
7.79k
  buf[0] = 0;
203
7.79k
  RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc));
204
7.79k
  RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc));
205
7.79k
  globalPos += p->size;
206
  
207
7.79k
  pos = XZ_GET_PAD_SIZE(globalPos);
208
7.79k
  buf[1] = 0;
209
7.79k
  buf[2] = 0;
210
7.79k
  buf[3] = 0;
211
7.79k
  globalPos += pos;
212
  
213
7.79k
  crc = CrcUpdate(crc, buf + 4 - pos, pos);
214
7.79k
  SetUi32(buf + 4, CRC_GET_DIGEST(crc));
215
  
216
7.79k
  SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2));
217
7.79k
  buf[8 + 8] = (Byte)(flags >> 8);
218
7.79k
  buf[8 + 9] = (Byte)(flags & 0xFF);
219
7.79k
  SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6));
220
7.79k
  buf[8 + 10] = XZ_FOOTER_SIG_0;
221
7.79k
  buf[8 + 11] = XZ_FOOTER_SIG_1;
222
  
223
7.79k
  return WriteBytes(s, buf + 4 - pos, pos + 4 + 12);
224
7.79k
}
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
7.79k
{
243
7.79k
  p->limit = (UInt64)(Int64)-1;
244
7.79k
  p->processed = 0;
245
7.79k
  p->realStreamFinished = 0;
246
7.79k
  XzCheck_Init(&p->check, checkMode);
247
7.79k
}
248
249
static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
250
7.79k
{
251
7.79k
  XzCheck_Final(&p->check, digest);
252
7.79k
}
253
254
static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
255
15.5k
{
256
15.5k
  CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt);
257
15.5k
  size_t size2 = *size;
258
15.5k
  SRes res = SZ_OK;
259
  
260
15.5k
  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
15.5k
  if (size2 != 0)
267
15.5k
  {
268
15.5k
    if (p->realStream)
269
15.5k
    {
270
15.5k
      res = ISeqInStream_Read(p->realStream, data, &size2);
271
15.5k
      p->realStreamFinished = (size2 == 0) ? 1 : 0;
272
15.5k
    }
273
0
    else
274
0
      memcpy(data, p->data + (size_t)p->processed, size2);
275
15.5k
    XzCheck_Update(&p->check, data, size2);
276
15.5k
    p->processed += size2;
277
15.5k
  }
278
15.5k
  *size = size2;
279
15.5k
  return res;
280
15.5k
}
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
35.9k
{
296
35.9k
  CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt);
297
35.9k
  if (p->realStream)
298
35.9k
    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
35.9k
  p->processed += size;
306
35.9k
  return size;
307
35.9k
}
308
309
310
/* ---------- CSeqInFilter ---------- */
311
312
6.50k
#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
3.25k
{
330
3.25k
  if (!p->buf)
331
3.25k
  {
332
3.25k
    p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE);
333
3.25k
    if (!p->buf)
334
0
      return SZ_ERROR_MEM;
335
3.25k
  }
336
3.25k
  p->curPos = p->endPos = 0;
337
3.25k
  p->srcWasFinished = 0;
338
3.25k
  RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc));
339
3.25k
  RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc));
340
3.25k
  p->StateCoder.Init(p->StateCoder.p);
341
3.25k
  return SZ_OK;
342
3.25k
}
343
344
345
static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size)
346
8.40k
{
347
8.40k
  CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p);
348
8.40k
  size_t sizeOriginal = *size;
349
8.40k
  if (sizeOriginal == 0)
350
0
    return SZ_OK;
351
8.40k
  *size = 0;
352
  
353
8.40k
  for (;;)
354
8.45k
  {
355
8.45k
    if (!p->srcWasFinished && p->curPos == p->endPos)
356
6.50k
    {
357
6.50k
      p->curPos = 0;
358
6.50k
      p->endPos = FILTER_BUF_SIZE;
359
6.50k
      RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos));
360
6.50k
      if (p->endPos == 0)
361
3.25k
        p->srcWasFinished = 1;
362
6.50k
    }
363
8.45k
    {
364
8.45k
      SizeT srcLen = p->endPos - p->curPos;
365
8.45k
      ECoderStatus status;
366
8.45k
      SRes res;
367
8.45k
      *size = sizeOriginal;
368
8.45k
      res = p->StateCoder.Code2(p->StateCoder.p,
369
8.45k
          (Byte *)data, size,
370
8.45k
          p->buf + p->curPos, &srcLen,
371
8.45k
          p->srcWasFinished, CODER_FINISH_ANY,
372
8.45k
          &status);
373
8.45k
      p->curPos += srcLen;
374
8.45k
      if (*size != 0 || srcLen == 0 || res != SZ_OK)
375
8.40k
        return res;
376
8.45k
    }
377
8.45k
  }
378
8.40k
}
379
380
static void SeqInFilter_Construct(CSeqInFilter *p)
381
7.79k
{
382
7.79k
  p->buf = NULL;
383
7.79k
  p->StateCoder.p = NULL;
384
7.79k
  p->p.Read = SeqInFilter_Read;
385
7.79k
}
386
387
static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
388
7.79k
{
389
7.79k
  if (p->StateCoder.p)
390
3.25k
  {
391
3.25k
    p->StateCoder.Free(p->StateCoder.p, alloc);
392
3.25k
    p->StateCoder.p = NULL;
393
3.25k
  }
394
7.79k
  if (p->buf)
395
3.25k
  {
396
3.25k
    ISzAlloc_Free(alloc, p->buf);
397
3.25k
    p->buf = NULL;
398
3.25k
  }
399
7.79k
}
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
15.5k
{
467
15.5k
  p->id = 0;
468
15.5k
  p->delta = 0;
469
15.5k
  p->ip = 0;
470
15.5k
  p->ipDefined = False;
471
15.5k
}
472
473
void XzProps_Init(CXzProps *p)
474
15.5k
{
475
15.5k
  p->checkId = XZ_CHECK_CRC32;
476
15.5k
  p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO;
477
15.5k
  p->numBlockThreads_Reduced = -1;
478
15.5k
  p->numBlockThreads_Max = -1;
479
15.5k
  p->numTotalThreads = -1;
480
15.5k
  p->reduceSize = (UInt64)(Int64)-1;
481
15.5k
  p->forceWriteSizesInHeader = 0;
482
  // p->forceWriteSizesInHeader = 1;
483
484
15.5k
  XzFilterProps_Init(&p->filterProps);
485
15.5k
  Lzma2EncProps_Init(&p->lzma2Props);
486
15.5k
}
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
15.5k
{
571
  /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
572
     Lzma2Enc_SetProps() will normalize lzma2Props later. */
573
  
574
15.5k
  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
15.5k
  else
584
15.5k
  {
585
15.5k
    CLzma2EncProps *lzma2 = &p->lzma2Props;
586
15.5k
    if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
587
15.5k
    {
588
      // xz-auto
589
15.5k
      p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
590
591
15.5k
      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
15.5k
      else
601
15.5k
      {
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
15.5k
        CLzma2EncProps tp = p->lzma2Props;
605
15.5k
        if (tp.numTotalThreads <= 0)
606
15.5k
          tp.numTotalThreads = p->numTotalThreads;
607
        
608
15.5k
        Lzma2EncProps_Normalize(&tp);
609
        
610
15.5k
        p->blockSize = tp.blockSize; // fixed or solid
611
15.5k
        p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced;
612
15.5k
        p->numBlockThreads_Max = tp.numBlockThreads_Max;
613
15.5k
        if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
614
15.5k
          lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
615
15.5k
        if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
616
0
          lzma2->lzmaProps.reduceSize = tp.blockSize;
617
15.5k
        lzma2->numBlockThreads_Reduced = 1;
618
15.5k
        lzma2->numBlockThreads_Max = 1;
619
15.5k
        return;
620
15.5k
      }
621
15.5k
    }
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
15.5k
  }
642
15.5k
}
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
7.79k
{
660
7.79k
  p->lzma2 = NULL;
661
7.79k
  SeqInFilter_Construct(&p->filter);
662
663
  #ifdef USE_SUBBLOCK
664
  SbEncInStream_Construct(&p->sb, alloc);
665
  #endif
666
7.79k
}
667
668
669
static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc)
670
7.79k
{
671
7.79k
  if (!p->lzma2)
672
7.79k
  {
673
7.79k
    p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc);
674
7.79k
    if (!p->lzma2)
675
0
      return SZ_ERROR_MEM;
676
7.79k
  }
677
7.79k
  return SZ_OK;
678
7.79k
}
679
680
681
static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
682
7.79k
{
683
  #ifdef USE_SUBBLOCK
684
  SbEncInStream_Free(&p->sb);
685
  #endif
686
687
7.79k
  SeqInFilter_Free(&p->filter, alloc);
688
7.79k
  if (p->lzma2)
689
7.79k
  {
690
7.79k
    Lzma2Enc_Destroy(p->lzma2);
691
7.79k
    p->lzma2 = NULL;
692
7.79k
  }
693
7.79k
}
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
7.79k
{
723
7.79k
  CSeqCheckInStream checkInStream;
724
7.79k
  CSeqSizeOutStream seqSizeOutStream;
725
7.79k
  CXzBlock block;
726
7.79k
  unsigned filterIndex = 0;
727
7.79k
  CXzFilter *filter = NULL;
728
7.79k
  const CXzFilterProps *fp = &props->filterProps;
729
7.79k
  if (fp->id == 0)
730
4.54k
    fp = NULL;
731
  
732
7.79k
  *inStreamFinished = False;
733
  
734
7.79k
  RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig));
735
  
736
7.79k
  RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props));
737
  
738
7.79k
  XzBlock_ClearFlags(&block);
739
7.79k
  XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0));
740
  
741
7.79k
  if (fp)
742
3.25k
  {
743
3.25k
    filter = &block.filters[filterIndex++];
744
3.25k
    filter->id = fp->id;
745
3.25k
    filter->propsSize = 0;
746
    
747
3.25k
    if (fp->id == XZ_ID_Delta)
748
673
    {
749
673
      filter->props[0] = (Byte)(fp->delta - 1);
750
673
      filter->propsSize = 1;
751
673
    }
752
2.58k
    else if (fp->ipDefined)
753
2.58k
    {
754
2.58k
      SetUi32(filter->props, fp->ip);
755
2.58k
      filter->propsSize = 4;
756
2.58k
    }
757
3.25k
  }
758
  
759
7.79k
  {
760
7.79k
    CXzFilter *f = &block.filters[filterIndex++];
761
7.79k
    f->id = XZ_ID_LZMA2;
762
7.79k
    f->propsSize = 1;
763
7.79k
    f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
764
7.79k
  }
765
  
766
7.79k
  seqSizeOutStream.vt.Write = SeqSizeOutStream_Write;
767
7.79k
  seqSizeOutStream.realStream = outStream;
768
7.79k
  seqSizeOutStream.outBuf = outBufData;
769
7.79k
  seqSizeOutStream.outBufLimit = outBufDataLimit;
770
7.79k
  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
7.79k
  if (outStream)
784
7.79k
  {
785
7.79k
    RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
786
7.79k
  }
787
  
788
7.79k
  checkInStream.vt.Read = SeqCheckInStream_Read;
789
7.79k
  SeqCheckInStream_Init(&checkInStream, props->checkId);
790
  
791
7.79k
  checkInStream.realStream = inStream;
792
7.79k
  checkInStream.data = inBuf;
793
7.79k
  checkInStream.limit = props->blockSize;
794
7.79k
  if (!inStream)
795
0
    checkInStream.limit = inBufSize;
796
797
7.79k
  if (fp)
798
3.25k
  {
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
3.25k
    {
808
3.25k
      lzmaf->filter.realStream = &checkInStream.vt;
809
3.25k
      RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc));
810
3.25k
    }
811
3.25k
  }
812
813
7.79k
  {
814
7.79k
    SRes res;
815
7.79k
    Byte *outBuf = NULL;
816
7.79k
    size_t outSize = 0;
817
7.79k
    BoolInt useStream = (fp || inStream);
818
    // useStream = True;
819
    
820
7.79k
    if (!useStream)
821
0
    {
822
0
      XzCheck_Update(&checkInStream.check, inBuf, inBufSize);
823
0
      checkInStream.processed = inBufSize;
824
0
    }
825
    
826
7.79k
    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
7.79k
    res = Lzma2Enc_Encode2(lzmaf->lzma2,
833
7.79k
        outBuf ? NULL : &seqSizeOutStream.vt,
834
7.79k
        outBuf,
835
7.79k
        outBuf ? &outSize : NULL,
836
      
837
7.79k
        useStream ?
838
7.79k
          (fp ?
839
3.25k
            (
840
            #ifdef USE_SUBBLOCK
841
            (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt:
842
            #endif
843
3.25k
            &lzmaf->filter.p) :
844
7.79k
            &checkInStream.vt) : NULL,
845
      
846
7.79k
        useStream ? NULL : inBuf,
847
7.79k
        useStream ? 0 : inBufSize,
848
        
849
7.79k
        progress);
850
    
851
7.79k
    if (outBuf)
852
0
      seqSizeOutStream.processed += outSize;
853
    
854
7.79k
    RINOK(res);
855
7.79k
    blockSizes->unpackSize = checkInStream.processed;
856
7.79k
  }
857
0
  {
858
7.79k
    Byte buf[4 + 64];
859
7.79k
    unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
860
7.79k
    UInt64 packSize = seqSizeOutStream.processed;
861
    
862
7.79k
    buf[0] = 0;
863
7.79k
    buf[1] = 0;
864
7.79k
    buf[2] = 0;
865
7.79k
    buf[3] = 0;
866
    
867
7.79k
    SeqCheckInStream_GetDigest(&checkInStream, buf + 4);
868
7.79k
    RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId)));
869
    
870
7.79k
    blockSizes->totalSize = seqSizeOutStream.processed - padSize;
871
    
872
7.79k
    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
7.79k
  }
890
  
891
7.79k
  if (inStream)
892
7.79k
    *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
7.79k
  return SZ_OK;
901
7.79k
}
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
7.79k
{
953
7.79k
  unsigned i;
954
955
7.79k
  XzEncIndex_Construct(&p->xzIndex);
956
957
15.5k
  for (i = 0; i < MTCODER__THREADS_MAX; i++)
958
7.79k
    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
7.79k
}
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
7.79k
{
986
7.79k
  unsigned i;
987
988
7.79k
  XzEncIndex_Free(&p->xzIndex, alloc);
989
990
15.5k
  for (i = 0; i < MTCODER__THREADS_MAX; i++)
991
7.79k
    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
7.79k
}
1002
1003
1004
CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
1005
7.79k
{
1006
7.79k
  CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc));
1007
7.79k
  if (!p)
1008
0
    return NULL;
1009
7.79k
  XzEnc_Construct(p);
1010
7.79k
  XzProps_Init(&p->xzProps);
1011
7.79k
  XzProps_Normalize(&p->xzProps);
1012
7.79k
  p->expectedDataSize = (UInt64)(Int64)-1;
1013
7.79k
  p->alloc = alloc;
1014
7.79k
  p->allocBig = allocBig;
1015
7.79k
  return p;
1016
7.79k
}
1017
1018
1019
void XzEnc_Destroy(CXzEncHandle pp)
1020
7.79k
{
1021
7.79k
  CXzEnc *p = (CXzEnc *)pp;
1022
7.79k
  XzEnc_Free(p, p->alloc);
1023
7.79k
  ISzAlloc_Free(p->alloc, p);
1024
7.79k
}
1025
1026
1027
SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props)
1028
7.79k
{
1029
7.79k
  CXzEnc *p = (CXzEnc *)pp;
1030
7.79k
  p->xzProps = *props;
1031
7.79k
  XzProps_Normalize(&p->xzProps);
1032
7.79k
  return SZ_OK;
1033
7.79k
}
1034
1035
1036
void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize)
1037
7.79k
{
1038
7.79k
  CXzEnc *p = (CXzEnc *)pp;
1039
7.79k
  p->expectedDataSize = expectedDataSiize;
1040
7.79k
}
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
7.79k
{
1130
7.79k
  CXzEnc *p = (CXzEnc *)pp;
1131
1132
7.79k
  const CXzProps *props = &p->xzProps;
1133
1134
7.79k
  XzEncIndex_Init(&p->xzIndex);
1135
7.79k
  {
1136
7.79k
    UInt64 numBlocks = 1;
1137
7.79k
    UInt64 blockSize = props->blockSize;
1138
    
1139
7.79k
    if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID
1140
7.79k
        && 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
7.79k
    else
1147
7.79k
      blockSize = (UInt64)1 << 62;
1148
    
1149
7.79k
    RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc));
1150
7.79k
  }
1151
1152
7.79k
  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
7.79k
  {
1207
7.79k
    int writeStartSizes;
1208
7.79k
    CCompressProgress_XzEncOffset progress2;
1209
7.79k
    Byte *bufData = NULL;
1210
7.79k
    size_t bufSize = 0;
1211
1212
7.79k
    progress2.vt.Progress = CompressProgress_XzEncOffset_Progress;
1213
7.79k
    progress2.inOffset = 0;
1214
7.79k
    progress2.outOffset = 0;
1215
7.79k
    progress2.progress = progress;
1216
    
1217
7.79k
    writeStartSizes = 0;
1218
    
1219
7.79k
    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
7.79k
    for (;;)
1247
7.79k
    {
1248
7.79k
      CXzEncBlockInfo blockSizes;
1249
7.79k
      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
7.79k
      blockSizes.headerSize = 0; // for GCC
1259
      
1260
7.79k
      RINOK(Xz_CompressBlock(
1261
7.79k
          &p->lzmaf_Items[0],
1262
          
1263
7.79k
          writeStartSizes ? NULL : outStream,
1264
7.79k
          writeStartSizes ? p->outBufs[0] : NULL,
1265
7.79k
          bufData, bufSize,
1266
          
1267
7.79k
          inStream,
1268
          // rem,
1269
7.79k
          NULL, 0,
1270
          
1271
7.79k
          props,
1272
7.79k
          progress ? &progress2.vt : NULL,
1273
7.79k
          &inStreamFinished,
1274
7.79k
          &blockSizes,
1275
7.79k
          p->alloc,
1276
7.79k
          p->allocBig));
1277
1278
7.79k
      {
1279
7.79k
        UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize);
1280
      
1281
7.79k
        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
7.79k
        RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc));
1288
        
1289
7.79k
        progress2.inOffset += blockSizes.unpackSize;
1290
7.79k
        progress2.outOffset += totalPackFull;
1291
7.79k
      }
1292
        
1293
7.79k
      if (inStreamFinished)
1294
7.79k
        break;
1295
7.79k
    }
1296
7.79k
  }
1297
1298
7.79k
  return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream);
1299
7.79k
}
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
}