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