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