all repos — mgba @ b2d406a411b31acce5bbf0246af32a80c22ca834

mGBA Game Boy Advance Emulator

src/third-party/lzma/XzEnc.c (view raw)

   1/* XzEnc.c -- Xz Encode
   22019-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#define MTCODER__THREADS_MAX 1
  27#define MTCODER__BLOCKS_MAX 1
  28#endif
  29
  30#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3)
  31
  32/* max pack size for LZMA2 block + check-64bytrs: */
  33#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)
  34
  35#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize))
  36
  37
  38#define XzBlock_ClearFlags(p)       (p)->flags = 0;
  39#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);
  40#define XzBlock_SetHasPackSize(p)   (p)->flags |= XZ_BF_PACK_SIZE;
  41#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
  42
  43
  44static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size)
  45{
  46  return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
  47}
  48
  49static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc)
  50{
  51  *crc = CrcUpdate(*crc, buf, size);
  52  return WriteBytes(s, buf, size);
  53}
  54
  55
  56static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
  57{
  58  UInt32 crc;
  59  Byte header[XZ_STREAM_HEADER_SIZE];
  60  memcpy(header, XZ_SIG, XZ_SIG_SIZE);
  61  header[XZ_SIG_SIZE] = (Byte)(f >> 8);
  62  header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
  63  crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
  64  SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
  65  return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
  66}
  67
  68
  69static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
  70{
  71  Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
  72
  73  unsigned pos = 1;
  74  unsigned numFilters, i;
  75  header[pos++] = p->flags;
  76
  77  if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
  78  if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
  79  numFilters = XzBlock_GetNumFilters(p);
  80  
  81  for (i = 0; i < numFilters; i++)
  82  {
  83    const CXzFilter *f = &p->filters[i];
  84    pos += Xz_WriteVarInt(header + pos, f->id);
  85    pos += Xz_WriteVarInt(header + pos, f->propsSize);
  86    memcpy(header + pos, f->props, f->propsSize);
  87    pos += f->propsSize;
  88  }
  89
  90  while ((pos & 3) != 0)
  91    header[pos++] = 0;
  92
  93  header[0] = (Byte)(pos >> 2);
  94  SetUi32(header + pos, CrcCalc(header, pos));
  95  return WriteBytes(s, header, pos + 4);
  96}
  97
  98
  99
 100
 101typedef struct
 102{
 103  size_t numBlocks;
 104  size_t size;
 105  size_t allocated;
 106  Byte *blocks;
 107} CXzEncIndex;
 108
 109
 110static void XzEncIndex_Construct(CXzEncIndex *p)
 111{
 112  p->numBlocks = 0;
 113  p->size = 0;
 114  p->allocated = 0;
 115  p->blocks = NULL;
 116}
 117
 118static void XzEncIndex_Init(CXzEncIndex *p)
 119{
 120  p->numBlocks = 0;
 121  p->size = 0;
 122}
 123
 124static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc)
 125{
 126  if (p->blocks)
 127  {
 128    ISzAlloc_Free(alloc, p->blocks);
 129    p->blocks = NULL;
 130  }
 131  p->numBlocks = 0;
 132  p->size = 0;
 133  p->allocated = 0;
 134}
 135
 136
 137static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc)
 138{
 139  Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize);
 140  if (!blocks)
 141    return SZ_ERROR_MEM;
 142  if (p->size != 0)
 143    memcpy(blocks, p->blocks, p->size);
 144  if (p->blocks)
 145    ISzAlloc_Free(alloc, p->blocks);
 146  p->blocks = blocks;
 147  p->allocated = newSize;
 148  return SZ_OK;
 149}
 150
 151
 152static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
 153{
 154  UInt64 pos;
 155  {
 156    Byte buf[32];
 157    unsigned pos2 = Xz_WriteVarInt(buf, totalSize);
 158    pos2 += Xz_WriteVarInt(buf + pos2, unpackSize);
 159    pos = numBlocks * pos2;
 160  }
 161  
 162  if (pos <= p->allocated - p->size)
 163    return SZ_OK;
 164  {
 165    UInt64 newSize64 = p->size + pos;
 166    size_t newSize = (size_t)newSize64;
 167    if (newSize != newSize64)
 168      return SZ_ERROR_MEM;
 169    return XzEncIndex_ReAlloc(p, newSize, alloc);
 170  }
 171}
 172
 173
 174static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
 175{
 176  Byte buf[32];
 177  unsigned pos = Xz_WriteVarInt(buf, totalSize);
 178  pos += Xz_WriteVarInt(buf + pos, unpackSize);
 179
 180  if (pos > p->allocated - p->size)
 181  {
 182    size_t newSize = p->allocated * 2 + 16 * 2;
 183    if (newSize < p->size + pos)
 184      return SZ_ERROR_MEM;
 185    RINOK(XzEncIndex_ReAlloc(p, newSize, alloc));
 186  }
 187  memcpy(p->blocks + p->size, buf, pos);
 188  p->size += pos;
 189  p->numBlocks++;
 190  return SZ_OK;
 191}
 192
 193
 194static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s)
 195{
 196  Byte buf[32];
 197  UInt64 globalPos;
 198  UInt32 crc = CRC_INIT_VAL;
 199  unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
 200  
 201  globalPos = pos;
 202  buf[0] = 0;
 203  RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc));
 204  RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc));
 205  globalPos += p->size;
 206  
 207  pos = XZ_GET_PAD_SIZE(globalPos);
 208  buf[1] = 0;
 209  buf[2] = 0;
 210  buf[3] = 0;
 211  globalPos += pos;
 212  
 213  crc = CrcUpdate(crc, buf + 4 - pos, pos);
 214  SetUi32(buf + 4, CRC_GET_DIGEST(crc));
 215  
 216  SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2));
 217  buf[8 + 8] = (Byte)(flags >> 8);
 218  buf[8 + 9] = (Byte)(flags & 0xFF);
 219  SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6));
 220  buf[8 + 10] = XZ_FOOTER_SIG_0;
 221  buf[8 + 11] = XZ_FOOTER_SIG_1;
 222  
 223  return WriteBytes(s, buf + 4 - pos, pos + 4 + 12);
 224}
 225
 226
 227
 228/* ---------- CSeqCheckInStream ---------- */
 229
 230typedef 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
 241static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode)
 242{
 243  p->limit = (UInt64)(Int64)-1;
 244  p->processed = 0;
 245  p->realStreamFinished = 0;
 246  XzCheck_Init(&p->check, checkMode);
 247}
 248
 249static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
 250{
 251  XzCheck_Final(&p->check, digest);
 252}
 253
 254static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
 255{
 256  CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt);
 257  size_t size2 = *size;
 258  SRes res = SZ_OK;
 259  
 260  if (p->limit != (UInt64)(Int64)-1)
 261  {
 262    UInt64 rem = p->limit - p->processed;
 263    if (size2 > rem)
 264      size2 = (size_t)rem;
 265  }
 266  if (size2 != 0)
 267  {
 268    if (p->realStream)
 269    {
 270      res = ISeqInStream_Read(p->realStream, data, &size2);
 271      p->realStreamFinished = (size2 == 0) ? 1 : 0;
 272    }
 273    else
 274      memcpy(data, p->data + (size_t)p->processed, size2);
 275    XzCheck_Update(&p->check, data, size2);
 276    p->processed += size2;
 277  }
 278  *size = size2;
 279  return res;
 280}
 281
 282
 283/* ---------- CSeqSizeOutStream ---------- */
 284
 285typedef struct
 286{
 287  ISeqOutStream vt;
 288  ISeqOutStream *realStream;
 289  Byte *outBuf;
 290  size_t outBufLimit;
 291  UInt64 processed;
 292} CSeqSizeOutStream;
 293
 294static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size)
 295{
 296  CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt);
 297  if (p->realStream)
 298    size = ISeqOutStream_Write(p->realStream, data, size);
 299  else
 300  {
 301    if (size > p->outBufLimit - (size_t)p->processed)
 302      return 0;
 303    memcpy(p->outBuf + (size_t)p->processed, data, size);
 304  }
 305  p->processed += size;
 306  return size;
 307}
 308
 309
 310/* ---------- CSeqInFilter ---------- */
 311
 312#define FILTER_BUF_SIZE (1 << 20)
 313
 314typedef 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
 326SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);
 327
 328static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc)
 329{
 330  if (!p->buf)
 331  {
 332    p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE);
 333    if (!p->buf)
 334      return SZ_ERROR_MEM;
 335  }
 336  p->curPos = p->endPos = 0;
 337  p->srcWasFinished = 0;
 338  RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc));
 339  RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc));
 340  p->StateCoder.Init(p->StateCoder.p);
 341  return SZ_OK;
 342}
 343
 344
 345static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size)
 346{
 347  CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p);
 348  size_t sizeOriginal = *size;
 349  if (sizeOriginal == 0)
 350    return SZ_OK;
 351  *size = 0;
 352  
 353  for (;;)
 354  {
 355    if (!p->srcWasFinished && p->curPos == p->endPos)
 356    {
 357      p->curPos = 0;
 358      p->endPos = FILTER_BUF_SIZE;
 359      RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos));
 360      if (p->endPos == 0)
 361        p->srcWasFinished = 1;
 362    }
 363    {
 364      SizeT srcLen = p->endPos - p->curPos;
 365      ECoderStatus status;
 366      SRes res;
 367      *size = sizeOriginal;
 368      res = p->StateCoder.Code2(p->StateCoder.p,
 369          (Byte *)data, size,
 370          p->buf + p->curPos, &srcLen,
 371          p->srcWasFinished, CODER_FINISH_ANY,
 372          &status);
 373      p->curPos += srcLen;
 374      if (*size != 0 || srcLen == 0 || res != SZ_OK)
 375        return res;
 376    }
 377  }
 378}
 379
 380static void SeqInFilter_Construct(CSeqInFilter *p)
 381{
 382  p->buf = NULL;
 383  p->StateCoder.p = NULL;
 384  p->p.Read = SeqInFilter_Read;
 385}
 386
 387static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
 388{
 389  if (p->StateCoder.p)
 390  {
 391    p->StateCoder.Free(p->StateCoder.p, alloc);
 392    p->StateCoder.p = NULL;
 393  }
 394  if (p->buf)
 395  {
 396    ISzAlloc_Free(alloc, p->buf);
 397    p->buf = NULL;
 398  }
 399}
 400
 401
 402/* ---------- CSbEncInStream ---------- */
 403
 404#ifdef USE_SUBBLOCK
 405
 406typedef struct
 407{
 408  ISeqInStream vt;
 409  ISeqInStream *inStream;
 410  CSbEnc enc;
 411} CSbEncInStream;
 412
 413static 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
 442void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
 443{
 444  SbEnc_Construct(&p->enc, alloc);
 445  p->vt.Read = SbEncInStream_Read;
 446}
 447
 448SRes SbEncInStream_Init(CSbEncInStream *p)
 449{
 450  return SbEnc_Init(&p->enc);
 451}
 452
 453void SbEncInStream_Free(CSbEncInStream *p)
 454{
 455  SbEnc_Free(&p->enc);
 456}
 457
 458#endif
 459
 460
 461
 462/* ---------- CXzProps ---------- */
 463
 464
 465void XzFilterProps_Init(CXzFilterProps *p)
 466{
 467  p->id = 0;
 468  p->delta = 0;
 469  p->ip = 0;
 470  p->ipDefined = False;
 471}
 472
 473void XzProps_Init(CXzProps *p)
 474{
 475  p->checkId = XZ_CHECK_CRC32;
 476  p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO;
 477  p->numBlockThreads_Reduced = -1;
 478  p->numBlockThreads_Max = -1;
 479  p->numTotalThreads = -1;
 480  p->reduceSize = (UInt64)(Int64)-1;
 481  p->forceWriteSizesInHeader = 0;
 482  // p->forceWriteSizesInHeader = 1;
 483
 484  XzFilterProps_Init(&p->filterProps);
 485  Lzma2EncProps_Init(&p->lzma2Props);
 486}
 487
 488
 489static void XzEncProps_Normalize_Fixed(CXzProps *p)
 490{
 491  UInt64 fileSize;
 492  int t1, t1n, t2, t2r, t3;
 493  {
 494    CLzma2EncProps tp = p->lzma2Props;
 495    if (tp.numTotalThreads <= 0)
 496      tp.numTotalThreads = p->numTotalThreads;
 497    Lzma2EncProps_Normalize(&tp);
 498    t1n = tp.numTotalThreads;
 499  }
 500
 501  t1 = p->lzma2Props.numTotalThreads;
 502  t2 = p->numBlockThreads_Max;
 503  t3 = p->numTotalThreads;
 504
 505  if (t2 > MTCODER__THREADS_MAX)
 506    t2 = MTCODER__THREADS_MAX;
 507
 508  if (t3 <= 0)
 509  {
 510    if (t2 <= 0)
 511      t2 = 1;
 512    t3 = t1n * t2;
 513  }
 514  else if (t2 <= 0)
 515  {
 516    t2 = t3 / t1n;
 517    if (t2 == 0)
 518    {
 519      t1 = 1;
 520      t2 = t3;
 521    }
 522    if (t2 > MTCODER__THREADS_MAX)
 523      t2 = MTCODER__THREADS_MAX;
 524  }
 525  else if (t1 <= 0)
 526  {
 527    t1 = t3 / t2;
 528    if (t1 == 0)
 529      t1 = 1;
 530  }
 531  else
 532    t3 = t1n * t2;
 533
 534  p->lzma2Props.numTotalThreads = t1;
 535
 536  t2r = t2;
 537
 538  fileSize = p->reduceSize;
 539
 540  if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
 541    p->lzma2Props.lzmaProps.reduceSize = p->blockSize;
 542
 543  Lzma2EncProps_Normalize(&p->lzma2Props);
 544
 545  t1 = p->lzma2Props.numTotalThreads;
 546
 547  {
 548    if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
 549    {
 550      UInt64 numBlocks = fileSize / p->blockSize;
 551      if (numBlocks * p->blockSize != fileSize)
 552        numBlocks++;
 553      if (numBlocks < (unsigned)t2)
 554      {
 555        t2r = (unsigned)numBlocks;
 556        if (t2r == 0)
 557          t2r = 1;
 558        t3 = t1 * t2r;
 559      }
 560    }
 561  }
 562  
 563  p->numBlockThreads_Max = t2;
 564  p->numBlockThreads_Reduced = t2r;
 565  p->numTotalThreads = t3;
 566}
 567
 568
 569static void XzProps_Normalize(CXzProps *p)
 570{
 571  /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
 572     Lzma2Enc_SetProps() will normalize lzma2Props later. */
 573  
 574  if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID)
 575  {
 576    p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
 577    p->numBlockThreads_Reduced = 1;
 578    p->numBlockThreads_Max = 1;
 579    if (p->lzma2Props.numTotalThreads <= 0)
 580      p->lzma2Props.numTotalThreads = p->numTotalThreads;
 581    return;
 582  }
 583  else
 584  {
 585    CLzma2EncProps *lzma2 = &p->lzma2Props;
 586    if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
 587    {
 588      // xz-auto
 589      p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
 590
 591      if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
 592      {
 593        // if (xz-auto && lzma2-solid) - we use solid for both
 594        p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID;
 595        p->numBlockThreads_Reduced = 1;
 596        p->numBlockThreads_Max = 1;
 597        if (p->lzma2Props.numTotalThreads <= 0)
 598          p->lzma2Props.numTotalThreads = p->numTotalThreads;
 599      }
 600      else
 601      {
 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        CLzma2EncProps tp = p->lzma2Props;
 605        if (tp.numTotalThreads <= 0)
 606          tp.numTotalThreads = p->numTotalThreads;
 607        
 608        Lzma2EncProps_Normalize(&tp);
 609        
 610        p->blockSize = tp.blockSize; // fixed or solid
 611        p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced;
 612        p->numBlockThreads_Max = tp.numBlockThreads_Max;
 613        if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
 614          lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
 615        if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
 616          lzma2->lzmaProps.reduceSize = tp.blockSize;
 617        lzma2->numBlockThreads_Reduced = 1;
 618        lzma2->numBlockThreads_Max = 1;
 619        return;
 620      }
 621    }
 622    else
 623    {
 624      // xz-fixed
 625      // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize
 626      
 627      p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
 628      {
 629        UInt64 r = p->reduceSize;
 630        if (r > p->blockSize || r == (UInt64)(Int64)-1)
 631          r = p->blockSize;
 632        lzma2->lzmaProps.reduceSize = r;
 633      }
 634      if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
 635        lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
 636      else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
 637        lzma2->blockSize = p->blockSize;
 638      
 639      XzEncProps_Normalize_Fixed(p);
 640    }
 641  }
 642}
 643
 644
 645/* ---------- CLzma2WithFilters ---------- */
 646
 647typedef struct
 648{
 649  CLzma2EncHandle lzma2;
 650  CSeqInFilter filter;
 651
 652  #ifdef USE_SUBBLOCK
 653  CSbEncInStream sb;
 654  #endif
 655} CLzma2WithFilters;
 656
 657
 658static void Lzma2WithFilters_Construct(CLzma2WithFilters *p)
 659{
 660  p->lzma2 = NULL;
 661  SeqInFilter_Construct(&p->filter);
 662
 663  #ifdef USE_SUBBLOCK
 664  SbEncInStream_Construct(&p->sb, alloc);
 665  #endif
 666}
 667
 668
 669static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc)
 670{
 671  if (!p->lzma2)
 672  {
 673    p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc);
 674    if (!p->lzma2)
 675      return SZ_ERROR_MEM;
 676  }
 677  return SZ_OK;
 678}
 679
 680
 681static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
 682{
 683  #ifdef USE_SUBBLOCK
 684  SbEncInStream_Free(&p->sb);
 685  #endif
 686
 687  SeqInFilter_Free(&p->filter, alloc);
 688  if (p->lzma2)
 689  {
 690    Lzma2Enc_Destroy(p->lzma2);
 691    p->lzma2 = NULL;
 692  }
 693}
 694
 695
 696typedef struct
 697{
 698  UInt64 unpackSize;
 699  UInt64 totalSize;
 700  size_t headerSize;
 701} CXzEncBlockInfo;
 702
 703
 704static 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{
 723  CSeqCheckInStream checkInStream;
 724  CSeqSizeOutStream seqSizeOutStream;
 725  CXzBlock block;
 726  unsigned filterIndex = 0;
 727  CXzFilter *filter = NULL;
 728  const CXzFilterProps *fp = &props->filterProps;
 729  if (fp->id == 0)
 730    fp = NULL;
 731  
 732  *inStreamFinished = False;
 733  
 734  RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig));
 735  
 736  RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props));
 737  
 738  XzBlock_ClearFlags(&block);
 739  XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0));
 740  
 741  if (fp)
 742  {
 743    filter = &block.filters[filterIndex++];
 744    filter->id = fp->id;
 745    filter->propsSize = 0;
 746    
 747    if (fp->id == XZ_ID_Delta)
 748    {
 749      filter->props[0] = (Byte)(fp->delta - 1);
 750      filter->propsSize = 1;
 751    }
 752    else if (fp->ipDefined)
 753    {
 754      SetUi32(filter->props, fp->ip);
 755      filter->propsSize = 4;
 756    }
 757  }
 758  
 759  {
 760    CXzFilter *f = &block.filters[filterIndex++];
 761    f->id = XZ_ID_LZMA2;
 762    f->propsSize = 1;
 763    f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
 764  }
 765  
 766  seqSizeOutStream.vt.Write = SeqSizeOutStream_Write;
 767  seqSizeOutStream.realStream = outStream;
 768  seqSizeOutStream.outBuf = outBufData;
 769  seqSizeOutStream.outBufLimit = outBufDataLimit;
 770  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  if (outStream)
 784  {
 785    RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
 786  }
 787  
 788  checkInStream.vt.Read = SeqCheckInStream_Read;
 789  SeqCheckInStream_Init(&checkInStream, props->checkId);
 790  
 791  checkInStream.realStream = inStream;
 792  checkInStream.data = inBuf;
 793  checkInStream.limit = props->blockSize;
 794  if (!inStream)
 795    checkInStream.limit = inBufSize;
 796
 797  if (fp)
 798  {
 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    {
 808      lzmaf->filter.realStream = &checkInStream.vt;
 809      RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc));
 810    }
 811  }
 812
 813  {
 814    SRes res;
 815    Byte *outBuf = NULL;
 816    size_t outSize = 0;
 817    BoolInt useStream = (fp || inStream);
 818    // useStream = True;
 819    
 820    if (!useStream)
 821    {
 822      XzCheck_Update(&checkInStream.check, inBuf, inBufSize);
 823      checkInStream.processed = inBufSize;
 824    }
 825    
 826    if (!outStream)
 827    {
 828      outBuf = seqSizeOutStream.outBuf; //  + (size_t)seqSizeOutStream.processed;
 829      outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed;
 830    }
 831    
 832    res = Lzma2Enc_Encode2(lzmaf->lzma2,
 833        outBuf ? NULL : &seqSizeOutStream.vt,
 834        outBuf,
 835        outBuf ? &outSize : NULL,
 836      
 837        useStream ?
 838          (fp ?
 839            (
 840            #ifdef USE_SUBBLOCK
 841            (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt:
 842            #endif
 843            &lzmaf->filter.p) :
 844            &checkInStream.vt) : NULL,
 845      
 846        useStream ? NULL : inBuf,
 847        useStream ? 0 : inBufSize,
 848        
 849        progress);
 850    
 851    if (outBuf)
 852      seqSizeOutStream.processed += outSize;
 853    
 854    RINOK(res);
 855    blockSizes->unpackSize = checkInStream.processed;
 856  }
 857  {
 858    Byte buf[4 + 64];
 859    unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
 860    UInt64 packSize = seqSizeOutStream.processed;
 861    
 862    buf[0] = 0;
 863    buf[1] = 0;
 864    buf[2] = 0;
 865    buf[3] = 0;
 866    
 867    SeqCheckInStream_GetDigest(&checkInStream, buf + 4);
 868    RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId)));
 869    
 870    blockSizes->totalSize = seqSizeOutStream.processed - padSize;
 871    
 872    if (!outStream)
 873    {
 874      seqSizeOutStream.outBuf = outBufHeader;
 875      seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX;
 876      seqSizeOutStream.processed = 0;
 877      
 878      block.unpackSize = blockSizes->unpackSize;
 879      XzBlock_SetHasUnpackSize(&block);
 880      
 881      block.packSize = packSize;
 882      XzBlock_SetHasPackSize(&block);
 883      
 884      RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
 885      
 886      blockSizes->headerSize = (size_t)seqSizeOutStream.processed;
 887      blockSizes->totalSize += seqSizeOutStream.processed;
 888    }
 889  }
 890  
 891  if (inStream)
 892    *inStreamFinished = checkInStream.realStreamFinished;
 893  else
 894  {
 895    *inStreamFinished = False;
 896    if (checkInStream.processed != inBufSize)
 897      return SZ_ERROR_FAIL;
 898  }
 899
 900  return SZ_OK;
 901}
 902
 903
 904
 905typedef struct
 906{
 907  ICompressProgress vt;
 908  ICompressProgress *progress;
 909  UInt64 inOffset;
 910  UInt64 outOffset;
 911} CCompressProgress_XzEncOffset;
 912
 913
 914static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize)
 915{
 916  const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt);
 917  inSize += p->inOffset;
 918  outSize += p->outOffset;
 919  return ICompressProgress_Progress(p->progress, inSize, outSize);
 920}
 921
 922
 923
 924
 925typedef 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
 951static void XzEnc_Construct(CXzEnc *p)
 952{
 953  unsigned i;
 954
 955  XzEncIndex_Construct(&p->xzIndex);
 956
 957  for (i = 0; i < MTCODER__THREADS_MAX; i++)
 958    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}
 969
 970
 971static void XzEnc_FreeOutBufs(CXzEnc *p)
 972{
 973  unsigned i;
 974  for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
 975    if (p->outBufs[i])
 976    {
 977      ISzAlloc_Free(p->alloc, p->outBufs[i]);
 978      p->outBufs[i] = NULL;
 979    }
 980  p->outBufSize = 0;
 981}
 982
 983
 984static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc)
 985{
 986  unsigned i;
 987
 988  XzEncIndex_Free(&p->xzIndex, alloc);
 989
 990  for (i = 0; i < MTCODER__THREADS_MAX; i++)
 991    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}
