1
/* 7zDec.c -- Decoding from 7z folder
2
2010-11-02 : Igor Pavlov : Public domain */
6
#define _7ZIP_PPMD_SUPPPORT
15
#ifdef _7ZIP_PPMD_SUPPPORT
21
#define k_LZMA 0x30101
22
#define k_BCJ 0x03030103
23
#define k_PPC 0x03030205
24
#define k_ARM 0x03030501
25
#define k_ARMT 0x03030701
26
#define k_SPARC 0x03030805
27
#define k_BCJ2 0x0303011B
29
#ifdef _7ZIP_PPMD_SUPPPORT
31
#define k_PPMD 0x30401
42
ILookInStream *inStream;
45
static Byte ReadByte(void *pp)
47
CByteInToLook *p = (CByteInToLook *)pp;
52
size_t size = p->cur - p->begin;
54
p->res = p->inStream->Skip(p->inStream, size);
56
p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
58
p->end = p->begin + size;
66
static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
67
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
74
s.inStream = inStream;
75
s.begin = s.end = s.cur = NULL;
80
if (coder->Props.size != 5)
81
return SZ_ERROR_UNSUPPORTED;
84
unsigned order = coder->Props.data[0];
85
UInt32 memSize = GetUi32(coder->Props.data + 1);
86
if (order < PPMD7_MIN_ORDER ||
87
order > PPMD7_MAX_ORDER ||
88
memSize < PPMD7_MIN_MEM_SIZE ||
89
memSize > PPMD7_MAX_MEM_SIZE)
90
return SZ_ERROR_UNSUPPORTED;
91
Ppmd7_Construct(&ppmd);
92
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
94
Ppmd7_Init(&ppmd, order);
98
Ppmd7z_RangeDec_CreateVTable(&rc);
100
if (!Ppmd7z_RangeDec_Init(&rc))
103
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
107
for (i = 0; i < outSize; i++)
109
int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
110
if (s.extra || sym < 0)
112
outBuffer[i] = (Byte)sym;
115
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
116
else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
120
Ppmd7_Free(&ppmd, allocMain);
127
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
128
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
133
LzmaDec_Construct(&state);
134
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
135
state.dic = outBuffer;
136
state.dicBufSize = outSize;
137
LzmaDec_Init(&state);
142
size_t lookahead = (1 << 18);
143
if (lookahead > inSize)
144
lookahead = (size_t)inSize;
145
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
150
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
152
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
153
lookahead -= inProcessed;
154
inSize -= inProcessed;
157
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
159
if (state.dicBufSize != outSize || lookahead != 0 ||
160
(status != LZMA_STATUS_FINISHED_WITH_MARK &&
161
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
165
res = inStream->Skip((void *)inStream, inProcessed);
171
LzmaDec_FreeProbs(&state, allocMain);
175
static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
176
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
181
Lzma2Dec_Construct(&state);
182
if (coder->Props.size != 1)
183
return SZ_ERROR_DATA;
184
RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
185
state.decoder.dic = outBuffer;
186
state.decoder.dicBufSize = outSize;
187
Lzma2Dec_Init(&state);
192
size_t lookahead = (1 << 18);
193
if (lookahead > inSize)
194
lookahead = (size_t)inSize;
195
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
200
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
202
res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
203
lookahead -= inProcessed;
204
inSize -= inProcessed;
207
if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
209
if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
210
(status != LZMA_STATUS_FINISHED_WITH_MARK))
214
res = inStream->Skip((void *)inStream, inProcessed);
220
Lzma2Dec_FreeProbs(&state, allocMain);
224
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
229
size_t curSize = (1 << 18);
230
if (curSize > inSize)
231
curSize = (size_t)inSize;
232
RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
234
return SZ_ERROR_INPUT_EOF;
235
memcpy(outBuffer, inBuf, curSize);
236
outBuffer += curSize;
238
RINOK(inStream->Skip((void *)inStream, curSize));
243
static Bool IS_MAIN_METHOD(UInt32 m)
250
#ifdef _7ZIP_PPMD_SUPPPORT
258
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
261
c->NumInStreams == 1 &&
262
c->NumOutStreams == 1 &&
263
c->MethodID <= (UInt32)0xFFFFFFFF &&
264
IS_MAIN_METHOD((UInt32)c->MethodID);
267
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
269
static SRes CheckSupportedFolder(const CSzFolder *f)
271
if (f->NumCoders < 1 || f->NumCoders > 4)
272
return SZ_ERROR_UNSUPPORTED;
274
if (f->Coders[0].MethodID == 0x06F10701) /* ACAB */
275
return SZ_ERROR_ENCRYPTED;
277
if (!IS_SUPPORTED_CODER(&f->Coders[0]))
278
return SZ_ERROR_UNSUPPORTED;
279
if (f->NumCoders == 1)
281
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
282
return SZ_ERROR_UNSUPPORTED;
285
if (f->NumCoders == 2)
287
CSzCoderInfo *c = &f->Coders[1];
288
if (c->MethodID > (UInt32)0xFFFFFFFF ||
289
c->NumInStreams != 1 ||
290
c->NumOutStreams != 1 ||
291
f->NumPackStreams != 1 ||
292
f->PackStreams[0] != 0 ||
293
f->NumBindPairs != 1 ||
294
f->BindPairs[0].InIndex != 1 ||
295
f->BindPairs[0].OutIndex != 0)
296
return SZ_ERROR_UNSUPPORTED;
297
switch ((UInt32)c->MethodID)
303
return SZ_ERROR_UNSUPPORTED;
307
if (f->NumCoders == 4)
309
if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
310
!IS_SUPPORTED_CODER(&f->Coders[2]) ||
311
!IS_BCJ2(&f->Coders[3]))
312
return SZ_ERROR_UNSUPPORTED;
313
if (f->NumPackStreams != 4 ||
314
f->PackStreams[0] != 2 ||
315
f->PackStreams[1] != 6 ||
316
f->PackStreams[2] != 1 ||
317
f->PackStreams[3] != 0 ||
318
f->NumBindPairs != 3 ||
319
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
320
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
321
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
322
return SZ_ERROR_UNSUPPORTED;
325
return SZ_ERROR_UNSUPPORTED;
328
static UInt64 GetSum(const UInt64 *values, UInt32 index)
332
for (i = 0; i < index; i++)
337
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
339
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
340
ILookInStream *inStream, UInt64 startPos,
341
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
345
SizeT tempSizes[3] = { 0, 0, 0};
349
RINOK(CheckSupportedFolder(folder));
351
for (ci = 0; ci < folder->NumCoders; ci++)
353
CSzCoderInfo *coder = &folder->Coders[ci];
355
if (IS_MAIN_METHOD((UInt32)coder->MethodID))
360
Byte *outBufCur = outBuffer;
361
SizeT outSizeCur = outSize;
362
if (folder->NumCoders == 4)
364
UInt32 indices[] = { 3, 2, 0 };
365
UInt64 unpackSize = folder->UnpackSizes[ci];
370
outSizeCur = (SizeT)unpackSize;
371
if (outSizeCur != unpackSize)
373
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
374
if (temp == 0 && outSizeCur != 0)
376
outBufCur = tempBuf[1 - ci] = temp;
377
tempSizes[1 - ci] = outSizeCur;
381
if (unpackSize > outSize) /* check it */
382
return SZ_ERROR_PARAM;
383
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
384
tempSize3 = outSizeCur = (SizeT)unpackSize;
387
return SZ_ERROR_UNSUPPORTED;
389
offset = GetSum(packSizes, si);
390
inSize = packSizes[si];
391
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
393
if (coder->MethodID == k_Copy)
395
if (inSize != outSizeCur) /* check it */
396
return SZ_ERROR_DATA;
397
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
399
else if (coder->MethodID == k_LZMA)
401
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
403
else if (coder->MethodID == k_LZMA2)
405
RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
409
#ifdef _7ZIP_PPMD_SUPPPORT
410
RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
412
return SZ_ERROR_UNSUPPORTED;
416
else if (coder->MethodID == k_BCJ2)
418
UInt64 offset = GetSum(packSizes, 1);
419
UInt64 s3Size = packSizes[1];
422
return SZ_ERROR_UNSUPPORTED;
423
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
424
tempSizes[2] = (SizeT)s3Size;
425
if (tempSizes[2] != s3Size)
427
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
428
if (tempBuf[2] == 0 && tempSizes[2] != 0)
430
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
435
tempBuf[0], tempSizes[0],
436
tempBuf[1], tempSizes[1],
437
tempBuf[2], tempSizes[2],
444
return SZ_ERROR_UNSUPPORTED;
445
switch(coder->MethodID)
450
x86_Convert_Init(state);
451
x86_Convert(outBuffer, outSize, 0, &state, 0);
456
return SZ_ERROR_UNSUPPORTED;
463
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
464
ILookInStream *inStream, UInt64 startPos,
465
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
467
Byte *tempBuf[3] = { 0, 0, 0};
469
SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
470
outBuffer, (SizeT)outSize, allocMain, tempBuf);
471
for (i = 0; i < 3; i++)
472
IAlloc_Free(allocMain, tempBuf[i]);