tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

7zDec.c (15816B)


      1 /* 7zDec.c -- Decoding from 7z folder
      2 2017-04-03 : 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 
     40 typedef struct
     41 {
     42  IByteIn vt;
     43  const Byte *cur;
     44  const Byte *end;
     45  const Byte *begin;
     46  UInt64 processed;
     47  Bool extra;
     48  SRes res;
     49  const ILookInStream *inStream;
     50 } CByteInToLook;
     51 
     52 static 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 
     73 static 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 
    134 static 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, 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 
    194 static 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, 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 
    253 static 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 
    272 static Bool 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 
    289 static Bool 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 
    299 static 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 
    370 static 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 
    549 SRes 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 }