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