1002
1003
1004CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
1005{
1006  CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc));
1007  if (!p)
1008    return NULL;
1009  XzEnc_Construct(p);
1010  XzProps_Init(&p->xzProps);
1011  XzProps_Normalize(&p->xzProps);
1012  p->expectedDataSize = (UInt64)(Int64)-1;
1013  p->alloc = alloc;
1014  p->allocBig = allocBig;
1015  return p;
1016}
1017
1018
1019void XzEnc_Destroy(CXzEncHandle pp)
1020{
1021  CXzEnc *p = (CXzEnc *)pp;
1022  XzEnc_Free(p, p->alloc);
1023  ISzAlloc_Free(p->alloc, p);
1024}
1025
1026
1027SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props)
1028{
1029  CXzEnc *p = (CXzEnc *)pp;
1030  p->xzProps = *props;
1031  XzProps_Normalize(&p->xzProps);
1032  return SZ_OK;
1033}
1034
1035
1036void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize)
1037{
1038  CXzEnc *p = (CXzEnc *)pp;
1039  p->expectedDataSize = expectedDataSiize;
1040}
1041
1042
1043
1044
1045#ifndef _7ZIP_ST
1046
1047static 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
1107static 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
1128SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
1129{
1130  CXzEnc *p = (CXzEnc *)pp;
1131
1132  const CXzProps *props = &p->xzProps;
1133
1134  XzEncIndex_Init(&p->xzIndex);
1135  {
1136    UInt64 numBlocks = 1;
1137    UInt64 blockSize = props->blockSize;
1138    
1139    if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID
1140        && props->reduceSize != (UInt64)(Int64)-1)
1141    {
1142      numBlocks = props->reduceSize / blockSize;
1143      if (numBlocks * blockSize != props->reduceSize)
1144        numBlocks++;
1145    }
1146    else
1147      blockSize = (UInt64)1 << 62;
1148    
1149    RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc));
1150  }
1151
1152  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  {
1207    int writeStartSizes;
1208    CCompressProgress_XzEncOffset progress2;
1209    Byte *bufData = NULL;
1210    size_t bufSize = 0;
1211
1212    progress2.vt.Progress = CompressProgress_XzEncOffset_Progress;
1213    progress2.inOffset = 0;
1214    progress2.outOffset = 0;
1215    progress2.progress = progress;
1216    
1217    writeStartSizes = 0;
1218    
1219    if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID)
1220    {
1221      writeStartSizes = (props->forceWriteSizesInHeader > 0);
1222      
1223      if (writeStartSizes)
1224      {
1225        size_t t2;
1226        size_t t = (size_t)props->blockSize;
1227        if (t != props->blockSize)
1228          return SZ_ERROR_PARAM;
1229        t = XZ_GET_MAX_BLOCK_PACK_SIZE(t);
1230        if (t < props->blockSize)
1231          return SZ_ERROR_PARAM;
1232        t2 = XZ_BLOCK_HEADER_SIZE_MAX + t;
1233        if (!p->outBufs[0] || t2 != p->outBufSize)
1234        {
1235          XzEnc_FreeOutBufs(p);
1236          p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2);
1237          if (!p->outBufs[0])
1238            return SZ_ERROR_MEM;
1239          p->outBufSize = t2;
1240        }
1241        bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX;
1242        bufSize = t;
1243      }
1244    }
1245    
1246    for (;;)
1247    {
1248      CXzEncBlockInfo blockSizes;
1249      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      blockSizes.headerSize = 0; // for GCC
1259      
1260      RINOK(Xz_CompressBlock(
1261          &p->lzmaf_Items[0],
1262          
1263          writeStartSizes ? NULL : outStream,
1264          writeStartSizes ? p->outBufs[0] : NULL,
1265          bufData, bufSize,
1266          
1267          inStream,
1268          // rem,
1269          NULL, 0,
1270          
1271          props,
1272          progress ? &progress2.vt : NULL,
1273          &inStreamFinished,
1274          &blockSizes,
1275          p->alloc,
1276          p->allocBig));
1277
1278      {
1279        UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize);
1280      
1281        if (writeStartSizes)
1282        {
1283          RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize));
1284          RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize));
1285        }
1286        
1287        RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc));
1288        
1289        progress2.inOffset += blockSizes.unpackSize;
1290        progress2.outOffset += totalPackFull;
1291      }
1292        
1293      if (inStreamFinished)
1294        break;
1295    }
1296  }
1297
1298  return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream);
1299}
1300
1301
1302#include "Alloc.h"
1303
1304SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
1305    const CXzProps *props, ICompressProgress *progress)
1306{
1307  SRes res;
1308  CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc);
1309  if (!xz)
1310    return SZ_ERROR_MEM;
1311  res = XzEnc_SetProps(xz, props);
1312  if (res == SZ_OK)
1313    res = XzEnc_Encode(xz, outStream, inStream, progress);
1314  XzEnc_Destroy(xz);
1315  return res;
1316}
1317
1318
1319SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
1320{
1321  SRes res;
1322  CXzEncIndex xzIndex;
1323  XzEncIndex_Construct(&xzIndex);
1324  res = Xz_WriteHeader((CXzStreamFlags)0, outStream);
1325  if (res == SZ_OK)
1326    res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream);
1327  XzEncIndex_Free(&xzIndex, NULL); // g_Alloc
1328  return res;
1329}