- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / lzma_sdk / 7zDec.c
1 /* 7zDec.c -- Decoding from 7z folder
2 2010-11-02 : Igor Pavlov : Public domain */
3
4 #include <string.h>
5
6 /* #define _7ZIP_PPMD_SUPPPORT */
7
8 #include "7z.h"
9
10 #include "Bcj2.h"
11 #include "Bra.h"
12 #include "CpuArch.h"
13 #include "LzmaDec.h"
14 #include "Lzma2Dec.h"
15 #ifdef _7ZIP_PPMD_SUPPPORT
16 #include "Ppmd7.h"
17 #endif
18
19 #define k_Copy 0
20 #define k_LZMA2 0x21
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
28
29 #ifdef _7ZIP_PPMD_SUPPPORT
30
31 #define k_PPMD 0x30401
32
33 typedef struct
34 {
35   IByteIn p;
36   const Byte *cur;
37   const Byte *end;
38   const Byte *begin;
39   UInt64 processed;
40   Bool extra;
41   SRes res;
42   ILookInStream *inStream;
43 } CByteInToLook;
44
45 static Byte ReadByte(void *pp)
46 {
47   CByteInToLook *p = (CByteInToLook *)pp;
48   if (p->cur != p->end)
49     return *p->cur++;
50   if (p->res == SZ_OK)
51   {
52     size_t size = p->cur - p->begin;
53     p->processed += size;
54     p->res = p->inStream->Skip(p->inStream, size);
55     size = (1 << 25);
56     p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
57     p->cur = p->begin;
58     p->end = p->begin + size;
59     if (size != 0)
60       return *p->cur++;;
61   }
62   p->extra = True;
63   return 0;
64 }
65
66 static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
67     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
68 {
69   CPpmd7 ppmd;
70   CByteInToLook s;
71   SRes res = SZ_OK;
72
73   s.p.Read = ReadByte;
74   s.inStream = inStream;
75   s.begin = s.end = s.cur = NULL;
76   s.extra = False;
77   s.res = SZ_OK;
78   s.processed = 0;
79
80   if (coder->Props.size != 5)
81     return SZ_ERROR_UNSUPPORTED;
82
83   {
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))
93       return SZ_ERROR_MEM;
94     Ppmd7_Init(&ppmd, order);
95   }
96   {
97     CPpmd7z_RangeDec rc;
98     Ppmd7z_RangeDec_CreateVTable(&rc);
99     rc.Stream = &s.p;
100     if (!Ppmd7z_RangeDec_Init(&rc))
101       res = SZ_ERROR_DATA;
102     else if (s.extra)
103       res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
104     else
105     {
106       SizeT i;
107       for (i = 0; i < outSize; i++)
108       {
109         int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
110         if (s.extra || sym < 0)
111           break;
112         outBuffer[i] = (Byte)sym;
113       }
114       if (i != outSize)
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))
117         res = SZ_ERROR_DATA;
118     }
119   }
120   Ppmd7_Free(&ppmd, allocMain);
121   return res;
122 }
123
124 #endif
125
126
127 static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
128     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
129 {
130   CLzmaDec state;
131   SRes res = SZ_OK;
132
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);
138
139   for (;;)
140   {
141     Byte *inBuf = NULL;
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);
146     if (res != SZ_OK)
147       break;
148
149     {
150       SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
151       ELzmaStatus status;
152       res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
153       lookahead -= inProcessed;
154       inSize -= inProcessed;
155       if (res != SZ_OK)
156         break;
157       if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
158       {
159         if (state.dicBufSize != outSize || lookahead != 0 ||
160             (status != LZMA_STATUS_FINISHED_WITH_MARK &&
161              status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
162           res = SZ_ERROR_DATA;
163         break;
164       }
165       res = inStream->Skip((void *)inStream, inProcessed);
166       if (res != SZ_OK)
167         break;
168     }
169   }
170
171   LzmaDec_FreeProbs(&state, allocMain);
172   return res;
173 }
174
175 static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
176     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
177 {
178   CLzma2Dec state;
179   SRes res = SZ_OK;
180
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);
188
189   for (;;)
190   {
191     Byte *inBuf = NULL;
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);
196     if (res != SZ_OK)
197       break;
198
199     {
200       SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
201       ELzmaStatus status;
202       res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
203       lookahead -= inProcessed;
204       inSize -= inProcessed;
205       if (res != SZ_OK)
206         break;
207       if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
208       {
209         if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
210             (status != LZMA_STATUS_FINISHED_WITH_MARK))
211           res = SZ_ERROR_DATA;
212         break;
213       }
214       res = inStream->Skip((void *)inStream, inProcessed);
215       if (res != SZ_OK)
216         break;
217     }
218   }
219
220   Lzma2Dec_FreeProbs(&state, allocMain);
221   return res;
222 }
223
224 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
225 {
226   while (inSize > 0)
227   {
228     void *inBuf;
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));
233     if (curSize == 0)
234       return SZ_ERROR_INPUT_EOF;
235     memcpy(outBuffer, inBuf, curSize);
236     outBuffer += curSize;
237     inSize -= curSize;
238     RINOK(inStream->Skip((void *)inStream, curSize));
239   }
240   return SZ_OK;
241 }
242
243 static Bool IS_MAIN_METHOD(UInt32 m)
244 {
245   switch(m)
246   {
247     case k_Copy:
248     case k_LZMA:
249     case k_LZMA2:
250     #ifdef _7ZIP_PPMD_SUPPPORT
251     case k_PPMD:
252     #endif
253       return True;
254   }
255   return False;
256 }
257
258 static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
259 {
260   return
261       c->NumInStreams == 1 &&
262       c->NumOutStreams == 1 &&
263       c->MethodID <= (UInt32)0xFFFFFFFF &&
264       IS_MAIN_METHOD((UInt32)c->MethodID);
265 }
266
267 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
268
269 static SRes CheckSupportedFolder(const CSzFolder *f)
270 {
271   if (f->NumCoders < 1 || f->NumCoders > 4)
272     return SZ_ERROR_UNSUPPORTED;
273   if (!IS_SUPPORTED_CODER(&f->Coders[0]))
274     return SZ_ERROR_UNSUPPORTED;
275   if (f->NumCoders == 1)
276   {
277     if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
278       return SZ_ERROR_UNSUPPORTED;
279     return SZ_OK;
280   }
281   if (f->NumCoders == 2)
282   {
283     CSzCoderInfo *c = &f->Coders[1];
284     if (c->MethodID > (UInt32)0xFFFFFFFF ||
285         c->NumInStreams != 1 ||
286         c->NumOutStreams != 1 ||
287         f->NumPackStreams != 1 ||
288         f->PackStreams[0] != 0 ||
289         f->NumBindPairs != 1 ||
290         f->BindPairs[0].InIndex != 1 ||
291         f->BindPairs[0].OutIndex != 0)
292       return SZ_ERROR_UNSUPPORTED;
293     switch ((UInt32)c->MethodID)
294     {
295       case k_BCJ:
296       case k_ARM:
297         break;
298       default:
299         return SZ_ERROR_UNSUPPORTED;
300     }
301     return SZ_OK;
302   }
303   if (f->NumCoders == 4)
304   {
305     if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
306         !IS_SUPPORTED_CODER(&f->Coders[2]) ||
307         !IS_BCJ2(&f->Coders[3]))
308       return SZ_ERROR_UNSUPPORTED;
309     if (f->NumPackStreams != 4 ||
310         f->PackStreams[0] != 2 ||
311         f->PackStreams[1] != 6 ||
312         f->PackStreams[2] != 1 ||
313         f->PackStreams[3] != 0 ||
314         f->NumBindPairs != 3 ||
315         f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
316         f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
317         f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
318       return SZ_ERROR_UNSUPPORTED;
319     return SZ_OK;
320   }
321   return SZ_ERROR_UNSUPPORTED;
322 }
323
324 static UInt64 GetSum(const UInt64 *values, UInt32 index)
325 {
326   UInt64 sum = 0;
327   UInt32 i;
328   for (i = 0; i < index; i++)
329     sum += values[i];
330   return sum;
331 }
332
333 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
334
335 static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
336     ILookInStream *inStream, UInt64 startPos,
337     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
338     Byte *tempBuf[])
339 {
340   UInt32 ci;
341   SizeT tempSizes[3] = { 0, 0, 0};
342   SizeT tempSize3 = 0;
343   Byte *tempBuf3 = 0;
344
345   RINOK(CheckSupportedFolder(folder));
346
347   for (ci = 0; ci < folder->NumCoders; ci++)
348   {
349     CSzCoderInfo *coder = &folder->Coders[ci];
350
351     if (IS_MAIN_METHOD((UInt32)coder->MethodID))
352     {
353       UInt32 si = 0;
354       UInt64 offset;
355       UInt64 inSize;
356       Byte *outBufCur = outBuffer;
357       SizeT outSizeCur = outSize;
358       if (folder->NumCoders == 4)
359       {
360         UInt32 indices[] = { 3, 2, 0 };
361         UInt64 unpackSize = folder->UnpackSizes[ci];
362         si = indices[ci];
363         if (ci < 2)
364         {
365           Byte *temp;
366           outSizeCur = (SizeT)unpackSize;
367           if (outSizeCur != unpackSize)
368             return SZ_ERROR_MEM;
369           temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
370           if (temp == 0 && outSizeCur != 0)
371             return SZ_ERROR_MEM;
372           outBufCur = tempBuf[1 - ci] = temp;
373           tempSizes[1 - ci] = outSizeCur;
374         }
375         else if (ci == 2)
376         {
377           if (unpackSize > outSize) /* check it */
378             return SZ_ERROR_PARAM;
379           tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
380           tempSize3 = outSizeCur = (SizeT)unpackSize;
381         }
382         else
383           return SZ_ERROR_UNSUPPORTED;
384       }
385       offset = GetSum(packSizes, si);
386       inSize = packSizes[si];
387       RINOK(LookInStream_SeekTo(inStream, startPos + offset));
388
389       if (coder->MethodID == k_Copy)
390       {
391         if (inSize != outSizeCur) /* check it */
392           return SZ_ERROR_DATA;
393         RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
394       }
395       else if (coder->MethodID == k_LZMA)
396       {
397         RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
398       }
399       else if (coder->MethodID == k_LZMA2)
400       {
401         RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
402       }
403       else
404       {
405         #ifdef _7ZIP_PPMD_SUPPPORT
406         RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
407         #else
408         return SZ_ERROR_UNSUPPORTED;
409         #endif
410       }
411     }
412     else if (coder->MethodID == k_BCJ2)
413     {
414       UInt64 offset = GetSum(packSizes, 1);
415       UInt64 s3Size = packSizes[1];
416       SRes res;
417       if (ci != 3)
418         return SZ_ERROR_UNSUPPORTED;
419       RINOK(LookInStream_SeekTo(inStream, startPos + offset));
420       tempSizes[2] = (SizeT)s3Size;
421       if (tempSizes[2] != s3Size)
422         return SZ_ERROR_MEM;
423       tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
424       if (tempBuf[2] == 0 && tempSizes[2] != 0)
425         return SZ_ERROR_MEM;
426       res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
427       RINOK(res)
428
429       res = Bcj2_Decode(
430           tempBuf3, tempSize3,
431           tempBuf[0], tempSizes[0],
432           tempBuf[1], tempSizes[1],
433           tempBuf[2], tempSizes[2],
434           outBuffer, outSize);
435       RINOK(res)
436     }
437     else
438     {
439       if (ci != 1)
440         return SZ_ERROR_UNSUPPORTED;
441       switch(coder->MethodID)
442       {
443         case k_BCJ:
444         {
445           UInt32 state;
446           x86_Convert_Init(state);
447           x86_Convert(outBuffer, outSize, 0, &state, 0);
448           break;
449         }
450         CASE_BRA_CONV(ARM)
451         default:
452           return SZ_ERROR_UNSUPPORTED;
453       }
454     }
455   }
456   return SZ_OK;
457 }
458
459 SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
460     ILookInStream *inStream, UInt64 startPos,
461     Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
462 {
463   Byte *tempBuf[3] = { 0, 0, 0};
464   int i;
465   SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
466       outBuffer, (SizeT)outSize, allocMain, tempBuf);
467   for (i = 0; i < 3; i++)
468     IAlloc_Free(allocMain, tempBuf[i]);
469   return res;
470 }