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