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