all repos — mgba @ b2d406a411b31acce5bbf0246af32a80c22ca834

mGBA Game Boy Advance Emulator

src/third-party/lzma/7zDec.c (view raw)

  1/* 7zDec.c -- Decoding from 7z folder
  22019-02-02 : Igor Pavlov : Public domain */
  3
  4#include "Precomp.h"
  5
  6#include <string.h>
  7
  8/* #define _7ZIP_PPMD_SUPPPORT */
  9
 10#include "7z.h"
 11#include "7zCrc.h"
 12
 13#include "Bcj2.h"
 14#include "Bra.h"
 15#include "CpuArch.h"
 16#include "Delta.h"
 17#include "LzmaDec.h"
 18#include "Lzma2Dec.h"
 19#ifdef _7ZIP_PPMD_SUPPPORT
 20#include "Ppmd7.h"
 21#endif
 22
 23#define k_Copy 0
 24#define k_Delta 3
 25#define k_LZMA2 0x21
 26#define k_LZMA  0x30101
 27#define k_BCJ   0x3030103
 28#define k_BCJ2  0x303011B
 29#define k_PPC   0x3030205
 30#define k_IA64  0x3030401
 31#define k_ARM   0x3030501
 32#define k_ARMT  0x3030701
 33#define k_SPARC 0x3030805
 34
 35
 36#ifdef _7ZIP_PPMD_SUPPPORT
 37
 38#define k_PPMD 0x30401
 39
 40typedef struct
 41{
 42  IByteIn vt;
 43  const Byte *cur;
 44  const Byte *end;
 45  const Byte *begin;
 46  UInt64 processed;
 47  BoolInt extra;
 48  SRes res;
 49  const ILookInStream *inStream;
 50} CByteInToLook;
 51
 52static Byte ReadByte(const IByteIn *pp)
 53{
 54  CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt);
 55  if (p->cur != p->end)
 56    return *p->cur++;
 57  if (p->res == SZ_OK)
 58  {
 59    size_t size = p->cur - p->begin;
 60    p->processed += size;
 61    p->res = ILookInStream_Skip(p->inStream, size);
 62    size = (1 << 25);
 63    p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
 64    p->cur = p->begin;
 65    p->end = p->begin + size;
 66    if (size != 0)
 67      return *p->cur++;;
 68  }
 69  p->extra = True;
 70  return 0;
 71}
 72
 73static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream,
 74    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
 75{
 76  CPpmd7 ppmd;
 77  CByteInToLook s;
 78  SRes res = SZ_OK;
 79
 80  s.vt.Read = ReadByte;
 81  s.inStream = inStream;
 82  s.begin = s.end = s.cur = NULL;
 83  s.extra = False;
 84  s.res = SZ_OK;
 85  s.processed = 0;
 86
 87  if (propsSize != 5)
 88    return SZ_ERROR_UNSUPPORTED;
 89
 90  {
 91    unsigned order = props[0];
 92    UInt32 memSize = GetUi32(props + 1);
 93    if (order < PPMD7_MIN_ORDER ||
 94        order > PPMD7_MAX_ORDER ||
 95        memSize < PPMD7_MIN_MEM_SIZE ||
 96        memSize > PPMD7_MAX_MEM_SIZE)
 97      return SZ_ERROR_UNSUPPORTED;
 98    Ppmd7_Construct(&ppmd);
 99    if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
100      return SZ_ERROR_MEM;
101    Ppmd7_Init(&ppmd, order);
102  }
103  {
104    CPpmd7z_RangeDec rc;
105    Ppmd7z_RangeDec_CreateVTable(&rc);
106    rc.Stream = &s.vt;
107    if (!Ppmd7z_RangeDec_Init(&rc))
108      res = SZ_ERROR_DATA;
109    else if (s.extra)
110      res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
111    else
112    {
113      SizeT i;
114      for (i = 0; i < outSize; i++)
115      {
116        int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt);
117        if (s.extra || sym < 0)
118          break;
119        outBuffer[i] = (Byte)sym;
120      }
121      if (i != outSize)
122        res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
123      else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
124        res = SZ_ERROR_DATA;
125    }
126  }
127  Ppmd7_Free(&ppmd, allocMain);
128  return res;
129}
130
131#endif
132
133
134static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
135    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
136{
137  CLzmaDec state;
138  SRes res = SZ_OK;
139
140  LzmaDec_Construct(&state);
141  RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
142  state.dic = outBuffer;
143  state.dicBufSize = outSize;
144  LzmaDec_Init(&state);
145
146  for (;;)
147  {
148    const void *inBuf = NULL;
149    size_t lookahead = (1 << 18);
150    if (lookahead > inSize)
151      lookahead = (size_t)inSize;
152    res = ILookInStream_Look(inStream, &inBuf, &lookahead);
153    if (res != SZ_OK)
154      break;
155
156    {
157      SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
158      ELzmaStatus status;
159      res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
160      lookahead -= inProcessed;
161      inSize -= inProcessed;
162      if (res != SZ_OK)
163        break;
164
165      if (status == LZMA_STATUS_FINISHED_WITH_MARK)
166      {
167        if (outSize != state.dicPos || inSize != 0)
168          res = SZ_ERROR_DATA;
169        break;
170      }
171
172      if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
173        break;
174
175      if (inProcessed == 0 && dicPos == state.dicPos)
176      {
177        res = SZ_ERROR_DATA;
178        break;
179      }
180
181      res = ILookInStream_Skip(inStream, inProcessed);
182      if (res != SZ_OK)
183        break;
184    }
185  }
186
187  LzmaDec_FreeProbs(&state, allocMain);
188  return res;
189}
190
191
192#ifndef _7Z_NO_METHOD_LZMA2
193
194static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
195    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
196{
197  CLzma2Dec state;
198  SRes res = SZ_OK;
199
200  Lzma2Dec_Construct(&state);
201  if (propsSize != 1)
202    return SZ_ERROR_DATA;
203  RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
204  state.decoder.dic = outBuffer;
205  state.decoder.dicBufSize = outSize;
206  Lzma2Dec_Init(&state);
207
208  for (;;)
209  {
210    const void *inBuf = NULL;
211    size_t lookahead = (1 << 18);
212    if (lookahead > inSize)
213      lookahead = (size_t)inSize;
214    res = ILookInStream_Look(inStream, &inBuf, &lookahead);
215    if (res != SZ_OK)
216      break;
217
218    {
219      SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
220      ELzmaStatus status;
221      res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
222      lookahead -= inProcessed;
223      inSize -= inProcessed;
224      if (res != SZ_OK)
225        break;
226
227      if (status == LZMA_STATUS_FINISHED_WITH_MARK)
228      {
229        if (outSize != state.decoder.dicPos || inSize != 0)
230          res = SZ_ERROR_DATA;
231        break;
232      }
233
234      if (inProcessed == 0 && dicPos == state.decoder.dicPos)
235      {
236        res = SZ_ERROR_DATA;
237        break;
238      }
239
240      res = ILookInStream_Skip(inStream, inProcessed);
241      if (res != SZ_OK)
242        break;
243    }
244  }
245
246  Lzma2Dec_FreeProbs(&state, allocMain);
247  return res;
248}
249
250#endif
251
252
253static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
254{
255  while (inSize > 0)
256  {
257    const void *inBuf;
258    size_t curSize = (1 << 18);
259    if (curSize > inSize)
260      curSize = (size_t)inSize;
261    RINOK(ILookInStream_Look(inStream, &inBuf, &curSize));
262    if (curSize == 0)
263      return SZ_ERROR_INPUT_EOF;
264    memcpy(outBuffer, inBuf, curSize);
265    outBuffer += curSize;
266    inSize -= curSize;
267    RINOK(ILookInStream_Skip(inStream, curSize));
268  }
269  return SZ_OK;
270}
271
272static BoolInt IS_MAIN_METHOD(UInt32 m)
273{
274  switch (m)
275  {
276    case k_Copy:
277    case k_LZMA:
278    #ifndef _7Z_NO_METHOD_LZMA2
279    case k_LZMA2:
280    #endif
281    #ifdef _7ZIP_PPMD_SUPPPORT
282    case k_PPMD:
283    #endif
284      return True;
285  }
286  return False;
287}
288
289static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
290{
291  return
292      c->NumStreams == 1
293      /* && c->MethodID <= (UInt32)0xFFFFFFFF */
294      && IS_MAIN_METHOD((UInt32)c->MethodID);
295}
296
297#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
298
299static SRes CheckSupportedFolder(const CSzFolder *f)
300{
301  if (f->NumCoders < 1 || f->NumCoders > 4)
302    return SZ_ERROR_UNSUPPORTED;
303  if (!IS_SUPPORTED_CODER(&f->Coders[0]))
304    return SZ_ERROR_UNSUPPORTED;
305  if (f->NumCoders == 1)
306  {
307    if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
308      return SZ_ERROR_UNSUPPORTED;
309    return SZ_OK;
310  }
311  
312  
313  #ifndef _7Z_NO_METHODS_FILTERS
314
315  if (f->NumCoders == 2)
316  {
317    const CSzCoderInfo *c = &f->Coders[1];
318    if (
319        /* c->MethodID > (UInt32)0xFFFFFFFF || */
320        c->NumStreams != 1
321        || f->NumPackStreams != 1
322        || f->PackStreams[0] != 0
323        || f->NumBonds != 1
324        || f->Bonds[0].InIndex != 1
325        || f->Bonds[0].OutIndex != 0)
326      return SZ_ERROR_UNSUPPORTED;
327    switch ((UInt32)c->MethodID)
328    {
329      case k_Delta:
330      case k_BCJ:
331      case k_PPC:
332      case k_IA64:
333      case k_SPARC:
334      case k_ARM:
335      case k_ARMT:
336        break;
337      default:
338        return SZ_ERROR_UNSUPPORTED;
339    }
340    return SZ_OK;
341  }
342
343  #endif
344
345  
346  if (f->NumCoders == 4)
347  {
348    if (!IS_SUPPORTED_CODER(&f->Coders[1])
349        || !IS_SUPPORTED_CODER(&f->Coders[2])
350        || !IS_BCJ2(&f->Coders[3]))
351      return SZ_ERROR_UNSUPPORTED;
352    if (f->NumPackStreams != 4
353        || f->PackStreams[0] != 2
354        || f->PackStreams[1] != 6
355        || f->PackStreams[2] != 1
356        || f->PackStreams[3] != 0
357        || f->NumBonds != 3
358        || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
359        || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
360        || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
361      return SZ_ERROR_UNSUPPORTED;
362    return SZ_OK;
363  }
364  
365  return SZ_ERROR_UNSUPPORTED;
366}
367
368#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
369
370static SRes SzFolder_Decode2(const CSzFolder *folder,
371    const Byte *propsData,
372    const UInt64 *unpackSizes,
373    const UInt64 *packPositions,
374    ILookInStream *inStream, UInt64 startPos,
375    Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
376    Byte *tempBuf[])
377{
378  UInt32 ci;
379  SizeT tempSizes[3] = { 0, 0, 0};
380  SizeT tempSize3 = 0;
381  Byte *tempBuf3 = 0;
382
383  RINOK(CheckSupportedFolder(folder));
384
385  for (ci = 0; ci < folder->NumCoders; ci++)
386  {
387    const CSzCoderInfo *coder = &folder->Coders[ci];
388
389    if (IS_MAIN_METHOD((UInt32)coder->MethodID))
390    {
391      UInt32 si = 0;
392      UInt64 offset;
393      UInt64 inSize;
394      Byte *outBufCur = outBuffer;
395      SizeT outSizeCur = outSize;
396      if (folder->NumCoders == 4)
397      {
398        UInt32 indices[] = { 3, 2, 0 };
399        UInt64 unpackSize = unpackSizes[ci];
400        si = indices[ci];
401        if (ci < 2)
402        {
403          Byte *temp;
404          outSizeCur = (SizeT)unpackSize;
405          if (outSizeCur != unpackSize)
406            return SZ_ERROR_MEM;
407          temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
408          if (!temp && outSizeCur != 0)
409            return SZ_ERROR_MEM;
410          outBufCur = tempBuf[1 - ci] = temp;
411          tempSizes[1 - ci] = outSizeCur;
412        }
413        else if (ci == 2)
414        {
415          if (unpackSize > outSize) /* check it */
416            return SZ_ERROR_PARAM;
417          tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
418          tempSize3 = outSizeCur = (SizeT)unpackSize;
419        }
420        else
421          return SZ_ERROR_UNSUPPORTED;
422      }
423      offset = packPositions[si];
424      inSize = packPositions[(size_t)si + 1] - offset;
425      RINOK(LookInStream_SeekTo(inStream, startPos + offset));
426
427      if (coder->MethodID == k_Copy)
428      {
429        if (inSize != outSizeCur) /* check it */
430          return SZ_ERROR_DATA;
431        RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
432      }
433      else if (coder->MethodID == k_LZMA)
434      {
435        RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
436      }
437      #ifndef _7Z_NO_METHOD_LZMA2
438      else if (coder->MethodID == k_LZMA2)
439      {
440        RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
441      }
442      #endif
443      #ifdef _7ZIP_PPMD_SUPPPORT
444      else if (coder->MethodID == k_PPMD)
445      {
446        RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
447      }
448      #endif
449      else
450        return SZ_ERROR_UNSUPPORTED;
451    }
452    else if (coder->MethodID == k_BCJ2)
453    {
454      UInt64 offset = packPositions[1];
455      UInt64 s3Size = packPositions[2] - offset;
456      
457      if (ci != 3)
458        return SZ_ERROR_UNSUPPORTED;
459      
460      tempSizes[2] = (SizeT)s3Size;
461      if (tempSizes[2] != s3Size)
462        return SZ_ERROR_MEM;
463      tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
464      if (!tempBuf[2] && tempSizes[2] != 0)
465        return SZ_ERROR_MEM;
466      
467      RINOK(LookInStream_SeekTo(inStream, startPos + offset));
468      RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
469
470      if ((tempSizes[0] & 3) != 0 ||
471          (tempSizes[1] & 3) != 0 ||
472          tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
473        return SZ_ERROR_DATA;
474
475      {
476        CBcj2Dec p;
477        
478        p.bufs[0] = tempBuf3;   p.lims[0] = tempBuf3 + tempSize3;
479        p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
480        p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
481        p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
482        
483        p.dest = outBuffer;
484        p.destLim = outBuffer + outSize;
485        
486        Bcj2Dec_Init(&p);
487        RINOK(Bcj2Dec_Decode(&p));
488
489        {
490          unsigned i;
491          for (i = 0; i < 4; i++)
492            if (p.bufs[i] != p.lims[i])
493              return SZ_ERROR_DATA;
494          
495          if (!Bcj2Dec_IsFinished(&p))
496            return SZ_ERROR_DATA;
497
498          if (p.dest != p.destLim
499             || p.state != BCJ2_STREAM_MAIN)
500            return SZ_ERROR_DATA;
501        }
502      }
503    }
504    #ifndef _7Z_NO_METHODS_FILTERS
505    else if (ci == 1)
506    {
507      if (coder->MethodID == k_Delta)
508      {
509        if (coder->PropsSize != 1)
510          return SZ_ERROR_UNSUPPORTED;
511        {
512          Byte state[DELTA_STATE_SIZE];
513          Delta_Init(state);
514          Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
515        }
516      }
517      else
518      {
519        if (coder->PropsSize != 0)
520          return SZ_ERROR_UNSUPPORTED;
521        switch (coder->MethodID)
522        {
523          case k_BCJ:
524          {
525            UInt32 state;
526            x86_Convert_Init(state);
527            x86_Convert(outBuffer, outSize, 0, &state, 0);
528            break;
529          }
530          CASE_BRA_CONV(PPC)
531          CASE_BRA_CONV(IA64)
532          CASE_BRA_CONV(SPARC)
533          CASE_BRA_CONV(ARM)
534          CASE_BRA_CONV(ARMT)
535          default:
536            return SZ_ERROR_UNSUPPORTED;
537        }
538      }
539    }
540    #endif
541    else
542      return SZ_ERROR_UNSUPPORTED;
543  }
544
545  return SZ_OK;
546}
547
548
549SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
550    ILookInStream *inStream, UInt64 startPos,
551    Byte *outBuffer, size_t outSize,
552    ISzAllocPtr allocMain)
553{
554  SRes res;
555  CSzFolder folder;
556  CSzData sd;
557  
558  const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
559  sd.Data = data;
560  sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
561  
562  res = SzGetNextFolderItem(&folder, &sd);
563  
564  if (res != SZ_OK)
565    return res;
566
567  if (sd.Size != 0
568      || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
569      || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
570    return SZ_ERROR_FAIL;
571  {
572    unsigned i;
573    Byte *tempBuf[3] = { 0, 0, 0};
574
575    res = SzFolder_Decode2(&folder, data,
576        &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
577        p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
578        inStream, startPos,
579        outBuffer, (SizeT)outSize, allocMain, tempBuf);
580    
581    for (i = 0; i < 3; i++)
582      ISzAlloc_Free(allocMain, tempBuf[i]);
583
584    if (res == SZ_OK)
585      if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
586        if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
587          res = SZ_ERROR_CRC;
588
589    return res;
590  }
591}