1 /* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread
2 2018-07-04 : Igor Pavlov : Public domain */
3 
4 #include "Precomp.h"
5 
6 // #define SHOW_DEBUG_INFO
7 
8 #ifdef SHOW_DEBUG_INFO
9 #include <stdio.h>
10 #endif
11 
12 #ifdef SHOW_DEBUG_INFO
13 #define PRF(x) x
14 #else
15 #define PRF(x)
16 #endif
17 
18 #define PRF_STR(s) PRF(printf("\n" s "\n"))
19 #define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
20 #define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2))
21 
22 // #define _7ZIP_ST
23 
24 #include "Alloc.h"
25 
26 #include "Lzma2Dec.h"
27 #include "Lzma2DecMt.h"
28 
29 #ifndef _7ZIP_ST
30 #include "MtDec.h"
31 #endif
32 
33 
34 #define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28)
35 
Lzma2DecMtProps_Init(CLzma2DecMtProps * p)36 void Lzma2DecMtProps_Init(CLzma2DecMtProps *p)
37 {
38   p->inBufSize_ST = 1 << 20;
39   p->outStep_ST = 1 << 20;
40 
41   #ifndef _7ZIP_ST
42   p->numThreads = 1;
43   p->inBufSize_MT = 1 << 18;
44   p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT;
45   p->inBlockMax = p->outBlockMax + p->outBlockMax / 16;
46   #endif
47 }
48 
49 
50 
51 #ifndef _7ZIP_ST
52 
53 /* ---------- CLzma2DecMtThread ---------- */
54 
55 typedef struct
56 {
57   CLzma2Dec dec;
58   Byte dec_created;
59   Byte needInit;
60 
61   Byte *outBuf;
62   size_t outBufSize;
63 
64   EMtDecParseState state;
65   ELzma2ParseStatus parseStatus;
66 
67   size_t inPreSize;
68   size_t outPreSize;
69 
70   size_t inCodeSize;
71   size_t outCodeSize;
72   SRes codeRes;
73 
74   CAlignOffsetAlloc alloc;
75 
76   Byte mtPad[1 << 7];
77 } CLzma2DecMtThread;
78 
79 #endif
80 
81 
82 /* ---------- CLzma2DecMt ---------- */
83 
84 typedef struct
85 {
86   // ISzAllocPtr alloc;
87   ISzAllocPtr allocMid;
88 
89   CAlignOffsetAlloc alignOffsetAlloc;
90   CLzma2DecMtProps props;
91   Byte prop;
92 
93   ISeqInStream *inStream;
94   ISeqOutStream *outStream;
95   ICompressProgress *progress;
96 
97   BoolInt finishMode;
98   BoolInt outSize_Defined;
99   UInt64 outSize;
100 
101   UInt64 outProcessed;
102   UInt64 inProcessed;
103   BoolInt readWasFinished;
104   SRes readRes;
105 
106   Byte *inBuf;
107   size_t inBufSize;
108   Byte dec_created;
109   CLzma2Dec dec;
110 
111   size_t inPos;
112   size_t inLim;
113 
114   #ifndef _7ZIP_ST
115   UInt64 outProcessed_Parse;
116   BoolInt mtc_WasConstructed;
117   CMtDec mtc;
118   CLzma2DecMtThread coders[MTDEC__THREADS_MAX];
119   #endif
120 
121 } CLzma2DecMt;
122 
123 
124 
Lzma2DecMt_Create(ISzAllocPtr alloc,ISzAllocPtr allocMid)125 CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
126 {
127   CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt));
128   if (!p)
129     return NULL;
130 
131   // p->alloc = alloc;
132   p->allocMid = allocMid;
133 
134   AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
135   p->alignOffsetAlloc.numAlignBits = 7;
136   p->alignOffsetAlloc.offset = 0;
137   p->alignOffsetAlloc.baseAlloc = alloc;
138 
139   p->inBuf = NULL;
140   p->inBufSize = 0;
141   p->dec_created = False;
142 
143   // Lzma2DecMtProps_Init(&p->props);
144 
145   #ifndef _7ZIP_ST
146   p->mtc_WasConstructed = False;
147   {
148     unsigned i;
149     for (i = 0; i < MTDEC__THREADS_MAX; i++)
150     {
151       CLzma2DecMtThread *t = &p->coders[i];
152       t->dec_created = False;
153       t->outBuf = NULL;
154       t->outBufSize = 0;
155     }
156   }
157   #endif
158 
159   return p;
160 }
161 
162 
163 #ifndef _7ZIP_ST
164 
Lzma2DecMt_FreeOutBufs(CLzma2DecMt * p)165 static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p)
166 {
167   unsigned i;
168   for (i = 0; i < MTDEC__THREADS_MAX; i++)
169   {
170     CLzma2DecMtThread *t = &p->coders[i];
171     if (t->outBuf)
172     {
173       ISzAlloc_Free(p->allocMid, t->outBuf);
174       t->outBuf = NULL;
175       t->outBufSize = 0;
176     }
177   }
178 }
179 
180 #endif
181 
182 
Lzma2DecMt_FreeSt(CLzma2DecMt * p)183 static void Lzma2DecMt_FreeSt(CLzma2DecMt *p)
184 {
185   if (p->dec_created)
186   {
187     Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt);
188     p->dec_created = False;
189   }
190   if (p->inBuf)
191   {
192     ISzAlloc_Free(p->allocMid, p->inBuf);
193     p->inBuf = NULL;
194   }
195   p->inBufSize = 0;
196 }
197 
198 
Lzma2DecMt_Destroy(CLzma2DecMtHandle pp)199 void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp)
200 {
201   CLzma2DecMt *p = (CLzma2DecMt *)pp;
202 
203   Lzma2DecMt_FreeSt(p);
204 
205   #ifndef _7ZIP_ST
206 
207   if (p->mtc_WasConstructed)
208   {
209     MtDec_Destruct(&p->mtc);
210     p->mtc_WasConstructed = False;
211   }
212   {
213     unsigned i;
214     for (i = 0; i < MTDEC__THREADS_MAX; i++)
215     {
216       CLzma2DecMtThread *t = &p->coders[i];
217       if (t->dec_created)
218       {
219         // we don't need to free dict here
220         Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!!
221         t->dec_created = False;
222       }
223     }
224   }
225   Lzma2DecMt_FreeOutBufs(p);
226 
227   #endif
228 
229   ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp);
230 }
231 
232 
233 
234 #ifndef _7ZIP_ST
235 
Lzma2DecMt_MtCallback_Parse(void * obj,unsigned coderIndex,CMtDecCallbackInfo * cc)236 static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
237 {
238   CLzma2DecMt *me = (CLzma2DecMt *)obj;
239   CLzma2DecMtThread *t = &me->coders[coderIndex];
240 
241   PRF_STR_INT_2("Parse", coderIndex, cc->srcSize);
242 
243   cc->state = MTDEC_PARSE_CONTINUE;
244 
245   if (cc->startCall)
246   {
247     if (!t->dec_created)
248     {
249       Lzma2Dec_Construct(&t->dec);
250       t->dec_created = True;
251       AlignOffsetAlloc_CreateVTable(&t->alloc);
252       {
253         /* (1 << 12) is expected size of one way in data cache.
254            We optimize alignment for cache line size of 128 bytes and smaller */
255         const unsigned kNumAlignBits = 12;
256         const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */
257         t->alloc.numAlignBits = kNumAlignBits;
258         t->alloc.offset = ((UInt32)coderIndex * ((1 << 11) + (1 << 8) + (1 << 6))) & ((1 << kNumAlignBits) - (1 << kNumCacheLineBits));
259         t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc;
260       }
261     }
262     Lzma2Dec_Init(&t->dec);
263 
264     t->inPreSize = 0;
265     t->outPreSize = 0;
266     // t->blockWasFinished = False;
267     // t->finishedWithMark = False;
268     t->parseStatus = LZMA_STATUS_NOT_SPECIFIED;
269     t->state = MTDEC_PARSE_CONTINUE;
270 
271     t->inCodeSize = 0;
272     t->outCodeSize = 0;
273     t->codeRes = SZ_OK;
274 
275     // (cc->srcSize == 0) is allowed
276   }
277 
278   {
279     ELzma2ParseStatus status;
280     BoolInt overflow;
281     UInt32 unpackRem = 0;
282 
283     int checkFinishBlock = True;
284     size_t limit = me->props.outBlockMax;
285     if (me->outSize_Defined)
286     {
287       UInt64 rem = me->outSize - me->outProcessed_Parse;
288       if (limit >= rem)
289       {
290         limit = (size_t)rem;
291         if (!me->finishMode)
292           checkFinishBlock = False;
293       }
294     }
295 
296     // checkFinishBlock = False, if we want to decode partial data
297     // that must be finished at position <= outBlockMax.
298 
299     {
300       const SizeT srcOrig = cc->srcSize;
301       SizeT srcSize_Point = 0;
302       SizeT dicPos_Point = 0;
303 
304       cc->srcSize = 0;
305       overflow = False;
306 
307       for (;;)
308       {
309         SizeT srcCur = srcOrig - cc->srcSize;
310 
311         status = Lzma2Dec_Parse(&t->dec,
312             limit - t->dec.decoder.dicPos,
313             cc->src + cc->srcSize, &srcCur,
314             checkFinishBlock);
315 
316         cc->srcSize += srcCur;
317 
318         if (status == LZMA2_PARSE_STATUS_NEW_CHUNK)
319         {
320           if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos)
321           {
322             overflow = True;
323             break;
324           }
325           continue;
326         }
327 
328         if (status == LZMA2_PARSE_STATUS_NEW_BLOCK)
329         {
330           if (t->dec.decoder.dicPos == 0)
331             continue;
332           // we decode small blocks in one thread
333           if (t->dec.decoder.dicPos >= (1 << 14))
334             break;
335           dicPos_Point = t->dec.decoder.dicPos;
336           srcSize_Point = cc->srcSize;
337           continue;
338         }
339 
340         if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock
341             // && limit == t->dec.decoder.dicPos
342             // && limit == me->props.outBlockMax
343             )
344         {
345           overflow = True;
346           break;
347         }
348 
349         unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec);
350         break;
351       }
352 
353       if (dicPos_Point != 0
354           && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK
355           && (int)status != LZMA_STATUS_FINISHED_WITH_MARK
356           && (int)status != LZMA_STATUS_NOT_SPECIFIED)
357       {
358         // we revert to latest newBlock state
359         status = LZMA2_PARSE_STATUS_NEW_BLOCK;
360         unpackRem = 0;
361         t->dec.decoder.dicPos = dicPos_Point;
362         cc->srcSize = srcSize_Point;
363         overflow = False;
364       }
365     }
366 
367     t->inPreSize += cc->srcSize;
368     t->parseStatus = status;
369 
370     if (overflow)
371       cc->state = MTDEC_PARSE_OVERFLOW;
372     else
373     {
374       size_t dicPos = t->dec.decoder.dicPos;
375 
376       if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT)
377       {
378         if (status == LZMA2_PARSE_STATUS_NEW_BLOCK)
379         {
380           cc->state = MTDEC_PARSE_NEW;
381           cc->srcSize--; // we don't need control byte of next block
382           t->inPreSize--;
383         }
384         else
385         {
386           cc->state = MTDEC_PARSE_END;
387           if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK)
388           {
389             // (status == LZMA_STATUS_NOT_SPECIFIED)
390             // (status == LZMA_STATUS_NOT_FINISHED)
391             if (unpackRem != 0)
392             {
393               /* we also reserve space for max possible number of output bytes of current LZMA chunk */
394               SizeT rem = limit - dicPos;
395               if (rem > unpackRem)
396                 rem = unpackRem;
397               dicPos += rem;
398             }
399           }
400         }
401 
402         me->outProcessed_Parse += dicPos;
403       }
404 
405       cc->outPos = dicPos;
406       t->outPreSize = (size_t)dicPos;
407     }
408 
409     t->state = cc->state;
410     return;
411   }
412 }
413 
414 
Lzma2DecMt_MtCallback_PreCode(void * pp,unsigned coderIndex)415 static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex)
416 {
417   CLzma2DecMt *me = (CLzma2DecMt *)pp;
418   CLzma2DecMtThread *t = &me->coders[coderIndex];
419   Byte *dest = t->outBuf;
420 
421   if (t->inPreSize == 0)
422   {
423     t->codeRes = SZ_ERROR_DATA;
424     return t->codeRes;
425   }
426 
427   if (!dest || t->outBufSize < t->outPreSize)
428   {
429     if (dest)
430     {
431       ISzAlloc_Free(me->allocMid, dest);
432       t->outBuf = NULL;
433       t->outBufSize = 0;
434     }
435 
436     dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize
437         // + (1 << 28)
438         );
439     // Sleep(200);
440     if (!dest)
441       return SZ_ERROR_MEM;
442     t->outBuf = dest;
443     t->outBufSize = t->outPreSize;
444   }
445 
446   t->dec.decoder.dic = dest;
447   t->dec.decoder.dicBufSize = t->outPreSize;
448 
449   t->needInit = True;
450 
451   return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt
452 }
453 
454 
Lzma2DecMt_MtCallback_Code(void * pp,unsigned coderIndex,const Byte * src,size_t srcSize,int srcFinished,UInt64 * inCodePos,UInt64 * outCodePos,int * stop)455 static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex,
456     const Byte *src, size_t srcSize, int srcFinished,
457     // int finished, int blockFinished,
458     UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
459 {
460   CLzma2DecMt *me = (CLzma2DecMt *)pp;
461   CLzma2DecMtThread *t = &me->coders[coderIndex];
462 
463   UNUSED_VAR(srcFinished)
464 
465   PRF_STR_INT_2("Code", coderIndex, srcSize);
466 
467   *inCodePos = t->inCodeSize;
468   *outCodePos = 0;
469   *stop = True;
470 
471   if (t->needInit)
472   {
473     Lzma2Dec_Init(&t->dec);
474     t->needInit = False;
475   }
476 
477   {
478     ELzmaStatus status;
479     size_t srcProcessed = srcSize;
480     BoolInt blockWasFinished =
481         ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
482         || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK);
483 
484     SRes res = Lzma2Dec_DecodeToDic(&t->dec,
485         t->outPreSize,
486         src, &srcProcessed,
487         blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY,
488         &status);
489 
490     t->codeRes = res;
491 
492     t->inCodeSize += srcProcessed;
493     *inCodePos = t->inCodeSize;
494     t->outCodeSize = t->dec.decoder.dicPos;
495     *outCodePos = t->dec.decoder.dicPos;
496 
497     if (res != SZ_OK)
498       return res;
499 
500     if (srcProcessed == srcSize)
501       *stop = False;
502 
503     if (blockWasFinished)
504     {
505       if (srcSize != srcProcessed)
506         return SZ_ERROR_FAIL;
507 
508       if (t->inPreSize == t->inCodeSize)
509       {
510         if (t->outPreSize != t->outCodeSize)
511           return SZ_ERROR_FAIL;
512         *stop = True;
513       }
514     }
515     else
516     {
517       if (t->outPreSize == t->outCodeSize)
518         *stop = True;
519     }
520 
521     return SZ_OK;
522   }
523 }
524 
525 
526 #define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24)
527 
Lzma2DecMt_MtCallback_Write(void * pp,unsigned coderIndex,BoolInt needWriteToStream,const Byte * src,size_t srcSize,BoolInt * needContinue,BoolInt * canRecode)528 static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex,
529     BoolInt needWriteToStream,
530     const Byte *src, size_t srcSize,
531     BoolInt *needContinue, BoolInt *canRecode)
532 {
533   CLzma2DecMt *me = (CLzma2DecMt *)pp;
534   const CLzma2DecMtThread *t = &me->coders[coderIndex];
535   size_t size = t->outCodeSize;
536   const Byte *data = t->outBuf;
537   BoolInt needContinue2 = True;
538 
539   PRF_STR_INT_2("Write", coderIndex, srcSize);
540 
541   *needContinue = False;
542   *canRecode = True;
543   UNUSED_VAR(src)
544   UNUSED_VAR(srcSize)
545 
546   if (
547       // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
548          t->state == MTDEC_PARSE_OVERFLOW
549       || t->state == MTDEC_PARSE_END)
550     needContinue2 = False;
551 
552 
553   if (!needWriteToStream)
554     return SZ_OK;
555 
556   me->mtc.inProcessed += t->inCodeSize;
557 
558   if (t->codeRes == SZ_OK)
559   if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
560       || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK)
561   if (t->outPreSize != t->outCodeSize
562       || t->inPreSize != t->inCodeSize)
563     return SZ_ERROR_FAIL;
564 
565   *canRecode = False;
566 
567   if (me->outStream)
568   {
569     for (;;)
570     {
571       size_t cur = size;
572       size_t written;
573       if (cur > LZMA2DECMT_STREAM_WRITE_STEP)
574         cur = LZMA2DECMT_STREAM_WRITE_STEP;
575 
576       written = ISeqOutStream_Write(me->outStream, data, cur);
577 
578       me->outProcessed += written;
579       // me->mtc.writtenTotal += written;
580       if (written != cur)
581         return SZ_ERROR_WRITE;
582       data += cur;
583       size -= cur;
584       if (size == 0)
585       {
586         *needContinue = needContinue2;
587         return SZ_OK;
588       }
589       RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0));
590     }
591   }
592 
593   return SZ_ERROR_FAIL;
594   /*
595   if (size > me->outBufSize)
596     return SZ_ERROR_OUTPUT_EOF;
597   memcpy(me->outBuf, data, size);
598   me->outBufSize -= size;
599   me->outBuf += size;
600   *needContinue = needContinue2;
601   return SZ_OK;
602   */
603 }
604 
605 #endif
606 
607 
Lzma2Dec_Prepare_ST(CLzma2DecMt * p)608 static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p)
609 {
610   if (!p->dec_created)
611   {
612     Lzma2Dec_Construct(&p->dec);
613     p->dec_created = True;
614   }
615 
616   RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt));
617 
618   if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
619   {
620     ISzAlloc_Free(p->allocMid, p->inBuf);
621     p->inBufSize = 0;
622     p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
623     if (!p->inBuf)
624       return SZ_ERROR_MEM;
625     p->inBufSize = p->props.inBufSize_ST;
626   }
627 
628   Lzma2Dec_Init(&p->dec);
629 
630   return SZ_OK;
631 }
632 
633 
Lzma2Dec_Decode_ST(CLzma2DecMt * p,BoolInt tMode)634 static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p
635     #ifndef _7ZIP_ST
636     , BoolInt tMode
637     #endif
638     )
639 {
640   SizeT wrPos;
641   size_t inPos, inLim;
642   const Byte *inData;
643   UInt64 inPrev, outPrev;
644 
645   CLzma2Dec *dec;
646 
647   #ifndef _7ZIP_ST
648   if (tMode)
649   {
650     Lzma2DecMt_FreeOutBufs(p);
651     tMode = MtDec_PrepareRead(&p->mtc);
652   }
653   #endif
654 
655   RINOK(Lzma2Dec_Prepare_ST(p));
656 
657   dec = &p->dec;
658 
659   inPrev = p->inProcessed;
660   outPrev = p->outProcessed;
661 
662   inPos = 0;
663   inLim = 0;
664   inData = NULL;
665   wrPos = dec->decoder.dicPos;
666 
667   for (;;)
668   {
669     SizeT dicPos;
670     SizeT size;
671     ELzmaFinishMode finishMode;
672     SizeT inProcessed;
673     ELzmaStatus status;
674     SRes res;
675 
676     SizeT outProcessed;
677     BoolInt outFinished;
678     BoolInt needStop;
679 
680     if (inPos == inLim)
681     {
682       #ifndef _7ZIP_ST
683       if (tMode)
684       {
685         inData = MtDec_Read(&p->mtc, &inLim);
686         inPos = 0;
687         if (inData)
688           continue;
689         tMode = False;
690         inLim = 0;
691       }
692       #endif
693 
694       if (!p->readWasFinished)
695       {
696         inPos = 0;
697         inLim = p->inBufSize;
698         inData = p->inBuf;
699         p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim);
700         // p->readProcessed += inLim;
701         // inLim -= 5; p->readWasFinished = True; // for test
702         if (inLim == 0 || p->readRes != SZ_OK)
703           p->readWasFinished = True;
704       }
705     }
706 
707     dicPos = dec->decoder.dicPos;
708     {
709       SizeT next = dec->decoder.dicBufSize;
710       if (next - wrPos > p->props.outStep_ST)
711         next = wrPos + p->props.outStep_ST;
712       size = next - dicPos;
713     }
714 
715     finishMode = LZMA_FINISH_ANY;
716     if (p->outSize_Defined)
717     {
718       const UInt64 rem = p->outSize - p->outProcessed;
719       if (size >= rem)
720       {
721         size = (SizeT)rem;
722         if (p->finishMode)
723           finishMode = LZMA_FINISH_END;
724       }
725     }
726 
727     inProcessed = inLim - inPos;
728 
729     res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status);
730 
731     inPos += inProcessed;
732     p->inProcessed += inProcessed;
733     outProcessed = dec->decoder.dicPos - dicPos;
734     p->outProcessed += outProcessed;
735 
736     outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed);
737 
738     needStop = (res != SZ_OK
739         || (inProcessed == 0 && outProcessed == 0)
740         || status == LZMA_STATUS_FINISHED_WITH_MARK
741         || (!p->finishMode && outFinished));
742 
743     if (needStop || outProcessed >= size)
744     {
745       SRes res2;
746       {
747         size_t writeSize = dec->decoder.dicPos - wrPos;
748         size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize);
749         res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE;
750       }
751 
752       if (dec->decoder.dicPos == dec->decoder.dicBufSize)
753         dec->decoder.dicPos = 0;
754       wrPos = dec->decoder.dicPos;
755 
756       RINOK(res2);
757 
758       if (needStop)
759       {
760         if (res != SZ_OK)
761           return res;
762 
763         if (status == LZMA_STATUS_FINISHED_WITH_MARK)
764         {
765           if (p->finishMode)
766           {
767             if (p->outSize_Defined && p->outSize != p->outProcessed)
768               return SZ_ERROR_DATA;
769           }
770           return SZ_OK;
771         }
772 
773         if (!p->finishMode && outFinished)
774           return SZ_OK;
775 
776         if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
777           return SZ_ERROR_INPUT_EOF;
778 
779         return SZ_ERROR_DATA;
780       }
781     }
782 
783     if (p->progress)
784     {
785       UInt64 inDelta = p->inProcessed - inPrev;
786       UInt64 outDelta = p->outProcessed - outPrev;
787       if (inDelta >= (1 << 22) || outDelta >= (1 << 22))
788       {
789         RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed));
790         inPrev = p->inProcessed;
791         outPrev = p->outProcessed;
792       }
793     }
794   }
795 }
796 
797 
798 
Lzma2DecMt_Decode(CLzma2DecMtHandle pp,Byte prop,const CLzma2DecMtProps * props,ISeqOutStream * outStream,const UInt64 * outDataSize,int finishMode,ISeqInStream * inStream,UInt64 * inProcessed,int * isMT,ICompressProgress * progress)799 SRes Lzma2DecMt_Decode(CLzma2DecMtHandle pp,
800     Byte prop,
801     const CLzma2DecMtProps *props,
802     ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode,
803     // Byte *outBuf, size_t *outBufSize,
804     ISeqInStream *inStream,
805     // const Byte *inData, size_t inDataSize,
806     UInt64 *inProcessed,
807     // UInt64 *outProcessed,
808     int *isMT,
809     ICompressProgress *progress)
810 {
811   CLzma2DecMt *p = (CLzma2DecMt *)pp;
812   #ifndef _7ZIP_ST
813   BoolInt tMode;
814   #endif
815 
816   *inProcessed = 0;
817 
818   if (prop > 40)
819     return SZ_ERROR_UNSUPPORTED;
820 
821   p->prop = prop;
822   p->props = *props;
823 
824   p->inStream = inStream;
825   p->outStream = outStream;
826   p->progress = progress;
827 
828   p->outSize = 0;
829   p->outSize_Defined = False;
830   if (outDataSize)
831   {
832     p->outSize_Defined = True;
833     p->outSize = *outDataSize;
834   }
835   p->finishMode = finishMode;
836 
837   p->outProcessed = 0;
838   p->inProcessed = 0;
839 
840   p->readWasFinished = False;
841 
842   *isMT = False;
843 
844 
845   #ifndef _7ZIP_ST
846 
847   tMode = False;
848 
849   // p->mtc.parseRes = SZ_OK;
850 
851   // p->mtc.numFilledThreads = 0;
852   // p->mtc.crossStart = 0;
853   // p->mtc.crossEnd = 0;
854   // p->mtc.allocError_for_Read_BlockIndex = 0;
855   // p->mtc.isAllocError = False;
856 
857   if (p->props.numThreads > 1)
858   {
859     IMtDecCallback vt;
860 
861     Lzma2DecMt_FreeSt(p);
862 
863     p->outProcessed_Parse = 0;
864 
865     if (!p->mtc_WasConstructed)
866     {
867       p->mtc_WasConstructed = True;
868       MtDec_Construct(&p->mtc);
869     }
870 
871     p->mtc.progress = progress;
872     p->mtc.inStream = inStream;
873 
874     // p->outBuf = NULL;
875     // p->outBufSize = 0;
876     /*
877     if (!outStream)
878     {
879       // p->outBuf = outBuf;
880       // p->outBufSize = *outBufSize;
881       // *outBufSize = 0;
882       return SZ_ERROR_PARAM;
883     }
884     */
885 
886     // p->mtc.inBlockMax = p->props.inBlockMax;
887     p->mtc.alloc = &p->alignOffsetAlloc.vt;
888       // p->alignOffsetAlloc.baseAlloc;
889     // p->mtc.inData = inData;
890     // p->mtc.inDataSize = inDataSize;
891     p->mtc.mtCallback = &vt;
892     p->mtc.mtCallbackObject = p;
893 
894     p->mtc.inBufSize = p->props.inBufSize_MT;
895 
896     p->mtc.numThreadsMax = p->props.numThreads;
897 
898     *isMT = True;
899 
900     vt.Parse = Lzma2DecMt_MtCallback_Parse;
901     vt.PreCode = Lzma2DecMt_MtCallback_PreCode;
902     vt.Code = Lzma2DecMt_MtCallback_Code;
903     vt.Write = Lzma2DecMt_MtCallback_Write;
904 
905     {
906       BoolInt needContinue = False;
907 
908       SRes res = MtDec_Code(&p->mtc);
909 
910       /*
911       if (!outStream)
912         *outBufSize = p->outBuf - outBuf;
913       */
914 
915       *inProcessed = p->mtc.inProcessed;
916 
917       needContinue = False;
918 
919       if (res == SZ_OK)
920       {
921         if (p->mtc.mtProgress.res != SZ_OK)
922           res = p->mtc.mtProgress.res;
923         else
924           needContinue = p->mtc.needContinue;
925       }
926 
927       if (!needContinue)
928       {
929         if (res == SZ_OK)
930           return p->mtc.readRes;
931         return res;
932       }
933 
934       tMode = True;
935       p->readRes = p->mtc.readRes;
936       p->readWasFinished = p->mtc.readWasFinished;
937       p->inProcessed = p->mtc.inProcessed;
938 
939       PRF_STR("----- decoding ST -----");
940     }
941   }
942 
943   #endif
944 
945 
946   *isMT = False;
947 
948   {
949     SRes res = Lzma2Dec_Decode_ST(p
950         #ifndef _7ZIP_ST
951         , tMode
952         #endif
953         );
954 
955     *inProcessed = p->inProcessed;
956 
957     // res = SZ_OK; // for test
958     if (res == SZ_OK && p->readRes != SZ_OK)
959       res = p->readRes;
960 
961     /*
962     #ifndef _7ZIP_ST
963     if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK)
964       res = p->mtc.parseRes;
965     #endif
966     */
967 
968     return res;
969   }
970 }
971 
972 
973 /* ---------- Read from CLzma2DecMtHandle Interface ---------- */
974 
Lzma2DecMt_Init(CLzma2DecMtHandle pp,Byte prop,const CLzma2DecMtProps * props,const UInt64 * outDataSize,int finishMode,ISeqInStream * inStream)975 SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,
976     Byte prop,
977     const CLzma2DecMtProps *props,
978     const UInt64 *outDataSize, int finishMode,
979     ISeqInStream *inStream)
980 {
981   CLzma2DecMt *p = (CLzma2DecMt *)pp;
982 
983   if (prop > 40)
984     return SZ_ERROR_UNSUPPORTED;
985 
986   p->prop = prop;
987   p->props = *props;
988 
989   p->inStream = inStream;
990 
991   p->outSize = 0;
992   p->outSize_Defined = False;
993   if (outDataSize)
994   {
995     p->outSize_Defined = True;
996     p->outSize = *outDataSize;
997   }
998   p->finishMode = finishMode;
999 
1000   p->outProcessed = 0;
1001   p->inProcessed = 0;
1002 
1003   p->inPos = 0;
1004   p->inLim = 0;
1005 
1006   return Lzma2Dec_Prepare_ST(p);
1007 }
1008 
1009 
Lzma2DecMt_Read(CLzma2DecMtHandle pp,Byte * data,size_t * outSize,UInt64 * inStreamProcessed)1010 SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp,
1011     Byte *data, size_t *outSize,
1012     UInt64 *inStreamProcessed)
1013 {
1014   CLzma2DecMt *p = (CLzma2DecMt *)pp;
1015   ELzmaFinishMode finishMode;
1016   SRes readRes;
1017   size_t size = *outSize;
1018 
1019   *outSize = 0;
1020   *inStreamProcessed = 0;
1021 
1022   finishMode = LZMA_FINISH_ANY;
1023   if (p->outSize_Defined)
1024   {
1025     const UInt64 rem = p->outSize - p->outProcessed;
1026     if (size >= rem)
1027     {
1028       size = (size_t)rem;
1029       if (p->finishMode)
1030         finishMode = LZMA_FINISH_END;
1031     }
1032   }
1033 
1034   readRes = SZ_OK;
1035 
1036   for (;;)
1037   {
1038     SizeT inCur;
1039     SizeT outCur;
1040     ELzmaStatus status;
1041     SRes res;
1042 
1043     if (p->inPos == p->inLim && readRes == SZ_OK)
1044     {
1045       p->inPos = 0;
1046       p->inLim = p->props.inBufSize_ST;
1047       readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim);
1048     }
1049 
1050     inCur = p->inLim - p->inPos;
1051     outCur = size;
1052 
1053     res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur,
1054         p->inBuf + p->inPos, &inCur, finishMode, &status);
1055 
1056     p->inPos += inCur;
1057     p->inProcessed += inCur;
1058     *inStreamProcessed += inCur;
1059     p->outProcessed += outCur;
1060     *outSize += outCur;
1061     size -= outCur;
1062     data += outCur;
1063 
1064     if (res != 0)
1065       return res;
1066 
1067     /*
1068     if (status == LZMA_STATUS_FINISHED_WITH_MARK)
1069       return readRes;
1070 
1071     if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
1072     {
1073       if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize)
1074         return SZ_ERROR_DATA;
1075       return readRes;
1076     }
1077     */
1078 
1079     if (inCur == 0 && outCur == 0)
1080       return readRes;
1081   }
1082 }
1083