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