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