Home | History | Annotate | Download | only in C
      1 /* XzDec.c -- Xz Decode
      2 2018-12-29 : Igor Pavlov : Public domain */
      3 
      4 #include "Precomp.h"
      5 
      6 // #include <stdio.h>
      7 
      8 // #define XZ_DUMP
      9 
     10 /* #define XZ_DUMP */
     11 
     12 #ifdef XZ_DUMP
     13 #include <stdio.h>
     14 #endif
     15 
     16 // #define SHOW_DEBUG_INFO
     17 
     18 #ifdef SHOW_DEBUG_INFO
     19 #include <stdio.h>
     20 #endif
     21 
     22 #ifdef SHOW_DEBUG_INFO
     23 #define PRF(x) x
     24 #else
     25 #define PRF(x)
     26 #endif
     27 
     28 #define PRF_STR(s) PRF(printf("\n" s "\n"))
     29 #define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
     30 
     31 #include <stdlib.h>
     32 #include <string.h>
     33 
     34 #include "7zCrc.h"
     35 #include "Alloc.h"
     36 #include "Bra.h"
     37 #include "CpuArch.h"
     38 #include "Delta.h"
     39 #include "Lzma2Dec.h"
     40 
     41 // #define USE_SUBBLOCK
     42 
     43 #ifdef USE_SUBBLOCK
     44 #include "Bcj3Dec.c"
     45 #include "SbDec.h"
     46 #endif
     47 
     48 #include "Xz.h"
     49 
     50 #define XZ_CHECK_SIZE_MAX 64
     51 
     52 #define CODER_BUF_SIZE ((size_t)1 << 17)
     53 
     54 unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
     55 {
     56   unsigned i, limit;
     57   *value = 0;
     58   limit = (maxSize > 9) ? 9 : (unsigned)maxSize;
     59 
     60   for (i = 0; i < limit;)
     61   {
     62     Byte b = p[i];
     63     *value |= (UInt64)(b & 0x7F) << (7 * i++);
     64     if ((b & 0x80) == 0)
     65       return (b == 0 && i != 1) ? 0 : i;
     66   }
     67   return 0;
     68 }
     69 
     70 /* ---------- BraState ---------- */
     71 
     72 #define BRA_BUF_SIZE (1 << 14)
     73 
     74 typedef struct
     75 {
     76   size_t bufPos;
     77   size_t bufConv;
     78   size_t bufTotal;
     79 
     80   int encodeMode;
     81 
     82   UInt32 methodId;
     83   UInt32 delta;
     84   UInt32 ip;
     85   UInt32 x86State;
     86   Byte deltaState[DELTA_STATE_SIZE];
     87 
     88   Byte buf[BRA_BUF_SIZE];
     89 } CBraState;
     90 
     91 static void BraState_Free(void *pp, ISzAllocPtr alloc)
     92 {
     93   ISzAlloc_Free(alloc, pp);
     94 }
     95 
     96 static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
     97 {
     98   CBraState *p = ((CBraState *)pp);
     99   UNUSED_VAR(alloc);
    100   p->ip = 0;
    101   if (p->methodId == XZ_ID_Delta)
    102   {
    103     if (propSize != 1)
    104       return SZ_ERROR_UNSUPPORTED;
    105     p->delta = (unsigned)props[0] + 1;
    106   }
    107   else
    108   {
    109     if (propSize == 4)
    110     {
    111       UInt32 v = GetUi32(props);
    112       switch (p->methodId)
    113       {
    114         case XZ_ID_PPC:
    115         case XZ_ID_ARM:
    116         case XZ_ID_SPARC:
    117           if ((v & 3) != 0)
    118             return SZ_ERROR_UNSUPPORTED;
    119           break;
    120         case XZ_ID_ARMT:
    121           if ((v & 1) != 0)
    122             return SZ_ERROR_UNSUPPORTED;
    123           break;
    124         case XZ_ID_IA64:
    125           if ((v & 0xF) != 0)
    126             return SZ_ERROR_UNSUPPORTED;
    127           break;
    128       }
    129       p->ip = v;
    130     }
    131     else if (propSize != 0)
    132       return SZ_ERROR_UNSUPPORTED;
    133   }
    134   return SZ_OK;
    135 }
    136 
    137 static void BraState_Init(void *pp)
    138 {
    139   CBraState *p = ((CBraState *)pp);
    140   p->bufPos = p->bufConv = p->bufTotal = 0;
    141   x86_Convert_Init(p->x86State);
    142   if (p->methodId == XZ_ID_Delta)
    143     Delta_Init(p->deltaState);
    144 }
    145 
    146 
    147 #define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break;
    148 
    149 static SizeT BraState_Filter(void *pp, Byte *data, SizeT size)
    150 {
    151   CBraState *p = ((CBraState *)pp);
    152   switch (p->methodId)
    153   {
    154     case XZ_ID_Delta:
    155       if (p->encodeMode)
    156         Delta_Encode(p->deltaState, p->delta, data, size);
    157       else
    158         Delta_Decode(p->deltaState, p->delta, data, size);
    159       break;
    160     case XZ_ID_X86:
    161       size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode);
    162       break;
    163     CASE_BRA_CONV(PPC)
    164     CASE_BRA_CONV(IA64)
    165     CASE_BRA_CONV(ARM)
    166     CASE_BRA_CONV(ARMT)
    167     CASE_BRA_CONV(SPARC)
    168   }
    169   p->ip += (UInt32)size;
    170   return size;
    171 }
    172 
    173 
    174 static SRes BraState_Code2(void *pp,
    175     Byte *dest, SizeT *destLen,
    176     const Byte *src, SizeT *srcLen, int srcWasFinished,
    177     ECoderFinishMode finishMode,
    178     // int *wasFinished
    179     ECoderStatus *status)
    180 {
    181   CBraState *p = ((CBraState *)pp);
    182   SizeT destRem = *destLen;
    183   SizeT srcRem = *srcLen;
    184   UNUSED_VAR(finishMode);
    185 
    186   *destLen = 0;
    187   *srcLen = 0;
    188   // *wasFinished = False;
    189   *status = CODER_STATUS_NOT_FINISHED;
    190 
    191   while (destRem > 0)
    192   {
    193     if (p->bufPos != p->bufConv)
    194     {
    195       size_t size = p->bufConv - p->bufPos;
    196       if (size > destRem)
    197         size = destRem;
    198       memcpy(dest, p->buf + p->bufPos, size);
    199       p->bufPos += size;
    200       *destLen += size;
    201       dest += size;
    202       destRem -= size;
    203       continue;
    204     }
    205 
    206     p->bufTotal -= p->bufPos;
    207     memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
    208     p->bufPos = 0;
    209     p->bufConv = 0;
    210     {
    211       size_t size = BRA_BUF_SIZE - p->bufTotal;
    212       if (size > srcRem)
    213         size = srcRem;
    214       memcpy(p->buf + p->bufTotal, src, size);
    215       *srcLen += size;
    216       src += size;
    217       srcRem -= size;
    218       p->bufTotal += size;
    219     }
    220     if (p->bufTotal == 0)
    221       break;
    222 
    223     p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal);
    224 
    225     if (p->bufConv == 0)
    226     {
    227       if (!srcWasFinished)
    228         break;
    229       p->bufConv = p->bufTotal;
    230     }
    231   }
    232 
    233   if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished)
    234   {
    235     *status = CODER_STATUS_FINISHED_WITH_MARK;
    236     // *wasFinished = 1;
    237   }
    238 
    239   return SZ_OK;
    240 }
    241 
    242 
    243 SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc)
    244 {
    245   CBraState *decoder;
    246   if (id < XZ_ID_Delta || id > XZ_ID_SPARC)
    247     return SZ_ERROR_UNSUPPORTED;
    248   decoder = p->p;
    249   if (!decoder)
    250   {
    251     decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState));
    252     if (!decoder)
    253       return SZ_ERROR_MEM;
    254     p->p = decoder;
    255     p->Free = BraState_Free;
    256     p->SetProps = BraState_SetProps;
    257     p->Init = BraState_Init;
    258     p->Code2 = BraState_Code2;
    259     p->Filter = BraState_Filter;
    260   }
    261   decoder->methodId = (UInt32)id;
    262   decoder->encodeMode = encodeMode;
    263   return SZ_OK;
    264 }
    265 
    266 
    267 
    268 /* ---------- SbState ---------- */
    269 
    270 #ifdef USE_SUBBLOCK
    271 
    272 static void SbState_Free(void *pp, ISzAllocPtr alloc)
    273 {
    274   CSbDec *p = (CSbDec *)pp;
    275   SbDec_Free(p);
    276   ISzAlloc_Free(alloc, pp);
    277 }
    278 
    279 static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
    280 {
    281   UNUSED_VAR(pp);
    282   UNUSED_VAR(props);
    283   UNUSED_VAR(alloc);
    284   return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
    285 }
    286 
    287 static void SbState_Init(void *pp)
    288 {
    289   SbDec_Init((CSbDec *)pp);
    290 }
    291 
    292 static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
    293     int srcWasFinished, ECoderFinishMode finishMode,
    294     // int *wasFinished
    295     ECoderStatus *status)
    296 {
    297   CSbDec *p = (CSbDec *)pp;
    298   SRes res;
    299   UNUSED_VAR(srcWasFinished);
    300   p->dest = dest;
    301   p->destLen = *destLen;
    302   p->src = src;
    303   p->srcLen = *srcLen;
    304   p->finish = finishMode; /* change it */
    305   res = SbDec_Decode((CSbDec *)pp);
    306   *destLen -= p->destLen;
    307   *srcLen -= p->srcLen;
    308   // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
    309   *status = (*destLen == 0 && *srcLen == 0) ?
    310       CODER_STATUS_FINISHED_WITH_MARK :
    311       CODER_STATUS_NOT_FINISHED;
    312   return res;
    313 }
    314 
    315 static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc)
    316 {
    317   CSbDec *decoder = (CSbDec *)p->p;
    318   if (!decoder)
    319   {
    320     decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec));
    321     if (!decoder)
    322       return SZ_ERROR_MEM;
    323     p->p = decoder;
    324     p->Free = SbState_Free;
    325     p->SetProps = SbState_SetProps;
    326     p->Init = SbState_Init;
    327     p->Code2 = SbState_Code2;
    328     p->Filter = NULL;
    329   }
    330   SbDec_Construct(decoder);
    331   SbDec_SetAlloc(decoder, alloc);
    332   return SZ_OK;
    333 }
    334 
    335 #endif
    336 
    337 
    338 
    339 /* ---------- Lzma2 ---------- */
    340 
    341 typedef struct
    342 {
    343   CLzma2Dec decoder;
    344   BoolInt outBufMode;
    345 } CLzma2Dec_Spec;
    346 
    347 
    348 static void Lzma2State_Free(void *pp, ISzAllocPtr alloc)
    349 {
    350   CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
    351   if (p->outBufMode)
    352     Lzma2Dec_FreeProbs(&p->decoder, alloc);
    353   else
    354     Lzma2Dec_Free(&p->decoder, alloc);
    355   ISzAlloc_Free(alloc, pp);
    356 }
    357 
    358 static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
    359 {
    360   if (propSize != 1)
    361     return SZ_ERROR_UNSUPPORTED;
    362   {
    363     CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
    364     if (p->outBufMode)
    365       return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc);
    366     else
    367       return Lzma2Dec_Allocate(&p->decoder, props[0], alloc);
    368   }
    369 }
    370 
    371 static void Lzma2State_Init(void *pp)
    372 {
    373   Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder);
    374 }
    375 
    376 
    377 /*
    378   if (outBufMode), then (dest) is not used. Use NULL.
    379          Data is unpacked to (spec->decoder.decoder.dic) output buffer.
    380 */
    381 
    382 static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
    383     int srcWasFinished, ECoderFinishMode finishMode,
    384     // int *wasFinished,
    385     ECoderStatus *status)
    386 {
    387   CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp;
    388   ELzmaStatus status2;
    389   /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
    390   SRes res;
    391   UNUSED_VAR(srcWasFinished);
    392   if (spec->outBufMode)
    393   {
    394     SizeT dicPos = spec->decoder.decoder.dicPos;
    395     SizeT dicLimit = dicPos + *destLen;
    396     res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
    397     *destLen = spec->decoder.decoder.dicPos - dicPos;
    398   }
    399   else
    400     res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
    401   // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK);
    402   // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
    403   *status = status2;
    404   return res;
    405 }
    406 
    407 
    408 static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc)
    409 {
    410   CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
    411   if (!spec)
    412   {
    413     spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec));
    414     if (!spec)
    415       return SZ_ERROR_MEM;
    416     p->p = spec;
    417     p->Free = Lzma2State_Free;
    418     p->SetProps = Lzma2State_SetProps;
    419     p->Init = Lzma2State_Init;
    420     p->Code2 = Lzma2State_Code2;
    421     p->Filter = NULL;
    422     Lzma2Dec_Construct(&spec->decoder);
    423   }
    424   spec->outBufMode = False;
    425   if (outBuf)
    426   {
    427     spec->outBufMode = True;
    428     spec->decoder.decoder.dic = outBuf;
    429     spec->decoder.decoder.dicBufSize = outBufSize;
    430   }
    431   return SZ_OK;
    432 }
    433 
    434 
    435 static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize)
    436 {
    437   CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
    438   if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf))
    439     return SZ_ERROR_FAIL;
    440   if (outBuf)
    441   {
    442     spec->decoder.decoder.dic = outBuf;
    443     spec->decoder.decoder.dicBufSize = outBufSize;
    444   }
    445   return SZ_OK;
    446 }
    447 
    448 
    449 
    450 static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc)
    451 {
    452   unsigned i;
    453   p->alloc = alloc;
    454   p->buf = NULL;
    455   p->numCoders = 0;
    456 
    457   p->outBufSize = 0;
    458   p->outBuf = NULL;
    459   // p->SingleBufMode = False;
    460 
    461   for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
    462     p->coders[i].p = NULL;
    463 }
    464 
    465 
    466 static void MixCoder_Free(CMixCoder *p)
    467 {
    468   unsigned i;
    469   p->numCoders = 0;
    470   for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
    471   {
    472     IStateCoder *sc = &p->coders[i];
    473     if (sc->p)
    474     {
    475       sc->Free(sc->p, p->alloc);
    476       sc->p = NULL;
    477     }
    478   }
    479   if (p->buf)
    480   {
    481     ISzAlloc_Free(p->alloc, p->buf);
    482     p->buf = NULL; /* 9.31: the BUG was fixed */
    483   }
    484 }
    485 
    486 static void MixCoder_Init(CMixCoder *p)
    487 {
    488   unsigned i;
    489   for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
    490   {
    491     p->size[i] = 0;
    492     p->pos[i] = 0;
    493     p->finished[i] = 0;
    494   }
    495   for (i = 0; i < p->numCoders; i++)
    496   {
    497     IStateCoder *coder = &p->coders[i];
    498     coder->Init(coder->p);
    499     p->results[i] = SZ_OK;
    500   }
    501   p->outWritten = 0;
    502   p->wasFinished = False;
    503   p->res = SZ_OK;
    504   p->status = CODER_STATUS_NOT_SPECIFIED;
    505 }
    506 
    507 
    508 static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
    509 {
    510   IStateCoder *sc = &p->coders[coderIndex];
    511   p->ids[coderIndex] = methodId;
    512   switch (methodId)
    513   {
    514     case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc);
    515     #ifdef USE_SUBBLOCK
    516     case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
    517     #endif
    518   }
    519   if (coderIndex == 0)
    520     return SZ_ERROR_UNSUPPORTED;
    521   return BraState_SetFromMethod(sc, methodId, 0, p->alloc);
    522 }
    523 
    524 
    525 static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
    526 {
    527   IStateCoder *sc = &p->coders[coderIndex];
    528   switch (methodId)
    529   {
    530     case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize);
    531   }
    532   return SZ_ERROR_UNSUPPORTED;
    533 }
    534 
    535 
    536 
    537 /*
    538  if (destFinish) - then unpack data block is finished at (*destLen) position,
    539                    and we can return data that were not processed by filter
    540 
    541 output (status) can be :
    542   CODER_STATUS_NOT_FINISHED
    543   CODER_STATUS_FINISHED_WITH_MARK
    544   CODER_STATUS_NEEDS_MORE_INPUT - not implemented still
    545 */
    546 
    547 static SRes MixCoder_Code(CMixCoder *p,
    548     Byte *dest, SizeT *destLen, int destFinish,
    549     const Byte *src, SizeT *srcLen, int srcWasFinished,
    550     ECoderFinishMode finishMode)
    551 {
    552   SizeT destLenOrig = *destLen;
    553   SizeT srcLenOrig = *srcLen;
    554 
    555   *destLen = 0;
    556   *srcLen = 0;
    557 
    558   if (p->wasFinished)
    559     return p->res;
    560 
    561   p->status = CODER_STATUS_NOT_FINISHED;
    562 
    563   // if (p->SingleBufMode)
    564   if (p->outBuf)
    565   {
    566     SRes res;
    567     SizeT destLen2, srcLen2;
    568     int wasFinished;
    569 
    570     PRF_STR("------- MixCoder Single ----------");
    571 
    572     srcLen2 = srcLenOrig;
    573     destLen2 = destLenOrig;
    574 
    575     {
    576       IStateCoder *coder = &p->coders[0];
    577       res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode,
    578           // &wasFinished,
    579           &p->status);
    580       wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK);
    581     }
    582 
    583     p->res = res;
    584 
    585     /*
    586     if (wasFinished)
    587       p->status = CODER_STATUS_FINISHED_WITH_MARK;
    588     else
    589     {
    590       if (res == SZ_OK)
    591         if (destLen2 != destLenOrig)
    592           p->status = CODER_STATUS_NEEDS_MORE_INPUT;
    593     }
    594     */
    595 
    596 
    597     *srcLen = srcLen2;
    598     src += srcLen2;
    599     p->outWritten += destLen2;
    600 
    601     if (res != SZ_OK || srcWasFinished || wasFinished)
    602       p->wasFinished = True;
    603 
    604     if (p->numCoders == 1)
    605       *destLen = destLen2;
    606     else if (p->wasFinished)
    607     {
    608       unsigned i;
    609       size_t processed = p->outWritten;
    610 
    611       for (i = 1; i < p->numCoders; i++)
    612       {
    613         IStateCoder *coder = &p->coders[i];
    614         processed = coder->Filter(coder->p, p->outBuf, processed);
    615         if (wasFinished || (destFinish && p->outWritten == destLenOrig))
    616           processed = p->outWritten;
    617         PRF_STR_INT("filter", i);
    618       }
    619       *destLen = processed;
    620     }
    621     return res;
    622   }
    623 
    624   PRF_STR("standard mix");
    625 
    626   if (p->numCoders != 1)
    627   {
    628     if (!p->buf)
    629     {
    630       p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
    631       if (!p->buf)
    632         return SZ_ERROR_MEM;
    633     }
    634 
    635     finishMode = CODER_FINISH_ANY;
    636   }
    637 
    638   for (;;)
    639   {
    640     BoolInt processed = False;
    641     BoolInt allFinished = True;
    642     SRes resMain = SZ_OK;
    643     unsigned i;
    644 
    645     p->status = CODER_STATUS_NOT_FINISHED;
    646     /*
    647     if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
    648       break;
    649     */
    650 
    651     for (i = 0; i < p->numCoders; i++)
    652     {
    653       SRes res;
    654       IStateCoder *coder = &p->coders[i];
    655       Byte *dest2;
    656       SizeT destLen2, srcLen2; // destLen2_Orig;
    657       const Byte *src2;
    658       int srcFinished2;
    659       int encodingWasFinished;
    660       ECoderStatus status2;
    661 
    662       if (i == 0)
    663       {
    664         src2 = src;
    665         srcLen2 = srcLenOrig - *srcLen;
    666         srcFinished2 = srcWasFinished;
    667       }
    668       else
    669       {
    670         size_t k = i - 1;
    671         src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k];
    672         srcLen2 = p->size[k] - p->pos[k];
    673         srcFinished2 = p->finished[k];
    674       }
    675 
    676       if (i == p->numCoders - 1)
    677       {
    678         dest2 = dest;
    679         destLen2 = destLenOrig - *destLen;
    680       }
    681       else
    682       {
    683         if (p->pos[i] != p->size[i])
    684           continue;
    685         dest2 = p->buf + (CODER_BUF_SIZE * i);
    686         destLen2 = CODER_BUF_SIZE;
    687       }
    688 
    689       // destLen2_Orig = destLen2;
    690 
    691       if (p->results[i] != SZ_OK)
    692       {
    693         if (resMain == SZ_OK)
    694           resMain = p->results[i];
    695         continue;
    696       }
    697 
    698       res = coder->Code2(coder->p,
    699           dest2, &destLen2,
    700           src2, &srcLen2, srcFinished2,
    701           finishMode,
    702           // &encodingWasFinished,
    703           &status2);
    704 
    705       if (res != SZ_OK)
    706       {
    707         p->results[i] = res;
    708         if (resMain == SZ_OK)
    709           resMain = res;
    710       }
    711 
    712       encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK);
    713 
    714       if (!encodingWasFinished)
    715       {
    716         allFinished = False;
    717         if (p->numCoders == 1 && res == SZ_OK)
    718           p->status = status2;
    719       }
    720 
    721       if (i == 0)
    722       {
    723         *srcLen += srcLen2;
    724         src += srcLen2;
    725       }
    726       else
    727         p->pos[(size_t)i - 1] += srcLen2;
    728 
    729       if (i == p->numCoders - 1)
    730       {
    731         *destLen += destLen2;
    732         dest += destLen2;
    733       }
    734       else
    735       {
    736         p->size[i] = destLen2;
    737         p->pos[i] = 0;
    738         p->finished[i] = encodingWasFinished;
    739       }
    740 
    741       if (destLen2 != 0 || srcLen2 != 0)
    742         processed = True;
    743     }
    744 
    745     if (!processed)
    746     {
    747       if (allFinished)
    748         p->status = CODER_STATUS_FINISHED_WITH_MARK;
    749       return resMain;
    750     }
    751   }
    752 }
    753 
    754 
    755 SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
    756 {
    757   *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
    758   if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
    759       GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
    760     return SZ_ERROR_NO_ARCHIVE;
    761   return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
    762 }
    763 
    764 static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
    765 {
    766   return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2)
    767       && GetUi32(buf) == CrcCalc(buf + 4, 6)
    768       && flags == GetBe16(buf + 8)
    769       && buf[10] == XZ_FOOTER_SIG_0
    770       && buf[11] == XZ_FOOTER_SIG_1;
    771 }
    772 
    773 #define READ_VARINT_AND_CHECK(buf, pos, size, res) \
    774   { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
    775   if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
    776 
    777 
    778 static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p)
    779 {
    780   unsigned numFilters = XzBlock_GetNumFilters(p) - 1;
    781   unsigned i;
    782   {
    783     const CXzFilter *f = &p->filters[numFilters];
    784     if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40)
    785       return False;
    786   }
    787 
    788   for (i = 0; i < numFilters; i++)
    789   {
    790     const CXzFilter *f = &p->filters[i];
    791     if (f->id == XZ_ID_Delta)
    792     {
    793       if (f->propsSize != 1)
    794         return False;
    795     }
    796     else if (f->id < XZ_ID_Delta
    797         || f->id > XZ_ID_SPARC
    798         || (f->propsSize != 0 && f->propsSize != 4))
    799       return False;
    800   }
    801   return True;
    802 }
    803 
    804 
    805 SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
    806 {
    807   unsigned pos;
    808   unsigned numFilters, i;
    809   unsigned headerSize = (unsigned)header[0] << 2;
    810 
    811   /* (headerSize != 0) : another code checks */
    812 
    813   if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
    814     return SZ_ERROR_ARCHIVE;
    815 
    816   pos = 1;
    817   p->flags = header[pos++];
    818 
    819   p->packSize = (UInt64)(Int64)-1;
    820   if (XzBlock_HasPackSize(p))
    821   {
    822     READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
    823     if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
    824       return SZ_ERROR_ARCHIVE;
    825   }
    826 
    827   p->unpackSize = (UInt64)(Int64)-1;
    828   if (XzBlock_HasUnpackSize(p))
    829     READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
    830 
    831   numFilters = XzBlock_GetNumFilters(p);
    832   for (i = 0; i < numFilters; i++)
    833   {
    834     CXzFilter *filter = p->filters + i;
    835     UInt64 size;
    836     READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
    837     READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
    838     if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
    839       return SZ_ERROR_ARCHIVE;
    840     filter->propsSize = (UInt32)size;
    841     memcpy(filter->props, header + pos, (size_t)size);
    842     pos += (unsigned)size;
    843 
    844     #ifdef XZ_DUMP
    845     printf("\nf[%u] = %2X: ", i, (unsigned)filter->id);
    846     {
    847       unsigned i;
    848       for (i = 0; i < size; i++)
    849         printf(" %2X", filter->props[i]);
    850     }
    851     #endif
    852   }
    853 
    854   if (XzBlock_HasUnsupportedFlags(p))
    855     return SZ_ERROR_UNSUPPORTED;
    856 
    857   while (pos < headerSize)
    858     if (header[pos++] != 0)
    859       return SZ_ERROR_ARCHIVE;
    860   return SZ_OK;
    861 }
    862 
    863 
    864 
    865 
    866 static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize)
    867 {
    868   unsigned i;
    869   BoolInt needReInit = True;
    870   unsigned numFilters = XzBlock_GetNumFilters(block);
    871 
    872   if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf)))
    873   {
    874     needReInit = False;
    875     for (i = 0; i < numFilters; i++)
    876       if (p->ids[i] != block->filters[numFilters - 1 - i].id)
    877       {
    878         needReInit = True;
    879         break;
    880       }
    881   }
    882 
    883   // p->SingleBufMode = (outBuf != NULL);
    884   p->outBuf = outBuf;
    885   p->outBufSize = outBufSize;
    886 
    887   // p->SingleBufMode = False;
    888   // outBuf = NULL;
    889 
    890   if (needReInit)
    891   {
    892     MixCoder_Free(p);
    893     for (i = 0; i < numFilters; i++)
    894     {
    895       RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize));
    896     }
    897     p->numCoders = numFilters;
    898   }
    899   else
    900   {
    901     RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize));
    902   }
    903 
    904   for (i = 0; i < numFilters; i++)
    905   {
    906     const CXzFilter *f = &block->filters[numFilters - 1 - i];
    907     IStateCoder *sc = &p->coders[i];
    908     RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
    909   }
    910 
    911   MixCoder_Init(p);
    912   return SZ_OK;
    913 }
    914 
    915 
    916 
    917 void XzUnpacker_Init(CXzUnpacker *p)
    918 {
    919   p->state = XZ_STATE_STREAM_HEADER;
    920   p->pos = 0;
    921   p->numStartedStreams = 0;
    922   p->numFinishedStreams = 0;
    923   p->numTotalBlocks = 0;
    924   p->padSize = 0;
    925   p->decodeOnlyOneBlock = 0;
    926 
    927   p->parseMode = False;
    928   p->decodeToStreamSignature = False;
    929 
    930   // p->outBuf = NULL;
    931   // p->outBufSize = 0;
    932   p->outDataWritten = 0;
    933 }
    934 
    935 
    936 void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize)
    937 {
    938   p->outBuf = outBuf;
    939   p->outBufSize = outBufSize;
    940 }
    941 
    942 
    943 void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc)
    944 {
    945   MixCoder_Construct(&p->decoder, alloc);
    946   p->outBuf = NULL;
    947   p->outBufSize = 0;
    948   XzUnpacker_Init(p);
    949 }
    950 
    951 
    952 void XzUnpacker_Free(CXzUnpacker *p)
    953 {
    954   MixCoder_Free(&p->decoder);
    955 }
    956 
    957 
    958 void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p)
    959 {
    960   p->indexSize = 0;
    961   p->numBlocks = 0;
    962   Sha256_Init(&p->sha);
    963   p->state = XZ_STATE_BLOCK_HEADER;
    964   p->pos = 0;
    965   p->decodeOnlyOneBlock = 1;
    966 }
    967 
    968 
    969 static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize)
    970 {
    971   Byte temp[32];
    972   unsigned num = Xz_WriteVarInt(temp, packSize);
    973   num += Xz_WriteVarInt(temp + num, unpackSize);
    974   Sha256_Update(&p->sha, temp, num);
    975   p->indexSize += num;
    976   p->numBlocks++;
    977 }
    978 
    979 
    980 
    981 SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
    982     const Byte *src, SizeT *srcLen, int srcFinished,
    983     ECoderFinishMode finishMode, ECoderStatus *status)
    984 {
    985   SizeT destLenOrig = *destLen;
    986   SizeT srcLenOrig = *srcLen;
    987   *destLen = 0;
    988   *srcLen = 0;
    989   *status = CODER_STATUS_NOT_SPECIFIED;
    990 
    991   for (;;)
    992   {
    993     SizeT srcRem;
    994 
    995     if (p->state == XZ_STATE_BLOCK)
    996     {
    997       SizeT destLen2 = destLenOrig - *destLen;
    998       SizeT srcLen2 = srcLenOrig - *srcLen;
    999       SRes res;
   1000 
   1001       ECoderFinishMode finishMode2 = finishMode;
   1002       BoolInt srcFinished2 = srcFinished;
   1003       BoolInt destFinish = False;
   1004 
   1005       if (p->block.packSize != (UInt64)(Int64)-1)
   1006       {
   1007         UInt64 rem = p->block.packSize - p->packSize;
   1008         if (srcLen2 >= rem)
   1009         {
   1010           srcFinished2 = True;
   1011           srcLen2 = (SizeT)rem;
   1012         }
   1013         if (rem == 0 && p->block.unpackSize == p->unpackSize)
   1014           return SZ_ERROR_DATA;
   1015       }
   1016 
   1017       if (p->block.unpackSize != (UInt64)(Int64)-1)
   1018       {
   1019         UInt64 rem = p->block.unpackSize - p->unpackSize;
   1020         if (destLen2 >= rem)
   1021         {
   1022           destFinish = True;
   1023           finishMode2 = CODER_FINISH_END;
   1024           destLen2 = (SizeT)rem;
   1025         }
   1026       }
   1027 
   1028       /*
   1029       if (srcLen2 == 0 && destLen2 == 0)
   1030       {
   1031         *status = CODER_STATUS_NOT_FINISHED;
   1032         return SZ_OK;
   1033       }
   1034       */
   1035 
   1036       {
   1037         res = MixCoder_Code(&p->decoder,
   1038             (p->outBuf ? NULL : dest), &destLen2, destFinish,
   1039             src, &srcLen2, srcFinished2,
   1040             finishMode2);
   1041 
   1042         *status = p->decoder.status;
   1043         XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2);
   1044         if (!p->outBuf)
   1045           dest += destLen2;
   1046         p->outDataWritten += destLen2;
   1047       }
   1048 
   1049       (*srcLen) += srcLen2;
   1050       src += srcLen2;
   1051       p->packSize += srcLen2;
   1052       (*destLen) += destLen2;
   1053       p->unpackSize += destLen2;
   1054 
   1055       RINOK(res);
   1056 
   1057       if (*status != CODER_STATUS_FINISHED_WITH_MARK)
   1058       {
   1059         if (p->block.packSize == p->packSize
   1060             && *status == CODER_STATUS_NEEDS_MORE_INPUT)
   1061         {
   1062           PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT");
   1063           *status = CODER_STATUS_NOT_SPECIFIED;
   1064           return SZ_ERROR_DATA;
   1065         }
   1066 
   1067         return SZ_OK;
   1068       }
   1069       {
   1070         XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize);
   1071         p->state = XZ_STATE_BLOCK_FOOTER;
   1072         p->pos = 0;
   1073         p->alignPos = 0;
   1074         *status = CODER_STATUS_NOT_SPECIFIED;
   1075 
   1076         if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize)
   1077            || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize))
   1078         {
   1079           PRF_STR("ERROR: block.size mismatch");
   1080           return SZ_ERROR_DATA;
   1081         }
   1082       }
   1083       // continue;
   1084     }
   1085 
   1086     srcRem = srcLenOrig - *srcLen;
   1087 
   1088     // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes
   1089     if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER)
   1090     {
   1091       *status = CODER_STATUS_NEEDS_MORE_INPUT;
   1092       return SZ_OK;
   1093     }
   1094 
   1095     switch (p->state)
   1096     {
   1097       case XZ_STATE_STREAM_HEADER:
   1098       {
   1099         if (p->pos < XZ_STREAM_HEADER_SIZE)
   1100         {
   1101           if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
   1102             return SZ_ERROR_NO_ARCHIVE;
   1103           if (p->decodeToStreamSignature)
   1104             return SZ_OK;
   1105           p->buf[p->pos++] = *src++;
   1106           (*srcLen)++;
   1107         }
   1108         else
   1109         {
   1110           RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
   1111           p->numStartedStreams++;
   1112           p->indexSize = 0;
   1113           p->numBlocks = 0;
   1114           Sha256_Init(&p->sha);
   1115           p->state = XZ_STATE_BLOCK_HEADER;
   1116           p->pos = 0;
   1117         }
   1118         break;
   1119       }
   1120 
   1121       case XZ_STATE_BLOCK_HEADER:
   1122       {
   1123         if (p->pos == 0)
   1124         {
   1125           p->buf[p->pos++] = *src++;
   1126           (*srcLen)++;
   1127           if (p->buf[0] == 0)
   1128           {
   1129             if (p->decodeOnlyOneBlock)
   1130               return SZ_ERROR_DATA;
   1131             p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
   1132             p->indexPos = p->indexPreSize;
   1133             p->indexSize += p->indexPreSize;
   1134             Sha256_Final(&p->sha, p->shaDigest);
   1135             Sha256_Init(&p->sha);
   1136             p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
   1137             p->state = XZ_STATE_STREAM_INDEX;
   1138             break;
   1139           }
   1140           p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
   1141           break;
   1142         }
   1143 
   1144         if (p->pos != p->blockHeaderSize)
   1145         {
   1146           UInt32 cur = p->blockHeaderSize - p->pos;
   1147           if (cur > srcRem)
   1148             cur = (UInt32)srcRem;
   1149           memcpy(p->buf + p->pos, src, cur);
   1150           p->pos += cur;
   1151           (*srcLen) += cur;
   1152           src += cur;
   1153         }
   1154         else
   1155         {
   1156           RINOK(XzBlock_Parse(&p->block, p->buf));
   1157           if (!XzBlock_AreSupportedFilters(&p->block))
   1158             return SZ_ERROR_UNSUPPORTED;
   1159           p->numTotalBlocks++;
   1160           p->state = XZ_STATE_BLOCK;
   1161           p->packSize = 0;
   1162           p->unpackSize = 0;
   1163           XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
   1164           if (p->parseMode)
   1165           {
   1166             p->headerParsedOk = True;
   1167             return SZ_OK;
   1168           }
   1169           RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize));
   1170         }
   1171         break;
   1172       }
   1173 
   1174       case XZ_STATE_BLOCK_FOOTER:
   1175       {
   1176         if ((((unsigned)p->packSize + p->alignPos) & 3) != 0)
   1177         {
   1178           if (srcRem == 0)
   1179           {
   1180             *status = CODER_STATUS_NEEDS_MORE_INPUT;
   1181             return SZ_OK;
   1182           }
   1183           (*srcLen)++;
   1184           p->alignPos++;
   1185           if (*src++ != 0)
   1186             return SZ_ERROR_CRC;
   1187         }
   1188         else
   1189         {
   1190           UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
   1191           UInt32 cur = checkSize - p->pos;
   1192           if (cur != 0)
   1193           {
   1194             if (srcRem == 0)
   1195             {
   1196               *status = CODER_STATUS_NEEDS_MORE_INPUT;
   1197               return SZ_OK;
   1198             }
   1199             if (cur > srcRem)
   1200               cur = (UInt32)srcRem;
   1201             memcpy(p->buf + p->pos, src, cur);
   1202             p->pos += cur;
   1203             (*srcLen) += cur;
   1204             src += cur;
   1205             if (checkSize != p->pos)
   1206               break;
   1207           }
   1208           {
   1209             Byte digest[XZ_CHECK_SIZE_MAX];
   1210             p->state = XZ_STATE_BLOCK_HEADER;
   1211             p->pos = 0;
   1212             if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
   1213               return SZ_ERROR_CRC;
   1214             if (p->decodeOnlyOneBlock)
   1215             {
   1216               *status = CODER_STATUS_FINISHED_WITH_MARK;
   1217               return SZ_OK;
   1218             }
   1219           }
   1220         }
   1221         break;
   1222       }
   1223 
   1224       case XZ_STATE_STREAM_INDEX:
   1225       {
   1226         if (p->pos < p->indexPreSize)
   1227         {
   1228           (*srcLen)++;
   1229           if (*src++ != p->buf[p->pos++])
   1230             return SZ_ERROR_CRC;
   1231         }
   1232         else
   1233         {
   1234           if (p->indexPos < p->indexSize)
   1235           {
   1236             UInt64 cur = p->indexSize - p->indexPos;
   1237             if (srcRem > cur)
   1238               srcRem = (SizeT)cur;
   1239             p->crc = CrcUpdate(p->crc, src, srcRem);
   1240             Sha256_Update(&p->sha, src, srcRem);
   1241             (*srcLen) += srcRem;
   1242             src += srcRem;
   1243             p->indexPos += srcRem;
   1244           }
   1245           else if ((p->indexPos & 3) != 0)
   1246           {
   1247             Byte b = *src++;
   1248             p->crc = CRC_UPDATE_BYTE(p->crc, b);
   1249             (*srcLen)++;
   1250             p->indexPos++;
   1251             p->indexSize++;
   1252             if (b != 0)
   1253               return SZ_ERROR_CRC;
   1254           }
   1255           else
   1256           {
   1257             Byte digest[SHA256_DIGEST_SIZE];
   1258             p->state = XZ_STATE_STREAM_INDEX_CRC;
   1259             p->indexSize += 4;
   1260             p->pos = 0;
   1261             Sha256_Final(&p->sha, digest);
   1262             if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
   1263               return SZ_ERROR_CRC;
   1264           }
   1265         }
   1266         break;
   1267       }
   1268 
   1269       case XZ_STATE_STREAM_INDEX_CRC:
   1270       {
   1271         if (p->pos < 4)
   1272         {
   1273           (*srcLen)++;
   1274           p->buf[p->pos++] = *src++;
   1275         }
   1276         else
   1277         {
   1278           p->state = XZ_STATE_STREAM_FOOTER;
   1279           p->pos = 0;
   1280           if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
   1281             return SZ_ERROR_CRC;
   1282         }
   1283         break;
   1284       }
   1285 
   1286       case XZ_STATE_STREAM_FOOTER:
   1287       {
   1288         UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
   1289         if (cur > srcRem)
   1290           cur = (UInt32)srcRem;
   1291         memcpy(p->buf + p->pos, src, cur);
   1292         p->pos += cur;
   1293         (*srcLen) += cur;
   1294         src += cur;
   1295         if (p->pos == XZ_STREAM_FOOTER_SIZE)
   1296         {
   1297           p->state = XZ_STATE_STREAM_PADDING;
   1298           p->numFinishedStreams++;
   1299           p->padSize = 0;
   1300           if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
   1301             return SZ_ERROR_CRC;
   1302         }
   1303         break;
   1304       }
   1305 
   1306       case XZ_STATE_STREAM_PADDING:
   1307       {
   1308         if (*src != 0)
   1309         {
   1310           if (((UInt32)p->padSize & 3) != 0)
   1311             return SZ_ERROR_NO_ARCHIVE;
   1312           p->pos = 0;
   1313           p->state = XZ_STATE_STREAM_HEADER;
   1314         }
   1315         else
   1316         {
   1317           (*srcLen)++;
   1318           src++;
   1319           p->padSize++;
   1320         }
   1321         break;
   1322       }
   1323 
   1324       case XZ_STATE_BLOCK: break; /* to disable GCC warning */
   1325     }
   1326   }
   1327   /*
   1328   if (p->state == XZ_STATE_FINISHED)
   1329     *status = CODER_STATUS_FINISHED_WITH_MARK;
   1330   return SZ_OK;
   1331   */
   1332 }
   1333 
   1334 
   1335 SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
   1336     const Byte *src, SizeT *srcLen,
   1337     ECoderFinishMode finishMode, ECoderStatus *status)
   1338 {
   1339   XzUnpacker_Init(p);
   1340   XzUnpacker_SetOutBuf(p, dest, *destLen);
   1341 
   1342   return XzUnpacker_Code(p,
   1343       NULL, destLen,
   1344       src, srcLen, True,
   1345       finishMode, status);
   1346 }
   1347 
   1348 
   1349 BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
   1350 {
   1351   return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
   1352 }
   1353 
   1354 BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
   1355 {
   1356   return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
   1357 }
   1358 
   1359 UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p)
   1360 {
   1361   UInt64 num = 0;
   1362   if (p->state == XZ_STATE_STREAM_PADDING)
   1363     num = p->padSize;
   1364   else if (p->state == XZ_STATE_STREAM_HEADER)
   1365     num = p->padSize + p->pos;
   1366   return num;
   1367 }
   1368 
   1369 
   1370 
   1371 
   1372 
   1373 
   1374 
   1375 
   1376 
   1377 
   1378 
   1379 
   1380 
   1381 
   1382 
   1383 
   1384 
   1385 
   1386 
   1387 
   1388 
   1389 #ifndef _7ZIP_ST
   1390 #include "MtDec.h"
   1391 #endif
   1392 
   1393 
   1394 void XzDecMtProps_Init(CXzDecMtProps *p)
   1395 {
   1396   p->inBufSize_ST = 1 << 18;
   1397   p->outStep_ST = 1 << 20;
   1398   p->ignoreErrors = False;
   1399 
   1400   #ifndef _7ZIP_ST
   1401   p->numThreads = 1;
   1402   p->inBufSize_MT = 1 << 18;
   1403   p->memUseMax = sizeof(size_t) << 28;
   1404   #endif
   1405 }
   1406 
   1407 
   1408 
   1409 #ifndef _7ZIP_ST
   1410 
   1411 /* ---------- CXzDecMtThread ---------- */
   1412 
   1413 typedef struct
   1414 {
   1415   Byte *outBuf;
   1416   size_t outBufSize;
   1417   size_t outPreSize;
   1418   size_t inPreSize;
   1419   size_t inPreHeaderSize;
   1420   size_t blockPackSize_for_Index;  // including block header and checksum.
   1421   size_t blockPackTotal;  // including stream header, block header and checksum.
   1422   size_t inCodeSize;
   1423   size_t outCodeSize;
   1424   ECoderStatus status;
   1425   SRes codeRes;
   1426   BoolInt skipMode;
   1427   // BoolInt finishedWithMark;
   1428   EMtDecParseState parseState;
   1429   BoolInt parsing_Truncated;
   1430   BoolInt atBlockHeader;
   1431   CXzStreamFlags streamFlags;
   1432   // UInt64 numFinishedStreams
   1433   UInt64 numStreams;
   1434   UInt64 numTotalBlocks;
   1435   UInt64 numBlocks;
   1436 
   1437   BoolInt dec_created;
   1438   CXzUnpacker dec;
   1439 
   1440   Byte mtPad[1 << 7];
   1441 } CXzDecMtThread;
   1442 
   1443 #endif
   1444 
   1445 
   1446 /* ---------- CXzDecMt ---------- */
   1447 
   1448 typedef struct
   1449 {
   1450   CAlignOffsetAlloc alignOffsetAlloc;
   1451   ISzAllocPtr allocMid;
   1452 
   1453   CXzDecMtProps props;
   1454   size_t unpackBlockMaxSize;
   1455 
   1456   ISeqInStream *inStream;
   1457   ISeqOutStream *outStream;
   1458   ICompressProgress *progress;
   1459   // CXzStatInfo *stat;
   1460 
   1461   BoolInt finishMode;
   1462   BoolInt outSize_Defined;
   1463   UInt64 outSize;
   1464 
   1465   UInt64 outProcessed;
   1466   UInt64 inProcessed;
   1467   UInt64 readProcessed;
   1468   BoolInt readWasFinished;
   1469   SRes readRes;
   1470   SRes writeRes;
   1471 
   1472   Byte *outBuf;
   1473   size_t outBufSize;
   1474   Byte *inBuf;
   1475   size_t inBufSize;
   1476 
   1477   CXzUnpacker dec;
   1478 
   1479   ECoderStatus status;
   1480   SRes codeRes;
   1481 
   1482   #ifndef _7ZIP_ST
   1483   BoolInt mainDecoderWasCalled;
   1484   // int statErrorDefined;
   1485   int finishedDecoderIndex;
   1486 
   1487   // global values that are used in Parse stage
   1488   CXzStreamFlags streamFlags;
   1489   // UInt64 numFinishedStreams
   1490   UInt64 numStreams;
   1491   UInt64 numTotalBlocks;
   1492   UInt64 numBlocks;
   1493 
   1494   // UInt64 numBadBlocks;
   1495   SRes mainErrorCode;
   1496 
   1497   BoolInt isBlockHeaderState_Parse;
   1498   BoolInt isBlockHeaderState_Write;
   1499   UInt64 outProcessed_Parse;
   1500   BoolInt parsing_Truncated;
   1501 
   1502   BoolInt mtc_WasConstructed;
   1503   CMtDec mtc;
   1504   CXzDecMtThread coders[MTDEC__THREADS_MAX];
   1505   #endif
   1506 
   1507 } CXzDecMt;
   1508 
   1509 
   1510 
   1511 CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
   1512 {
   1513   CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt));
   1514   if (!p)
   1515     return NULL;
   1516 
   1517   AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
   1518   p->alignOffsetAlloc.baseAlloc = alloc;
   1519   p->alignOffsetAlloc.numAlignBits = 7;
   1520   p->alignOffsetAlloc.offset = 0;
   1521 
   1522   p->allocMid = allocMid;
   1523 
   1524   p->outBuf = NULL;
   1525   p->outBufSize = 0;
   1526   p->inBuf = NULL;
   1527   p->inBufSize = 0;
   1528 
   1529   XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt);
   1530 
   1531   p->unpackBlockMaxSize = 0;
   1532 
   1533   XzDecMtProps_Init(&p->props);
   1534 
   1535   #ifndef _7ZIP_ST
   1536   p->mtc_WasConstructed = False;
   1537   {
   1538     unsigned i;
   1539     for (i = 0; i < MTDEC__THREADS_MAX; i++)
   1540     {
   1541       CXzDecMtThread *coder = &p->coders[i];
   1542       coder->dec_created = False;
   1543       coder->outBuf = NULL;
   1544       coder->outBufSize = 0;
   1545     }
   1546   }
   1547   #endif
   1548 
   1549   return p;
   1550 }
   1551 
   1552 
   1553 #ifndef _7ZIP_ST
   1554 
   1555 static void XzDecMt_FreeOutBufs(CXzDecMt *p)
   1556 {
   1557   unsigned i;
   1558   for (i = 0; i < MTDEC__THREADS_MAX; i++)
   1559   {
   1560     CXzDecMtThread *coder = &p->coders[i];
   1561     if (coder->outBuf)
   1562     {
   1563       ISzAlloc_Free(p->allocMid, coder->outBuf);
   1564       coder->outBuf = NULL;
   1565       coder->outBufSize = 0;
   1566     }
   1567   }
   1568   p->unpackBlockMaxSize = 0;
   1569 }
   1570 
   1571 #endif
   1572 
   1573 
   1574 
   1575 static void XzDecMt_FreeSt(CXzDecMt *p)
   1576 {
   1577   XzUnpacker_Free(&p->dec);
   1578 
   1579   if (p->outBuf)
   1580   {
   1581     ISzAlloc_Free(p->allocMid, p->outBuf);
   1582     p->outBuf = NULL;
   1583   }
   1584   p->outBufSize = 0;
   1585 
   1586   if (p->inBuf)
   1587   {
   1588     ISzAlloc_Free(p->allocMid, p->inBuf);
   1589     p->inBuf = NULL;
   1590   }
   1591   p->inBufSize = 0;
   1592 }
   1593 
   1594 
   1595 void XzDecMt_Destroy(CXzDecMtHandle pp)
   1596 {
   1597   CXzDecMt *p = (CXzDecMt *)pp;
   1598 
   1599   XzDecMt_FreeSt(p);
   1600 
   1601   #ifndef _7ZIP_ST
   1602 
   1603   if (p->mtc_WasConstructed)
   1604   {
   1605     MtDec_Destruct(&p->mtc);
   1606     p->mtc_WasConstructed = False;
   1607   }
   1608   {
   1609     unsigned i;
   1610     for (i = 0; i < MTDEC__THREADS_MAX; i++)
   1611     {
   1612       CXzDecMtThread *t = &p->coders[i];
   1613       if (t->dec_created)
   1614       {
   1615         // we don't need to free dict here
   1616         XzUnpacker_Free(&t->dec);
   1617         t->dec_created = False;
   1618       }
   1619     }
   1620   }
   1621   XzDecMt_FreeOutBufs(p);
   1622 
   1623   #endif
   1624 
   1625   ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp);
   1626 }
   1627 
   1628 
   1629 
   1630 #ifndef _7ZIP_ST
   1631 
   1632 static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
   1633 {
   1634   CXzDecMt *me = (CXzDecMt *)obj;
   1635   CXzDecMtThread *coder = &me->coders[coderIndex];
   1636   size_t srcSize = cc->srcSize;
   1637 
   1638   cc->srcSize = 0;
   1639   cc->outPos = 0;
   1640   cc->state = MTDEC_PARSE_CONTINUE;
   1641 
   1642   cc->canCreateNewThread = True;
   1643 
   1644   if (cc->startCall)
   1645   {
   1646     coder->outPreSize = 0;
   1647     coder->inPreSize = 0;
   1648     coder->inPreHeaderSize = 0;
   1649     coder->parseState = MTDEC_PARSE_CONTINUE;
   1650     coder->parsing_Truncated = False;
   1651     coder->skipMode = False;
   1652     coder->codeRes = SZ_OK;
   1653     coder->status = CODER_STATUS_NOT_SPECIFIED;
   1654     coder->inCodeSize = 0;
   1655     coder->outCodeSize = 0;
   1656 
   1657     coder->numStreams = me->numStreams;
   1658     coder->numTotalBlocks = me->numTotalBlocks;
   1659     coder->numBlocks = me->numBlocks;
   1660 
   1661     if (!coder->dec_created)
   1662     {
   1663       XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt);
   1664       coder->dec_created = True;
   1665     }
   1666 
   1667     XzUnpacker_Init(&coder->dec);
   1668 
   1669     if (me->isBlockHeaderState_Parse)
   1670     {
   1671       coder->dec.streamFlags = me->streamFlags;
   1672       coder->atBlockHeader = True;
   1673       XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec);
   1674     }
   1675     else
   1676     {
   1677       coder->atBlockHeader = False;
   1678       me->isBlockHeaderState_Parse = True;
   1679     }
   1680 
   1681     coder->dec.numStartedStreams = me->numStreams;
   1682     coder->dec.numTotalBlocks = me->numTotalBlocks;
   1683     coder->dec.numBlocks = me->numBlocks;
   1684   }
   1685 
   1686   while (!coder->skipMode)
   1687   {
   1688     ECoderStatus status;
   1689     SRes res;
   1690     size_t srcSize2 = srcSize;
   1691     size_t destSize = (size_t)0 - 1;
   1692 
   1693     coder->dec.parseMode = True;
   1694     coder->dec.headerParsedOk = False;
   1695 
   1696     PRF_STR_INT("Parse", srcSize2);
   1697 
   1698     res = XzUnpacker_Code(&coder->dec,
   1699         NULL, &destSize,
   1700         cc->src, &srcSize2, cc->srcFinished,
   1701         CODER_FINISH_END, &status);
   1702 
   1703     // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2));
   1704 
   1705     coder->codeRes = res;
   1706     coder->status = status;
   1707     cc->srcSize += srcSize2;
   1708     srcSize -= srcSize2;
   1709     coder->inPreHeaderSize += srcSize2;
   1710     coder->inPreSize = coder->inPreHeaderSize;
   1711 
   1712     if (res != SZ_OK)
   1713     {
   1714       cc->state =
   1715       coder->parseState = MTDEC_PARSE_END;
   1716       /*
   1717       if (res == SZ_ERROR_MEM)
   1718         return res;
   1719       return SZ_OK;
   1720       */
   1721       return; // res;
   1722     }
   1723 
   1724     if (coder->dec.headerParsedOk)
   1725     {
   1726       const CXzBlock *block = &coder->dec.block;
   1727       if (XzBlock_HasUnpackSize(block)
   1728           // && block->unpackSize <= me->props.outBlockMax
   1729           && XzBlock_HasPackSize(block))
   1730       {
   1731         {
   1732           if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax)
   1733           {
   1734             cc->state = MTDEC_PARSE_OVERFLOW;
   1735             return; // SZ_OK;
   1736           }
   1737         }
   1738         {
   1739         UInt64 packSize = block->packSize;
   1740         UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
   1741         UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags);
   1742         UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize;
   1743         // if (blockPackSum <= me->props.inBlockMax)
   1744         // unpackBlockMaxSize
   1745         {
   1746           coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize);
   1747           coder->blockPackTotal = (size_t)blockPackSum;
   1748           coder->outPreSize = (size_t)block->unpackSize;
   1749           coder->streamFlags = coder->dec.streamFlags;
   1750           me->streamFlags = coder->dec.streamFlags;
   1751           coder->skipMode = True;
   1752           break;
   1753         }
   1754         }
   1755       }
   1756     }
   1757     else
   1758     // if (coder->inPreSize <= me->props.inBlockMax)
   1759     {
   1760       if (!cc->srcFinished)
   1761         return; // SZ_OK;
   1762       cc->state =
   1763       coder->parseState = MTDEC_PARSE_END;
   1764       return; // SZ_OK;
   1765     }
   1766     cc->state = MTDEC_PARSE_OVERFLOW;
   1767     return; // SZ_OK;
   1768   }
   1769 
   1770   // ---------- skipMode ----------
   1771   {
   1772     UInt64 rem = coder->blockPackTotal - coder->inPreSize;
   1773     size_t cur = srcSize;
   1774     if (cur > rem)
   1775       cur = (size_t)rem;
   1776     cc->srcSize += cur;
   1777     coder->inPreSize += cur;
   1778     srcSize -= cur;
   1779 
   1780     if (coder->inPreSize == coder->blockPackTotal)
   1781     {
   1782       if (srcSize == 0)
   1783       {
   1784         if (!cc->srcFinished)
   1785           return; // SZ_OK;
   1786         cc->state = MTDEC_PARSE_END;
   1787       }
   1788       else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block
   1789         cc->state = MTDEC_PARSE_END;
   1790       else
   1791       {
   1792         cc->state = MTDEC_PARSE_NEW;
   1793 
   1794         {
   1795           size_t blockMax = me->unpackBlockMaxSize;
   1796           if (blockMax < coder->outPreSize)
   1797             blockMax = coder->outPreSize;
   1798           {
   1799             UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2;
   1800             if (me->props.memUseMax < required)
   1801               cc->canCreateNewThread = False;
   1802           }
   1803         }
   1804 
   1805         if (me->outSize_Defined)
   1806         {
   1807           // next block can be zero size
   1808           const UInt64 rem2 = me->outSize - me->outProcessed_Parse;
   1809           if (rem2 < coder->outPreSize)
   1810           {
   1811             coder->parsing_Truncated = True;
   1812             cc->state = MTDEC_PARSE_END;
   1813           }
   1814           me->outProcessed_Parse += coder->outPreSize;
   1815         }
   1816       }
   1817     }
   1818     else if (cc->srcFinished)
   1819       cc->state = MTDEC_PARSE_END;
   1820     else
   1821       return; // SZ_OK;
   1822 
   1823     coder->parseState = cc->state;
   1824     cc->outPos = coder->outPreSize;
   1825 
   1826     me->numStreams = coder->dec.numStartedStreams;
   1827     me->numTotalBlocks = coder->dec.numTotalBlocks;
   1828     me->numBlocks = coder->dec.numBlocks + 1;
   1829     return; // SZ_OK;
   1830   }
   1831 }
   1832 
   1833 
   1834 static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex)
   1835 {
   1836   CXzDecMt *me = (CXzDecMt *)pp;
   1837   CXzDecMtThread *coder = &me->coders[coderIndex];
   1838   Byte *dest;
   1839 
   1840   if (!coder->dec.headerParsedOk)
   1841     return SZ_OK;
   1842 
   1843   dest = coder->outBuf;
   1844 
   1845   if (!dest || coder->outBufSize < coder->outPreSize)
   1846   {
   1847     if (dest)
   1848     {
   1849       ISzAlloc_Free(me->allocMid, dest);
   1850       coder->outBuf = NULL;
   1851       coder->outBufSize = 0;
   1852     }
   1853     {
   1854       size_t outPreSize = coder->outPreSize;
   1855       if (outPreSize == 0)
   1856         outPreSize = 1;
   1857       dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize);
   1858     }
   1859     if (!dest)
   1860       return SZ_ERROR_MEM;
   1861     coder->outBuf = dest;
   1862     coder->outBufSize = coder->outPreSize;
   1863 
   1864     if (coder->outBufSize > me->unpackBlockMaxSize)
   1865       me->unpackBlockMaxSize = coder->outBufSize;
   1866   }
   1867 
   1868   // return SZ_ERROR_MEM;
   1869 
   1870   XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize);
   1871 
   1872   {
   1873     SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize);
   1874     // res = SZ_ERROR_UNSUPPORTED; // to test
   1875     coder->codeRes = res;
   1876     if (res != SZ_OK)
   1877     {
   1878       // if (res == SZ_ERROR_MEM) return res;
   1879       if (me->props.ignoreErrors && res != SZ_ERROR_MEM)
   1880         return S_OK;
   1881       return res;
   1882     }
   1883   }
   1884 
   1885   return SZ_OK;
   1886 }
   1887 
   1888 
   1889 static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex,
   1890     const Byte *src, size_t srcSize, int srcFinished,
   1891     // int finished, int blockFinished,
   1892     UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
   1893 {
   1894   CXzDecMt *me = (CXzDecMt *)pp;
   1895   CXzDecMtThread *coder = &me->coders[coderIndex];
   1896 
   1897   *inCodePos = coder->inCodeSize;
   1898   *outCodePos = coder->outCodeSize;
   1899   *stop = True;
   1900 
   1901   if (coder->inCodeSize < coder->inPreHeaderSize)
   1902   {
   1903     UInt64 rem = coder->inPreHeaderSize - coder->inCodeSize;
   1904     size_t step = srcSize;
   1905     if (step > rem)
   1906       step = (size_t)rem;
   1907     src += step;
   1908     srcSize -= step;
   1909     coder->inCodeSize += step;
   1910     if (coder->inCodeSize < coder->inPreHeaderSize)
   1911     {
   1912       *stop = False;
   1913       return SZ_OK;
   1914     }
   1915   }
   1916 
   1917   if (!coder->dec.headerParsedOk)
   1918     return SZ_OK;
   1919   if (!coder->outBuf)
   1920     return SZ_OK;
   1921 
   1922   if (coder->codeRes == SZ_OK)
   1923   {
   1924     ECoderStatus status;
   1925     SRes res;
   1926     size_t srcProcessed = srcSize;
   1927     size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten;
   1928 
   1929     // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur));
   1930 
   1931     res = XzUnpacker_Code(&coder->dec,
   1932         NULL, &outSizeCur,
   1933         src, &srcProcessed, srcFinished,
   1934         // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY,
   1935         CODER_FINISH_END,
   1936         &status);
   1937 
   1938     // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur));
   1939 
   1940     coder->codeRes = res;
   1941     coder->status = status;
   1942     coder->inCodeSize += srcProcessed;
   1943     coder->outCodeSize = coder->dec.outDataWritten;
   1944     *inCodePos = coder->inCodeSize;
   1945     *outCodePos = coder->outCodeSize;
   1946 
   1947     if (res == SZ_OK)
   1948     {
   1949       if (srcProcessed == srcSize)
   1950         *stop = False;
   1951       return SZ_OK;
   1952     }
   1953   }
   1954 
   1955   if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM)
   1956   {
   1957     *inCodePos = coder->inPreSize;
   1958     *outCodePos = coder->outPreSize;
   1959     return S_OK;
   1960   }
   1961   return coder->codeRes;
   1962 }
   1963 
   1964 
   1965 #define XZDECMT_STREAM_WRITE_STEP (1 << 24)
   1966 
   1967 static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex,
   1968     BoolInt needWriteToStream,
   1969     const Byte *src, size_t srcSize,
   1970     // int srcFinished,
   1971     BoolInt *needContinue,
   1972     BoolInt *canRecode)
   1973 {
   1974   CXzDecMt *me = (CXzDecMt *)pp;
   1975   const CXzDecMtThread *coder = &me->coders[coderIndex];
   1976 
   1977   // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize));
   1978 
   1979   *needContinue = False;
   1980   *canRecode = True;
   1981 
   1982   if (!needWriteToStream)
   1983     return SZ_OK;
   1984 
   1985   if (!coder->dec.headerParsedOk || !coder->outBuf)
   1986   {
   1987     if (me->finishedDecoderIndex < 0)
   1988       me->finishedDecoderIndex = coderIndex;
   1989     return SZ_OK;
   1990   }
   1991 
   1992   if (me->finishedDecoderIndex >= 0)
   1993     return SZ_OK;
   1994 
   1995   me->mtc.inProcessed += coder->inCodeSize;
   1996 
   1997   *canRecode = False;
   1998 
   1999   {
   2000     SRes res;
   2001     size_t size = coder->outCodeSize;
   2002     Byte *data = coder->outBuf;
   2003 
   2004     // we use in me->dec: sha, numBlocks, indexSize
   2005 
   2006     if (!me->isBlockHeaderState_Write)
   2007     {
   2008       XzUnpacker_PrepareToRandomBlockDecoding(&me->dec);
   2009       me->dec.decodeOnlyOneBlock = False;
   2010       me->dec.numStartedStreams = coder->dec.numStartedStreams;
   2011       me->dec.streamFlags = coder->streamFlags;
   2012 
   2013       me->isBlockHeaderState_Write = True;
   2014     }
   2015 
   2016     me->dec.numTotalBlocks = coder->dec.numTotalBlocks;
   2017     XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize);
   2018 
   2019     if (coder->outPreSize != size)
   2020     {
   2021       if (me->props.ignoreErrors)
   2022       {
   2023         memset(data + size, 0, coder->outPreSize - size);
   2024         size = coder->outPreSize;
   2025       }
   2026       // me->numBadBlocks++;
   2027       if (me->mainErrorCode == SZ_OK)
   2028       {
   2029         if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT)
   2030           me->mainErrorCode = SZ_ERROR_INPUT_EOF;
   2031         else
   2032           me->mainErrorCode = SZ_ERROR_DATA;
   2033       }
   2034     }
   2035 
   2036     if (me->writeRes != SZ_OK)
   2037       return me->writeRes;
   2038 
   2039     res = SZ_OK;
   2040     {
   2041       if (me->outSize_Defined)
   2042       {
   2043         const UInt64 rem = me->outSize - me->outProcessed;
   2044         if (size > rem)
   2045           size = (SizeT)rem;
   2046       }
   2047 
   2048       for (;;)
   2049       {
   2050         size_t cur = size;
   2051         size_t written;
   2052         if (cur > XZDECMT_STREAM_WRITE_STEP)
   2053           cur = XZDECMT_STREAM_WRITE_STEP;
   2054 
   2055         written = ISeqOutStream_Write(me->outStream, data, cur);
   2056 
   2057         // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written));
   2058 
   2059         me->outProcessed += written;
   2060         if (written != cur)
   2061         {
   2062           me->writeRes = SZ_ERROR_WRITE;
   2063           res = me->writeRes;
   2064           break;
   2065         }
   2066         data += cur;
   2067         size -= cur;
   2068         // PRF_STR_INT("Written size =", size);
   2069         if (size == 0)
   2070           break;
   2071         res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0);
   2072         if (res != SZ_OK)
   2073           break;
   2074       }
   2075     }
   2076 
   2077     if (coder->codeRes != SZ_OK)
   2078       if (!me->props.ignoreErrors)
   2079       {
   2080         me->finishedDecoderIndex = coderIndex;
   2081         return res;
   2082       }
   2083 
   2084     RINOK(res);
   2085 
   2086     if (coder->inPreSize != coder->inCodeSize
   2087         || coder->blockPackTotal != coder->inCodeSize)
   2088     {
   2089       me->finishedDecoderIndex = coderIndex;
   2090       return SZ_OK;
   2091     }
   2092 
   2093     if (coder->parseState != MTDEC_PARSE_END)
   2094     {
   2095       *needContinue = True;
   2096       return SZ_OK;
   2097     }
   2098   }
   2099 
   2100   // (coder->state == MTDEC_PARSE_END) means that there are no other working threads
   2101   // so we can use mtc variables without lock
   2102 
   2103   PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed);
   2104 
   2105   me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
   2106   {
   2107     CXzUnpacker *dec = &me->dec;
   2108 
   2109     PRF_STR_INT("PostSingle", srcSize);
   2110 
   2111     {
   2112       size_t srcProcessed = srcSize;
   2113       ECoderStatus status;
   2114       size_t outSizeCur = 0;
   2115       SRes res;
   2116 
   2117       // dec->decodeOnlyOneBlock = False;
   2118       dec->decodeToStreamSignature = True;
   2119 
   2120       me->mainDecoderWasCalled = True;
   2121 
   2122       if (coder->parsing_Truncated)
   2123       {
   2124         me->parsing_Truncated = True;
   2125         return SZ_OK;
   2126       }
   2127 
   2128       res = XzUnpacker_Code(dec,
   2129           NULL, &outSizeCur,
   2130           src, &srcProcessed,
   2131           me->mtc.readWasFinished, // srcFinished
   2132           CODER_FINISH_END, // CODER_FINISH_ANY,
   2133           &status);
   2134 
   2135       me->status = status;
   2136       me->codeRes = res;
   2137 
   2138       me->mtc.inProcessed += srcProcessed;
   2139       me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
   2140 
   2141       if (res != SZ_OK)
   2142       {
   2143         return S_OK;
   2144         // return res;
   2145       }
   2146 
   2147       if (dec->state == XZ_STATE_STREAM_HEADER)
   2148       {
   2149         *needContinue = True;
   2150         me->isBlockHeaderState_Parse = False;
   2151         me->isBlockHeaderState_Write = False;
   2152         {
   2153           Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
   2154           if (!crossBuf)
   2155             return SZ_ERROR_MEM;
   2156           memcpy(crossBuf, src + srcProcessed, srcSize - srcProcessed);
   2157         }
   2158         me->mtc.crossStart = 0;
   2159         me->mtc.crossEnd = srcSize - srcProcessed;
   2160         return SZ_OK;
   2161       }
   2162 
   2163       if (status != CODER_STATUS_NEEDS_MORE_INPUT)
   2164       {
   2165         return E_FAIL;
   2166       }
   2167 
   2168       if (me->mtc.readWasFinished)
   2169       {
   2170         return SZ_OK;
   2171       }
   2172     }
   2173 
   2174     {
   2175       size_t inPos;
   2176       size_t inLim;
   2177       const Byte *inData;
   2178       UInt64 inProgressPrev = me->mtc.inProcessed;
   2179 
   2180       // XzDecMt_Prepare_InBuf_ST(p);
   2181       Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
   2182       if (!crossBuf)
   2183         return SZ_ERROR_MEM;
   2184 
   2185       inPos = 0;
   2186       inLim = 0;
   2187       // outProcessed = 0;
   2188 
   2189       inData = crossBuf;
   2190 
   2191       for (;;)
   2192       {
   2193         SizeT inProcessed;
   2194         SizeT outProcessed;
   2195         ECoderStatus status;
   2196         SRes res;
   2197 
   2198         if (inPos == inLim)
   2199         {
   2200           if (!me->mtc.readWasFinished)
   2201           {
   2202             inPos = 0;
   2203             inLim = me->mtc.inBufSize;
   2204             me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)inData, &inLim);
   2205             me->mtc.readProcessed += inLim;
   2206             if (inLim == 0 || me->mtc.readRes != SZ_OK)
   2207               me->mtc.readWasFinished = True;
   2208           }
   2209         }
   2210 
   2211         inProcessed = inLim - inPos;
   2212         outProcessed = 0;
   2213 
   2214         res = XzUnpacker_Code(dec,
   2215             NULL, &outProcessed,
   2216             inData + inPos, &inProcessed,
   2217             (inProcessed == 0), // srcFinished
   2218             CODER_FINISH_END, &status);
   2219 
   2220         me->codeRes = res;
   2221         me->status = status;
   2222         inPos += inProcessed;
   2223         me->mtc.inProcessed += inProcessed;
   2224         me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
   2225 
   2226         if (res != SZ_OK)
   2227         {
   2228           return S_OK;
   2229           // return res;
   2230         }
   2231 
   2232         if (dec->state == XZ_STATE_STREAM_HEADER)
   2233         {
   2234           *needContinue = True;
   2235           me->mtc.crossStart = inPos;
   2236           me->mtc.crossEnd = inLim;
   2237           me->isBlockHeaderState_Parse = False;
   2238           me->isBlockHeaderState_Write = False;
   2239           return SZ_OK;
   2240         }
   2241 
   2242         if (status != CODER_STATUS_NEEDS_MORE_INPUT)
   2243           return E_FAIL;
   2244 
   2245         if (me->mtc.progress)
   2246         {
   2247           UInt64 inDelta = me->mtc.inProcessed - inProgressPrev;
   2248           if (inDelta >= (1 << 22))
   2249           {
   2250             RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress));
   2251             inProgressPrev = me->mtc.inProcessed;
   2252           }
   2253         }
   2254         if (me->mtc.readWasFinished)
   2255           return SZ_OK;
   2256       }
   2257     }
   2258   }
   2259 }
   2260 
   2261 
   2262 #endif
   2263 
   2264 
   2265 
   2266 void XzStatInfo_Clear(CXzStatInfo *p)
   2267 {
   2268   p->InSize = 0;
   2269   p->OutSize = 0;
   2270 
   2271   p->NumStreams = 0;
   2272   p->NumBlocks = 0;
   2273 
   2274   p->UnpackSize_Defined = False;
   2275 
   2276   p->NumStreams_Defined = False;
   2277   p->NumBlocks_Defined = False;
   2278 
   2279   // p->IsArc = False;
   2280   // p->UnexpectedEnd = False;
   2281   // p->Unsupported = False;
   2282   // p->HeadersError = False;
   2283   // p->DataError = False;
   2284   // p->CrcError = False;
   2285 
   2286   p->DataAfterEnd = False;
   2287   p->DecodingTruncated = False;
   2288 
   2289   p->DecodeRes = SZ_OK;
   2290   p->ReadRes = SZ_OK;
   2291   p->ProgressRes = SZ_OK;
   2292 
   2293   p->CombinedRes = SZ_OK;
   2294   p->CombinedRes_Type = SZ_OK;
   2295 }
   2296 
   2297 
   2298 
   2299 
   2300 static SRes XzDecMt_Decode_ST(CXzDecMt *p
   2301     #ifndef _7ZIP_ST
   2302     , BoolInt tMode
   2303     #endif
   2304     , CXzStatInfo *stat)
   2305 {
   2306   size_t outPos;
   2307   size_t inPos, inLim;
   2308   const Byte *inData;
   2309   UInt64 inPrev, outPrev;
   2310 
   2311   CXzUnpacker *dec;
   2312 
   2313   #ifndef _7ZIP_ST
   2314   if (tMode)
   2315   {
   2316     XzDecMt_FreeOutBufs(p);
   2317     tMode = MtDec_PrepareRead(&p->mtc);
   2318   }
   2319   #endif
   2320 
   2321   if (!p->outBuf || p->outBufSize != p->props.outStep_ST)
   2322   {
   2323     ISzAlloc_Free(p->allocMid, p->outBuf);
   2324     p->outBufSize = 0;
   2325     p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST);
   2326     if (!p->outBuf)
   2327       return SZ_ERROR_MEM;
   2328     p->outBufSize = p->props.outStep_ST;
   2329   }
   2330 
   2331   if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
   2332   {
   2333     ISzAlloc_Free(p->allocMid, p->inBuf);
   2334     p->inBufSize = 0;
   2335     p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
   2336     if (!p->inBuf)
   2337       return SZ_ERROR_MEM;
   2338     p->inBufSize = p->props.inBufSize_ST;
   2339   }
   2340 
   2341   dec = &p->dec;
   2342   dec->decodeToStreamSignature = False;
   2343   // dec->decodeOnlyOneBlock = False;
   2344 
   2345   XzUnpacker_SetOutBuf(dec, NULL, 0);
   2346 
   2347   inPrev = p->inProcessed;
   2348   outPrev = p->outProcessed;
   2349 
   2350   inPos = 0;
   2351   inLim = 0;
   2352   inData = NULL;
   2353   outPos = 0;
   2354 
   2355   for (;;)
   2356   {
   2357     SizeT outSize;
   2358     BoolInt finished;
   2359     ECoderFinishMode finishMode;
   2360     SizeT inProcessed;
   2361     ECoderStatus status;
   2362     SRes res;
   2363 
   2364     SizeT outProcessed;
   2365 
   2366 
   2367 
   2368     if (inPos == inLim)
   2369     {
   2370       #ifndef _7ZIP_ST
   2371       if (tMode)
   2372       {
   2373         inData = MtDec_Read(&p->mtc, &inLim);
   2374         inPos = 0;
   2375         if (inData)
   2376           continue;
   2377         tMode = False;
   2378         inLim = 0;
   2379       }
   2380       #endif
   2381 
   2382       if (!p->readWasFinished)
   2383       {
   2384         inPos = 0;
   2385         inLim = p->inBufSize;
   2386         inData = p->inBuf;
   2387         p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim);
   2388         p->readProcessed += inLim;
   2389         if (inLim == 0 || p->readRes != SZ_OK)
   2390           p->readWasFinished = True;
   2391       }
   2392     }
   2393 
   2394     outSize = p->props.outStep_ST - outPos;
   2395 
   2396     finishMode = CODER_FINISH_ANY;
   2397     if (p->outSize_Defined)
   2398     {
   2399       const UInt64 rem = p->outSize - p->outProcessed;
   2400       if (outSize >= rem)
   2401       {
   2402         outSize = (SizeT)rem;
   2403         if (p->finishMode)
   2404           finishMode = CODER_FINISH_END;
   2405       }
   2406     }
   2407 
   2408     inProcessed = inLim - inPos;
   2409     outProcessed = outSize;
   2410 
   2411     res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed,
   2412         inData + inPos, &inProcessed,
   2413         (inPos == inLim), // srcFinished
   2414         finishMode, &status);
   2415 
   2416     p->codeRes = res;
   2417     p->status = status;
   2418 
   2419     inPos += inProcessed;
   2420     outPos += outProcessed;
   2421     p->inProcessed += inProcessed;
   2422     p->outProcessed += outProcessed;
   2423 
   2424     finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK);
   2425 
   2426     if (finished || outProcessed >= outSize)
   2427       if (outPos != 0)
   2428       {
   2429         size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos);
   2430         p->outProcessed += written;
   2431         if (written != outPos)
   2432         {
   2433           stat->CombinedRes_Type = SZ_ERROR_WRITE;
   2434           return SZ_ERROR_WRITE;
   2435         }
   2436         outPos = 0;
   2437       }
   2438 
   2439     if (p->progress && res == SZ_OK)
   2440     {
   2441       UInt64 inDelta = p->inProcessed - inPrev;
   2442       UInt64 outDelta = p->outProcessed - outPrev;
   2443       if (inDelta >= (1 << 22) || outDelta >= (1 << 22))
   2444       {
   2445         res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed);
   2446         if (res != SZ_OK)
   2447         {
   2448           stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
   2449           stat->ProgressRes = res;
   2450           return res;
   2451         }
   2452         inPrev = p->inProcessed;
   2453         outPrev = p->outProcessed;
   2454       }
   2455     }
   2456 
   2457     if (finished)
   2458       return res;
   2459   }
   2460 }
   2461 
   2462 static SRes XzStatInfo_SetStat(const CXzUnpacker *dec,
   2463     int finishMode,
   2464     UInt64 readProcessed, UInt64 inProcessed,
   2465     SRes res, ECoderStatus status,
   2466     BoolInt decodingTruncated,
   2467     CXzStatInfo *stat)
   2468 {
   2469   UInt64 extraSize;
   2470 
   2471   stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0);
   2472   stat->InSize = inProcessed;
   2473   stat->NumStreams = dec->numStartedStreams;
   2474   stat->NumBlocks = dec->numTotalBlocks;
   2475 
   2476   stat->UnpackSize_Defined = True;
   2477   stat->NumStreams_Defined = True;
   2478   stat->NumBlocks_Defined = True;
   2479 
   2480   extraSize = XzUnpacker_GetExtraSize(dec);
   2481 
   2482   if (res == SZ_OK)
   2483   {
   2484     if (status == CODER_STATUS_NEEDS_MORE_INPUT)
   2485     {
   2486       // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams
   2487       extraSize = 0;
   2488       if (!XzUnpacker_IsStreamWasFinished(dec))
   2489         res = SZ_ERROR_INPUT_EOF;
   2490     }
   2491     else if (!decodingTruncated || finishMode) // (status == CODER_STATUS_NOT_FINISHED)
   2492       res = SZ_ERROR_DATA;
   2493   }
   2494   else if (res == SZ_ERROR_NO_ARCHIVE)
   2495   {
   2496     /*
   2497     SZ_ERROR_NO_ARCHIVE is possible for 2 states:
   2498       XZ_STATE_STREAM_HEADER  - if bad signature or bad CRC
   2499       XZ_STATE_STREAM_PADDING - if non-zero padding data
   2500     extraSize / inProcessed don't include "bad" byte
   2501     */
   2502     if (inProcessed != extraSize) // if good streams before error
   2503       if (extraSize != 0 || readProcessed != inProcessed)
   2504       {
   2505         stat->DataAfterEnd = True;
   2506         // there is some good xz stream before. So we set SZ_OK
   2507         res = SZ_OK;
   2508       }
   2509   }
   2510 
   2511   stat->DecodeRes = res;
   2512 
   2513   stat->InSize -= extraSize;
   2514   return res;
   2515 }
   2516 
   2517 
   2518 SRes XzDecMt_Decode(CXzDecMtHandle pp,
   2519     const CXzDecMtProps *props,
   2520     const UInt64 *outDataSize, int finishMode,
   2521     ISeqOutStream *outStream,
   2522     // Byte *outBuf, size_t *outBufSize,
   2523     ISeqInStream *inStream,
   2524     // const Byte *inData, size_t inDataSize,
   2525     CXzStatInfo *stat,
   2526     int *isMT,
   2527     ICompressProgress *progress)
   2528 {
   2529   CXzDecMt *p = (CXzDecMt *)pp;
   2530   #ifndef _7ZIP_ST
   2531   BoolInt tMode;
   2532   #endif
   2533 
   2534   XzStatInfo_Clear(stat);
   2535 
   2536   p->props = *props;
   2537 
   2538   p->inStream = inStream;
   2539   p->outStream = outStream;
   2540   p->progress = progress;
   2541   // p->stat = stat;
   2542 
   2543   p->outSize = 0;
   2544   p->outSize_Defined = False;
   2545   if (outDataSize)
   2546   {
   2547     p->outSize_Defined = True;
   2548     p->outSize = *outDataSize;
   2549   }
   2550 
   2551   p->finishMode = finishMode;
   2552 
   2553   // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test
   2554 
   2555   p->writeRes = SZ_OK;
   2556   p->outProcessed = 0;
   2557   p->inProcessed = 0;
   2558   p->readProcessed = 0;
   2559   p->readWasFinished = False;
   2560 
   2561   p->codeRes = 0;
   2562   p->status = CODER_STATUS_NOT_SPECIFIED;
   2563 
   2564   XzUnpacker_Init(&p->dec);
   2565 
   2566   *isMT = False;
   2567 
   2568     /*
   2569     p->outBuf = NULL;
   2570     p->outBufSize = 0;
   2571     if (!outStream)
   2572     {
   2573       p->outBuf = outBuf;
   2574       p->outBufSize = *outBufSize;
   2575       *outBufSize = 0;
   2576     }
   2577     */
   2578 
   2579 
   2580   #ifndef _7ZIP_ST
   2581 
   2582   p->isBlockHeaderState_Parse = False;
   2583   p->isBlockHeaderState_Write = False;
   2584   // p->numBadBlocks = 0;
   2585   p->mainErrorCode = SZ_OK;
   2586   p->mainDecoderWasCalled = False;
   2587 
   2588   tMode = False;
   2589 
   2590   if (p->props.numThreads > 1)
   2591   {
   2592     IMtDecCallback vt;
   2593 
   2594     // we just free ST buffers here
   2595     // but we still keep state variables, that was set in XzUnpacker_Init()
   2596     XzDecMt_FreeSt(p);
   2597 
   2598     p->outProcessed_Parse = 0;
   2599     p->parsing_Truncated = False;
   2600 
   2601     p->numStreams = 0;
   2602     p->numTotalBlocks = 0;
   2603     p->numBlocks = 0;
   2604     p->finishedDecoderIndex = -1;
   2605 
   2606     if (!p->mtc_WasConstructed)
   2607     {
   2608       p->mtc_WasConstructed = True;
   2609       MtDec_Construct(&p->mtc);
   2610     }
   2611 
   2612     p->mtc.mtCallback = &vt;
   2613     p->mtc.mtCallbackObject = p;
   2614 
   2615     p->mtc.progress = progress;
   2616     p->mtc.inStream = inStream;
   2617     p->mtc.alloc = &p->alignOffsetAlloc.vt;
   2618     // p->mtc.inData = inData;
   2619     // p->mtc.inDataSize = inDataSize;
   2620     p->mtc.inBufSize = p->props.inBufSize_MT;
   2621     // p->mtc.inBlockMax = p->props.inBlockMax;
   2622     p->mtc.numThreadsMax = p->props.numThreads;
   2623 
   2624     *isMT = True;
   2625 
   2626     vt.Parse = XzDecMt_Callback_Parse;
   2627     vt.PreCode = XzDecMt_Callback_PreCode;
   2628     vt.Code = XzDecMt_Callback_Code;
   2629     vt.Write = XzDecMt_Callback_Write;
   2630 
   2631     {
   2632       BoolInt needContinue;
   2633 
   2634       SRes res = MtDec_Code(&p->mtc);
   2635 
   2636       stat->InSize = p->mtc.inProcessed;
   2637 
   2638       p->inProcessed = p->mtc.inProcessed;
   2639       p->readRes = p->mtc.readRes;
   2640       p->readWasFinished = p->mtc.readWasFinished;
   2641       p->readProcessed = p->mtc.readProcessed;
   2642 
   2643       tMode = True;
   2644       needContinue = False;
   2645 
   2646       if (res == SZ_OK)
   2647       {
   2648         if (p->mtc.mtProgress.res != SZ_OK)
   2649         {
   2650           res = p->mtc.mtProgress.res;
   2651           stat->ProgressRes = res;
   2652           stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
   2653         }
   2654         else
   2655           needContinue = p->mtc.needContinue;
   2656       }
   2657 
   2658       if (!needContinue)
   2659       {
   2660         SRes codeRes;
   2661         BoolInt truncated = False;
   2662         ECoderStatus status;
   2663         CXzUnpacker *dec;
   2664 
   2665         stat->OutSize = p->outProcessed;
   2666 
   2667         if (p->finishedDecoderIndex >= 0)
   2668         {
   2669           CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex];
   2670           codeRes = coder->codeRes;
   2671           dec = &coder->dec;
   2672           status = coder->status;
   2673         }
   2674         else if (p->mainDecoderWasCalled)
   2675         {
   2676           codeRes = p->codeRes;
   2677           dec = &p->dec;
   2678           status = p->status;
   2679           truncated = p->parsing_Truncated;
   2680         }
   2681         else
   2682           return E_FAIL;
   2683 
   2684         XzStatInfo_SetStat(dec, p->finishMode,
   2685             p->mtc.readProcessed, p->mtc.inProcessed,
   2686             codeRes, status,
   2687             truncated,
   2688             stat);
   2689 
   2690         if (res == SZ_OK)
   2691         {
   2692           if (p->writeRes != SZ_OK)
   2693           {
   2694             res = p->writeRes;
   2695             stat->CombinedRes_Type = SZ_ERROR_WRITE;
   2696           }
   2697           else if (p->mtc.readRes != SZ_OK && p->mtc.inProcessed == p->mtc.readProcessed)
   2698           {
   2699             res = p->mtc.readRes;
   2700             stat->ReadRes = res;
   2701             stat->CombinedRes_Type = SZ_ERROR_READ;
   2702           }
   2703           else if (p->mainErrorCode != SZ_OK)
   2704           {
   2705             res = p->mainErrorCode;
   2706           }
   2707         }
   2708 
   2709         stat->CombinedRes = res;
   2710         if (stat->CombinedRes_Type == SZ_OK)
   2711           stat->CombinedRes_Type = res;
   2712         return res;
   2713       }
   2714 
   2715       PRF_STR("----- decoding ST -----");
   2716     }
   2717   }
   2718 
   2719   #endif
   2720 
   2721 
   2722   *isMT = False;
   2723 
   2724   {
   2725     SRes res = XzDecMt_Decode_ST(p
   2726         #ifndef _7ZIP_ST
   2727         , tMode
   2728         #endif
   2729         , stat
   2730         );
   2731 
   2732     XzStatInfo_SetStat(&p->dec,
   2733         p->finishMode,
   2734         p->readProcessed, p->inProcessed,
   2735         p->codeRes, p->status,
   2736         False, // truncated
   2737         stat);
   2738 
   2739     if (res == SZ_OK)
   2740     {
   2741       /*
   2742       if (p->writeRes != SZ_OK)
   2743       {
   2744         res = p->writeRes;
   2745         stat->CombinedRes_Type = SZ_ERROR_WRITE;
   2746       }
   2747       else
   2748       */
   2749       if (p->readRes != SZ_OK && p->inProcessed == p->readProcessed)
   2750       {
   2751         res = p->readRes;
   2752         stat->ReadRes = res;
   2753         stat->CombinedRes_Type = SZ_ERROR_READ;
   2754       }
   2755       #ifndef _7ZIP_ST
   2756       else if (p->mainErrorCode != SZ_OK)
   2757         res = p->mainErrorCode;
   2758       #endif
   2759     }
   2760 
   2761     stat->CombinedRes = res;
   2762     if (stat->CombinedRes_Type == SZ_OK)
   2763       stat->CombinedRes_Type = res;
   2764     return res;
   2765   }
   2766 }
   2767