1
/* 7zDecode.c -- Decoding from 7z folder
2
2008-11-23 : Igor Pavlov : Public domain */
6
#include "../../Bcj2.h"
8
#include "../../LzmaDec.h"
12
#define k_LZMA 0x30101
13
#define k_BCJ 0x03030103
14
#define k_BCJ2 0x0303011B
16
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
17
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
22
LzmaDec_Construct(&state);
23
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
24
state.dic = outBuffer;
25
state.dicBufSize = outSize;
31
size_t lookahead = (1 << 18);
32
if (lookahead > inSize)
33
lookahead = (size_t)inSize;
34
res = inStream->Look((void *)inStream, (void **)&inBuf, &lookahead);
39
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
41
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
42
lookahead -= inProcessed;
43
inSize -= inProcessed;
46
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
48
if (state.dicBufSize != outSize || lookahead != 0 ||
49
(status != LZMA_STATUS_FINISHED_WITH_MARK &&
50
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
54
res = inStream->Skip((void *)inStream, inProcessed);
60
LzmaDec_FreeProbs(&state, allocMain);
64
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
69
size_t curSize = (1 << 18);
71
curSize = (size_t)inSize;
72
RINOK(inStream->Look((void *)inStream, (void **)&inBuf, &curSize));
74
return SZ_ERROR_INPUT_EOF;
75
memcpy(outBuffer, inBuf, curSize);
78
RINOK(inStream->Skip((void *)inStream, curSize));
83
#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
84
#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
85
#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
86
#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
88
SRes CheckSupportedFolder(const CSzFolder *f)
90
if (f->NumCoders < 1 || f->NumCoders > 4)
91
return SZ_ERROR_UNSUPPORTED;
92
if (IS_UNSUPPORTED_CODER(f->Coders[0]))
93
return SZ_ERROR_UNSUPPORTED;
94
if (f->NumCoders == 1)
96
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
97
return SZ_ERROR_UNSUPPORTED;
100
if (f->NumCoders == 2)
102
if (IS_NO_BCJ(f->Coders[1]) ||
103
f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
104
f->NumBindPairs != 1 ||
105
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
106
return SZ_ERROR_UNSUPPORTED;
109
if (f->NumCoders == 4)
111
if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
112
IS_UNSUPPORTED_CODER(f->Coders[2]) ||
113
IS_NO_BCJ2(f->Coders[3]))
114
return SZ_ERROR_UNSUPPORTED;
115
if (f->NumPackStreams != 4 ||
116
f->PackStreams[0] != 2 ||
117
f->PackStreams[1] != 6 ||
118
f->PackStreams[2] != 1 ||
119
f->PackStreams[3] != 0 ||
120
f->NumBindPairs != 3 ||
121
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
122
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
123
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
124
return SZ_ERROR_UNSUPPORTED;
127
return SZ_ERROR_UNSUPPORTED;
130
UInt64 GetSum(const UInt64 *values, UInt32 index)
134
for (i = 0; i < index; i++)
139
SRes SzDecode2(const UInt64 *packSizes, const CSzFolder *folder,
140
ILookInStream *inStream, UInt64 startPos,
141
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
145
SizeT tempSizes[3] = { 0, 0, 0};
149
RINOK(CheckSupportedFolder(folder));
151
for (ci = 0; ci < folder->NumCoders; ci++)
153
CSzCoderInfo *coder = &folder->Coders[ci];
155
if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
160
Byte *outBufCur = outBuffer;
161
SizeT outSizeCur = outSize;
162
if (folder->NumCoders == 4)
164
UInt32 indices[] = { 3, 2, 0 };
165
UInt64 unpackSize = folder->UnpackSizes[ci];
170
outSizeCur = (SizeT)unpackSize;
171
if (outSizeCur != unpackSize)
173
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
174
if (temp == 0 && outSizeCur != 0)
176
outBufCur = tempBuf[1 - ci] = temp;
177
tempSizes[1 - ci] = outSizeCur;
181
if (unpackSize > outSize) /* check it */
182
return SZ_ERROR_PARAM;
183
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
184
tempSize3 = outSizeCur = (SizeT)unpackSize;
187
return SZ_ERROR_UNSUPPORTED;
189
offset = GetSum(packSizes, si);
190
inSize = packSizes[si];
191
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
193
if (coder->MethodID == k_Copy)
195
if (inSize != outSizeCur) /* check it */
196
return SZ_ERROR_DATA;
197
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
201
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
204
else if (coder->MethodID == k_BCJ)
208
return SZ_ERROR_UNSUPPORTED;
209
x86_Convert_Init(state);
210
x86_Convert(outBuffer, outSize, 0, &state, 0);
212
else if (coder->MethodID == k_BCJ2)
214
UInt64 offset = GetSum(packSizes, 1);
215
UInt64 s3Size = packSizes[1];
218
return SZ_ERROR_UNSUPPORTED;
219
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
220
tempSizes[2] = (SizeT)s3Size;
221
if (tempSizes[2] != s3Size)
223
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
224
if (tempBuf[2] == 0 && tempSizes[2] != 0)
226
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
231
tempBuf[0], tempSizes[0],
232
tempBuf[1], tempSizes[1],
233
tempBuf[2], tempSizes[2],
238
return SZ_ERROR_UNSUPPORTED;
243
SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder,
244
ILookInStream *inStream, UInt64 startPos,
245
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
247
Byte *tempBuf[3] = { 0, 0, 0};
249
SRes res = SzDecode2(packSizes, folder, inStream, startPos,
250
outBuffer, (SizeT)outSize, allocMain, tempBuf);
251
for (i = 0; i < 3; i++)
252
IAlloc_Free(allocMain, tempBuf[i]);