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