"Fossies" - the Fresh Open Source Software Archive

Member "clamav-0.102.3/libclamav/7z/7zIn.c" (12 May 2020, 37633 Bytes) of package /linux/misc/clamav-0.102.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "7zIn.c" see the Fossies "Dox" file reference documentation.

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