add CHD support.
[pcsx_rearmed.git] / deps / lzma-16.04 / C / 7zDec.c
1 /* 7zDec.c -- Decoding from 7z folder\r
2 2015-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
40 typedef 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
52 static 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
73 static 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
134 static 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
194 static 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
253 static 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
272 static 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
289 static 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
299 static 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
370 static 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
549 SRes 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