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