• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* XzDec.c -- Xz Decode
2 2019-02-02 : 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 /* ---------- 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 
BraState_Free(void * pp,ISzAllocPtr alloc)91 static void BraState_Free(void *pp, ISzAllocPtr alloc)
92 {
93   ISzAlloc_Free(alloc, pp);
94 }
95 
BraState_SetProps(void * pp,const Byte * props,size_t propSize,ISzAllocPtr alloc)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 
BraState_Init(void * pp)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 
BraState_Filter(void * pp,Byte * data,SizeT size)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 
BraState_Code2(void * pp,Byte * dest,SizeT * destLen,const Byte * src,SizeT * srcLen,int srcWasFinished,ECoderFinishMode finishMode,ECoderStatus * status)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 
BraState_SetFromMethod(IStateCoder * p,UInt64 id,int encodeMode,ISzAllocPtr alloc)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 = (CBraState *)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 
SbState_Free(void * pp,ISzAllocPtr alloc)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 
SbState_SetProps(void * pp,const Byte * props,size_t propSize,ISzAllocPtr alloc)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 
SbState_Init(void * pp)287 static void SbState_Init(void *pp)
288 {
289   SbDec_Init((CSbDec *)pp);
290 }
291 
SbState_Code2(void * pp,Byte * dest,SizeT * destLen,const Byte * src,SizeT * srcLen,int srcWasFinished,ECoderFinishMode finishMode,ECoderStatus * status)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 
SbState_SetFromMethod(IStateCoder * p,ISzAllocPtr alloc)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 
Lzma2State_Free(void * pp,ISzAllocPtr alloc)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 
Lzma2State_SetProps(void * pp,const Byte * props,size_t propSize,ISzAllocPtr alloc)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 
Lzma2State_Init(void * pp)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 
Lzma2State_Code2(void * pp,Byte * dest,SizeT * destLen,const Byte * src,SizeT * srcLen,int srcWasFinished,ECoderFinishMode finishMode,ECoderStatus * status)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 = (ECoderStatus)status2;
404   return res;
405 }
406 
407 
Lzma2State_SetFromMethod(IStateCoder * p,Byte * outBuf,size_t outBufSize,ISzAllocPtr alloc)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 
Lzma2State_ResetOutBuf(IStateCoder * p,Byte * outBuf,size_t outBufSize)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 
MixCoder_Construct(CMixCoder * p,ISzAllocPtr alloc)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 
MixCoder_Free(CMixCoder * p)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 
MixCoder_Init(CMixCoder * p)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 
MixCoder_SetFromMethod(CMixCoder * p,unsigned coderIndex,UInt64 methodId,Byte * outBuf,size_t outBufSize)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 
MixCoder_ResetFromMethod(CMixCoder * p,unsigned coderIndex,UInt64 methodId,Byte * outBuf,size_t outBufSize)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 
MixCoder_Code(CMixCoder * p,Byte * dest,SizeT * destLen,int destFinish,const Byte * src,SizeT * srcLen,int srcWasFinished,ECoderFinishMode finishMode)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 
Xz_ParseHeader(CXzStreamFlags * p,const Byte * buf)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 
Xz_CheckFooter(CXzStreamFlags flags,UInt64 indexSize,const Byte * buf)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 
XzBlock_AreSupportedFilters(const CXzBlock * p)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 
XzBlock_Parse(CXzBlock * p,const Byte * header)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 
XzDecMix_Init(CMixCoder * p,const CXzBlock * block,Byte * outBuf,size_t outBufSize)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 
XzUnpacker_Init(CXzUnpacker * p)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 
XzUnpacker_SetOutBuf(CXzUnpacker * p,Byte * outBuf,size_t outBufSize)936 void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize)
937 {
938   p->outBuf = outBuf;
939   p->outBufSize = outBufSize;
940 }
941 
942 
XzUnpacker_Construct(CXzUnpacker * p,ISzAllocPtr alloc)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 
XzUnpacker_Free(CXzUnpacker * p)952 void XzUnpacker_Free(CXzUnpacker *p)
953 {
954   MixCoder_Free(&p->decoder);
955 }
956 
957 
XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker * p)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 
XzUnpacker_UpdateIndex(CXzUnpacker * p,UInt64 packSize,UInt64 unpackSize)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 
XzUnpacker_Code(CXzUnpacker * p,Byte * dest,SizeT * destLen,const Byte * src,SizeT * srcLen,int srcFinished,ECoderFinishMode finishMode,ECoderStatus * status)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 
XzUnpacker_CodeFull(CXzUnpacker * p,Byte * dest,SizeT * destLen,const Byte * src,SizeT * srcLen,ECoderFinishMode finishMode,ECoderStatus * status)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 
XzUnpacker_IsBlockFinished(const CXzUnpacker * p)1349 BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
1350 {
1351   return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
1352 }
1353 
XzUnpacker_IsStreamWasFinished(const CXzUnpacker * p)1354 BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
1355 {
1356   return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
1357 }
1358 
XzUnpacker_GetExtraSize(const CXzUnpacker * p)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 
XzDecMtProps_Init(CXzDecMtProps * p)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 
XzDecMt_Create(ISzAllocPtr alloc,ISzAllocPtr allocMid)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 
XzDecMt_FreeOutBufs(CXzDecMt * p)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 
XzDecMt_FreeSt(CXzDecMt * p)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 
XzDecMt_Destroy(CXzDecMtHandle pp)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 
XzDecMt_Callback_Parse(void * obj,unsigned coderIndex,CMtDecCallbackInfo * cc)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 
XzDecMt_Callback_PreCode(void * pp,unsigned coderIndex)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 
XzDecMt_Callback_Code(void * pp,unsigned coderIndex,const Byte * src,size_t srcSize,int srcFinished,UInt64 * inCodePos,UInt64 * outCodePos,int * stop)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 
XzDecMt_Callback_Write(void * pp,unsigned coderIndex,BoolInt needWriteToStream,const Byte * src,size_t srcSize,BoolInt * needContinue,BoolInt * canRecode)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 
XzStatInfo_Clear(CXzStatInfo * p)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 
XzDecMt_Decode_ST(CXzDecMt * p,BoolInt tMode,CXzStatInfo * stat)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 
XzStatInfo_SetStat(const CXzUnpacker * dec,int finishMode,UInt64 readProcessed,UInt64 inProcessed,SRes res,ECoderStatus status,BoolInt decodingTruncated,CXzStatInfo * stat)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 
XzDecMt_Decode(CXzDecMtHandle pp,const CXzDecMtProps * props,const UInt64 * outDataSize,int finishMode,ISeqOutStream * outStream,ISeqInStream * inStream,CXzStatInfo * stat,int * isMT,ICompressProgress * progress)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