|
1 /* 7zDecode.c */ |
|
2 |
|
3 #include <memory.h> |
|
4 |
|
5 /* BEGIN PHYSFS CHANGE */ |
|
6 #include <string.h> |
|
7 /* END PHYSFS CHANGE */ |
|
8 |
|
9 #include "7zDecode.h" |
|
10 #ifdef _SZ_ONE_DIRECTORY |
|
11 #include "LzmaDecode.h" |
|
12 #else |
|
13 #include "../../Compress/Lzma/LzmaDecode.h" |
|
14 #include "../../Compress/Branch/BranchX86.h" |
|
15 #include "../../Compress/Branch/BranchX86_2.h" |
|
16 #endif |
|
17 |
|
18 #define k_Copy 0 |
|
19 #define k_LZMA 0x30101 |
|
20 #define k_BCJ 0x03030103 |
|
21 #define k_BCJ2 0x0303011B |
|
22 |
|
23 #ifdef _LZMA_IN_CB |
|
24 |
|
25 typedef struct _CLzmaInCallbackImp |
|
26 { |
|
27 ILzmaInCallback InCallback; |
|
28 ISzInStream *InStream; |
|
29 CFileSize Size; |
|
30 } CLzmaInCallbackImp; |
|
31 |
|
32 int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size) |
|
33 { |
|
34 CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object; |
|
35 size_t processedSize; |
|
36 SZ_RESULT res; |
|
37 size_t curSize = (1 << 20); |
|
38 if (curSize > cb->Size) |
|
39 curSize = (size_t)cb->Size; |
|
40 *size = 0; |
|
41 res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, curSize, &processedSize); |
|
42 *size = (SizeT)processedSize; |
|
43 if (processedSize > curSize) |
|
44 return (int)SZE_FAIL; |
|
45 cb->Size -= processedSize; |
|
46 if (res == SZ_OK) |
|
47 return 0; |
|
48 return (int)res; |
|
49 } |
|
50 |
|
51 #endif |
|
52 |
|
53 SZ_RESULT SzDecodeLzma(CCoderInfo *coder, CFileSize inSize, |
|
54 #ifdef _LZMA_IN_CB |
|
55 ISzInStream *inStream, |
|
56 #else |
|
57 const Byte *inBuffer, |
|
58 #endif |
|
59 Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) |
|
60 { |
|
61 #ifdef _LZMA_IN_CB |
|
62 CLzmaInCallbackImp lzmaCallback; |
|
63 #else |
|
64 SizeT inProcessed; |
|
65 #endif |
|
66 |
|
67 CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */ |
|
68 int result; |
|
69 SizeT outSizeProcessedLoc; |
|
70 |
|
71 #ifdef _LZMA_IN_CB |
|
72 lzmaCallback.Size = inSize; |
|
73 lzmaCallback.InStream = inStream; |
|
74 lzmaCallback.InCallback.Read = LzmaReadImp; |
|
75 #endif |
|
76 |
|
77 if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items, |
|
78 (unsigned)coder->Properties.Capacity) != LZMA_RESULT_OK) |
|
79 return SZE_FAIL; |
|
80 |
|
81 state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); |
|
82 if (state.Probs == 0) |
|
83 return SZE_OUTOFMEMORY; |
|
84 |
|
85 #ifdef _LZMA_OUT_READ |
|
86 if (state.Properties.DictionarySize == 0) |
|
87 state.Dictionary = 0; |
|
88 else |
|
89 { |
|
90 state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize); |
|
91 if (state.Dictionary == 0) |
|
92 { |
|
93 allocMain->Free(state.Probs); |
|
94 return SZE_OUTOFMEMORY; |
|
95 } |
|
96 } |
|
97 LzmaDecoderInit(&state); |
|
98 #endif |
|
99 |
|
100 result = LzmaDecode(&state, |
|
101 #ifdef _LZMA_IN_CB |
|
102 &lzmaCallback.InCallback, |
|
103 #else |
|
104 inBuffer, (SizeT)inSize, &inProcessed, |
|
105 #endif |
|
106 outBuffer, (SizeT)outSize, &outSizeProcessedLoc); |
|
107 allocMain->Free(state.Probs); |
|
108 #ifdef _LZMA_OUT_READ |
|
109 allocMain->Free(state.Dictionary); |
|
110 #endif |
|
111 if (result == LZMA_RESULT_DATA_ERROR) |
|
112 return SZE_DATA_ERROR; |
|
113 if (result != LZMA_RESULT_OK) |
|
114 return SZE_FAIL; |
|
115 return (outSizeProcessedLoc == outSize) ? SZ_OK : SZE_DATA_ERROR; |
|
116 } |
|
117 |
|
118 #ifdef _LZMA_IN_CB |
|
119 SZ_RESULT SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer) |
|
120 { |
|
121 while (inSize > 0) |
|
122 { |
|
123 void *inBuffer; |
|
124 size_t processedSize, curSize = (1 << 18); |
|
125 if (curSize > inSize) |
|
126 curSize = (size_t)(inSize); |
|
127 RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, curSize, &processedSize)); |
|
128 if (processedSize == 0) |
|
129 return SZE_DATA_ERROR; |
|
130 if (processedSize > curSize) |
|
131 return SZE_FAIL; |
|
132 memcpy(outBuffer, inBuffer, processedSize); |
|
133 outBuffer += processedSize; |
|
134 inSize -= processedSize; |
|
135 } |
|
136 return SZ_OK; |
|
137 } |
|
138 #endif |
|
139 |
|
140 #define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA) |
|
141 #define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1) |
|
142 #define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1) |
|
143 #define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1) |
|
144 |
|
145 SZ_RESULT CheckSupportedFolder(const CFolder *f) |
|
146 { |
|
147 if (f->NumCoders < 1 || f->NumCoders > 4) |
|
148 return SZE_NOTIMPL; |
|
149 if (IS_UNSUPPORTED_CODER(f->Coders[0])) |
|
150 return SZE_NOTIMPL; |
|
151 if (f->NumCoders == 1) |
|
152 { |
|
153 if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) |
|
154 return SZE_NOTIMPL; |
|
155 return SZ_OK; |
|
156 } |
|
157 if (f->NumCoders == 2) |
|
158 { |
|
159 if (IS_NO_BCJ(f->Coders[1]) || |
|
160 f->NumPackStreams != 1 || f->PackStreams[0] != 0 || |
|
161 f->NumBindPairs != 1 || |
|
162 f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0) |
|
163 return SZE_NOTIMPL; |
|
164 return SZ_OK; |
|
165 } |
|
166 if (f->NumCoders == 4) |
|
167 { |
|
168 if (IS_UNSUPPORTED_CODER(f->Coders[1]) || |
|
169 IS_UNSUPPORTED_CODER(f->Coders[2]) || |
|
170 IS_NO_BCJ2(f->Coders[3])) |
|
171 return SZE_NOTIMPL; |
|
172 if (f->NumPackStreams != 4 || |
|
173 f->PackStreams[0] != 2 || |
|
174 f->PackStreams[1] != 6 || |
|
175 f->PackStreams[2] != 1 || |
|
176 f->PackStreams[3] != 0 || |
|
177 f->NumBindPairs != 3 || |
|
178 f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || |
|
179 f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || |
|
180 f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) |
|
181 return SZE_NOTIMPL; |
|
182 return SZ_OK; |
|
183 } |
|
184 return SZE_NOTIMPL; |
|
185 } |
|
186 |
|
187 CFileSize GetSum(const CFileSize *values, UInt32 index) |
|
188 { |
|
189 CFileSize sum = 0; |
|
190 UInt32 i; |
|
191 for (i = 0; i < index; i++) |
|
192 sum += values[i]; |
|
193 return sum; |
|
194 } |
|
195 |
|
196 SZ_RESULT SzDecode2(const CFileSize *packSizes, const CFolder *folder, |
|
197 #ifdef _LZMA_IN_CB |
|
198 ISzInStream *inStream, CFileSize startPos, |
|
199 #else |
|
200 const Byte *inBuffer, |
|
201 #endif |
|
202 Byte *outBuffer, size_t outSize, ISzAlloc *allocMain, |
|
203 Byte *tempBuf[]) |
|
204 { |
|
205 UInt32 ci; |
|
206 size_t tempSizes[3] = { 0, 0, 0}; |
|
207 size_t tempSize3 = 0; |
|
208 Byte *tempBuf3 = 0; |
|
209 |
|
210 RINOK(CheckSupportedFolder(folder)); |
|
211 |
|
212 for (ci = 0; ci < folder->NumCoders; ci++) |
|
213 { |
|
214 CCoderInfo *coder = &folder->Coders[ci]; |
|
215 |
|
216 if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA) |
|
217 { |
|
218 UInt32 si = 0; |
|
219 CFileSize offset; |
|
220 CFileSize inSize; |
|
221 Byte *outBufCur = outBuffer; |
|
222 size_t outSizeCur = outSize; |
|
223 if (folder->NumCoders == 4) |
|
224 { |
|
225 UInt32 indices[] = { 3, 2, 0 }; |
|
226 CFileSize unpackSize = folder->UnPackSizes[ci]; |
|
227 si = indices[ci]; |
|
228 if (ci < 2) |
|
229 { |
|
230 Byte *temp; |
|
231 outSizeCur = (size_t)unpackSize; |
|
232 if (outSizeCur != unpackSize) |
|
233 return SZE_OUTOFMEMORY; |
|
234 temp = (Byte *)allocMain->Alloc(outSizeCur); |
|
235 if (temp == 0 && outSizeCur != 0) |
|
236 return SZE_OUTOFMEMORY; |
|
237 outBufCur = tempBuf[1 - ci] = temp; |
|
238 tempSizes[1 - ci] = outSizeCur; |
|
239 } |
|
240 else if (ci == 2) |
|
241 { |
|
242 if (unpackSize > outSize) |
|
243 return SZE_OUTOFMEMORY; |
|
244 tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); |
|
245 tempSize3 = outSizeCur = (size_t)unpackSize; |
|
246 } |
|
247 else |
|
248 return SZE_NOTIMPL; |
|
249 } |
|
250 offset = GetSum(packSizes, si); |
|
251 inSize = packSizes[si]; |
|
252 #ifdef _LZMA_IN_CB |
|
253 RINOK(inStream->Seek(inStream, startPos + offset)); |
|
254 #endif |
|
255 |
|
256 if (coder->MethodID == k_Copy) |
|
257 { |
|
258 if (inSize != outSizeCur) |
|
259 return SZE_DATA_ERROR; |
|
260 |
|
261 #ifdef _LZMA_IN_CB |
|
262 RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); |
|
263 #else |
|
264 memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize); |
|
265 #endif |
|
266 } |
|
267 else |
|
268 { |
|
269 SZ_RESULT res = SzDecodeLzma(coder, inSize, |
|
270 #ifdef _LZMA_IN_CB |
|
271 inStream, |
|
272 #else |
|
273 inBuffer + (size_t)offset, |
|
274 #endif |
|
275 outBufCur, outSizeCur, allocMain); |
|
276 RINOK(res) |
|
277 } |
|
278 } |
|
279 else if (coder->MethodID == k_BCJ) |
|
280 { |
|
281 UInt32 state; |
|
282 if (ci != 1) |
|
283 return SZE_NOTIMPL; |
|
284 x86_Convert_Init(state); |
|
285 x86_Convert(outBuffer, outSize, 0, &state, 0); |
|
286 } |
|
287 else if (coder->MethodID == k_BCJ2) |
|
288 { |
|
289 CFileSize offset = GetSum(packSizes, 1); |
|
290 CFileSize s3Size = packSizes[1]; |
|
291 SZ_RESULT res; |
|
292 if (ci != 3) |
|
293 return SZE_NOTIMPL; |
|
294 |
|
295 #ifdef _LZMA_IN_CB |
|
296 RINOK(inStream->Seek(inStream, startPos + offset)); |
|
297 tempSizes[2] = (size_t)s3Size; |
|
298 if (tempSizes[2] != s3Size) |
|
299 return SZE_OUTOFMEMORY; |
|
300 tempBuf[2] = (Byte *)allocMain->Alloc(tempSizes[2]); |
|
301 if (tempBuf[2] == 0 && tempSizes[2] != 0) |
|
302 return SZE_OUTOFMEMORY; |
|
303 res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); |
|
304 RINOK(res) |
|
305 #endif |
|
306 |
|
307 res = x86_2_Decode( |
|
308 tempBuf3, tempSize3, |
|
309 tempBuf[0], tempSizes[0], |
|
310 tempBuf[1], tempSizes[1], |
|
311 #ifdef _LZMA_IN_CB |
|
312 tempBuf[2], tempSizes[2], |
|
313 #else |
|
314 inBuffer + (size_t)offset, (size_t)s3Size, |
|
315 #endif |
|
316 outBuffer, outSize); |
|
317 RINOK(res) |
|
318 } |
|
319 else |
|
320 return SZE_NOTIMPL; |
|
321 } |
|
322 return SZ_OK; |
|
323 } |
|
324 |
|
325 SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder, |
|
326 #ifdef _LZMA_IN_CB |
|
327 ISzInStream *inStream, CFileSize startPos, |
|
328 #else |
|
329 const Byte *inBuffer, |
|
330 #endif |
|
331 Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) |
|
332 { |
|
333 Byte *tempBuf[3] = { 0, 0, 0}; |
|
334 int i; |
|
335 SZ_RESULT res = SzDecode2(packSizes, folder, |
|
336 #ifdef _LZMA_IN_CB |
|
337 inStream, startPos, |
|
338 #else |
|
339 inBuffer, |
|
340 #endif |
|
341 outBuffer, outSize, allocMain, tempBuf); |
|
342 for (i = 0; i < 3; i++) |
|
343 allocMain->Free(tempBuf[i]); |
|
344 return res; |
|
345 } |