tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XzEnc.c (33160B)


      1 /* XzEnc.c -- Xz Encode
      2 2018-04-28 : 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 
     44 static 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 
     49 static 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 
     56 static 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 
     69 static 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 
    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 {
    112  p->numBlocks = 0;
    113  p->size = 0;
    114  p->allocated = 0;
    115  p->blocks = NULL;
    116 }
    117 
    118 static void XzEncIndex_Init(CXzEncIndex *p)
    119 {
    120  p->numBlocks = 0;
    121  p->size = 0;
    122 }
    123 
    124 static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc)
    125 {
    126  if (p->blocks)
    127  {
    128    ISzAlloc_Free(alloc, p->blocks);
    129    p->blocks = NULL;
    130  }
    131  p->numBlocks = 0;
    132  p->size = 0;
    133  p->allocated = 0;
    134 }
    135 
    136 
    137 static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc)
    138 {
    139  Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize);
    140  if (!blocks)
    141    return SZ_ERROR_MEM;
    142  if (p->size != 0)
    143    memcpy(blocks, p->blocks, p->size);
    144  if (p->blocks)
    145    ISzAlloc_Free(alloc, p->blocks);
    146  p->blocks = blocks;
    147  p->allocated = newSize;
    148  return SZ_OK;
    149 }
    150 
    151 
    152 static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
    153 {
    154  UInt64 pos;
    155  {
    156    Byte buf[32];
    157    unsigned pos2 = Xz_WriteVarInt(buf, totalSize);
    158    pos2 += Xz_WriteVarInt(buf + pos2, unpackSize);
    159    pos = numBlocks * pos2;
    160  }
    161  
    162  if (pos <= p->allocated - p->size)
    163    return SZ_OK;
    164  {
    165    UInt64 newSize64 = p->size + pos;
    166    size_t newSize = (size_t)newSize64;
    167    if (newSize != newSize64)
    168      return SZ_ERROR_MEM;
    169    return XzEncIndex_ReAlloc(p, newSize, alloc);
    170  }
    171 }
    172 
    173 
    174 static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
    175 {
    176  Byte buf[32];
    177  unsigned pos = Xz_WriteVarInt(buf, totalSize);
    178  pos += Xz_WriteVarInt(buf + pos, unpackSize);
    179 
    180  if (pos > p->allocated - p->size)
    181  {
    182    size_t newSize = p->allocated * 2 + 16 * 2;
    183    if (newSize < p->size + pos)
    184      return SZ_ERROR_MEM;
    185    RINOK(XzEncIndex_ReAlloc(p, newSize, alloc));
    186  }
    187  memcpy(p->blocks + p->size, buf, pos);
    188  p->size += pos;
    189  p->numBlocks++;
    190  return SZ_OK;
    191 }
    192 
    193 
    194 static 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 
    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 {
    243  p->limit = (UInt64)(Int64)-1;
    244  p->processed = 0;
    245  p->realStreamFinished = 0;
    246  XzCheck_Init(&p->check, checkMode);
    247 }
    248 
    249 static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
    250 {
    251  XzCheck_Final(&p->check, digest);
    252 }
    253 
    254 static 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 
    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 {
    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 
    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 {
    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 
    345 static 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          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 
    380 static void SeqInFilter_Construct(CSeqInFilter *p)
    381 {
    382  p->buf = NULL;
    383  p->StateCoder.p = NULL;
    384  p->p.Read = SeqInFilter_Read;
    385 }
    386 
    387 static 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 
    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 {
    467  p->id = 0;
    468  p->delta = 0;
    469  p->ip = 0;
    470  p->ipDefined = False;
    471 }
    472 
    473 void 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 
    489 static 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 
    569 static 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 
    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 {
    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 
    669 static 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 
    681 static 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 
    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 {
    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    Bool 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 
    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 {
    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 
    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  Bool 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 {
    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 
    971 static 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 
    984 static 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 
   1004 CXzEncHandle 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 
   1019 void 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 
   1027 SRes 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 
   1036 void 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 
   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 {
   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 
   1304 SRes 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 
   1319 SRes 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 }