Home | History | Annotate | Download | only in C
      1 /* 7zDec.c -- Decoding from 7z folder
      2 2014-06-16 : 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 
     12 #include "Bcj2.h"
     13 #include "Bra.h"
     14 #include "CpuArch.h"
     15 #include "LzmaDec.h"
     16 #include "Lzma2Dec.h"
     17 #ifdef _7ZIP_PPMD_SUPPPORT
     18 #include "Ppmd7.h"
     19 #endif
     20 
     21 #define k_Copy 0
     22 #define k_LZMA2 0x21
     23 #define k_LZMA  0x30101
     24 #define k_BCJ   0x03030103
     25 #define k_PPC   0x03030205
     26 #define k_ARM   0x03030501
     27 #define k_ARMT  0x03030701
     28 #define k_SPARC 0x03030805
     29 #define k_BCJ2  0x0303011B
     30 
     31 #ifdef _7ZIP_PPMD_SUPPPORT
     32 
     33 #define k_PPMD 0x30401
     34 
     35 typedef struct
     36 {
     37   IByteIn p;
     38   const Byte *cur;
     39   const Byte *end;
     40   const Byte *begin;
     41   UInt64 processed;
     42   Bool extra;
     43   SRes res;
     44   ILookInStream *inStream;
     45 } CByteInToLook;
     46 
     47 static Byte ReadByte(void *pp)
     48 {
     49   CByteInToLook *p = (CByteInToLook *)pp;
     50   if (p->cur != p->end)
     51     return *p->cur++;
     52   if (p->res == SZ_OK)
     53   {
     54     size_t size = p->cur - p->begin;
     55     p->processed += size;
     56     p->res = p->inStream->Skip(p->inStream, size);
     57     size = (1 << 25);
     58     p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
     59     p->cur = p->begin;
     60     p->end = p->begin + size;
     61     if (size != 0)
     62       return *p->cur++;;
     63   }
     64   p->extra = True;
     65   return 0;
     66 }
     67 
     68 static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
     69     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
     70 {
     71   CPpmd7 ppmd;
     72   CByteInToLook s;
     73   SRes res = SZ_OK;
     74 
     75   s.p.Read = ReadByte;
     76   s.inStream = inStream;
     77   s.begin = s.end = s.cur = NULL;
     78   s.extra = False;
     79   s.res = SZ_OK;
     80   s.processed = 0;
     81 
     82   if (propsSize != 5)
     83     return SZ_ERROR_UNSUPPORTED;
     84 
     85   {
     86     unsigned order = props[0];
     87     UInt32 memSize = GetUi32(props + 1);
     88     if (order < PPMD7_MIN_ORDER ||
     89         order > PPMD7_MAX_ORDER ||
     90         memSize < PPMD7_MIN_MEM_SIZE ||
     91         memSize > PPMD7_MAX_MEM_SIZE)
     92       return SZ_ERROR_UNSUPPORTED;
     93     Ppmd7_Construct(&ppmd);
     94     if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
     95       return SZ_ERROR_MEM;
     96     Ppmd7_Init(&ppmd, order);
     97   }
     98   {
     99     CPpmd7z_RangeDec rc;
    100     Ppmd7z_RangeDec_CreateVTable(&rc);
    101     rc.Stream = &s.p;
    102     if (!Ppmd7z_RangeDec_Init(&rc))
    103       res = SZ_ERROR_DATA;
    104     else if (s.extra)
    105       res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
    106     else
    107     {
    108       SizeT i;
    109       for (i = 0; i < outSize; i++)
    110       {
    111         int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
    112         if (s.extra || sym < 0)
    113           break;
    114         outBuffer[i] = (Byte)sym;
    115       }
    116       if (i != outSize)
    117         res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
    118       else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
    119         res = SZ_ERROR_DATA;
    120     }
    121   }
    122   Ppmd7_Free(&ppmd, allocMain);
    123   return res;
    124 }
    125 
    126 #endif
    127 
    128 
    129 static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
    130     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
    131 {
    132   CLzmaDec state;
    133   SRes res = SZ_OK;
    134 
    135   LzmaDec_Construct(&state);
    136   RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
    137   state.dic = outBuffer;
    138   state.dicBufSize = outSize;
    139   LzmaDec_Init(&state);
    140 
    141   for (;;)
    142   {
    143     Byte *inBuf = NULL;
    144     size_t lookahead = (1 << 18);
    145     if (lookahead > inSize)
    146       lookahead = (size_t)inSize;
    147     res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
    148     if (res != SZ_OK)
    149       break;
    150 
    151     {
    152       SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
    153       ELzmaStatus status;
    154       res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
    155       lookahead -= inProcessed;
    156       inSize -= inProcessed;
    157       if (res != SZ_OK)
    158         break;
    159       if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
    160       {
    161         if (state.dicBufSize != outSize || lookahead != 0 ||
    162             (status != LZMA_STATUS_FINISHED_WITH_MARK &&
    163              status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
    164           res = SZ_ERROR_DATA;
    165         break;
    166       }
    167       res = inStream->Skip((void *)inStream, inProcessed);
    168       if (res != SZ_OK)
    169         break;
    170     }
    171   }
    172 
    173   LzmaDec_FreeProbs(&state, allocMain);
    174   return res;
    175 }
    176 
    177 static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
    178     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
    179 {
    180   CLzma2Dec state;
    181   SRes res = SZ_OK;
    182 
    183   Lzma2Dec_Construct(&state);
    184   if (propsSize != 1)
    185     return SZ_ERROR_DATA;
    186   RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
    187   state.decoder.dic = outBuffer;
    188   state.decoder.dicBufSize = outSize;
    189   Lzma2Dec_Init(&state);
    190 
    191   for (;;)
    192   {
    193     Byte *inBuf = NULL;
    194     size_t lookahead = (1 << 18);
    195     if (lookahead > inSize)
    196       lookahead = (size_t)inSize;
    197     res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
    198     if (res != SZ_OK)
    199       break;
    200 
    201     {
    202       SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
    203       ELzmaStatus status;
    204       res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
    205       lookahead -= inProcessed;
    206       inSize -= inProcessed;
    207       if (res != SZ_OK)
    208         break;
    209       if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
    210       {
    211         if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
    212             (status != LZMA_STATUS_FINISHED_WITH_MARK))
    213           res = SZ_ERROR_DATA;
    214         break;
    215       }
    216       res = inStream->Skip((void *)inStream, inProcessed);
    217       if (res != SZ_OK)
    218         break;
    219     }
    220   }
    221 
    222   Lzma2Dec_FreeProbs(&state, allocMain);
    223   return res;
    224 }
    225 
    226 static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
    227 {
    228   while (inSize > 0)
    229   {
    230     void *inBuf;
    231     size_t curSize = (1 << 18);
    232     if (curSize > inSize)
    233       curSize = (size_t)inSize;
    234     RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
    235     if (curSize == 0)
    236       return SZ_ERROR_INPUT_EOF;
    237     memcpy(outBuffer, inBuf, curSize);
    238     outBuffer += curSize;
    239     inSize -= curSize;
    240     RINOK(inStream->Skip((void *)inStream, curSize));
    241   }
    242   return SZ_OK;
    243 }
    244 
    245 static Bool IS_MAIN_METHOD(UInt32 m)
    246 {
    247   switch (m)
    248   {
    249     case k_Copy:
    250     case k_LZMA:
    251     case k_LZMA2:
    252     #ifdef _7ZIP_PPMD_SUPPPORT
    253     case k_PPMD:
    254     #endif
    255       return True;
    256   }
    257   return False;
    258 }
    259 
    260 static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
    261 {
    262   return
    263       c->NumInStreams == 1 &&
    264       c->NumOutStreams == 1 &&
    265       /* c->MethodID <= (UInt32)0xFFFFFFFF && */
    266       IS_MAIN_METHOD((UInt32)c->MethodID);
    267 }
    268 
    269 #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
    270 
    271 static SRes CheckSupportedFolder(const CSzFolder *f)
    272 {
    273   if (f->NumCoders < 1 || f->NumCoders > 4)
    274     return SZ_ERROR_UNSUPPORTED;
    275   if (!IS_SUPPORTED_CODER(&f->Coders[0]))
    276     return SZ_ERROR_UNSUPPORTED;
    277   if (f->NumCoders == 1)
    278   {
    279     if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
    280       return SZ_ERROR_UNSUPPORTED;
    281     return SZ_OK;
    282   }
    283   if (f->NumCoders == 2)
    284   {
    285     const CSzCoderInfo *c = &f->Coders[1];
    286     if (
    287         /* c->MethodID > (UInt32)0xFFFFFFFF || */
    288         c->NumInStreams != 1 ||
    289         c->NumOutStreams != 1 ||
    290         f->NumPackStreams != 1 ||
    291         f->PackStreams[0] != 0 ||
    292         f->NumBindPairs != 1 ||
    293         f->BindPairs[0].InIndex != 1 ||
    294         f->BindPairs[0].OutIndex != 0)
    295       return SZ_ERROR_UNSUPPORTED;
    296     switch ((UInt32)c->MethodID)
    297     {
    298       case k_BCJ:
    299       case k_ARM:
    300         break;
    301       default:
    302         return SZ_ERROR_UNSUPPORTED;
    303     }
    304     return SZ_OK;
    305   }
    306   if (f->NumCoders == 4)
    307   {
    308     if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
    309         !IS_SUPPORTED_CODER(&f->Coders[2]) ||
    310         !IS_BCJ2(&f->Coders[3]))
    311       return SZ_ERROR_UNSUPPORTED;
    312     if (f->NumPackStreams != 4 ||
    313         f->PackStreams[0] != 2 ||
    314         f->PackStreams[1] != 6 ||
    315         f->PackStreams[2] != 1 ||
    316         f->PackStreams[3] != 0 ||
    317         f->NumBindPairs != 3 ||
    318         f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
    319         f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
    320         f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
    321       return SZ_ERROR_UNSUPPORTED;
    322     return SZ_OK;
    323   }
    324   return SZ_ERROR_UNSUPPORTED;
    325 }
    326 
    327 #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
    328 
    329 static SRes SzFolder_Decode2(const CSzFolder *folder,
    330     const Byte *propsData,
    331     const UInt64 *unpackSizes,
    332     const UInt64 *packPositions,
    333     ILookInStream *inStream, UInt64 startPos,
    334     Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
    335     Byte *tempBuf[])
    336 {
    337   UInt32 ci;
    338   SizeT tempSizes[3] = { 0, 0, 0};
    339   SizeT tempSize3 = 0;
    340   Byte *tempBuf3 = 0;
    341 
    342   RINOK(CheckSupportedFolder(folder));
    343 
    344   for (ci = 0; ci < folder->NumCoders; ci++)
    345   {
    346     const CSzCoderInfo *coder = &folder->Coders[ci];
    347 
    348     if (IS_MAIN_METHOD((UInt32)coder->MethodID))
    349     {
    350       UInt32 si = 0;
    351       UInt64 offset;
    352       UInt64 inSize;
    353       Byte *outBufCur = outBuffer;
    354       SizeT outSizeCur = outSize;
    355       if (folder->NumCoders == 4)
    356       {
    357         UInt32 indices[] = { 3, 2, 0 };
    358         UInt64 unpackSize = unpackSizes[ci];
    359         si = indices[ci];
    360         if (ci < 2)
    361         {
    362           Byte *temp;
    363           outSizeCur = (SizeT)unpackSize;
    364           if (outSizeCur != unpackSize)
    365             return SZ_ERROR_MEM;
    366           temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
    367           if (temp == 0 && outSizeCur != 0)
    368             return SZ_ERROR_MEM;
    369           outBufCur = tempBuf[1 - ci] = temp;
    370           tempSizes[1 - ci] = outSizeCur;
    371         }
    372         else if (ci == 2)
    373         {
    374           if (unpackSize > outSize) /* check it */
    375             return SZ_ERROR_PARAM;
    376           tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
    377           tempSize3 = outSizeCur = (SizeT)unpackSize;
    378         }
    379         else
    380           return SZ_ERROR_UNSUPPORTED;
    381       }
    382       offset = packPositions[si];
    383       inSize = packPositions[si + 1] - offset;
    384       RINOK(LookInStream_SeekTo(inStream, startPos + offset));
    385 
    386       if (coder->MethodID == k_Copy)
    387       {
    388         if (inSize != outSizeCur) /* check it */
    389           return SZ_ERROR_DATA;
    390         RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
    391       }
    392       else if (coder->MethodID == k_LZMA)
    393       {
    394         RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
    395       }
    396       else if (coder->MethodID == k_LZMA2)
    397       {
    398         RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
    399       }
    400       else
    401       {
    402         #ifdef _7ZIP_PPMD_SUPPPORT
    403         RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
    404         #else
    405         return SZ_ERROR_UNSUPPORTED;
    406         #endif
    407       }
    408     }
    409     else if (coder->MethodID == k_BCJ2)
    410     {
    411       UInt64 offset = packPositions[1];
    412       UInt64 s3Size = packPositions[2] - offset;
    413       SRes res;
    414       if (ci != 3)
    415         return SZ_ERROR_UNSUPPORTED;
    416       RINOK(LookInStream_SeekTo(inStream, startPos + offset));
    417       tempSizes[2] = (SizeT)s3Size;
    418       if (tempSizes[2] != s3Size)
    419         return SZ_ERROR_MEM;
    420       tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
    421       if (tempBuf[2] == 0 && tempSizes[2] != 0)
    422         return SZ_ERROR_MEM;
    423       res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
    424       RINOK(res)
    425 
    426       res = Bcj2_Decode(
    427           tempBuf3, tempSize3,
    428           tempBuf[0], tempSizes[0],
    429           tempBuf[1], tempSizes[1],
    430           tempBuf[2], tempSizes[2],
    431           outBuffer, outSize);
    432       RINOK(res)
    433     }
    434     else
    435     {
    436       if (ci != 1)
    437         return SZ_ERROR_UNSUPPORTED;
    438       switch (coder->MethodID)
    439       {
    440         case k_BCJ:
    441         {
    442           UInt32 state;
    443           x86_Convert_Init(state);
    444           x86_Convert(outBuffer, outSize, 0, &state, 0);
    445           break;
    446         }
    447         CASE_BRA_CONV(ARM)
    448         default:
    449           return SZ_ERROR_UNSUPPORTED;
    450       }
    451     }
    452   }
    453   return SZ_OK;
    454 }
    455 
    456 SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
    457     ILookInStream *inStream, UInt64 startPos,
    458     Byte *outBuffer, size_t outSize,
    459     ISzAlloc *allocMain)
    460 {
    461   SRes res;
    462   CSzFolder folder;
    463   CSzData sd;
    464   CSzData sdSizes;
    465 
    466   const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
    467   sd.Data = data;
    468   sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
    469 
    470   sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex];
    471   sdSizes.Size =
    472       p->FoSizesOffsets[folderIndex + 1] -
    473       p->FoSizesOffsets[folderIndex];
    474 
    475   res = SzGetNextFolderItem(&folder, &sd, &sdSizes);
    476 
    477   if (res != SZ_OK)
    478     return res;
    479 
    480   if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.MainOutStream])
    481     return SZ_ERROR_FAIL;
    482   {
    483     int i;
    484     Byte *tempBuf[3] = { 0, 0, 0};
    485     res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes,
    486         p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
    487         inStream, startPos,
    488         outBuffer, (SizeT)outSize, allocMain, tempBuf);
    489     for (i = 0; i < 3; i++)
    490       IAlloc_Free(allocMain, tempBuf[i]);
    491     return res;
    492   }
    493 }
    494