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