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