• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* 7zDec.c -- Decoding from 7z folder
2 2023-04-02 : Igor Pavlov : Public domain */
3 
4 #include "Precomp.h"
5 
6 #include <string.h>
7 
8 /* #define Z7_PPMD_SUPPORT */
9 
10 #include "7z.h"
11 #include "7zCrc.h"
12 
13 #include "Bcj2.h"
14 #include "Bra.h"
15 #include "CpuArch.h"
16 #include "Delta.h"
17 #include "LzmaDec.h"
18 #include "Lzma2Dec.h"
19 #ifdef Z7_PPMD_SUPPORT
20 #include "Ppmd7.h"
21 #endif
22 
23 #define k_Copy 0
24 #ifndef Z7_NO_METHOD_LZMA2
25 #define k_LZMA2 0x21
26 #endif
27 #define k_LZMA  0x30101
28 #define k_BCJ2  0x303011B
29 
30 #if !defined(Z7_NO_METHODS_FILTERS)
31 #define Z7_USE_BRANCH_FILTER
32 #endif
33 
34 #if !defined(Z7_NO_METHODS_FILTERS) || \
35      defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64)
36 #define Z7_USE_FILTER_ARM64
37 #ifndef Z7_USE_BRANCH_FILTER
38 #define Z7_USE_BRANCH_FILTER
39 #endif
40 #define k_ARM64 0xa
41 #endif
42 
43 #if !defined(Z7_NO_METHODS_FILTERS) || \
44      defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT)
45 #define Z7_USE_FILTER_ARMT
46 #ifndef Z7_USE_BRANCH_FILTER
47 #define Z7_USE_BRANCH_FILTER
48 #endif
49 #define k_ARMT  0x3030701
50 #endif
51 
52 #ifndef Z7_NO_METHODS_FILTERS
53 #define k_Delta 3
54 #define k_BCJ   0x3030103
55 #define k_PPC   0x3030205
56 #define k_IA64  0x3030401
57 #define k_ARM   0x3030501
58 #define k_SPARC 0x3030805
59 #endif
60 
61 #ifdef Z7_PPMD_SUPPORT
62 
63 #define k_PPMD 0x30401
64 
65 typedef struct
66 {
67   IByteIn vt;
68   const Byte *cur;
69   const Byte *end;
70   const Byte *begin;
71   UInt64 processed;
72   BoolInt extra;
73   SRes res;
74   ILookInStreamPtr inStream;
75 } CByteInToLook;
76 
ReadByte(IByteInPtr pp)77 static Byte ReadByte(IByteInPtr pp)
78 {
79   Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook)
80   if (p->cur != p->end)
81     return *p->cur++;
82   if (p->res == SZ_OK)
83   {
84     size_t size = (size_t)(p->cur - p->begin);
85     p->processed += size;
86     p->res = ILookInStream_Skip(p->inStream, size);
87     size = (1 << 25);
88     p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
89     p->cur = p->begin;
90     p->end = p->begin + size;
91     if (size != 0)
92       return *p->cur++;
93   }
94   p->extra = True;
95   return 0;
96 }
97 
SzDecodePpmd(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStreamPtr inStream,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain)98 static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
99     Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
100 {
101   CPpmd7 ppmd;
102   CByteInToLook s;
103   SRes res = SZ_OK;
104 
105   s.vt.Read = ReadByte;
106   s.inStream = inStream;
107   s.begin = s.end = s.cur = NULL;
108   s.extra = False;
109   s.res = SZ_OK;
110   s.processed = 0;
111 
112   if (propsSize != 5)
113     return SZ_ERROR_UNSUPPORTED;
114 
115   {
116     unsigned order = props[0];
117     UInt32 memSize = GetUi32(props + 1);
118     if (order < PPMD7_MIN_ORDER ||
119         order > PPMD7_MAX_ORDER ||
120         memSize < PPMD7_MIN_MEM_SIZE ||
121         memSize > PPMD7_MAX_MEM_SIZE)
122       return SZ_ERROR_UNSUPPORTED;
123     Ppmd7_Construct(&ppmd);
124     if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
125       return SZ_ERROR_MEM;
126     Ppmd7_Init(&ppmd, order);
127   }
128   {
129     ppmd.rc.dec.Stream = &s.vt;
130     if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec))
131       res = SZ_ERROR_DATA;
132     else if (!s.extra)
133     {
134       Byte *buf = outBuffer;
135       const Byte *lim = buf + outSize;
136       for (; buf != lim; buf++)
137       {
138         int sym = Ppmd7z_DecodeSymbol(&ppmd);
139         if (s.extra || sym < 0)
140           break;
141         *buf = (Byte)sym;
142       }
143       if (buf != lim)
144         res = SZ_ERROR_DATA;
145       else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
146       {
147         /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */
148         res = SZ_ERROR_DATA;
149       }
150     }
151     if (s.extra)
152       res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
153     else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
154       res = SZ_ERROR_DATA;
155   }
156   Ppmd7_Free(&ppmd, allocMain);
157   return res;
158 }
159 
160 #endif
161 
162 
SzDecodeLzma(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStreamPtr inStream,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain)163 static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
164     Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
165 {
166   CLzmaDec state;
167   SRes res = SZ_OK;
168 
169   LzmaDec_CONSTRUCT(&state)
170   RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain))
171   state.dic = outBuffer;
172   state.dicBufSize = outSize;
173   LzmaDec_Init(&state);
174 
175   for (;;)
176   {
177     const void *inBuf = NULL;
178     size_t lookahead = (1 << 18);
179     if (lookahead > inSize)
180       lookahead = (size_t)inSize;
181     res = ILookInStream_Look(inStream, &inBuf, &lookahead);
182     if (res != SZ_OK)
183       break;
184 
185     {
186       SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
187       ELzmaStatus status;
188       res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
189       lookahead -= inProcessed;
190       inSize -= inProcessed;
191       if (res != SZ_OK)
192         break;
193 
194       if (status == LZMA_STATUS_FINISHED_WITH_MARK)
195       {
196         if (outSize != state.dicPos || inSize != 0)
197           res = SZ_ERROR_DATA;
198         break;
199       }
200 
201       if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
202         break;
203 
204       if (inProcessed == 0 && dicPos == state.dicPos)
205       {
206         res = SZ_ERROR_DATA;
207         break;
208       }
209 
210       res = ILookInStream_Skip(inStream, inProcessed);
211       if (res != SZ_OK)
212         break;
213     }
214   }
215 
216   LzmaDec_FreeProbs(&state, allocMain);
217   return res;
218 }
219 
220 
221 #ifndef Z7_NO_METHOD_LZMA2
222 
SzDecodeLzma2(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStreamPtr inStream,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain)223 static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
224     Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
225 {
226   CLzma2Dec state;
227   SRes res = SZ_OK;
228 
229   Lzma2Dec_CONSTRUCT(&state)
230   if (propsSize != 1)
231     return SZ_ERROR_DATA;
232   RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain))
233   state.decoder.dic = outBuffer;
234   state.decoder.dicBufSize = outSize;
235   Lzma2Dec_Init(&state);
236 
237   for (;;)
238   {
239     const void *inBuf = NULL;
240     size_t lookahead = (1 << 18);
241     if (lookahead > inSize)
242       lookahead = (size_t)inSize;
243     res = ILookInStream_Look(inStream, &inBuf, &lookahead);
244     if (res != SZ_OK)
245       break;
246 
247     {
248       SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
249       ELzmaStatus status;
250       res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
251       lookahead -= inProcessed;
252       inSize -= inProcessed;
253       if (res != SZ_OK)
254         break;
255 
256       if (status == LZMA_STATUS_FINISHED_WITH_MARK)
257       {
258         if (outSize != state.decoder.dicPos || inSize != 0)
259           res = SZ_ERROR_DATA;
260         break;
261       }
262 
263       if (inProcessed == 0 && dicPos == state.decoder.dicPos)
264       {
265         res = SZ_ERROR_DATA;
266         break;
267       }
268 
269       res = ILookInStream_Skip(inStream, inProcessed);
270       if (res != SZ_OK)
271         break;
272     }
273   }
274 
275   Lzma2Dec_FreeProbs(&state, allocMain);
276   return res;
277 }
278 
279 #endif
280 
281 
SzDecodeCopy(UInt64 inSize,ILookInStreamPtr inStream,Byte * outBuffer)282 static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer)
283 {
284   while (inSize > 0)
285   {
286     const void *inBuf;
287     size_t curSize = (1 << 18);
288     if (curSize > inSize)
289       curSize = (size_t)inSize;
290     RINOK(ILookInStream_Look(inStream, &inBuf, &curSize))
291     if (curSize == 0)
292       return SZ_ERROR_INPUT_EOF;
293     memcpy(outBuffer, inBuf, curSize);
294     outBuffer += curSize;
295     inSize -= curSize;
296     RINOK(ILookInStream_Skip(inStream, curSize))
297   }
298   return SZ_OK;
299 }
300 
IS_MAIN_METHOD(UInt32 m)301 static BoolInt IS_MAIN_METHOD(UInt32 m)
302 {
303   switch (m)
304   {
305     case k_Copy:
306     case k_LZMA:
307   #ifndef Z7_NO_METHOD_LZMA2
308     case k_LZMA2:
309   #endif
310   #ifdef Z7_PPMD_SUPPORT
311     case k_PPMD:
312   #endif
313       return True;
314   }
315   return False;
316 }
317 
IS_SUPPORTED_CODER(const CSzCoderInfo * c)318 static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
319 {
320   return
321       c->NumStreams == 1
322       /* && c->MethodID <= (UInt32)0xFFFFFFFF */
323       && IS_MAIN_METHOD((UInt32)c->MethodID);
324 }
325 
326 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
327 
CheckSupportedFolder(const CSzFolder * f)328 static SRes CheckSupportedFolder(const CSzFolder *f)
329 {
330   if (f->NumCoders < 1 || f->NumCoders > 4)
331     return SZ_ERROR_UNSUPPORTED;
332   if (!IS_SUPPORTED_CODER(&f->Coders[0]))
333     return SZ_ERROR_UNSUPPORTED;
334   if (f->NumCoders == 1)
335   {
336     if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
337       return SZ_ERROR_UNSUPPORTED;
338     return SZ_OK;
339   }
340 
341 
342   #if defined(Z7_USE_BRANCH_FILTER)
343 
344   if (f->NumCoders == 2)
345   {
346     const CSzCoderInfo *c = &f->Coders[1];
347     if (
348         /* c->MethodID > (UInt32)0xFFFFFFFF || */
349         c->NumStreams != 1
350         || f->NumPackStreams != 1
351         || f->PackStreams[0] != 0
352         || f->NumBonds != 1
353         || f->Bonds[0].InIndex != 1
354         || f->Bonds[0].OutIndex != 0)
355       return SZ_ERROR_UNSUPPORTED;
356     switch ((UInt32)c->MethodID)
357     {
358     #if !defined(Z7_NO_METHODS_FILTERS)
359       case k_Delta:
360       case k_BCJ:
361       case k_PPC:
362       case k_IA64:
363       case k_SPARC:
364       case k_ARM:
365     #endif
366     #ifdef Z7_USE_FILTER_ARM64
367       case k_ARM64:
368     #endif
369     #ifdef Z7_USE_FILTER_ARMT
370       case k_ARMT:
371     #endif
372         break;
373       default:
374         return SZ_ERROR_UNSUPPORTED;
375     }
376     return SZ_OK;
377   }
378 
379   #endif
380 
381 
382   if (f->NumCoders == 4)
383   {
384     if (!IS_SUPPORTED_CODER(&f->Coders[1])
385         || !IS_SUPPORTED_CODER(&f->Coders[2])
386         || !IS_BCJ2(&f->Coders[3]))
387       return SZ_ERROR_UNSUPPORTED;
388     if (f->NumPackStreams != 4
389         || f->PackStreams[0] != 2
390         || f->PackStreams[1] != 6
391         || f->PackStreams[2] != 1
392         || f->PackStreams[3] != 0
393         || f->NumBonds != 3
394         || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
395         || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
396         || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
397       return SZ_ERROR_UNSUPPORTED;
398     return SZ_OK;
399   }
400 
401   return SZ_ERROR_UNSUPPORTED;
402 }
403 
404 
405 
406 
407 
408 
SzFolder_Decode2(const CSzFolder * folder,const Byte * propsData,const UInt64 * unpackSizes,const UInt64 * packPositions,ILookInStreamPtr inStream,UInt64 startPos,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain,Byte * tempBuf[])409 static SRes SzFolder_Decode2(const CSzFolder *folder,
410     const Byte *propsData,
411     const UInt64 *unpackSizes,
412     const UInt64 *packPositions,
413     ILookInStreamPtr inStream, UInt64 startPos,
414     Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
415     Byte *tempBuf[])
416 {
417   UInt32 ci;
418   SizeT tempSizes[3] = { 0, 0, 0};
419   SizeT tempSize3 = 0;
420   Byte *tempBuf3 = 0;
421 
422   RINOK(CheckSupportedFolder(folder))
423 
424   for (ci = 0; ci < folder->NumCoders; ci++)
425   {
426     const CSzCoderInfo *coder = &folder->Coders[ci];
427 
428     if (IS_MAIN_METHOD((UInt32)coder->MethodID))
429     {
430       UInt32 si = 0;
431       UInt64 offset;
432       UInt64 inSize;
433       Byte *outBufCur = outBuffer;
434       SizeT outSizeCur = outSize;
435       if (folder->NumCoders == 4)
436       {
437         const UInt32 indices[] = { 3, 2, 0 };
438         const UInt64 unpackSize = unpackSizes[ci];
439         si = indices[ci];
440         if (ci < 2)
441         {
442           Byte *temp;
443           outSizeCur = (SizeT)unpackSize;
444           if (outSizeCur != unpackSize)
445             return SZ_ERROR_MEM;
446           temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
447           if (!temp && outSizeCur != 0)
448             return SZ_ERROR_MEM;
449           outBufCur = tempBuf[1 - ci] = temp;
450           tempSizes[1 - ci] = outSizeCur;
451         }
452         else if (ci == 2)
453         {
454           if (unpackSize > outSize) /* check it */
455             return SZ_ERROR_PARAM;
456           tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
457           tempSize3 = outSizeCur = (SizeT)unpackSize;
458         }
459         else
460           return SZ_ERROR_UNSUPPORTED;
461       }
462       offset = packPositions[si];
463       inSize = packPositions[(size_t)si + 1] - offset;
464       RINOK(LookInStream_SeekTo(inStream, startPos + offset))
465 
466       if (coder->MethodID == k_Copy)
467       {
468         if (inSize != outSizeCur) /* check it */
469           return SZ_ERROR_DATA;
470         RINOK(SzDecodeCopy(inSize, inStream, outBufCur))
471       }
472       else if (coder->MethodID == k_LZMA)
473       {
474         RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
475       }
476     #ifndef Z7_NO_METHOD_LZMA2
477       else if (coder->MethodID == k_LZMA2)
478       {
479         RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
480       }
481     #endif
482     #ifdef Z7_PPMD_SUPPORT
483       else if (coder->MethodID == k_PPMD)
484       {
485         RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
486       }
487     #endif
488       else
489         return SZ_ERROR_UNSUPPORTED;
490     }
491     else if (coder->MethodID == k_BCJ2)
492     {
493       const UInt64 offset = packPositions[1];
494       const UInt64 s3Size = packPositions[2] - offset;
495 
496       if (ci != 3)
497         return SZ_ERROR_UNSUPPORTED;
498 
499       tempSizes[2] = (SizeT)s3Size;
500       if (tempSizes[2] != s3Size)
501         return SZ_ERROR_MEM;
502       tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
503       if (!tempBuf[2] && tempSizes[2] != 0)
504         return SZ_ERROR_MEM;
505 
506       RINOK(LookInStream_SeekTo(inStream, startPos + offset))
507       RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]))
508 
509       if ((tempSizes[0] & 3) != 0 ||
510           (tempSizes[1] & 3) != 0 ||
511           tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
512         return SZ_ERROR_DATA;
513 
514       {
515         CBcj2Dec p;
516 
517         p.bufs[0] = tempBuf3;   p.lims[0] = tempBuf3 + tempSize3;
518         p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
519         p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
520         p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
521 
522         p.dest = outBuffer;
523         p.destLim = outBuffer + outSize;
524 
525         Bcj2Dec_Init(&p);
526         RINOK(Bcj2Dec_Decode(&p))
527 
528         {
529           unsigned i;
530           for (i = 0; i < 4; i++)
531             if (p.bufs[i] != p.lims[i])
532               return SZ_ERROR_DATA;
533           if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p))
534             return SZ_ERROR_DATA;
535         }
536       }
537     }
538   #if defined(Z7_USE_BRANCH_FILTER)
539     else if (ci == 1)
540     {
541      #if !defined(Z7_NO_METHODS_FILTERS)
542       if (coder->MethodID == k_Delta)
543       {
544         if (coder->PropsSize != 1)
545           return SZ_ERROR_UNSUPPORTED;
546         {
547           Byte state[DELTA_STATE_SIZE];
548           Delta_Init(state);
549           Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
550         }
551         continue;
552       }
553      #endif
554 
555      #ifdef Z7_USE_FILTER_ARM64
556       if (coder->MethodID == k_ARM64)
557       {
558         UInt32 pc = 0;
559         if (coder->PropsSize == 4)
560           pc = GetUi32(propsData + coder->PropsOffset);
561         else if (coder->PropsSize != 0)
562           return SZ_ERROR_UNSUPPORTED;
563         z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc);
564         continue;
565       }
566      #endif
567 
568      #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
569       {
570         if (coder->PropsSize != 0)
571           return SZ_ERROR_UNSUPPORTED;
572        #define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0;
573         switch (coder->MethodID)
574         {
575          #if !defined(Z7_NO_METHODS_FILTERS)
576           case k_BCJ:
577           {
578             UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
579             z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0
580             break;
581           }
582           CASE_BRA_CONV(PPC)
583           CASE_BRA_CONV(IA64)
584           CASE_BRA_CONV(SPARC)
585           CASE_BRA_CONV(ARM)
586          #endif
587          #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
588           CASE_BRA_CONV(ARMT)
589          #endif
590           default:
591             return SZ_ERROR_UNSUPPORTED;
592         }
593         continue;
594       }
595      #endif
596     } // (c == 1)
597   #endif
598     else
599       return SZ_ERROR_UNSUPPORTED;
600   }
601 
602   return SZ_OK;
603 }
604 
605 
SzAr_DecodeFolder(const CSzAr * p,UInt32 folderIndex,ILookInStreamPtr inStream,UInt64 startPos,Byte * outBuffer,size_t outSize,ISzAllocPtr allocMain)606 SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
607     ILookInStreamPtr inStream, UInt64 startPos,
608     Byte *outBuffer, size_t outSize,
609     ISzAllocPtr allocMain)
610 {
611   SRes res;
612   CSzFolder folder;
613   CSzData sd;
614 
615   const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
616   sd.Data = data;
617   sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
618 
619   res = SzGetNextFolderItem(&folder, &sd);
620 
621   if (res != SZ_OK)
622     return res;
623 
624   if (sd.Size != 0
625       || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
626       || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
627     return SZ_ERROR_FAIL;
628   {
629     unsigned i;
630     Byte *tempBuf[3] = { 0, 0, 0};
631 
632     res = SzFolder_Decode2(&folder, data,
633         &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
634         p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
635         inStream, startPos,
636         outBuffer, (SizeT)outSize, allocMain, tempBuf);
637 
638     for (i = 0; i < 3; i++)
639       ISzAlloc_Free(allocMain, tempBuf[i]);
640 
641     if (res == SZ_OK)
642       if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
643         if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
644           res = SZ_ERROR_CRC;
645 
646     return res;
647   }
648 }
649