1 /* 7zDec.c -- Decoding from 7z folder
2 2021-02-09 : 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 #ifndef _7Z_NO_METHOD_LZMA2
25 #define k_LZMA2 0x21
26 #endif
27 #define k_LZMA 0x30101
28 #define k_BCJ2 0x303011B
29 #ifndef _7Z_NO_METHODS_FILTERS
30 #define k_Delta 3
31 #define k_BCJ 0x3030103
32 #define k_PPC 0x3030205
33 #define k_IA64 0x3030401
34 #define k_ARM 0x3030501
35 #define k_ARMT 0x3030701
36 #define k_SPARC 0x3030805
37 #endif
38
39 #ifdef _7ZIP_PPMD_SUPPPORT
40
41 #define k_PPMD 0x30401
42
43 typedef struct
44 {
45 IByteIn vt;
46 const Byte *cur;
47 const Byte *end;
48 const Byte *begin;
49 UInt64 processed;
50 BoolInt extra;
51 SRes res;
52 const ILookInStream *inStream;
53 } CByteInToLook;
54
ReadByte(const IByteIn * pp)55 static Byte ReadByte(const IByteIn *pp)
56 {
57 CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt);
58 if (p->cur != p->end)
59 return *p->cur++;
60 if (p->res == SZ_OK)
61 {
62 size_t size = (size_t)(p->cur - p->begin);
63 p->processed += size;
64 p->res = ILookInStream_Skip(p->inStream, size);
65 size = (1 << 25);
66 p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
67 p->cur = p->begin;
68 p->end = p->begin + size;
69 if (size != 0)
70 return *p->cur++;;
71 }
72 p->extra = True;
73 return 0;
74 }
75
SzDecodePpmd(const Byte * props,unsigned propsSize,UInt64 inSize,const ILookInStream * inStream,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain)76 static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream,
77 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
78 {
79 CPpmd7 ppmd;
80 CByteInToLook s;
81 SRes res = SZ_OK;
82
83 s.vt.Read = ReadByte;
84 s.inStream = inStream;
85 s.begin = s.end = s.cur = NULL;
86 s.extra = False;
87 s.res = SZ_OK;
88 s.processed = 0;
89
90 if (propsSize != 5)
91 return SZ_ERROR_UNSUPPORTED;
92
93 {
94 unsigned order = props[0];
95 UInt32 memSize = GetUi32(props + 1);
96 if (order < PPMD7_MIN_ORDER ||
97 order > PPMD7_MAX_ORDER ||
98 memSize < PPMD7_MIN_MEM_SIZE ||
99 memSize > PPMD7_MAX_MEM_SIZE)
100 return SZ_ERROR_UNSUPPORTED;
101 Ppmd7_Construct(&ppmd);
102 if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
103 return SZ_ERROR_MEM;
104 Ppmd7_Init(&ppmd, order);
105 }
106 {
107 ppmd.rc.dec.Stream = &s.vt;
108 if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec))
109 res = SZ_ERROR_DATA;
110 else if (!s.extra)
111 {
112 Byte *buf = outBuffer;
113 const Byte *lim = buf + outSize;
114 for (; buf != lim; buf++)
115 {
116 int sym = Ppmd7z_DecodeSymbol(&ppmd);
117 if (s.extra || sym < 0)
118 break;
119 *buf = (Byte)sym;
120 }
121 if (buf != lim)
122 res = SZ_ERROR_DATA;
123 else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
124 {
125 /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */
126 res = SZ_ERROR_DATA;
127 }
128 }
129 if (s.extra)
130 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
131 else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
132 res = SZ_ERROR_DATA;
133 }
134 Ppmd7_Free(&ppmd, allocMain);
135 return res;
136 }
137
138 #endif
139
140
SzDecodeLzma(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStream * inStream,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain)141 static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
142 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
143 {
144 CLzmaDec state;
145 SRes res = SZ_OK;
146
147 LzmaDec_Construct(&state);
148 RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
149 state.dic = outBuffer;
150 state.dicBufSize = outSize;
151 LzmaDec_Init(&state);
152
153 for (;;)
154 {
155 const void *inBuf = NULL;
156 size_t lookahead = (1 << 18);
157 if (lookahead > inSize)
158 lookahead = (size_t)inSize;
159 res = ILookInStream_Look(inStream, &inBuf, &lookahead);
160 if (res != SZ_OK)
161 break;
162
163 {
164 SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
165 ELzmaStatus status;
166 res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
167 lookahead -= inProcessed;
168 inSize -= inProcessed;
169 if (res != SZ_OK)
170 break;
171
172 if (status == LZMA_STATUS_FINISHED_WITH_MARK)
173 {
174 if (outSize != state.dicPos || inSize != 0)
175 res = SZ_ERROR_DATA;
176 break;
177 }
178
179 if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
180 break;
181
182 if (inProcessed == 0 && dicPos == state.dicPos)
183 {
184 res = SZ_ERROR_DATA;
185 break;
186 }
187
188 res = ILookInStream_Skip(inStream, inProcessed);
189 if (res != SZ_OK)
190 break;
191 }
192 }
193
194 LzmaDec_FreeProbs(&state, allocMain);
195 return res;
196 }
197
198
199 #ifndef _7Z_NO_METHOD_LZMA2
200
SzDecodeLzma2(const Byte * props,unsigned propsSize,UInt64 inSize,ILookInStream * inStream,Byte * outBuffer,SizeT outSize,ISzAllocPtr allocMain)201 static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
202 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
203 {
204 CLzma2Dec state;
205 SRes res = SZ_OK;
206
207 Lzma2Dec_Construct(&state);
208 if (propsSize != 1)
209 return SZ_ERROR_DATA;
210 RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
211 state.decoder.dic = outBuffer;
212 state.decoder.dicBufSize = outSize;
213 Lzma2Dec_Init(&state);
214
215 for (;;)
216 {
217 const void *inBuf = NULL;
218 size_t lookahead = (1 << 18);
219 if (lookahead > inSize)
220 lookahead = (size_t)inSize;
221 res = ILookInStream_Look(inStream, &inBuf, &lookahead);
222 if (res != SZ_OK)
223 break;
224
225 {
226 SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
227 ELzmaStatus status;
228 res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
229 lookahead -= inProcessed;
230 inSize -= inProcessed;
231 if (res != SZ_OK)
232 break;
233
234 if (status == LZMA_STATUS_FINISHED_WITH_MARK)
235 {
236 if (outSize != state.decoder.dicPos || inSize != 0)
237 res = SZ_ERROR_DATA;
238 break;
239 }
240
241 if (inProcessed == 0 && dicPos == state.decoder.dicPos)
242 {
243 res = SZ_ERROR_DATA;
244 break;
245 }
246
247 res = ILookInStream_Skip(inStream, inProcessed);
248 if (res != SZ_OK)
249 break;
250 }
251 }
252
253 Lzma2Dec_FreeProbs(&state, allocMain);
254 return res;
255 }
256
257 #endif
258
259
SzDecodeCopy(UInt64 inSize,ILookInStream * inStream,Byte * outBuffer)260 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
261 {
262 while (inSize > 0)
263 {
264 const void *inBuf;
265 size_t curSize = (1 << 18);
266 if (curSize > inSize)
267 curSize = (size_t)inSize;
268 RINOK(ILookInStream_Look(inStream, &inBuf, &curSize));
269 if (curSize == 0)
270 return SZ_ERROR_INPUT_EOF;
271 memcpy(outBuffer, inBuf, curSize);
272 outBuffer += curSize;
273 inSize -= curSize;
274 RINOK(ILookInStream_Skip(inStream, curSize));
275 }
276 return SZ_OK;
277 }
278
IS_MAIN_METHOD(UInt32 m)279 static BoolInt IS_MAIN_METHOD(UInt32 m)
280 {
281 switch (m)
282 {
283 case k_Copy:
284 case k_LZMA:
285 #ifndef _7Z_NO_METHOD_LZMA2
286 case k_LZMA2:
287 #endif
288 #ifdef _7ZIP_PPMD_SUPPPORT
289 case k_PPMD:
290 #endif
291 return True;
292 }
293 return False;
294 }
295
IS_SUPPORTED_CODER(const CSzCoderInfo * c)296 static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
297 {
298 return
299 c->NumStreams == 1
300 /* && c->MethodID <= (UInt32)0xFFFFFFFF */
301 && IS_MAIN_METHOD((UInt32)c->MethodID);
302 }
303
304 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
305
CheckSupportedFolder(const CSzFolder * f)306 static SRes CheckSupportedFolder(const CSzFolder *f)
307 {
308 if (f->NumCoders < 1 || f->NumCoders > 4)
309 return SZ_ERROR_UNSUPPORTED;
310 if (!IS_SUPPORTED_CODER(&f->Coders[0]))
311 return SZ_ERROR_UNSUPPORTED;
312 if (f->NumCoders == 1)
313 {
314 if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
315 return SZ_ERROR_UNSUPPORTED;
316 return SZ_OK;
317 }
318
319
320 #ifndef _7Z_NO_METHODS_FILTERS
321
322 if (f->NumCoders == 2)
323 {
324 const CSzCoderInfo *c = &f->Coders[1];
325 if (
326 /* c->MethodID > (UInt32)0xFFFFFFFF || */
327 c->NumStreams != 1
328 || f->NumPackStreams != 1
329 || f->PackStreams[0] != 0
330 || f->NumBonds != 1
331 || f->Bonds[0].InIndex != 1
332 || f->Bonds[0].OutIndex != 0)
333 return SZ_ERROR_UNSUPPORTED;
334 switch ((UInt32)c->MethodID)
335 {
336 case k_Delta:
337 case k_BCJ:
338 case k_PPC:
339 case k_IA64:
340 case k_SPARC:
341 case k_ARM:
342 case k_ARMT:
343 break;
344 default:
345 return SZ_ERROR_UNSUPPORTED;
346 }
347 return SZ_OK;
348 }
349
350 #endif
351
352
353 if (f->NumCoders == 4)
354 {
355 if (!IS_SUPPORTED_CODER(&f->Coders[1])
356 || !IS_SUPPORTED_CODER(&f->Coders[2])
357 || !IS_BCJ2(&f->Coders[3]))
358 return SZ_ERROR_UNSUPPORTED;
359 if (f->NumPackStreams != 4
360 || f->PackStreams[0] != 2
361 || f->PackStreams[1] != 6
362 || f->PackStreams[2] != 1
363 || f->PackStreams[3] != 0
364 || f->NumBonds != 3
365 || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
366 || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
367 || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
368 return SZ_ERROR_UNSUPPORTED;
369 return SZ_OK;
370 }
371
372 return SZ_ERROR_UNSUPPORTED;
373 }
374
375 #ifndef _7Z_NO_METHODS_FILTERS
376 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
377 #endif
378
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[])379 static SRes SzFolder_Decode2(const CSzFolder *folder,
380 const Byte *propsData,
381 const UInt64 *unpackSizes,
382 const UInt64 *packPositions,
383 ILookInStream *inStream, UInt64 startPos,
384 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
385 Byte *tempBuf[])
386 {
387 UInt32 ci;
388 SizeT tempSizes[3] = { 0, 0, 0};
389 SizeT tempSize3 = 0;
390 Byte *tempBuf3 = 0;
391
392 RINOK(CheckSupportedFolder(folder));
393
394 for (ci = 0; ci < folder->NumCoders; ci++)
395 {
396 const CSzCoderInfo *coder = &folder->Coders[ci];
397
398 if (IS_MAIN_METHOD((UInt32)coder->MethodID))
399 {
400 UInt32 si = 0;
401 UInt64 offset;
402 UInt64 inSize;
403 Byte *outBufCur = outBuffer;
404 SizeT outSizeCur = outSize;
405 if (folder->NumCoders == 4)
406 {
407 UInt32 indices[] = { 3, 2, 0 };
408 UInt64 unpackSize = unpackSizes[ci];
409 si = indices[ci];
410 if (ci < 2)
411 {
412 Byte *temp;
413 outSizeCur = (SizeT)unpackSize;
414 if (outSizeCur != unpackSize)
415 return SZ_ERROR_MEM;
416 temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
417 if (!temp && outSizeCur != 0)
418 return SZ_ERROR_MEM;
419 outBufCur = tempBuf[1 - ci] = temp;
420 tempSizes[1 - ci] = outSizeCur;
421 }
422 else if (ci == 2)
423 {
424 if (unpackSize > outSize) /* check it */
425 return SZ_ERROR_PARAM;
426 tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
427 tempSize3 = outSizeCur = (SizeT)unpackSize;
428 }
429 else
430 return SZ_ERROR_UNSUPPORTED;
431 }
432 offset = packPositions[si];
433 inSize = packPositions[(size_t)si + 1] - offset;
434 RINOK(LookInStream_SeekTo(inStream, startPos + offset));
435
436 if (coder->MethodID == k_Copy)
437 {
438 if (inSize != outSizeCur) /* check it */
439 return SZ_ERROR_DATA;
440 RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
441 }
442 else if (coder->MethodID == k_LZMA)
443 {
444 RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
445 }
446 #ifndef _7Z_NO_METHOD_LZMA2
447 else if (coder->MethodID == k_LZMA2)
448 {
449 RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
450 }
451 #endif
452 #ifdef _7ZIP_PPMD_SUPPPORT
453 else if (coder->MethodID == k_PPMD)
454 {
455 RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
456 }
457 #endif
458 else
459 return SZ_ERROR_UNSUPPORTED;
460 }
461 else if (coder->MethodID == k_BCJ2)
462 {
463 UInt64 offset = packPositions[1];
464 UInt64 s3Size = packPositions[2] - offset;
465
466 if (ci != 3)
467 return SZ_ERROR_UNSUPPORTED;
468
469 tempSizes[2] = (SizeT)s3Size;
470 if (tempSizes[2] != s3Size)
471 return SZ_ERROR_MEM;
472 tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
473 if (!tempBuf[2] && tempSizes[2] != 0)
474 return SZ_ERROR_MEM;
475
476 RINOK(LookInStream_SeekTo(inStream, startPos + offset));
477 RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
478
479 if ((tempSizes[0] & 3) != 0 ||
480 (tempSizes[1] & 3) != 0 ||
481 tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
482 return SZ_ERROR_DATA;
483
484 {
485 CBcj2Dec p;
486
487 p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
488 p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
489 p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
490 p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
491
492 p.dest = outBuffer;
493 p.destLim = outBuffer + outSize;
494
495 Bcj2Dec_Init(&p);
496 RINOK(Bcj2Dec_Decode(&p));
497
498 {
499 unsigned i;
500 for (i = 0; i < 4; i++)
501 if (p.bufs[i] != p.lims[i])
502 return SZ_ERROR_DATA;
503
504 if (!Bcj2Dec_IsFinished(&p))
505 return SZ_ERROR_DATA;
506
507 if (p.dest != p.destLim
508 || p.state != BCJ2_STREAM_MAIN)
509 return SZ_ERROR_DATA;
510 }
511 }
512 }
513 #ifndef _7Z_NO_METHODS_FILTERS
514 else if (ci == 1)
515 {
516 if (coder->MethodID == k_Delta)
517 {
518 if (coder->PropsSize != 1)
519 return SZ_ERROR_UNSUPPORTED;
520 {
521 Byte state[DELTA_STATE_SIZE];
522 Delta_Init(state);
523 Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
524 }
525 }
526 else
527 {
528 if (coder->PropsSize != 0)
529 return SZ_ERROR_UNSUPPORTED;
530 switch (coder->MethodID)
531 {
532 case k_BCJ:
533 {
534 UInt32 state;
535 x86_Convert_Init(state);
536 x86_Convert(outBuffer, outSize, 0, &state, 0);
537 break;
538 }
539 CASE_BRA_CONV(PPC)
540 CASE_BRA_CONV(IA64)
541 CASE_BRA_CONV(SPARC)
542 CASE_BRA_CONV(ARM)
543 CASE_BRA_CONV(ARMT)
544 default:
545 return SZ_ERROR_UNSUPPORTED;
546 }
547 }
548 }
549 #endif
550 else
551 return SZ_ERROR_UNSUPPORTED;
552 }
553
554 return SZ_OK;
555 }
556
557
SzAr_DecodeFolder(const CSzAr * p,UInt32 folderIndex,ILookInStream * inStream,UInt64 startPos,Byte * outBuffer,size_t outSize,ISzAllocPtr allocMain)558 SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
559 ILookInStream *inStream, UInt64 startPos,
560 Byte *outBuffer, size_t outSize,
561 ISzAllocPtr allocMain)
562 {
563 SRes res;
564 CSzFolder folder;
565 CSzData sd;
566
567 const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
568 sd.Data = data;
569 sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
570
571 res = SzGetNextFolderItem(&folder, &sd);
572
573 if (res != SZ_OK)
574 return res;
575
576 if (sd.Size != 0
577 || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
578 || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
579 return SZ_ERROR_FAIL;
580 {
581 unsigned i;
582 Byte *tempBuf[3] = { 0, 0, 0};
583
584 res = SzFolder_Decode2(&folder, data,
585 &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
586 p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
587 inStream, startPos,
588 outBuffer, (SizeT)outSize, allocMain, tempBuf);
589
590 for (i = 0; i < 3; i++)
591 ISzAlloc_Free(allocMain, tempBuf[i]);
592
593 if (res == SZ_OK)
594 if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
595 if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
596 res = SZ_ERROR_CRC;
597
598 return res;
599 }
600 }
601