1 /* 7zDec.c -- Decoding from 7z folder
\r
2 2010-11-02 : Igor Pavlov : Public domain */
\r
6 #define _7ZIP_PPMD_SUPPPORT
\r
12 #include "CpuArch.h"
\r
13 #include "LzmaDec.h"
\r
14 #include "Lzma2Dec.h"
\r
15 #ifdef _7ZIP_PPMD_SUPPPORT
\r
20 #define k_LZMA2 0x21
\r
21 #define k_LZMA 0x30101
\r
22 #define k_BCJ 0x03030103
\r
23 #define k_PPC 0x03030205
\r
24 #define k_ARM 0x03030501
\r
25 #define k_ARMT 0x03030701
\r
26 #define k_SPARC 0x03030805
\r
27 #define k_BCJ2 0x0303011B
\r
29 #ifdef _7ZIP_PPMD_SUPPPORT
\r
31 #define k_PPMD 0x30401
\r
42 ILookInStream *inStream;
\r
45 static Byte ReadByte(void *pp)
\r
47 CByteInToLook *p = (CByteInToLook *)pp;
\r
48 if (p->cur != p->end)
\r
50 if (p->res == SZ_OK)
\r
52 size_t size = p->cur - p->begin;
\r
53 p->processed += size;
\r
54 p->res = p->inStream->Skip(p->inStream, size);
\r
56 p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
\r
58 p->end = p->begin + size;
\r
66 static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
\r
67 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
\r
73 s.p.Read = ReadByte;
\r
74 s.inStream = inStream;
\r
75 s.begin = s.end = s.cur = NULL;
\r
80 if (coder->Props.size != 5)
\r
81 return SZ_ERROR_UNSUPPORTED;
\r
84 unsigned order = coder->Props.data[0];
\r
85 UInt32 memSize = GetUi32(coder->Props.data + 1);
\r
86 if (order < PPMD7_MIN_ORDER ||
\r
87 order > PPMD7_MAX_ORDER ||
\r
88 memSize < PPMD7_MIN_MEM_SIZE ||
\r
89 memSize > PPMD7_MAX_MEM_SIZE)
\r
90 return SZ_ERROR_UNSUPPORTED;
\r
91 Ppmd7_Construct(&ppmd);
\r
92 if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
\r
93 return SZ_ERROR_MEM;
\r
94 Ppmd7_Init(&ppmd, order);
\r
97 CPpmd7z_RangeDec rc;
\r
98 Ppmd7z_RangeDec_CreateVTable(&rc);
\r
100 if (!Ppmd7z_RangeDec_Init(&rc))
\r
101 res = SZ_ERROR_DATA;
\r
103 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
\r
107 for (i = 0; i < outSize; i++)
\r
109 int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
\r
110 if (s.extra || sym < 0)
\r
112 outBuffer[i] = (Byte)sym;
\r
115 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
\r
116 else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
\r
117 res = SZ_ERROR_DATA;
\r
120 Ppmd7_Free(&ppmd, allocMain);
\r
127 static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
\r
128 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
\r
133 LzmaDec_Construct(&state);
\r
134 RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
\r
135 state.dic = outBuffer;
\r
136 state.dicBufSize = outSize;
\r
137 LzmaDec_Init(&state);
\r
141 Byte *inBuf = NULL;
\r
142 size_t lookahead = (1 << 18);
\r
143 if (lookahead > inSize)
\r
144 lookahead = (size_t)inSize;
\r
145 res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
\r
150 SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
\r
151 ELzmaStatus status;
\r
152 res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
\r
153 lookahead -= inProcessed;
\r
154 inSize -= inProcessed;
\r
157 if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
\r
159 if (state.dicBufSize != outSize || lookahead != 0 ||
\r
160 (status != LZMA_STATUS_FINISHED_WITH_MARK &&
\r
161 status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
\r
162 res = SZ_ERROR_DATA;
\r
165 res = inStream->Skip((void *)inStream, inProcessed);
\r
171 LzmaDec_FreeProbs(&state, allocMain);
\r
175 static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
\r
176 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
\r
181 Lzma2Dec_Construct(&state);
\r
182 if (coder->Props.size != 1)
\r
183 return SZ_ERROR_DATA;
\r
184 RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
\r
185 state.decoder.dic = outBuffer;
\r
186 state.decoder.dicBufSize = outSize;
\r
187 Lzma2Dec_Init(&state);
\r
191 Byte *inBuf = NULL;
\r
192 size_t lookahead = (1 << 18);
\r
193 if (lookahead > inSize)
\r
194 lookahead = (size_t)inSize;
\r
195 res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
\r
200 SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
\r
201 ELzmaStatus status;
\r
202 res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
\r
203 lookahead -= inProcessed;
\r
204 inSize -= inProcessed;
\r
207 if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
\r
209 if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
\r
210 (status != LZMA_STATUS_FINISHED_WITH_MARK))
\r
211 res = SZ_ERROR_DATA;
\r
214 res = inStream->Skip((void *)inStream, inProcessed);
\r
220 Lzma2Dec_FreeProbs(&state, allocMain);
\r
224 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
\r
229 size_t curSize = (1 << 18);
\r
230 if (curSize > inSize)
\r
231 curSize = (size_t)inSize;
\r
232 RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
\r
234 return SZ_ERROR_INPUT_EOF;
\r
235 memcpy(outBuffer, inBuf, curSize);
\r
236 outBuffer += curSize;
\r
238 RINOK(inStream->Skip((void *)inStream, curSize));
\r
243 static Bool IS_MAIN_METHOD(UInt32 m)
\r
250 #ifdef _7ZIP_PPMD_SUPPPORT
\r
258 static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
\r
261 c->NumInStreams == 1 &&
\r
262 c->NumOutStreams == 1 &&
\r
263 c->MethodID <= (UInt32)0xFFFFFFFF &&
\r
264 IS_MAIN_METHOD((UInt32)c->MethodID);
\r
267 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
\r
269 static SRes CheckSupportedFolder(const CSzFolder *f)
\r
271 if (f->NumCoders < 1 || f->NumCoders > 4)
\r
272 return SZ_ERROR_UNSUPPORTED;
\r
273 if (!IS_SUPPORTED_CODER(&f->Coders[0]))
\r
274 return SZ_ERROR_UNSUPPORTED;
\r
275 if (f->NumCoders == 1)
\r
277 if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
\r
278 return SZ_ERROR_UNSUPPORTED;
\r
281 if (f->NumCoders == 2)
\r
283 CSzCoderInfo *c = &f->Coders[1];
\r
284 if (c->MethodID > (UInt32)0xFFFFFFFF ||
\r
285 c->NumInStreams != 1 ||
\r
286 c->NumOutStreams != 1 ||
\r
287 f->NumPackStreams != 1 ||
\r
288 f->PackStreams[0] != 0 ||
\r
289 f->NumBindPairs != 1 ||
\r
290 f->BindPairs[0].InIndex != 1 ||
\r
291 f->BindPairs[0].OutIndex != 0)
\r
292 return SZ_ERROR_UNSUPPORTED;
\r
293 switch ((UInt32)c->MethodID)
\r
299 return SZ_ERROR_UNSUPPORTED;
\r
303 if (f->NumCoders == 4)
\r
305 if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
\r
306 !IS_SUPPORTED_CODER(&f->Coders[2]) ||
\r
307 !IS_BCJ2(&f->Coders[3]))
\r
308 return SZ_ERROR_UNSUPPORTED;
\r
309 if (f->NumPackStreams != 4 ||
\r
310 f->PackStreams[0] != 2 ||
\r
311 f->PackStreams[1] != 6 ||
\r
312 f->PackStreams[2] != 1 ||
\r
313 f->PackStreams[3] != 0 ||
\r
314 f->NumBindPairs != 3 ||
\r
315 f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
\r
316 f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
\r
317 f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
\r
318 return SZ_ERROR_UNSUPPORTED;
\r
321 return SZ_ERROR_UNSUPPORTED;
\r
324 static UInt64 GetSum(const UInt64 *values, UInt32 index)
\r
328 for (i = 0; i < index; i++)
\r
333 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
\r
335 static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
\r
336 ILookInStream *inStream, UInt64 startPos,
\r
337 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
\r
341 SizeT tempSizes[3] = { 0, 0, 0};
\r
342 SizeT tempSize3 = 0;
\r
343 Byte *tempBuf3 = 0;
\r
345 RINOK(CheckSupportedFolder(folder));
\r
347 for (ci = 0; ci < folder->NumCoders; ci++)
\r
349 CSzCoderInfo *coder = &folder->Coders[ci];
\r
351 if (IS_MAIN_METHOD((UInt32)coder->MethodID))
\r
356 Byte *outBufCur = outBuffer;
\r
357 SizeT outSizeCur = outSize;
\r
358 if (folder->NumCoders == 4)
\r
360 UInt32 indices[] = { 3, 2, 0 };
\r
361 UInt64 unpackSize = folder->UnpackSizes[ci];
\r
366 outSizeCur = (SizeT)unpackSize;
\r
367 if (outSizeCur != unpackSize)
\r
368 return SZ_ERROR_MEM;
\r
369 temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
\r
370 if (temp == 0 && outSizeCur != 0)
\r
371 return SZ_ERROR_MEM;
\r
372 outBufCur = tempBuf[1 - ci] = temp;
\r
373 tempSizes[1 - ci] = outSizeCur;
\r
377 if (unpackSize > outSize) /* check it */
\r
378 return SZ_ERROR_PARAM;
\r
379 tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
\r
380 tempSize3 = outSizeCur = (SizeT)unpackSize;
\r
383 return SZ_ERROR_UNSUPPORTED;
\r
385 offset = GetSum(packSizes, si);
\r
386 inSize = packSizes[si];
\r
387 RINOK(LookInStream_SeekTo(inStream, startPos + offset));
\r
389 if (coder->MethodID == k_Copy)
\r
391 if (inSize != outSizeCur) /* check it */
\r
392 return SZ_ERROR_DATA;
\r
393 RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
\r
395 else if (coder->MethodID == k_LZMA)
\r
397 RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
\r
399 else if (coder->MethodID == k_LZMA2)
\r
401 RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
\r
405 #ifdef _7ZIP_PPMD_SUPPPORT
\r
406 RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
\r
408 return SZ_ERROR_UNSUPPORTED;
\r
412 else if (coder->MethodID == k_BCJ2)
\r
414 UInt64 offset = GetSum(packSizes, 1);
\r
415 UInt64 s3Size = packSizes[1];
\r
418 return SZ_ERROR_UNSUPPORTED;
\r
419 RINOK(LookInStream_SeekTo(inStream, startPos + offset));
\r
420 tempSizes[2] = (SizeT)s3Size;
\r
421 if (tempSizes[2] != s3Size)
\r
422 return SZ_ERROR_MEM;
\r
423 tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
\r
424 if (tempBuf[2] == 0 && tempSizes[2] != 0)
\r
425 return SZ_ERROR_MEM;
\r
426 res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
\r
430 tempBuf3, tempSize3,
\r
431 tempBuf[0], tempSizes[0],
\r
432 tempBuf[1], tempSizes[1],
\r
433 tempBuf[2], tempSizes[2],
\r
434 outBuffer, outSize);
\r
440 return SZ_ERROR_UNSUPPORTED;
\r
441 switch(coder->MethodID)
\r
446 x86_Convert_Init(state);
\r
447 x86_Convert(outBuffer, outSize, 0, &state, 0);
\r
452 return SZ_ERROR_UNSUPPORTED;
\r
459 SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
\r
460 ILookInStream *inStream, UInt64 startPos,
\r
461 Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
\r
463 Byte *tempBuf[3] = { 0, 0, 0};
\r
465 SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
\r
466 outBuffer, (SizeT)outSize, allocMain, tempBuf);
\r
467 for (i = 0; i < 3; i++)
\r
468 IAlloc_Free(allocMain, tempBuf[i]);
\r