Home | History | Annotate | Download | only in lzma_sdk
      1 /* 7zIn.c -- 7z Input functions
      2 2010-10-29 : Igor Pavlov : Public domain */
      3 
      4 #include <string.h>
      5 
      6 #include "7z.h"
      7 #include "7zCrc.h"
      8 #include "CpuArch.h"
      9 
     10 Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
     11 
     12 #define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; }
     13 
     14 #define NUM_FOLDER_CODERS_MAX 32
     15 #define NUM_CODER_STREAMS_MAX 32
     16 
     17 void SzCoderInfo_Init(CSzCoderInfo *p)
     18 {
     19   Buf_Init(&p->Props);
     20 }
     21 
     22 void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
     23 {
     24   Buf_Free(&p->Props, alloc);
     25   SzCoderInfo_Init(p);
     26 }
     27 
     28 void SzFolder_Init(CSzFolder *p)
     29 {
     30   p->Coders = 0;
     31   p->BindPairs = 0;
     32   p->PackStreams = 0;
     33   p->UnpackSizes = 0;
     34   p->NumCoders = 0;
     35   p->NumBindPairs = 0;
     36   p->NumPackStreams = 0;
     37   p->UnpackCRCDefined = 0;
     38   p->UnpackCRC = 0;
     39   p->NumUnpackStreams = 0;
     40 }
     41 
     42 void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc)
     43 {
     44   UInt32 i;
     45   if (p->Coders)
     46     for (i = 0; i < p->NumCoders; i++)
     47       SzCoderInfo_Free(&p->Coders[i], alloc);
     48   IAlloc_Free(alloc, p->Coders);
     49   IAlloc_Free(alloc, p->BindPairs);
     50   IAlloc_Free(alloc, p->PackStreams);
     51   IAlloc_Free(alloc, p->UnpackSizes);
     52   SzFolder_Init(p);
     53 }
     54 
     55 UInt32 SzFolder_GetNumOutStreams(CSzFolder *p)
     56 {
     57   UInt32 result = 0;
     58   UInt32 i;
     59   for (i = 0; i < p->NumCoders; i++)
     60     result += p->Coders[i].NumOutStreams;
     61   return result;
     62 }
     63 
     64 int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex)
     65 {
     66   UInt32 i;
     67   for (i = 0; i < p->NumBindPairs; i++)
     68     if (p->BindPairs[i].InIndex == inStreamIndex)
     69       return i;
     70   return -1;
     71 }
     72 
     73 
     74 int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex)
     75 {
     76   UInt32 i;
     77   for (i = 0; i < p->NumBindPairs; i++)
     78     if (p->BindPairs[i].OutIndex == outStreamIndex)
     79       return i;
     80   return -1;
     81 }
     82 
     83 UInt64 SzFolder_GetUnpackSize(CSzFolder *p)
     84 {
     85   int i = (int)SzFolder_GetNumOutStreams(p);
     86   if (i == 0)
     87     return 0;
     88   for (i--; i >= 0; i--)
     89     if (SzFolder_FindBindPairForOutStream(p, i) < 0)
     90       return p->UnpackSizes[i];
     91   /* throw 1; */
     92   return 0;
     93 }
     94 
     95 void SzFile_Init(CSzFileItem *p)
     96 {
     97   p->HasStream = 1;
     98   p->IsDir = 0;
     99   p->IsAnti = 0;
    100   p->CrcDefined = 0;
    101   p->MTimeDefined = 0;
    102 }
    103 
    104 void SzAr_Init(CSzAr *p)
    105 {
    106   p->PackSizes = 0;
    107   p->PackCRCsDefined = 0;
    108   p->PackCRCs = 0;
    109   p->Folders = 0;
    110   p->Files = 0;
    111   p->NumPackStreams = 0;
    112   p->NumFolders = 0;
    113   p->NumFiles = 0;
    114 }
    115 
    116 void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
    117 {
    118   UInt32 i;
    119   if (p->Folders)
    120     for (i = 0; i < p->NumFolders; i++)
    121       SzFolder_Free(&p->Folders[i], alloc);
    122 
    123   IAlloc_Free(alloc, p->PackSizes);
    124   IAlloc_Free(alloc, p->PackCRCsDefined);
    125   IAlloc_Free(alloc, p->PackCRCs);
    126   IAlloc_Free(alloc, p->Folders);
    127   IAlloc_Free(alloc, p->Files);
    128   SzAr_Init(p);
    129 }
    130 
    131 
    132 void SzArEx_Init(CSzArEx *p)
    133 {
    134   SzAr_Init(&p->db);
    135   p->FolderStartPackStreamIndex = 0;
    136   p->PackStreamStartPositions = 0;
    137   p->FolderStartFileIndex = 0;
    138   p->FileIndexToFolderIndexMap = 0;
    139   p->FileNameOffsets = 0;
    140   Buf_Init(&p->FileNames);
    141 }
    142 
    143 void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
    144 {
    145   IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
    146   IAlloc_Free(alloc, p->PackStreamStartPositions);
    147   IAlloc_Free(alloc, p->FolderStartFileIndex);
    148   IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
    149 
    150   IAlloc_Free(alloc, p->FileNameOffsets);
    151   Buf_Free(&p->FileNames, alloc);
    152 
    153   SzAr_Free(&p->db, alloc);
    154   SzArEx_Init(p);
    155 }
    156 
    157 /*
    158 UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
    159 {
    160   return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
    161 }
    162 
    163 UInt64 GetFilePackSize(int fileIndex) const
    164 {
    165   int folderIndex = FileIndexToFolderIndexMap[fileIndex];
    166   if (folderIndex >= 0)
    167   {
    168     const CSzFolder &folderInfo = Folders[folderIndex];
    169     if (FolderStartFileIndex[folderIndex] == fileIndex)
    170     return GetFolderFullPackSize(folderIndex);
    171   }
    172   return 0;
    173 }
    174 */
    175 
    176 #define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \
    177   if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; }
    178 
    179 static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc)
    180 {
    181   UInt32 startPos = 0;
    182   UInt64 startPosSize = 0;
    183   UInt32 i;
    184   UInt32 folderIndex = 0;
    185   UInt32 indexInFolder = 0;
    186   MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc);
    187   for (i = 0; i < p->db.NumFolders; i++)
    188   {
    189     p->FolderStartPackStreamIndex[i] = startPos;
    190     startPos += p->db.Folders[i].NumPackStreams;
    191   }
    192 
    193   MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc);
    194 
    195   for (i = 0; i < p->db.NumPackStreams; i++)
    196   {
    197     p->PackStreamStartPositions[i] = startPosSize;
    198     startPosSize += p->db.PackSizes[i];
    199   }
    200 
    201   MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc);
    202   MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc);
    203 
    204   for (i = 0; i < p->db.NumFiles; i++)
    205   {
    206     CSzFileItem *file = p->db.Files + i;
    207     int emptyStream = !file->HasStream;
    208     if (emptyStream && indexInFolder == 0)
    209     {
    210       p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
    211       continue;
    212     }
    213     if (indexInFolder == 0)
    214     {
    215       /*
    216       v3.13 incorrectly worked with empty folders
    217       v4.07: Loop for skipping empty folders
    218       */
    219       for (;;)
    220       {
    221         if (folderIndex >= p->db.NumFolders)
    222           return SZ_ERROR_ARCHIVE;
    223         p->FolderStartFileIndex[folderIndex] = i;
    224         if (p->db.Folders[folderIndex].NumUnpackStreams != 0)
    225           break;
    226         folderIndex++;
    227       }
    228     }
    229     p->FileIndexToFolderIndexMap[i] = folderIndex;
    230     if (emptyStream)
    231       continue;
    232     indexInFolder++;
    233     if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams)
    234     {
    235       folderIndex++;
    236       indexInFolder = 0;
    237     }
    238   }
    239   return SZ_OK;
    240 }
    241 
    242 
    243 UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder)
    244 {
    245   return p->dataPos +
    246     p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
    247 }
    248 
    249 int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize)
    250 {
    251   UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex];
    252   CSzFolder *folder = p->db.Folders + folderIndex;
    253   UInt64 size = 0;
    254   UInt32 i;
    255   for (i = 0; i < folder->NumPackStreams; i++)
    256   {
    257     UInt64 t = size + p->db.PackSizes[packStreamIndex + i];
    258     if (t < size) /* check it */
    259       return SZ_ERROR_FAIL;
    260     size = t;
    261   }
    262   *resSize = size;
    263   return SZ_OK;
    264 }
    265 
    266 
    267 /*
    268 SRes SzReadTime(const CObjectVector<CBuf> &dataVector,
    269     CObjectVector<CSzFileItem> &files, UInt64 type)
    270 {
    271   CBoolVector boolVector;
    272   RINOK(ReadBoolVector2(files.Size(), boolVector))
    273 
    274   CStreamSwitch streamSwitch;
    275   RINOK(streamSwitch.Set(this, &dataVector));
    276 
    277   for (int i = 0; i < files.Size(); i++)
    278   {
    279     CSzFileItem &file = files[i];
    280     CArchiveFileTime fileTime;
    281     bool defined = boolVector[i];
    282     if (defined)
    283     {
    284       UInt32 low, high;
    285       RINOK(SzReadUInt32(low));
    286       RINOK(SzReadUInt32(high));
    287       fileTime.dwLowDateTime = low;
    288       fileTime.dwHighDateTime = high;
    289     }
    290     switch(type)
    291     {
    292       case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break;
    293       case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break;
    294       case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break;
    295     }
    296   }
    297   return SZ_OK;
    298 }
    299 */
    300 
    301 static int TestSignatureCandidate(Byte *testBytes)
    302 {
    303   size_t i;
    304   for (i = 0; i < k7zSignatureSize; i++)
    305     if (testBytes[i] != k7zSignature[i])
    306       return 0;
    307   return 1;
    308 }
    309 
    310 typedef struct _CSzState
    311 {
    312   Byte *Data;
    313   size_t Size;
    314 }CSzData;
    315 
    316 static SRes SzReadByte(CSzData *sd, Byte *b)
    317 {
    318   if (sd->Size == 0)
    319     return SZ_ERROR_ARCHIVE;
    320   sd->Size--;
    321   *b = *sd->Data++;
    322   return SZ_OK;
    323 }
    324 
    325 static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size)
    326 {
    327   size_t i;
    328   for (i = 0; i < size; i++)
    329   {
    330     RINOK(SzReadByte(sd, data + i));
    331   }
    332   return SZ_OK;
    333 }
    334 
    335 static SRes SzReadUInt32(CSzData *sd, UInt32 *value)
    336 {
    337   int i;
    338   *value = 0;
    339   for (i = 0; i < 4; i++)
    340   {
    341     Byte b;
    342     RINOK(SzReadByte(sd, &b));
    343     *value |= ((UInt32)(b) << (8 * i));
    344   }
    345   return SZ_OK;
    346 }
    347 
    348 static SRes SzReadNumber(CSzData *sd, UInt64 *value)
    349 {
    350   Byte firstByte;
    351   Byte mask = 0x80;
    352   int i;
    353   RINOK(SzReadByte(sd, &firstByte));
    354   *value = 0;
    355   for (i = 0; i < 8; i++)
    356   {
    357     Byte b;
    358     if ((firstByte & mask) == 0)
    359     {
    360       UInt64 highPart = firstByte & (mask - 1);
    361       *value += (highPart << (8 * i));
    362       return SZ_OK;
    363     }
    364     RINOK(SzReadByte(sd, &b));
    365     *value |= ((UInt64)b << (8 * i));
    366     mask >>= 1;
    367   }
    368   return SZ_OK;
    369 }
    370 
    371 static SRes SzReadNumber32(CSzData *sd, UInt32 *value)
    372 {
    373   UInt64 value64;
    374   RINOK(SzReadNumber(sd, &value64));
    375   if (value64 >= 0x80000000)
    376     return SZ_ERROR_UNSUPPORTED;
    377   if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
    378     return SZ_ERROR_UNSUPPORTED;
    379   *value = (UInt32)value64;
    380   return SZ_OK;
    381 }
    382 
    383 static SRes SzReadID(CSzData *sd, UInt64 *value)
    384 {
    385   return SzReadNumber(sd, value);
    386 }
    387 
    388 static SRes SzSkeepDataSize(CSzData *sd, UInt64 size)
    389 {
    390   if (size > sd->Size)
    391     return SZ_ERROR_ARCHIVE;
    392   sd->Size -= (size_t)size;
    393   sd->Data += (size_t)size;
    394   return SZ_OK;
    395 }
    396 
    397 static SRes SzSkeepData(CSzData *sd)
    398 {
    399   UInt64 size;
    400   RINOK(SzReadNumber(sd, &size));
    401   return SzSkeepDataSize(sd, size);
    402 }
    403 
    404 static SRes SzReadArchiveProperties(CSzData *sd)
    405 {
    406   for (;;)
    407   {
    408     UInt64 type;
    409     RINOK(SzReadID(sd, &type));
    410     if (type == k7zIdEnd)
    411       break;
    412     SzSkeepData(sd);
    413   }
    414   return SZ_OK;
    415 }
    416 
    417 static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute)
    418 {
    419   for (;;)
    420   {
    421     UInt64 type;
    422     RINOK(SzReadID(sd, &type));
    423     if (type == attribute)
    424       return SZ_OK;
    425     if (type == k7zIdEnd)
    426       return SZ_ERROR_ARCHIVE;
    427     RINOK(SzSkeepData(sd));
    428   }
    429 }
    430 
    431 static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
    432 {
    433   Byte b = 0;
    434   Byte mask = 0;
    435   size_t i;
    436   MY_ALLOC(Byte, *v, numItems, alloc);
    437   for (i = 0; i < numItems; i++)
    438   {
    439     if (mask == 0)
    440     {
    441       RINOK(SzReadByte(sd, &b));
    442       mask = 0x80;
    443     }
    444     (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
    445     mask >>= 1;
    446   }
    447   return SZ_OK;
    448 }
    449 
    450 static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
    451 {
    452   Byte allAreDefined;
    453   size_t i;
    454   RINOK(SzReadByte(sd, &allAreDefined));
    455   if (allAreDefined == 0)
    456     return SzReadBoolVector(sd, numItems, v, alloc);
    457   MY_ALLOC(Byte, *v, numItems, alloc);
    458   for (i = 0; i < numItems; i++)
    459     (*v)[i] = 1;
    460   return SZ_OK;
    461 }
    462 
    463 static SRes SzReadHashDigests(
    464     CSzData *sd,
    465     size_t numItems,
    466     Byte **digestsDefined,
    467     UInt32 **digests,
    468     ISzAlloc *alloc)
    469 {
    470   size_t i;
    471   RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc));
    472   MY_ALLOC(UInt32, *digests, numItems, alloc);
    473   for (i = 0; i < numItems; i++)
    474     if ((*digestsDefined)[i])
    475     {
    476       RINOK(SzReadUInt32(sd, (*digests) + i));
    477     }
    478   return SZ_OK;
    479 }
    480 
    481 static SRes SzReadPackInfo(
    482     CSzData *sd,
    483     UInt64 *dataOffset,
    484     UInt32 *numPackStreams,
    485     UInt64 **packSizes,
    486     Byte **packCRCsDefined,
    487     UInt32 **packCRCs,
    488     ISzAlloc *alloc)
    489 {
    490   UInt32 i;
    491   RINOK(SzReadNumber(sd, dataOffset));
    492   RINOK(SzReadNumber32(sd, numPackStreams));
    493 
    494   RINOK(SzWaitAttribute(sd, k7zIdSize));
    495 
    496   MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc);
    497 
    498   for (i = 0; i < *numPackStreams; i++)
    499   {
    500     RINOK(SzReadNumber(sd, (*packSizes) + i));
    501   }
    502 
    503   for (;;)
    504   {
    505     UInt64 type;
    506     RINOK(SzReadID(sd, &type));
    507     if (type == k7zIdEnd)
    508       break;
    509     if (type == k7zIdCRC)
    510     {
    511       RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc));
    512       continue;
    513     }
    514     RINOK(SzSkeepData(sd));
    515   }
    516   if (*packCRCsDefined == 0)
    517   {
    518     MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc);
    519     MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc);
    520     for (i = 0; i < *numPackStreams; i++)
    521     {
    522       (*packCRCsDefined)[i] = 0;
    523       (*packCRCs)[i] = 0;
    524     }
    525   }
    526   return SZ_OK;
    527 }
    528 
    529 static SRes SzReadSwitch(CSzData *sd)
    530 {
    531   Byte external;
    532   RINOK(SzReadByte(sd, &external));
    533   return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
    534 }
    535 
    536 static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc)
    537 {
    538   UInt32 numCoders, numBindPairs, numPackStreams, i;
    539   UInt32 numInStreams = 0, numOutStreams = 0;
    540 
    541   RINOK(SzReadNumber32(sd, &numCoders));
    542   if (numCoders > NUM_FOLDER_CODERS_MAX)
    543     return SZ_ERROR_UNSUPPORTED;
    544   folder->NumCoders = numCoders;
    545 
    546   MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc);
    547 
    548   for (i = 0; i < numCoders; i++)
    549     SzCoderInfo_Init(folder->Coders + i);
    550 
    551   for (i = 0; i < numCoders; i++)
    552   {
    553     Byte mainByte;
    554     CSzCoderInfo *coder = folder->Coders + i;
    555     {
    556       unsigned idSize, j;
    557       Byte longID[15];
    558       RINOK(SzReadByte(sd, &mainByte));
    559       idSize = (unsigned)(mainByte & 0xF);
    560       RINOK(SzReadBytes(sd, longID, idSize));
    561       if (idSize > sizeof(coder->MethodID))
    562         return SZ_ERROR_UNSUPPORTED;
    563       coder->MethodID = 0;
    564       for (j = 0; j < idSize; j++)
    565         coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j);
    566 
    567       if ((mainByte & 0x10) != 0)
    568       {
    569         RINOK(SzReadNumber32(sd, &coder->NumInStreams));
    570         RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
    571         if (coder->NumInStreams > NUM_CODER_STREAMS_MAX ||
    572             coder->NumOutStreams > NUM_CODER_STREAMS_MAX)
    573           return SZ_ERROR_UNSUPPORTED;
    574       }
    575       else
    576       {
    577         coder->NumInStreams = 1;
    578         coder->NumOutStreams = 1;
    579       }
    580       if ((mainByte & 0x20) != 0)
    581       {
    582         UInt64 propertiesSize = 0;
    583         RINOK(SzReadNumber(sd, &propertiesSize));
    584         if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc))
    585           return SZ_ERROR_MEM;
    586         RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize));
    587       }
    588     }
    589     while ((mainByte & 0x80) != 0)
    590     {
    591       RINOK(SzReadByte(sd, &mainByte));
    592       RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
    593       if ((mainByte & 0x10) != 0)
    594       {
    595         UInt32 n;
    596         RINOK(SzReadNumber32(sd, &n));
    597         RINOK(SzReadNumber32(sd, &n));
    598       }
    599       if ((mainByte & 0x20) != 0)
    600       {
    601         UInt64 propertiesSize = 0;
    602         RINOK(SzReadNumber(sd, &propertiesSize));
    603         RINOK(SzSkeepDataSize(sd, propertiesSize));
    604       }
    605     }
    606     numInStreams += coder->NumInStreams;
    607     numOutStreams += coder->NumOutStreams;
    608   }
    609 
    610   if (numOutStreams == 0)
    611     return SZ_ERROR_UNSUPPORTED;
    612 
    613   folder->NumBindPairs = numBindPairs = numOutStreams - 1;
    614   MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc);
    615 
    616   for (i = 0; i < numBindPairs; i++)
    617   {
    618     CSzBindPair *bp = folder->BindPairs + i;
    619     RINOK(SzReadNumber32(sd, &bp->InIndex));
    620     RINOK(SzReadNumber32(sd, &bp->OutIndex));
    621   }
    622 
    623   if (numInStreams < numBindPairs)
    624     return SZ_ERROR_UNSUPPORTED;
    625 
    626   folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
    627   MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc);
    628 
    629   if (numPackStreams == 1)
    630   {
    631     for (i = 0; i < numInStreams ; i++)
    632       if (SzFolder_FindBindPairForInStream(folder, i) < 0)
    633         break;
    634     if (i == numInStreams)
    635       return SZ_ERROR_UNSUPPORTED;
    636     folder->PackStreams[0] = i;
    637   }
    638   else
    639     for (i = 0; i < numPackStreams; i++)
    640     {
    641       RINOK(SzReadNumber32(sd, folder->PackStreams + i));
    642     }
    643   return SZ_OK;
    644 }
    645 
    646 static SRes SzReadUnpackInfo(
    647     CSzData *sd,
    648     UInt32 *numFolders,
    649     CSzFolder **folders,  /* for alloc */
    650     ISzAlloc *alloc,
    651     ISzAlloc *allocTemp)
    652 {
    653   UInt32 i;
    654   RINOK(SzWaitAttribute(sd, k7zIdFolder));
    655   RINOK(SzReadNumber32(sd, numFolders));
    656   {
    657     RINOK(SzReadSwitch(sd));
    658 
    659     MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc);
    660 
    661     for (i = 0; i < *numFolders; i++)
    662       SzFolder_Init((*folders) + i);
    663 
    664     for (i = 0; i < *numFolders; i++)
    665     {
    666       RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc));
    667     }
    668   }
    669 
    670   RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize));
    671 
    672   for (i = 0; i < *numFolders; i++)
    673   {
    674     UInt32 j;
    675     CSzFolder *folder = (*folders) + i;
    676     UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder);
    677 
    678     MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc);
    679 
    680     for (j = 0; j < numOutStreams; j++)
    681     {
    682       RINOK(SzReadNumber(sd, folder->UnpackSizes + j));
    683     }
    684   }
    685 
    686   for (;;)
    687   {
    688     UInt64 type;
    689     RINOK(SzReadID(sd, &type));
    690     if (type == k7zIdEnd)
    691       return SZ_OK;
    692     if (type == k7zIdCRC)
    693     {
    694       SRes res;
    695       Byte *crcsDefined = 0;
    696       UInt32 *crcs = 0;
    697       res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp);
    698       if (res == SZ_OK)
    699       {
    700         for (i = 0; i < *numFolders; i++)
    701         {
    702           CSzFolder *folder = (*folders) + i;
    703           folder->UnpackCRCDefined = crcsDefined[i];
    704           folder->UnpackCRC = crcs[i];
    705         }
    706       }
    707       IAlloc_Free(allocTemp, crcs);
    708       IAlloc_Free(allocTemp, crcsDefined);
    709       RINOK(res);
    710       continue;
    711     }
    712     RINOK(SzSkeepData(sd));
    713   }
    714 }
    715 
    716 static SRes SzReadSubStreamsInfo(
    717     CSzData *sd,
    718     UInt32 numFolders,
    719     CSzFolder *folders,
    720     UInt32 *numUnpackStreams,
    721     UInt64 **unpackSizes,
    722     Byte **digestsDefined,
    723     UInt32 **digests,
    724     ISzAlloc *allocTemp)
    725 {
    726   UInt64 type = 0;
    727   UInt32 i;
    728   UInt32 si = 0;
    729   UInt32 numDigests = 0;
    730 
    731   for (i = 0; i < numFolders; i++)
    732     folders[i].NumUnpackStreams = 1;
    733   *numUnpackStreams = numFolders;
    734 
    735   for (;;)
    736   {
    737     RINOK(SzReadID(sd, &type));
    738     if (type == k7zIdNumUnpackStream)
    739     {
    740       *numUnpackStreams = 0;
    741       for (i = 0; i < numFolders; i++)
    742       {
    743         UInt32 numStreams;
    744         RINOK(SzReadNumber32(sd, &numStreams));
    745         folders[i].NumUnpackStreams = numStreams;
    746         *numUnpackStreams += numStreams;
    747       }
    748       continue;
    749     }
    750     if (type == k7zIdCRC || type == k7zIdSize)
    751       break;
    752     if (type == k7zIdEnd)
    753       break;
    754     RINOK(SzSkeepData(sd));
    755   }
    756 
    757   if (*numUnpackStreams == 0)
    758   {
    759     *unpackSizes = 0;
    760     *digestsDefined = 0;
    761     *digests = 0;
    762   }
    763   else
    764   {
    765     *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64));
    766     RINOM(*unpackSizes);
    767     *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte));
    768     RINOM(*digestsDefined);
    769     *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32));
    770     RINOM(*digests);
    771   }
    772 
    773   for (i = 0; i < numFolders; i++)
    774   {
    775     /*
    776     v3.13 incorrectly worked with empty folders
    777     v4.07: we check that folder is empty
    778     */
    779     UInt64 sum = 0;
    780     UInt32 j;
    781     UInt32 numSubstreams = folders[i].NumUnpackStreams;
    782     if (numSubstreams == 0)
    783       continue;
    784     if (type == k7zIdSize)
    785     for (j = 1; j < numSubstreams; j++)
    786     {
    787       UInt64 size;
    788       RINOK(SzReadNumber(sd, &size));
    789       (*unpackSizes)[si++] = size;
    790       sum += size;
    791     }
    792     (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum;
    793   }
    794   if (type == k7zIdSize)
    795   {
    796     RINOK(SzReadID(sd, &type));
    797   }
    798 
    799   for (i = 0; i < *numUnpackStreams; i++)
    800   {
    801     (*digestsDefined)[i] = 0;
    802     (*digests)[i] = 0;
    803   }
    804 
    805 
    806   for (i = 0; i < numFolders; i++)
    807   {
    808     UInt32 numSubstreams = folders[i].NumUnpackStreams;
    809     if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
    810       numDigests += numSubstreams;
    811   }
    812 
    813 
    814   si = 0;
    815   for (;;)
    816   {
    817     if (type == k7zIdCRC)
    818     {
    819       int digestIndex = 0;
    820       Byte *digestsDefined2 = 0;
    821       UInt32 *digests2 = 0;
    822       SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp);
    823       if (res == SZ_OK)
    824       {
    825         for (i = 0; i < numFolders; i++)
    826         {
    827           CSzFolder *folder = folders + i;
    828           UInt32 numSubstreams = folder->NumUnpackStreams;
    829           if (numSubstreams == 1 && folder->UnpackCRCDefined)
    830           {
    831             (*digestsDefined)[si] = 1;
    832             (*digests)[si] = folder->UnpackCRC;
    833             si++;
    834           }
    835           else
    836           {
    837             UInt32 j;
    838             for (j = 0; j < numSubstreams; j++, digestIndex++)
    839             {
    840               (*digestsDefined)[si] = digestsDefined2[digestIndex];
    841               (*digests)[si] = digests2[digestIndex];
    842               si++;
    843             }
    844           }
    845         }
    846       }
    847       IAlloc_Free(allocTemp, digestsDefined2);
    848       IAlloc_Free(allocTemp, digests2);
    849       RINOK(res);
    850     }
    851     else if (type == k7zIdEnd)
    852       return SZ_OK;
    853     else
    854     {
    855       RINOK(SzSkeepData(sd));
    856     }
    857     RINOK(SzReadID(sd, &type));
    858   }
    859 }
    860 
    861 
    862 static SRes SzReadStreamsInfo(
    863     CSzData *sd,
    864     UInt64 *dataOffset,
    865     CSzAr *p,
    866     UInt32 *numUnpackStreams,
    867     UInt64 **unpackSizes, /* allocTemp */
    868     Byte **digestsDefined,   /* allocTemp */
    869     UInt32 **digests,        /* allocTemp */
    870     ISzAlloc *alloc,
    871     ISzAlloc *allocTemp)
    872 {
    873   for (;;)
    874   {
    875     UInt64 type;
    876     RINOK(SzReadID(sd, &type));
    877     if ((UInt64)(int)type != type)
    878       return SZ_ERROR_UNSUPPORTED;
    879     switch((int)type)
    880     {
    881       case k7zIdEnd:
    882         return SZ_OK;
    883       case k7zIdPackInfo:
    884       {
    885         RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams,
    886             &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc));
    887         break;
    888       }
    889       case k7zIdUnpackInfo:
    890       {
    891         RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp));
    892         break;
    893       }
    894       case k7zIdSubStreamsInfo:
    895       {
    896         RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders,
    897             numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp));
    898         break;
    899       }
    900       default:
    901         return SZ_ERROR_UNSUPPORTED;
    902     }
    903   }
    904 }
    905 
    906 size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
    907 {
    908   size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
    909   if (dest != 0)
    910   {
    911     size_t i;
    912     const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2);
    913     for (i = 0; i < len; i++)
    914       dest[i] = GetUi16(src + i * 2);
    915   }
    916   return len;
    917 }
    918 
    919 static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes)
    920 {
    921   UInt32 i;
    922   size_t pos = 0;
    923   for (i = 0; i < numFiles; i++)
    924   {
    925     sizes[i] = pos;
    926     for (;;)
    927     {
    928       if (pos >= size)
    929         return SZ_ERROR_ARCHIVE;
    930       if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0)
    931         break;
    932       pos++;
    933     }
    934     pos++;
    935   }
    936   sizes[i] = pos;
    937   return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
    938 }
    939 
    940 static SRes SzReadHeader2(
    941     CSzArEx *p,   /* allocMain */
    942     CSzData *sd,
    943     UInt64 **unpackSizes,  /* allocTemp */
    944     Byte **digestsDefined,    /* allocTemp */
    945     UInt32 **digests,         /* allocTemp */
    946     Byte **emptyStreamVector, /* allocTemp */
    947     Byte **emptyFileVector,   /* allocTemp */
    948     Byte **lwtVector,         /* allocTemp */
    949     ISzAlloc *allocMain,
    950     ISzAlloc *allocTemp)
    951 {
    952   UInt64 type;
    953   UInt32 numUnpackStreams = 0;
    954   UInt32 numFiles = 0;
    955   CSzFileItem *files = 0;
    956   UInt32 numEmptyStreams = 0;
    957   UInt32 i;
    958 
    959   RINOK(SzReadID(sd, &type));
    960 
    961   if (type == k7zIdArchiveProperties)
    962   {
    963     RINOK(SzReadArchiveProperties(sd));
    964     RINOK(SzReadID(sd, &type));
    965   }
    966 
    967 
    968   if (type == k7zIdMainStreamsInfo)
    969   {
    970     RINOK(SzReadStreamsInfo(sd,
    971         &p->dataPos,
    972         &p->db,
    973         &numUnpackStreams,
    974         unpackSizes,
    975         digestsDefined,
    976         digests, allocMain, allocTemp));
    977     p->dataPos += p->startPosAfterHeader;
    978     RINOK(SzReadID(sd, &type));
    979   }
    980 
    981   if (type == k7zIdEnd)
    982     return SZ_OK;
    983   if (type != k7zIdFilesInfo)
    984     return SZ_ERROR_ARCHIVE;
    985 
    986   RINOK(SzReadNumber32(sd, &numFiles));
    987   p->db.NumFiles = numFiles;
    988 
    989   MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain);
    990 
    991   p->db.Files = files;
    992   for (i = 0; i < numFiles; i++)
    993     SzFile_Init(files + i);
    994 
    995   for (;;)
    996   {
    997     UInt64 type;
    998     UInt64 size;
    999     RINOK(SzReadID(sd, &type));
   1000     if (type == k7zIdEnd)
   1001       break;
   1002     RINOK(SzReadNumber(sd, &size));
   1003     if (size > sd->Size)
   1004       return SZ_ERROR_ARCHIVE;
   1005     if ((UInt64)(int)type != type)
   1006     {
   1007       RINOK(SzSkeepDataSize(sd, size));
   1008     }
   1009     else
   1010     switch((int)type)
   1011     {
   1012       case k7zIdName:
   1013       {
   1014         size_t namesSize;
   1015         RINOK(SzReadSwitch(sd));
   1016         namesSize = (size_t)size - 1;
   1017         if ((namesSize & 1) != 0)
   1018           return SZ_ERROR_ARCHIVE;
   1019         if (!Buf_Create(&p->FileNames, namesSize, allocMain))
   1020           return SZ_ERROR_MEM;
   1021         MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
   1022         memcpy(p->FileNames.data, sd->Data, namesSize);
   1023         RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets))
   1024         RINOK(SzSkeepDataSize(sd, namesSize));
   1025         break;
   1026       }
   1027       case k7zIdEmptyStream:
   1028       {
   1029         RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp));
   1030         numEmptyStreams = 0;
   1031         for (i = 0; i < numFiles; i++)
   1032           if ((*emptyStreamVector)[i])
   1033             numEmptyStreams++;
   1034         break;
   1035       }
   1036       case k7zIdEmptyFile:
   1037       {
   1038         RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp));
   1039         break;
   1040       }
   1041       case k7zIdWinAttributes:
   1042       {
   1043         RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
   1044         RINOK(SzReadSwitch(sd));
   1045         for (i = 0; i < numFiles; i++)
   1046         {
   1047           CSzFileItem *f = &files[i];
   1048           Byte defined = (*lwtVector)[i];
   1049           f->AttribDefined = defined;
   1050           f->Attrib = 0;
   1051           if (defined)
   1052           {
   1053             RINOK(SzReadUInt32(sd, &f->Attrib));
   1054           }
   1055         }
   1056         IAlloc_Free(allocTemp, *lwtVector);
   1057         *lwtVector = NULL;
   1058         break;
   1059       }
   1060       case k7zIdMTime:
   1061       {
   1062         RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
   1063         RINOK(SzReadSwitch(sd));
   1064         for (i = 0; i < numFiles; i++)
   1065         {
   1066           CSzFileItem *f = &files[i];
   1067           Byte defined = (*lwtVector)[i];
   1068           f->MTimeDefined = defined;
   1069           f->MTime.Low = f->MTime.High = 0;
   1070           if (defined)
   1071           {
   1072             RINOK(SzReadUInt32(sd, &f->MTime.Low));
   1073             RINOK(SzReadUInt32(sd, &f->MTime.High));
   1074           }
   1075         }
   1076         IAlloc_Free(allocTemp, *lwtVector);
   1077         *lwtVector = NULL;
   1078         break;
   1079       }
   1080       default:
   1081       {
   1082         RINOK(SzSkeepDataSize(sd, size));
   1083       }
   1084     }
   1085   }
   1086 
   1087   {
   1088     UInt32 emptyFileIndex = 0;
   1089     UInt32 sizeIndex = 0;
   1090     for (i = 0; i < numFiles; i++)
   1091     {
   1092       CSzFileItem *file = files + i;
   1093       file->IsAnti = 0;
   1094       if (*emptyStreamVector == 0)
   1095         file->HasStream = 1;
   1096       else
   1097         file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
   1098       if (file->HasStream)
   1099       {
   1100         file->IsDir = 0;
   1101         file->Size = (*unpackSizes)[sizeIndex];
   1102         file->Crc = (*digests)[sizeIndex];
   1103         file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex];
   1104         sizeIndex++;
   1105       }
   1106       else
   1107       {
   1108         if (*emptyFileVector == 0)
   1109           file->IsDir = 1;
   1110         else
   1111           file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
   1112         emptyFileIndex++;
   1113         file->Size = 0;
   1114         file->Crc = 0;
   1115         file->CrcDefined = 0;
   1116       }
   1117     }
   1118   }
   1119   return SzArEx_Fill(p, allocMain);
   1120 }
   1121 
   1122 static SRes SzReadHeader(
   1123     CSzArEx *p,
   1124     CSzData *sd,
   1125     ISzAlloc *allocMain,
   1126     ISzAlloc *allocTemp)
   1127 {
   1128   UInt64 *unpackSizes = 0;
   1129   Byte *digestsDefined = 0;
   1130   UInt32 *digests = 0;
   1131   Byte *emptyStreamVector = 0;
   1132   Byte *emptyFileVector = 0;
   1133   Byte *lwtVector = 0;
   1134   SRes res = SzReadHeader2(p, sd,
   1135       &unpackSizes, &digestsDefined, &digests,
   1136       &emptyStreamVector, &emptyFileVector, &lwtVector,
   1137       allocMain, allocTemp);
   1138   IAlloc_Free(allocTemp, unpackSizes);
   1139   IAlloc_Free(allocTemp, digestsDefined);
   1140   IAlloc_Free(allocTemp, digests);
   1141   IAlloc_Free(allocTemp, emptyStreamVector);
   1142   IAlloc_Free(allocTemp, emptyFileVector);
   1143   IAlloc_Free(allocTemp, lwtVector);
   1144   return res;
   1145 }
   1146 
   1147 static SRes SzReadAndDecodePackedStreams2(
   1148     ILookInStream *inStream,
   1149     CSzData *sd,
   1150     CBuf *outBuffer,
   1151     UInt64 baseOffset,
   1152     CSzAr *p,
   1153     UInt64 **unpackSizes,
   1154     Byte **digestsDefined,
   1155     UInt32 **digests,
   1156     ISzAlloc *allocTemp)
   1157 {
   1158 
   1159   UInt32 numUnpackStreams = 0;
   1160   UInt64 dataStartPos;
   1161   CSzFolder *folder;
   1162   UInt64 unpackSize;
   1163   SRes res;
   1164 
   1165   RINOK(SzReadStreamsInfo(sd, &dataStartPos, p,
   1166       &numUnpackStreams,  unpackSizes, digestsDefined, digests,
   1167       allocTemp, allocTemp));
   1168 
   1169   dataStartPos += baseOffset;
   1170   if (p->NumFolders != 1)
   1171     return SZ_ERROR_ARCHIVE;
   1172 
   1173   folder = p->Folders;
   1174   unpackSize = SzFolder_GetUnpackSize(folder);
   1175 
   1176   RINOK(LookInStream_SeekTo(inStream, dataStartPos));
   1177 
   1178   if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp))
   1179     return SZ_ERROR_MEM;
   1180 
   1181   res = SzFolder_Decode(folder, p->PackSizes,
   1182           inStream, dataStartPos,
   1183           outBuffer->data, (size_t)unpackSize, allocTemp);
   1184   RINOK(res);
   1185   if (folder->UnpackCRCDefined)
   1186     if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC)
   1187       return SZ_ERROR_CRC;
   1188   return SZ_OK;
   1189 }
   1190 
   1191 static SRes SzReadAndDecodePackedStreams(
   1192     ILookInStream *inStream,
   1193     CSzData *sd,
   1194     CBuf *outBuffer,
   1195     UInt64 baseOffset,
   1196     ISzAlloc *allocTemp)
   1197 {
   1198   CSzAr p;
   1199   UInt64 *unpackSizes = 0;
   1200   Byte *digestsDefined = 0;
   1201   UInt32 *digests = 0;
   1202   SRes res;
   1203   SzAr_Init(&p);
   1204   res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset,
   1205     &p, &unpackSizes, &digestsDefined, &digests,
   1206     allocTemp);
   1207   SzAr_Free(&p, allocTemp);
   1208   IAlloc_Free(allocTemp, unpackSizes);
   1209   IAlloc_Free(allocTemp, digestsDefined);
   1210   IAlloc_Free(allocTemp, digests);
   1211   return res;
   1212 }
   1213 
   1214 static SRes SzArEx_Open2(
   1215     CSzArEx *p,
   1216     ILookInStream *inStream,
   1217     ISzAlloc *allocMain,
   1218     ISzAlloc *allocTemp)
   1219 {
   1220   Byte header[k7zStartHeaderSize];
   1221   Int64 startArcPos;
   1222   UInt64 nextHeaderOffset, nextHeaderSize;
   1223   size_t nextHeaderSizeT;
   1224   UInt32 nextHeaderCRC;
   1225   CBuf buffer;
   1226   SRes res;
   1227 
   1228   startArcPos = 0;
   1229   RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
   1230 
   1231   RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
   1232 
   1233   if (!TestSignatureCandidate(header))
   1234     return SZ_ERROR_NO_ARCHIVE;
   1235   if (header[6] != k7zMajorVersion)
   1236     return SZ_ERROR_UNSUPPORTED;
   1237 
   1238   nextHeaderOffset = GetUi64(header + 12);
   1239   nextHeaderSize = GetUi64(header + 20);
   1240   nextHeaderCRC = GetUi32(header + 28);
   1241 
   1242   p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
   1243 
   1244   if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
   1245     return SZ_ERROR_CRC;
   1246 
   1247   nextHeaderSizeT = (size_t)nextHeaderSize;
   1248   if (nextHeaderSizeT != nextHeaderSize)
   1249     return SZ_ERROR_MEM;
   1250   if (nextHeaderSizeT == 0)
   1251     return SZ_OK;
   1252   if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
   1253       nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
   1254     return SZ_ERROR_NO_ARCHIVE;
   1255 
   1256   {
   1257     Int64 pos = 0;
   1258     RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
   1259     if ((UInt64)pos < startArcPos + nextHeaderOffset ||
   1260         (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
   1261         (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
   1262       return SZ_ERROR_INPUT_EOF;
   1263   }
   1264 
   1265   RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
   1266 
   1267   if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
   1268     return SZ_ERROR_MEM;
   1269 
   1270   res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT);
   1271   if (res == SZ_OK)
   1272   {
   1273     res = SZ_ERROR_ARCHIVE;
   1274     if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC)
   1275     {
   1276       CSzData sd;
   1277       UInt64 type;
   1278       sd.Data = buffer.data;
   1279       sd.Size = buffer.size;
   1280       res = SzReadID(&sd, &type);
   1281       if (res == SZ_OK)
   1282       {
   1283         if (type == k7zIdEncodedHeader)
   1284         {
   1285           CBuf outBuffer;
   1286           Buf_Init(&outBuffer);
   1287           res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp);
   1288           if (res != SZ_OK)
   1289             Buf_Free(&outBuffer, allocTemp);
   1290           else
   1291           {
   1292             Buf_Free(&buffer, allocTemp);
   1293             buffer.data = outBuffer.data;
   1294             buffer.size = outBuffer.size;
   1295             sd.Data = buffer.data;
   1296             sd.Size = buffer.size;
   1297             res = SzReadID(&sd, &type);
   1298           }
   1299         }
   1300       }
   1301       if (res == SZ_OK)
   1302       {
   1303         if (type == k7zIdHeader)
   1304           res = SzReadHeader(p, &sd, allocMain, allocTemp);
   1305         else
   1306           res = SZ_ERROR_UNSUPPORTED;
   1307       }
   1308     }
   1309   }
   1310   Buf_Free(&buffer, allocTemp);
   1311   return res;
   1312 }
   1313 
   1314 SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp)
   1315 {
   1316   SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
   1317   if (res != SZ_OK)
   1318     SzArEx_Free(p, allocMain);
   1319   return res;
   1320 }
   1321 
   1322 SRes SzArEx_Extract(
   1323     const CSzArEx *p,
   1324     ILookInStream *inStream,
   1325     UInt32 fileIndex,
   1326     UInt32 *blockIndex,
   1327     Byte **outBuffer,
   1328     size_t *outBufferSize,
   1329     size_t *offset,
   1330     size_t *outSizeProcessed,
   1331     ISzAlloc *allocMain,
   1332     ISzAlloc *allocTemp)
   1333 {
   1334   UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
   1335   SRes res = SZ_OK;
   1336   *offset = 0;
   1337   *outSizeProcessed = 0;
   1338   if (folderIndex == (UInt32)-1)
   1339   {
   1340     IAlloc_Free(allocMain, *outBuffer);
   1341     *blockIndex = folderIndex;
   1342     *outBuffer = 0;
   1343     *outBufferSize = 0;
   1344     return SZ_OK;
   1345   }
   1346 
   1347   if (*outBuffer == 0 || *blockIndex != folderIndex)
   1348   {
   1349     CSzFolder *folder = p->db.Folders + folderIndex;
   1350     UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder);
   1351     size_t unpackSize = (size_t)unpackSizeSpec;
   1352     UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0);
   1353 
   1354     if (unpackSize != unpackSizeSpec)
   1355       return SZ_ERROR_MEM;
   1356     *blockIndex = folderIndex;
   1357     IAlloc_Free(allocMain, *outBuffer);
   1358     *outBuffer = 0;
   1359 
   1360     RINOK(LookInStream_SeekTo(inStream, startOffset));
   1361 
   1362     if (res == SZ_OK)
   1363     {
   1364       *outBufferSize = unpackSize;
   1365       if (unpackSize != 0)
   1366       {
   1367         *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
   1368         if (*outBuffer == 0)
   1369           res = SZ_ERROR_MEM;
   1370       }
   1371       if (res == SZ_OK)
   1372       {
   1373         res = SzFolder_Decode(folder,
   1374           p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex],
   1375           inStream, startOffset,
   1376           *outBuffer, unpackSize, allocTemp);
   1377         if (res == SZ_OK)
   1378         {
   1379           if (folder->UnpackCRCDefined)
   1380           {
   1381             if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC)
   1382               res = SZ_ERROR_CRC;
   1383           }
   1384         }
   1385       }
   1386     }
   1387   }
   1388   if (res == SZ_OK)
   1389   {
   1390     UInt32 i;
   1391     CSzFileItem *fileItem = p->db.Files + fileIndex;
   1392     *offset = 0;
   1393     for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
   1394       *offset += (UInt32)p->db.Files[i].Size;
   1395     *outSizeProcessed = (size_t)fileItem->Size;
   1396     if (*offset + *outSizeProcessed > *outBufferSize)
   1397       return SZ_ERROR_FAIL;
   1398     if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc)
   1399       res = SZ_ERROR_CRC;
   1400   }
   1401   return res;
   1402 }
   1403