Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / 3rdparty / seven_zip / 7zDec.c
blob7c463521112282a42de3009906c73aa2ae9cde4a
1 /* 7zDec.c -- Decoding from 7z folder
2 2019-02-02 : Igor Pavlov : Public domain */
4 #include "Precomp.h"
6 #include <string.h>
8 /* #define _7ZIP_PPMD_SUPPPORT */
10 #include "7z.h"
11 #include "7zCrc.h"
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
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
36 #ifdef _7ZIP_PPMD_SUPPPORT
38 #define k_PPMD 0x30401
40 typedef struct
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;
52 static Byte ReadByte(const IByteIn *pp)
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)
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++;;
69 p->extra = True;
70 return 0;
73 static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream,
74 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
76 CPpmd7 ppmd;
77 CByteInToLook s;
78 SRes res = SZ_OK;
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;
87 if (propsSize != 5)
88 return SZ_ERROR_UNSUPPORTED;
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);
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
113 SizeT i;
114 for (i = 0; i < outSize; i++)
116 int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt);
117 if (s.extra || sym < 0)
118 break;
119 outBuffer[i] = (Byte)sym;
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;
127 Ppmd7_Free(&ppmd, allocMain);
128 return res;
131 #endif
134 static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
135 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
137 CLzmaDec state;
138 SRes res = SZ_OK;
140 LzmaDec_Construct(&state);
141 RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
142 state.dic = outBuffer;
143 state.dicBufSize = outSize;
144 LzmaDec_Init(&state);
146 for (;;)
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;
157 SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
158 ELzmaStatus status;
159 res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
160 lookahead -= inProcessed;
161 inSize -= inProcessed;
162 if (res != SZ_OK)
163 break;
165 if (status == LZMA_STATUS_FINISHED_WITH_MARK)
167 if (outSize != state.dicPos || inSize != 0)
168 res = SZ_ERROR_DATA;
169 break;
172 if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
173 break;
175 if (inProcessed == 0 && dicPos == state.dicPos)
177 res = SZ_ERROR_DATA;
178 break;
181 res = ILookInStream_Skip(inStream, inProcessed);
182 if (res != SZ_OK)
183 break;
187 LzmaDec_FreeProbs(&state, allocMain);
188 return res;
192 #ifndef _7Z_NO_METHOD_LZMA2
194 static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
195 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
197 CLzma2Dec state;
198 SRes res = SZ_OK;
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);
208 for (;;)
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;
219 SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
220 ELzmaStatus status;
221 res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
222 lookahead -= inProcessed;
223 inSize -= inProcessed;
224 if (res != SZ_OK)
225 break;
227 if (status == LZMA_STATUS_FINISHED_WITH_MARK)
229 if (outSize != state.decoder.dicPos || inSize != 0)
230 res = SZ_ERROR_DATA;
231 break;
234 if (inProcessed == 0 && dicPos == state.decoder.dicPos)
236 res = SZ_ERROR_DATA;
237 break;
240 res = ILookInStream_Skip(inStream, inProcessed);
241 if (res != SZ_OK)
242 break;
246 Lzma2Dec_FreeProbs(&state, allocMain);
247 return res;
250 #endif
253 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
255 while (inSize > 0)
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));
269 return SZ_OK;
272 static BoolInt IS_MAIN_METHOD(UInt32 m)
274 switch (m)
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;
286 return False;
289 static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
291 return
292 c->NumStreams == 1
293 /* && c->MethodID <= (UInt32)0xFFFFFFFF */
294 && IS_MAIN_METHOD((UInt32)c->MethodID);
297 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
299 static SRes CheckSupportedFolder(const CSzFolder *f)
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)
307 if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
308 return SZ_ERROR_UNSUPPORTED;
309 return SZ_OK;
313 #ifndef _7Z_NO_METHODS_FILTERS
315 if (f->NumCoders == 2)
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)
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;
340 return SZ_OK;
343 #endif
346 if (f->NumCoders == 4)
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;
365 return SZ_ERROR_UNSUPPORTED;
368 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
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[])
378 UInt32 ci;
379 SizeT tempSizes[3] = { 0, 0, 0};
380 SizeT tempSize3 = 0;
381 Byte *tempBuf3 = 0;
383 RINOK(CheckSupportedFolder(folder));
385 for (ci = 0; ci < folder->NumCoders; ci++)
387 const CSzCoderInfo *coder = &folder->Coders[ci];
389 if (IS_MAIN_METHOD((UInt32)coder->MethodID))
391 UInt32 si = 0;
392 UInt64 offset;
393 UInt64 inSize;
394 Byte *outBufCur = outBuffer;
395 SizeT outSizeCur = outSize;
396 if (folder->NumCoders == 4)
398 UInt32 indices[] = { 3, 2, 0 };
399 UInt64 unpackSize = unpackSizes[ci];
400 si = indices[ci];
401 if (ci < 2)
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;
413 else if (ci == 2)
415 if (unpackSize > outSize) /* check it */
416 return SZ_ERROR_PARAM;
417 tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
418 tempSize3 = outSizeCur = (SizeT)unpackSize;
420 else
421 return SZ_ERROR_UNSUPPORTED;
423 offset = packPositions[si];
424 inSize = packPositions[(size_t)si + 1] - offset;
425 RINOK(LookInStream_SeekTo(inStream, startPos + offset));
427 if (coder->MethodID == k_Copy)
429 if (inSize != outSizeCur) /* check it */
430 return SZ_ERROR_DATA;
431 RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
433 else if (coder->MethodID == k_LZMA)
435 RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
437 #ifndef _7Z_NO_METHOD_LZMA2
438 else if (coder->MethodID == k_LZMA2)
440 RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
442 #endif
443 #ifdef _7ZIP_PPMD_SUPPPORT
444 else if (coder->MethodID == k_PPMD)
446 RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
448 #endif
449 else
450 return SZ_ERROR_UNSUPPORTED;
452 else if (coder->MethodID == k_BCJ2)
454 UInt64 offset = packPositions[1];
455 UInt64 s3Size = packPositions[2] - offset;
457 if (ci != 3)
458 return SZ_ERROR_UNSUPPORTED;
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;
467 RINOK(LookInStream_SeekTo(inStream, startPos + offset));
468 RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
470 if ((tempSizes[0] & 3) != 0 ||
471 (tempSizes[1] & 3) != 0 ||
472 tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
473 return SZ_ERROR_DATA;
476 CBcj2Dec p;
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];
483 p.dest = outBuffer;
484 p.destLim = outBuffer + outSize;
486 Bcj2Dec_Init(&p);
487 RINOK(Bcj2Dec_Decode(&p));
490 unsigned i;
491 for (i = 0; i < 4; i++)
492 if (p.bufs[i] != p.lims[i])
493 return SZ_ERROR_DATA;
495 if (!Bcj2Dec_IsFinished(&p))
496 return SZ_ERROR_DATA;
498 if (p.dest != p.destLim
499 || p.state != BCJ2_STREAM_MAIN)
500 return SZ_ERROR_DATA;
504 #ifndef _7Z_NO_METHODS_FILTERS
505 else if (ci == 1)
507 if (coder->MethodID == k_Delta)
509 if (coder->PropsSize != 1)
510 return SZ_ERROR_UNSUPPORTED;
512 Byte state[DELTA_STATE_SIZE];
513 Delta_Init(state);
514 Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
517 else
519 if (coder->PropsSize != 0)
520 return SZ_ERROR_UNSUPPORTED;
521 switch (coder->MethodID)
523 case k_BCJ:
525 UInt32 state;
526 x86_Convert_Init(state);
527 x86_Convert(outBuffer, outSize, 0, &state, 0);
528 break;
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;
540 #endif
541 else
542 return SZ_ERROR_UNSUPPORTED;
545 return SZ_OK;
549 SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
550 ILookInStream *inStream, UInt64 startPos,
551 Byte *outBuffer, size_t outSize,
552 ISzAllocPtr allocMain)
554 SRes res;
555 CSzFolder folder;
556 CSzData sd;
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];
562 res = SzGetNextFolderItem(&folder, &sd);
564 if (res != SZ_OK)
565 return res;
567 if (sd.Size != 0
568 || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
569 || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
570 return SZ_ERROR_FAIL;
572 unsigned i;
573 Byte *tempBuf[3] = { 0, 0, 0};
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);
581 for (i = 0; i < 3; i++)
582 ISzAlloc_Free(allocMain, tempBuf[i]);
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;
589 return res;