• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* 7zDec.c -- Decoding from 7z folder
2 2014-06-16 : 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 
12 #include "Bcj2.h"
13 #include "Bra.h"
14 #include "CpuArch.h"
15 #include "LzmaDec.h"
16 #include "Lzma2Dec.h"
17 #ifdef _7ZIP_PPMD_SUPPPORT
18 #include "Ppmd7.h"
19 #endif
20 
21 #define k_Copy 0
22 #define k_LZMA2 0x21
23 #define k_LZMA  0x30101
24 #define k_BCJ   0x03030103
25 #define k_PPC   0x03030205
26 #define k_ARM   0x03030501
27 #define k_ARMT  0x03030701
28 #define k_SPARC 0x03030805
29 #define k_BCJ2  0x0303011B
30 
31 #ifdef _7ZIP_PPMD_SUPPPORT
32 
33 #define k_PPMD 0x30401
34 
35 typedef struct
36 {
37   IByteIn p;
38   const Byte *cur;
39   const Byte *end;
40   const Byte *begin;
41   UInt64 processed;
42   Bool extra;
43   SRes res;
44   ILookInStream *inStream;
45 } CByteInToLook;
46 
ReadByte(void * pp)47 static Byte ReadByte(void *pp)
48 {
49   CByteInToLook *p = (CByteInToLook *)pp;
50   if (p->cur != p->end)
51     return *p->cur++;
52   if (p->res == SZ_OK)
53   {
54     size_t size = p->cur - p->begin;
55     p->processed += size;
56     p->res = p->inStream->Skip(p->inStream, size);
57     size = (1 << 25);
58     p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
59     p->cur = p->begin;
60     p->end = p->begin + size;
61     if (size != 0)
62       return *p->cur++;;
63   }
64   p->extra = True;
65   return 0;
66 }
67 
SzDecodePpmd(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStream * inStream,Byte * outBuffer,SizeT outSize,ISzAlloc * allocMain)68 static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
69     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
70 {
71   CPpmd7 ppmd;
72   CByteInToLook s;
73   SRes res = SZ_OK;
74 
75   s.p.Read = ReadByte;
76   s.inStream = inStream;
77   s.begin = s.end = s.cur = NULL;
78   s.extra = False;
79   s.res = SZ_OK;
80   s.processed = 0;
81 
82   if (propsSize != 5)
83     return SZ_ERROR_UNSUPPORTED;
84 
85   {
86     unsigned order = props[0];
87     UInt32 memSize = GetUi32(props + 1);
88     if (order < PPMD7_MIN_ORDER ||
89         order > PPMD7_MAX_ORDER ||
90         memSize < PPMD7_MIN_MEM_SIZE ||
91         memSize > PPMD7_MAX_MEM_SIZE)
92       return SZ_ERROR_UNSUPPORTED;
93     Ppmd7_Construct(&ppmd);
94     if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
95       return SZ_ERROR_MEM;
96     Ppmd7_Init(&ppmd, order);
97   }
98   {
99     CPpmd7z_RangeDec rc;
100     Ppmd7z_RangeDec_CreateVTable(&rc);
101     rc.Stream = &s.p;
102     if (!Ppmd7z_RangeDec_Init(&rc))
103       res = SZ_ERROR_DATA;
104     else if (s.extra)
105       res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
106     else
107     {
108       SizeT i;
109       for (i = 0; i < outSize; i++)
110       {
111         int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
112         if (s.extra || sym < 0)
113           break;
114         outBuffer[i] = (Byte)sym;
115       }
116       if (i != outSize)
117         res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
118       else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
119         res = SZ_ERROR_DATA;
120     }
121   }
122   Ppmd7_Free(&ppmd, allocMain);
123   return res;
124 }
125 
126 #endif
127 
128 
SzDecodeLzma(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStream * inStream,Byte * outBuffer,SizeT outSize,ISzAlloc * allocMain)129 static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
130     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
131 {
132   CLzmaDec state;
133   SRes res = SZ_OK;
134 
135   LzmaDec_Construct(&state);
136   RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
137   state.dic = outBuffer;
138   state.dicBufSize = outSize;
139   LzmaDec_Init(&state);
140 
141   for (;;)
142   {
143     Byte *inBuf = NULL;
144     size_t lookahead = (1 << 18);
145     if (lookahead > inSize)
146       lookahead = (size_t)inSize;
147     res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
148     if (res != SZ_OK)
149       break;
150 
151     {
152       SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
153       ELzmaStatus status;
154       res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
155       lookahead -= inProcessed;
156       inSize -= inProcessed;
157       if (res != SZ_OK)
158         break;
159       if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
160       {
161         if (state.dicBufSize != outSize || lookahead != 0 ||
162             (status != LZMA_STATUS_FINISHED_WITH_MARK &&
163              status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
164           res = SZ_ERROR_DATA;
165         break;
166       }
167       res = inStream->Skip((void *)inStream, inProcessed);
168       if (res != SZ_OK)
169         break;
170     }
171   }
172 
173   LzmaDec_FreeProbs(&state, allocMain);
174   return res;
175 }
176 
SzDecodeLzma2(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStream * inStream,Byte * outBuffer,SizeT outSize,ISzAlloc * allocMain)177 static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
178     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
179 {
180   CLzma2Dec state;
181   SRes res = SZ_OK;
182 
183   Lzma2Dec_Construct(&state);
184   if (propsSize != 1)
185     return SZ_ERROR_DATA;
186   RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
187   state.decoder.dic = outBuffer;
188   state.decoder.dicBufSize = outSize;
189   Lzma2Dec_Init(&state);
190 
191   for (;;)
192   {
193     Byte *inBuf = NULL;
194     size_t lookahead = (1 << 18);
195     if (lookahead > inSize)
196       lookahead = (size_t)inSize;
197     res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
198     if (res != SZ_OK)
199       break;
200 
201     {
202       SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
203       ELzmaStatus status;
204       res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
205       lookahead -= inProcessed;
206       inSize -= inProcessed;
207       if (res != SZ_OK)
208         break;
209       if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
210       {
211         if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
212             (status != LZMA_STATUS_FINISHED_WITH_MARK))
213           res = SZ_ERROR_DATA;
214         break;
215       }
216       res = inStream->Skip((void *)inStream, inProcessed);
217       if (res != SZ_OK)
218         break;
219     }
220   }
221 
222   Lzma2Dec_FreeProbs(&state, allocMain);
223   return res;
224 }
225 
SzDecodeCopy(UInt64 inSize,ILookInStream * inStream,Byte * outBuffer)226 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
227 {
228   while (inSize > 0)
229   {
230     void *inBuf;
231     size_t curSize = (1 << 18);
232     if (curSize > inSize)
233       curSize = (size_t)inSize;
234     RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
235     if (curSize == 0)
236       return SZ_ERROR_INPUT_EOF;
237     memcpy(outBuffer, inBuf, curSize);
238     outBuffer += curSize;
239     inSize -= curSize;
240     RINOK(inStream->Skip((void *)inStream, curSize));
241   }
242   return SZ_OK;
243 }
244 
IS_MAIN_METHOD(UInt32 m)245 static Bool IS_MAIN_METHOD(UInt32 m)
246 {
247   switch (m)
248   {
249     case k_Copy:
250     case k_LZMA:
251     case k_LZMA2:
252     #ifdef _7ZIP_PPMD_SUPPPORT
253     case k_PPMD:
254     #endif
255       return True;
256   }
257   return False;
258 }
259 
IS_SUPPORTED_CODER(const CSzCoderInfo * c)260 static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
261 {
262   return
263       c->NumInStreams == 1 &&
264       c->NumOutStreams == 1 &&
265       /* c->MethodID <= (UInt32)0xFFFFFFFF && */
266       IS_MAIN_METHOD((UInt32)c->MethodID);
267 }
268 
269 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
270 
CheckSupportedFolder(const CSzFolder * f)271 static SRes CheckSupportedFolder(const CSzFolder *f)
272 {
273   if (f->NumCoders < 1 || f->NumCoders > 4)
274     return SZ_ERROR_UNSUPPORTED;
275   if (!IS_SUPPORTED_CODER(&f->Coders[0]))
276     return SZ_ERROR_UNSUPPORTED;
277   if (f->NumCoders == 1)
278   {
279     if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
280       return SZ_ERROR_UNSUPPORTED;
281     return SZ_OK;
282   }
283   if (f->NumCoders == 2)
284   {
285     const CSzCoderInfo *c = &f->Coders[1];
286     if (
287         /* c->MethodID > (UInt32)0xFFFFFFFF || */
288         c->NumInStreams != 1 ||
289         c->NumOutStreams != 1 ||
290         f->NumPackStreams != 1 ||
291         f->PackStreams[0] != 0 ||
292         f->NumBindPairs != 1 ||
293         f->BindPairs[0].InIndex != 1 ||
294         f->BindPairs[0].OutIndex != 0)
295       return SZ_ERROR_UNSUPPORTED;
296     switch ((UInt32)c->MethodID)
297     {
298       case k_BCJ:
299       case k_ARM:
300         break;
301       default:
302         return SZ_ERROR_UNSUPPORTED;
303     }
304     return SZ_OK;
305   }
306   if (f->NumCoders == 4)
307   {
308     if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
309         !IS_SUPPORTED_CODER(&f->Coders[2]) ||
310         !IS_BCJ2(&f->Coders[3]))
311       return SZ_ERROR_UNSUPPORTED;
312     if (f->NumPackStreams != 4 ||
313         f->PackStreams[0] != 2 ||
314         f->PackStreams[1] != 6 ||
315         f->PackStreams[2] != 1 ||
316         f->PackStreams[3] != 0 ||
317         f->NumBindPairs != 3 ||
318         f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
319         f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
320         f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
321       return SZ_ERROR_UNSUPPORTED;
322     return SZ_OK;
323   }
324   return SZ_ERROR_UNSUPPORTED;
325 }
326 
327 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
328 
SzFolder_Decode2(const CSzFolder * folder,const Byte * propsData,const UInt64 * unpackSizes,const UInt64 * packPositions,ILookInStream * inStream,UInt64 startPos,Byte * outBuffer,SizeT outSize,ISzAlloc * allocMain,Byte * tempBuf[])329 static SRes SzFolder_Decode2(const CSzFolder *folder,
330     const Byte *propsData,
331     const UInt64 *unpackSizes,
332     const UInt64 *packPositions,
333     ILookInStream *inStream, UInt64 startPos,
334     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
335     Byte *tempBuf[])
336 {
337   UInt32 ci;
338   SizeT tempSizes[3] = { 0, 0, 0};
339   SizeT tempSize3 = 0;
340   Byte *tempBuf3 = 0;
341 
342   RINOK(CheckSupportedFolder(folder));
343 
344   for (ci = 0; ci < folder->NumCoders; ci++)
345   {
346     const CSzCoderInfo *coder = &folder->Coders[ci];
347 
348     if (IS_MAIN_METHOD((UInt32)coder->MethodID))
349     {
350       UInt32 si = 0;
351       UInt64 offset;
352       UInt64 inSize;
353       Byte *outBufCur = outBuffer;
354       SizeT outSizeCur = outSize;
355       if (folder->NumCoders == 4)
356       {
357         UInt32 indices[] = { 3, 2, 0 };
358         UInt64 unpackSize = unpackSizes[ci];
359         si = indices[ci];
360         if (ci < 2)
361         {
362           Byte *temp;
363           outSizeCur = (SizeT)unpackSize;
364           if (outSizeCur != unpackSize)
365             return SZ_ERROR_MEM;
366           temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
367           if (temp == 0 && outSizeCur != 0)
368             return SZ_ERROR_MEM;
369           outBufCur = tempBuf[1 - ci] = temp;
370           tempSizes[1 - ci] = outSizeCur;
371         }
372         else if (ci == 2)
373         {
374           if (unpackSize > outSize) /* check it */
375             return SZ_ERROR_PARAM;
376           tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
377           tempSize3 = outSizeCur = (SizeT)unpackSize;
378         }
379         else
380           return SZ_ERROR_UNSUPPORTED;
381       }
382       offset = packPositions[si];
383       inSize = packPositions[si + 1] - offset;
384       RINOK(LookInStream_SeekTo(inStream, startPos + offset));
385 
386       if (coder->MethodID == k_Copy)
387       {
388         if (inSize != outSizeCur) /* check it */
389           return SZ_ERROR_DATA;
390         RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
391       }
392       else if (coder->MethodID == k_LZMA)
393       {
394         RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
395       }
396       else if (coder->MethodID == k_LZMA2)
397       {
398         RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
399       }
400       else
401       {
402         #ifdef _7ZIP_PPMD_SUPPPORT
403         RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
404         #else
405         return SZ_ERROR_UNSUPPORTED;
406         #endif
407       }
408     }
409     else if (coder->MethodID == k_BCJ2)
410     {
411       UInt64 offset = packPositions[1];
412       UInt64 s3Size = packPositions[2] - offset;
413       SRes res;
414       if (ci != 3)
415         return SZ_ERROR_UNSUPPORTED;
416       RINOK(LookInStream_SeekTo(inStream, startPos + offset));
417       tempSizes[2] = (SizeT)s3Size;
418       if (tempSizes[2] != s3Size)
419         return SZ_ERROR_MEM;
420       tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
421       if (tempBuf[2] == 0 && tempSizes[2] != 0)
422         return SZ_ERROR_MEM;
423       res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
424       RINOK(res)
425 
426       res = Bcj2_Decode(
427           tempBuf3, tempSize3,
428           tempBuf[0], tempSizes[0],
429           tempBuf[1], tempSizes[1],
430           tempBuf[2], tempSizes[2],
431           outBuffer, outSize);
432       RINOK(res)
433     }
434     else
435     {
436       if (ci != 1)
437         return SZ_ERROR_UNSUPPORTED;
438       switch (coder->MethodID)
439       {
440         case k_BCJ:
441         {
442           UInt32 state;
443           x86_Convert_Init(state);
444           x86_Convert(outBuffer, outSize, 0, &state, 0);
445           break;
446         }
447         CASE_BRA_CONV(ARM)
448         default:
449           return SZ_ERROR_UNSUPPORTED;
450       }
451     }
452   }
453   return SZ_OK;
454 }
455 
SzAr_DecodeFolder(const CSzAr * p,UInt32 folderIndex,ILookInStream * inStream,UInt64 startPos,Byte * outBuffer,size_t outSize,ISzAlloc * allocMain)456 SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
457     ILookInStream *inStream, UInt64 startPos,
458     Byte *outBuffer, size_t outSize,
459     ISzAlloc *allocMain)
460 {
461   SRes res;
462   CSzFolder folder;
463   CSzData sd;
464   CSzData sdSizes;
465 
466   const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
467   sd.Data = data;
468   sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
469 
470   sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex];
471   sdSizes.Size =
472       p->FoSizesOffsets[folderIndex + 1] -
473       p->FoSizesOffsets[folderIndex];
474 
475   res = SzGetNextFolderItem(&folder, &sd, &sdSizes);
476 
477   if (res != SZ_OK)
478     return res;
479 
480   if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.MainOutStream])
481     return SZ_ERROR_FAIL;
482   {
483     int i;
484     Byte *tempBuf[3] = { 0, 0, 0};
485     res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes,
486         p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
487         inStream, startPos,
488         outBuffer, (SizeT)outSize, allocMain, tempBuf);
489     for (i = 0; i < 3; i++)
490       IAlloc_Free(allocMain, tempBuf[i]);
491     return res;
492   }
493 }
494