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