misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zIn.cpp
changeset 13904 99b265e0d1d0
parent 13903 5f819b90d479
child 13905 b172a5d40eee
equal deleted inserted replaced
13903:5f819b90d479 13904:99b265e0d1d0
     1 // 7zIn.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "7zIn.h"
       
     6 #include "7zDecode.h"
       
     7 #include "../../Common/StreamObjects.h"
       
     8 #include "../../Common/StreamUtils.h"
       
     9 extern "C" 
       
    10 { 
       
    11 #include "../../../../C/7zCrc.h"
       
    12 }
       
    13 
       
    14 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader 
       
    15 #ifndef _SFX
       
    16 #define FORMAT_7Z_RECOVERY
       
    17 #endif
       
    18 
       
    19 namespace NArchive {
       
    20 namespace N7z {
       
    21 
       
    22 class CInArchiveException {};
       
    23 
       
    24 static void ThrowException() { throw CInArchiveException(); }
       
    25 static inline void ThrowEndOfData()   { ThrowException(); }
       
    26 static inline void ThrowUnsupported() { ThrowException(); }
       
    27 static inline void ThrowIncorrect()   { ThrowException(); }
       
    28 static inline void ThrowUnsupportedVersion() { ThrowException(); }
       
    29 
       
    30 /*
       
    31 class CInArchiveException
       
    32 {
       
    33 public:
       
    34   enum CCauseType
       
    35   {
       
    36     kUnsupportedVersion = 0,
       
    37     kUnsupported,
       
    38     kIncorrect, 
       
    39     kEndOfData,
       
    40   } Cause;
       
    41   CInArchiveException(CCauseType cause): Cause(cause) {};
       
    42 };
       
    43 
       
    44 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
       
    45 static void ThrowEndOfData()   { ThrowException(CInArchiveException::kEndOfData); }
       
    46 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
       
    47 static void ThrowIncorrect()   { ThrowException(CInArchiveException::kIncorrect); }
       
    48 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
       
    49 */
       
    50 
       
    51 class CStreamSwitch
       
    52 {
       
    53   CInArchive *_archive;
       
    54   bool _needRemove;
       
    55 public:
       
    56   CStreamSwitch(): _needRemove(false) {}
       
    57   ~CStreamSwitch() { Remove(); }
       
    58   void Remove();
       
    59   void Set(CInArchive *archive, const Byte *data, size_t size);
       
    60   void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
       
    61   void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
       
    62 };
       
    63 
       
    64 void CStreamSwitch::Remove()
       
    65 {
       
    66   if (_needRemove)
       
    67   {
       
    68     _archive->DeleteByteStream();
       
    69     _needRemove = false;
       
    70   }
       
    71 }
       
    72 
       
    73 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
       
    74 {
       
    75   Remove();
       
    76   _archive = archive;
       
    77   _archive->AddByteStream(data, size);
       
    78   _needRemove = true;
       
    79 }
       
    80 
       
    81 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
       
    82 {
       
    83   Set(archive, byteBuffer, byteBuffer.GetCapacity());
       
    84 }
       
    85 
       
    86 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
       
    87 {
       
    88   Remove();
       
    89   Byte external = archive->ReadByte();
       
    90   if (external != 0)
       
    91   {
       
    92     int dataIndex = (int)archive->ReadNum();
       
    93     if (dataIndex < 0 || dataIndex >= dataVector->Size())
       
    94       ThrowIncorrect();
       
    95     Set(archive, (*dataVector)[dataIndex]);
       
    96   }
       
    97 }
       
    98 
       
    99 #if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
       
   100 #define SZ_LITTLE_ENDIAN_UNALIGN
       
   101 #endif
       
   102 
       
   103 #ifdef SZ_LITTLE_ENDIAN_UNALIGN
       
   104 static inline UInt16 GetUInt16FromMem(const Byte *p) { return *(const UInt16 *)p; }
       
   105 static inline UInt32 GetUInt32FromMem(const Byte *p) { return *(const UInt32 *)p; }
       
   106 static inline UInt64 GetUInt64FromMem(const Byte *p) { return *(const UInt64 *)p; }
       
   107 #else
       
   108 static inline UInt16 GetUInt16FromMem(const Byte *p) { return p[0] | ((UInt16)p[1] << 8); }
       
   109 static inline UInt32 GetUInt32FromMem(const Byte *p) { return p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24); }
       
   110 static inline UInt64 GetUInt64FromMem(const Byte *p) { return GetUInt32FromMem(p) | ((UInt64)GetUInt32FromMem(p + 4) << 32); }
       
   111 #endif
       
   112 
       
   113 Byte CInByte2::ReadByte()
       
   114 {
       
   115   if (_pos >= _size)
       
   116     ThrowEndOfData();
       
   117   return _buffer[_pos++];
       
   118 }
       
   119 
       
   120 void CInByte2::ReadBytes(Byte *data, size_t size)
       
   121 {
       
   122   if (size > _size - _pos)
       
   123     ThrowEndOfData();
       
   124   for (size_t i = 0; i < size; i++)
       
   125     data[i] = _buffer[_pos++];
       
   126 }
       
   127 
       
   128 void CInByte2::SkeepData(UInt64 size)
       
   129 {
       
   130   if (size > _size - _pos)
       
   131     ThrowEndOfData();
       
   132 }
       
   133 
       
   134 void CInByte2::SkeepData()
       
   135 {
       
   136   SkeepData(ReadNumber());
       
   137 }
       
   138 
       
   139 UInt64 CInByte2::ReadNumber()
       
   140 {
       
   141   if (_pos >= _size)
       
   142     ThrowEndOfData();
       
   143   Byte firstByte = _buffer[_pos++];
       
   144   Byte mask = 0x80;
       
   145   UInt64 value = 0;
       
   146   for (int i = 0; i < 8; i++)
       
   147   {
       
   148     if ((firstByte & mask) == 0)
       
   149     {
       
   150       UInt64 highPart = firstByte & (mask - 1);
       
   151       value += (highPart << (i * 8));
       
   152       return value;
       
   153     }
       
   154     if (_pos >= _size)
       
   155       ThrowEndOfData();
       
   156     value |= ((UInt64)_buffer[_pos++] << (8 * i));
       
   157     mask >>= 1;
       
   158   }
       
   159   return value;
       
   160 }
       
   161 
       
   162 CNum CInByte2::ReadNum()
       
   163 { 
       
   164   UInt64 value = ReadNumber(); 
       
   165   if (value > kNumMax)
       
   166     ThrowUnsupported();
       
   167   return (CNum)value;
       
   168 }
       
   169 
       
   170 UInt32 CInByte2::ReadUInt32()
       
   171 {
       
   172   if (_pos + 4 > _size)
       
   173     ThrowEndOfData();
       
   174   UInt32 res = GetUInt32FromMem(_buffer + _pos);
       
   175   _pos += 4;
       
   176   return res;
       
   177 }
       
   178 
       
   179 UInt64 CInByte2::ReadUInt64()
       
   180 {
       
   181   if (_pos + 8 > _size)
       
   182     ThrowEndOfData();
       
   183   UInt64 res = GetUInt64FromMem(_buffer + _pos);
       
   184   _pos += 8;
       
   185   return res;
       
   186 }
       
   187 
       
   188 void CInByte2::ReadString(UString &s)
       
   189 {
       
   190   const Byte *buf = _buffer + _pos;
       
   191   size_t rem = (_size - _pos) / 2 * 2;
       
   192   {
       
   193     size_t i;
       
   194     for (i = 0; i < rem; i += 2)
       
   195       if (buf[i] == 0 && buf[i + 1] == 0)
       
   196         break;
       
   197     if (i == rem)
       
   198       ThrowEndOfData();
       
   199     rem = i;
       
   200   }
       
   201   int len = (int)(rem / 2);
       
   202   if (len < 0 || (size_t)len * 2 != rem)
       
   203     ThrowUnsupported();
       
   204   wchar_t *p = s.GetBuffer(len);
       
   205   int i;
       
   206   for (i = 0; i < len; i++, buf += 2) 
       
   207     p[i] = (wchar_t)GetUInt16FromMem(buf);
       
   208   p[i] = 0;
       
   209   s.ReleaseBuffer(len);
       
   210   _pos += rem + 2;
       
   211 }
       
   212 
       
   213 static inline bool TestSignatureCandidate(const Byte *p)
       
   214 {
       
   215   for (int i = 0; i < kSignatureSize; i++)
       
   216     if (p[i] != kSignature[i])
       
   217       return false;
       
   218   return (p[0x1A] == 0 && p[0x1B] == 0);
       
   219 }
       
   220 
       
   221 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
       
   222 {
       
   223   UInt32 processedSize; 
       
   224   RINOK(ReadStream(stream, _header, kHeaderSize, &processedSize));
       
   225   if (processedSize != kHeaderSize)
       
   226     return S_FALSE;
       
   227   if (TestSignatureCandidate(_header))
       
   228     return S_OK;
       
   229 
       
   230   CByteBuffer byteBuffer;
       
   231   const UInt32 kBufferSize = (1 << 16);
       
   232   byteBuffer.SetCapacity(kBufferSize);
       
   233   Byte *buffer = byteBuffer;
       
   234   UInt32 numPrevBytes = kHeaderSize - 1;
       
   235   memcpy(buffer, _header + 1, numPrevBytes);
       
   236   UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
       
   237   for (;;)
       
   238   {
       
   239     if (searchHeaderSizeLimit != NULL)
       
   240       if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
       
   241         break;
       
   242     UInt32 numReadBytes = kBufferSize - numPrevBytes;
       
   243     RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
       
   244     UInt32 numBytesInBuffer = numPrevBytes + processedSize;
       
   245     if (numBytesInBuffer < kHeaderSize)
       
   246       break;
       
   247     UInt32 numTests = numBytesInBuffer - kHeaderSize + 1;
       
   248     for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++)
       
   249     { 
       
   250       if (TestSignatureCandidate(buffer + pos))
       
   251       {
       
   252         memcpy(_header, buffer + pos, kHeaderSize);
       
   253         _arhiveBeginStreamPosition = curTestPos;
       
   254         return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
       
   255       }
       
   256     }
       
   257     numPrevBytes = numBytesInBuffer - numTests;
       
   258     memmove(buffer, buffer + numTests, numPrevBytes);
       
   259   }
       
   260   return S_FALSE;
       
   261 }
       
   262 
       
   263 // S_FALSE means that file is not archive
       
   264 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
       
   265 {
       
   266   Close();
       
   267   RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
       
   268   RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
       
   269   _stream = stream;
       
   270   return S_OK;
       
   271 }
       
   272   
       
   273 void CInArchive::Close()
       
   274 {
       
   275   _stream.Release();
       
   276 }
       
   277 
       
   278 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
       
   279 {
       
   280   for (;;)
       
   281   {
       
   282     if (ReadID() == NID::kEnd)
       
   283       break;
       
   284     SkeepData();
       
   285   }
       
   286 }
       
   287 
       
   288 void CInArchive::GetNextFolderItem(CFolder &folder)
       
   289 {
       
   290   CNum numCoders = ReadNum();
       
   291 
       
   292   folder.Coders.Clear();
       
   293   folder.Coders.Reserve((int)numCoders);
       
   294   CNum numInStreams = 0;
       
   295   CNum numOutStreams = 0;
       
   296   CNum i;
       
   297   for (i = 0; i < numCoders; i++)
       
   298   {
       
   299     folder.Coders.Add(CCoderInfo());
       
   300     CCoderInfo &coder = folder.Coders.Back();
       
   301 
       
   302     {
       
   303       Byte mainByte = ReadByte();
       
   304       int idSize = (mainByte & 0xF);
       
   305       Byte longID[15];
       
   306       ReadBytes(longID, idSize);
       
   307       if (idSize > 8)
       
   308         ThrowUnsupported();
       
   309       UInt64 id = 0;
       
   310       for (int j = 0; j < idSize; j++)
       
   311         id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
       
   312       coder.MethodID = id;
       
   313 
       
   314       if ((mainByte & 0x10) != 0)
       
   315       {
       
   316         coder.NumInStreams = ReadNum();
       
   317         coder.NumOutStreams = ReadNum();
       
   318       }
       
   319       else
       
   320       {
       
   321         coder.NumInStreams = 1;
       
   322         coder.NumOutStreams = 1;
       
   323       }
       
   324       if ((mainByte & 0x20) != 0)
       
   325       {
       
   326         CNum propertiesSize = ReadNum();
       
   327         coder.Properties.SetCapacity((size_t)propertiesSize);
       
   328         ReadBytes((Byte *)coder.Properties, (size_t)propertiesSize);
       
   329       }
       
   330       if ((mainByte & 0x80) != 0)
       
   331         ThrowUnsupported();
       
   332     }
       
   333     numInStreams += coder.NumInStreams;
       
   334     numOutStreams += coder.NumOutStreams;
       
   335   }
       
   336 
       
   337   CNum numBindPairs;
       
   338   numBindPairs = numOutStreams - 1;
       
   339   folder.BindPairs.Clear();
       
   340   folder.BindPairs.Reserve(numBindPairs);
       
   341   for (i = 0; i < numBindPairs; i++)
       
   342   {
       
   343     CBindPair bindPair;
       
   344     bindPair.InIndex = ReadNum();
       
   345     bindPair.OutIndex = ReadNum(); 
       
   346     folder.BindPairs.Add(bindPair);
       
   347   }
       
   348 
       
   349   CNum numPackedStreams = numInStreams - numBindPairs;
       
   350   folder.PackStreams.Reserve(numPackedStreams);
       
   351   if (numPackedStreams == 1)
       
   352   {
       
   353     for (CNum j = 0; j < numInStreams; j++)
       
   354       if (folder.FindBindPairForInStream(j) < 0)
       
   355       {
       
   356         folder.PackStreams.Add(j);
       
   357         break;
       
   358       }
       
   359   }
       
   360   else
       
   361     for(i = 0; i < numPackedStreams; i++)
       
   362       folder.PackStreams.Add(ReadNum());
       
   363 }
       
   364 
       
   365 void CInArchive::WaitAttribute(UInt64 attribute)
       
   366 {
       
   367   for (;;)
       
   368   {
       
   369     UInt64 type = ReadID();
       
   370     if (type == attribute)
       
   371       return;
       
   372     if (type == NID::kEnd)
       
   373       ThrowIncorrect();
       
   374     SkeepData();
       
   375   }
       
   376 }
       
   377 
       
   378 void CInArchive::ReadHashDigests(int numItems,
       
   379     CRecordVector<bool> &digestsDefined, 
       
   380     CRecordVector<UInt32> &digests)
       
   381 {
       
   382   ReadBoolVector2(numItems, digestsDefined);
       
   383   digests.Clear();
       
   384   digests.Reserve(numItems);
       
   385   for(int i = 0; i < numItems; i++)
       
   386   {
       
   387     UInt32 crc = 0;
       
   388     if (digestsDefined[i])
       
   389       crc = ReadUInt32();
       
   390     digests.Add(crc);
       
   391   }
       
   392 }
       
   393 
       
   394 void CInArchive::ReadPackInfo(
       
   395     UInt64 &dataOffset,
       
   396     CRecordVector<UInt64> &packSizes,
       
   397     CRecordVector<bool> &packCRCsDefined,
       
   398     CRecordVector<UInt32> &packCRCs)
       
   399 {
       
   400   dataOffset = ReadNumber();
       
   401   CNum numPackStreams = ReadNum();
       
   402 
       
   403   WaitAttribute(NID::kSize);
       
   404   packSizes.Clear();
       
   405   packSizes.Reserve(numPackStreams);
       
   406   for (CNum i = 0; i < numPackStreams; i++)
       
   407     packSizes.Add(ReadNumber());
       
   408 
       
   409   UInt64 type;
       
   410   for (;;)
       
   411   {
       
   412     type = ReadID();
       
   413     if (type == NID::kEnd)
       
   414       break;
       
   415     if (type == NID::kCRC)
       
   416     {
       
   417       ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); 
       
   418       continue;
       
   419     }
       
   420     SkeepData();
       
   421   }
       
   422   if (packCRCsDefined.IsEmpty())
       
   423   {
       
   424     packCRCsDefined.Reserve(numPackStreams);
       
   425     packCRCsDefined.Clear();
       
   426     packCRCs.Reserve(numPackStreams);
       
   427     packCRCs.Clear();
       
   428     for(CNum i = 0; i < numPackStreams; i++)
       
   429     {
       
   430       packCRCsDefined.Add(false);
       
   431       packCRCs.Add(0);
       
   432     }
       
   433   }
       
   434 }
       
   435 
       
   436 void CInArchive::ReadUnPackInfo(
       
   437     const CObjectVector<CByteBuffer> *dataVector,
       
   438     CObjectVector<CFolder> &folders)
       
   439 {
       
   440   WaitAttribute(NID::kFolder);
       
   441   CNum numFolders = ReadNum();
       
   442 
       
   443   {
       
   444     CStreamSwitch streamSwitch;
       
   445     streamSwitch.Set(this, dataVector);
       
   446     folders.Clear();
       
   447     folders.Reserve(numFolders);
       
   448     for(CNum i = 0; i < numFolders; i++)
       
   449     {
       
   450       folders.Add(CFolder());
       
   451       GetNextFolderItem(folders.Back());
       
   452     }
       
   453   }
       
   454 
       
   455   WaitAttribute(NID::kCodersUnPackSize);
       
   456 
       
   457   CNum i;
       
   458   for (i = 0; i < numFolders; i++)
       
   459   {
       
   460     CFolder &folder = folders[i];
       
   461     CNum numOutStreams = folder.GetNumOutStreams();
       
   462     folder.UnPackSizes.Reserve(numOutStreams);
       
   463     for (CNum j = 0; j < numOutStreams; j++)
       
   464       folder.UnPackSizes.Add(ReadNumber());
       
   465   }
       
   466 
       
   467   for (;;)
       
   468   {
       
   469     UInt64 type = ReadID();
       
   470     if (type == NID::kEnd)
       
   471       return;
       
   472     if (type == NID::kCRC)
       
   473     {
       
   474       CRecordVector<bool> crcsDefined;
       
   475       CRecordVector<UInt32> crcs;
       
   476       ReadHashDigests(numFolders, crcsDefined, crcs); 
       
   477       for(i = 0; i < numFolders; i++)
       
   478       {
       
   479         CFolder &folder = folders[i];
       
   480         folder.UnPackCRCDefined = crcsDefined[i];
       
   481         folder.UnPackCRC = crcs[i];
       
   482       }
       
   483       continue;
       
   484     }
       
   485     SkeepData();
       
   486   }
       
   487 }
       
   488 
       
   489 void CInArchive::ReadSubStreamsInfo(
       
   490     const CObjectVector<CFolder> &folders,
       
   491     CRecordVector<CNum> &numUnPackStreamsInFolders,
       
   492     CRecordVector<UInt64> &unPackSizes,
       
   493     CRecordVector<bool> &digestsDefined, 
       
   494     CRecordVector<UInt32> &digests)
       
   495 {
       
   496   numUnPackStreamsInFolders.Clear();
       
   497   numUnPackStreamsInFolders.Reserve(folders.Size());
       
   498   UInt64 type;
       
   499   for (;;)
       
   500   {
       
   501     type = ReadID();
       
   502     if (type == NID::kNumUnPackStream)
       
   503     {
       
   504       for(int i = 0; i < folders.Size(); i++)
       
   505         numUnPackStreamsInFolders.Add(ReadNum());
       
   506       continue;
       
   507     }
       
   508     if (type == NID::kCRC || type == NID::kSize)
       
   509       break;
       
   510     if (type == NID::kEnd)
       
   511       break;
       
   512     SkeepData();
       
   513   }
       
   514 
       
   515   if (numUnPackStreamsInFolders.IsEmpty())
       
   516     for(int i = 0; i < folders.Size(); i++)
       
   517       numUnPackStreamsInFolders.Add(1);
       
   518 
       
   519   int i;
       
   520   for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
       
   521   {
       
   522     // v3.13 incorrectly worked with empty folders
       
   523     // v4.07: we check that folder is empty
       
   524     CNum numSubstreams = numUnPackStreamsInFolders[i];
       
   525     if (numSubstreams == 0)
       
   526       continue;
       
   527     UInt64 sum = 0;
       
   528     for (CNum j = 1; j < numSubstreams; j++)
       
   529       if (type == NID::kSize)
       
   530       {
       
   531         UInt64 size = ReadNumber();
       
   532         unPackSizes.Add(size);
       
   533         sum += size;
       
   534       }
       
   535     unPackSizes.Add(folders[i].GetUnPackSize() - sum);
       
   536   }
       
   537   if (type == NID::kSize)
       
   538     type = ReadID();
       
   539 
       
   540   int numDigests = 0;
       
   541   int numDigestsTotal = 0;
       
   542   for(i = 0; i < folders.Size(); i++)
       
   543   {
       
   544     CNum numSubstreams = numUnPackStreamsInFolders[i];
       
   545     if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
       
   546       numDigests += numSubstreams;
       
   547     numDigestsTotal += numSubstreams;
       
   548   }
       
   549 
       
   550   for (;;)
       
   551   {
       
   552     if (type == NID::kCRC)
       
   553     {
       
   554       CRecordVector<bool> digestsDefined2; 
       
   555       CRecordVector<UInt32> digests2;
       
   556       ReadHashDigests(numDigests, digestsDefined2, digests2);
       
   557       int digestIndex = 0;
       
   558       for (i = 0; i < folders.Size(); i++)
       
   559       {
       
   560         CNum numSubstreams = numUnPackStreamsInFolders[i];
       
   561         const CFolder &folder = folders[i];
       
   562         if (numSubstreams == 1 && folder.UnPackCRCDefined)
       
   563         {
       
   564           digestsDefined.Add(true);
       
   565           digests.Add(folder.UnPackCRC);
       
   566         }
       
   567         else
       
   568           for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
       
   569           {
       
   570             digestsDefined.Add(digestsDefined2[digestIndex]);
       
   571             digests.Add(digests2[digestIndex]);
       
   572           }
       
   573       }
       
   574     }
       
   575     else if (type == NID::kEnd)
       
   576     {
       
   577       if (digestsDefined.IsEmpty())
       
   578       {
       
   579         digestsDefined.Clear();
       
   580         digests.Clear();
       
   581         for (int i = 0; i < numDigestsTotal; i++)
       
   582         {
       
   583           digestsDefined.Add(false);
       
   584           digests.Add(0);
       
   585         }
       
   586       }
       
   587       return;
       
   588     }
       
   589     else
       
   590       SkeepData();
       
   591     type = ReadID();
       
   592   }
       
   593 }
       
   594 
       
   595 void CInArchive::ReadStreamsInfo(
       
   596     const CObjectVector<CByteBuffer> *dataVector,
       
   597     UInt64 &dataOffset,
       
   598     CRecordVector<UInt64> &packSizes,
       
   599     CRecordVector<bool> &packCRCsDefined,
       
   600     CRecordVector<UInt32> &packCRCs,
       
   601     CObjectVector<CFolder> &folders,
       
   602     CRecordVector<CNum> &numUnPackStreamsInFolders,
       
   603     CRecordVector<UInt64> &unPackSizes,
       
   604     CRecordVector<bool> &digestsDefined, 
       
   605     CRecordVector<UInt32> &digests)
       
   606 {
       
   607   for (;;)
       
   608   {
       
   609     UInt64 type = ReadID();
       
   610     if (type > ((UInt32)1 << 30))
       
   611       ThrowIncorrect();
       
   612     switch((UInt32)type)
       
   613     {
       
   614       case NID::kEnd:
       
   615         return;
       
   616       case NID::kPackInfo:
       
   617       {
       
   618         ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
       
   619         break;
       
   620       }
       
   621       case NID::kUnPackInfo:
       
   622       {
       
   623         ReadUnPackInfo(dataVector, folders);
       
   624         break;
       
   625       }
       
   626       case NID::kSubStreamsInfo:
       
   627       {
       
   628         ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
       
   629             unPackSizes, digestsDefined, digests);
       
   630         break;
       
   631       }
       
   632       default:
       
   633         ThrowIncorrect();
       
   634     }
       
   635   }
       
   636 }
       
   637 
       
   638 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
       
   639 {
       
   640   v.Clear();
       
   641   v.Reserve(numItems);
       
   642   Byte b = 0;
       
   643   Byte mask = 0;
       
   644   for(int i = 0; i < numItems; i++)
       
   645   {
       
   646     if (mask == 0)
       
   647     {
       
   648       b = ReadByte();
       
   649       mask = 0x80;
       
   650     }
       
   651     v.Add((b & mask) != 0);
       
   652     mask >>= 1;
       
   653   }
       
   654 }
       
   655 
       
   656 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
       
   657 {
       
   658   Byte allAreDefined = ReadByte();
       
   659   if (allAreDefined == 0)
       
   660   {
       
   661     ReadBoolVector(numItems, v);
       
   662     return;
       
   663   }
       
   664   v.Clear();
       
   665   v.Reserve(numItems);
       
   666   for (int i = 0; i < numItems; i++)
       
   667     v.Add(true);
       
   668 }
       
   669 
       
   670 void CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector,
       
   671     CObjectVector<CFileItem> &files, UInt32 type)
       
   672 {
       
   673   CBoolVector boolVector;
       
   674   ReadBoolVector2(files.Size(), boolVector);
       
   675 
       
   676   CStreamSwitch streamSwitch;
       
   677   streamSwitch.Set(this, &dataVector);
       
   678 
       
   679   for(int i = 0; i < files.Size(); i++)
       
   680   {
       
   681     CFileItem &file = files[i];
       
   682     CArchiveFileTime fileTime;
       
   683     fileTime.dwLowDateTime = 0;
       
   684     fileTime.dwHighDateTime = 0;
       
   685     bool defined = boolVector[i];
       
   686     if (defined)
       
   687     {
       
   688       fileTime.dwLowDateTime = ReadUInt32();
       
   689       fileTime.dwHighDateTime = ReadUInt32();
       
   690     }
       
   691     switch(type)
       
   692     {
       
   693       case NID::kCreationTime:
       
   694         file.IsCreationTimeDefined = defined;
       
   695         if (defined)
       
   696           file.CreationTime = fileTime;
       
   697         break;
       
   698       case NID::kLastWriteTime:
       
   699         file.IsLastWriteTimeDefined = defined;
       
   700         if (defined)
       
   701           file.LastWriteTime = fileTime;
       
   702         break;
       
   703       case NID::kLastAccessTime:
       
   704         file.IsLastAccessTimeDefined = defined;
       
   705         if (defined)
       
   706           file.LastAccessTime = fileTime;
       
   707         break;
       
   708     }
       
   709   }
       
   710 }
       
   711 
       
   712 HRESULT CInArchive::ReadAndDecodePackedStreams(
       
   713     DECL_EXTERNAL_CODECS_LOC_VARS
       
   714     UInt64 baseOffset, 
       
   715     UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
       
   716     #ifndef _NO_CRYPTO
       
   717     , ICryptoGetTextPassword *getTextPassword
       
   718     #endif
       
   719     )
       
   720 {
       
   721   CRecordVector<UInt64> packSizes;
       
   722   CRecordVector<bool> packCRCsDefined;
       
   723   CRecordVector<UInt32> packCRCs;
       
   724   CObjectVector<CFolder> folders;
       
   725   
       
   726   CRecordVector<CNum> numUnPackStreamsInFolders;
       
   727   CRecordVector<UInt64> unPackSizes;
       
   728   CRecordVector<bool> digestsDefined;
       
   729   CRecordVector<UInt32> digests;
       
   730   
       
   731   ReadStreamsInfo(NULL, 
       
   732     dataOffset,
       
   733     packSizes, 
       
   734     packCRCsDefined, 
       
   735     packCRCs, 
       
   736     folders,
       
   737     numUnPackStreamsInFolders,
       
   738     unPackSizes,
       
   739     digestsDefined, 
       
   740     digests);
       
   741   
       
   742   // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
       
   743   
       
   744   CNum packIndex = 0;
       
   745   CDecoder decoder(
       
   746     #ifdef _ST_MODE
       
   747     false
       
   748     #else
       
   749     true
       
   750     #endif
       
   751     );
       
   752   UInt64 dataStartPos = baseOffset + dataOffset;
       
   753   for(int i = 0; i < folders.Size(); i++)
       
   754   {
       
   755     const CFolder &folder = folders[i];
       
   756     dataVector.Add(CByteBuffer());
       
   757     CByteBuffer &data = dataVector.Back();
       
   758     UInt64 unPackSize64 = folder.GetUnPackSize();
       
   759     size_t unPackSize = (size_t)unPackSize64;
       
   760     if (unPackSize != unPackSize64)
       
   761       ThrowUnsupported();
       
   762     data.SetCapacity(unPackSize);
       
   763     
       
   764     CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
       
   765     CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
       
   766     outStreamSpec->Init(data, unPackSize);
       
   767     
       
   768     HRESULT result = decoder.Decode(
       
   769       EXTERNAL_CODECS_LOC_VARS
       
   770       _stream, dataStartPos, 
       
   771       &packSizes[packIndex], folder, outStream, NULL
       
   772       #ifndef _NO_CRYPTO
       
   773       , getTextPassword
       
   774       #endif
       
   775       #ifdef COMPRESS_MT
       
   776       , false, 1
       
   777       #endif
       
   778       );
       
   779     RINOK(result);
       
   780     
       
   781     if (folder.UnPackCRCDefined)
       
   782       if (CrcCalc(data, unPackSize) != folder.UnPackCRC)
       
   783         ThrowIncorrect();
       
   784       for (int j = 0; j < folder.PackStreams.Size(); j++)
       
   785         dataStartPos += packSizes[packIndex++];
       
   786   }
       
   787   return S_OK;
       
   788 }
       
   789 
       
   790 HRESULT CInArchive::ReadHeader(
       
   791     DECL_EXTERNAL_CODECS_LOC_VARS
       
   792     CArchiveDatabaseEx &database
       
   793     #ifndef _NO_CRYPTO
       
   794     , ICryptoGetTextPassword *getTextPassword
       
   795     #endif
       
   796     )
       
   797 {
       
   798   UInt64 type = ReadID();
       
   799 
       
   800   if (type == NID::kArchiveProperties)
       
   801   {
       
   802     ReadArchiveProperties(database.ArchiveInfo);
       
   803     type = ReadID();
       
   804   }
       
   805  
       
   806   CObjectVector<CByteBuffer> dataVector;
       
   807   
       
   808   if (type == NID::kAdditionalStreamsInfo)
       
   809   {
       
   810     HRESULT result = ReadAndDecodePackedStreams(
       
   811         EXTERNAL_CODECS_LOC_VARS
       
   812         database.ArchiveInfo.StartPositionAfterHeader, 
       
   813         database.ArchiveInfo.DataStartPosition2,
       
   814         dataVector
       
   815         #ifndef _NO_CRYPTO
       
   816         , getTextPassword
       
   817         #endif
       
   818         );
       
   819     RINOK(result);
       
   820     database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
       
   821     type = ReadID();
       
   822   }
       
   823 
       
   824   CRecordVector<UInt64> unPackSizes;
       
   825   CRecordVector<bool> digestsDefined;
       
   826   CRecordVector<UInt32> digests;
       
   827   
       
   828   if (type == NID::kMainStreamsInfo)
       
   829   {
       
   830     ReadStreamsInfo(&dataVector,
       
   831         database.ArchiveInfo.DataStartPosition,
       
   832         database.PackSizes, 
       
   833         database.PackCRCsDefined, 
       
   834         database.PackCRCs, 
       
   835         database.Folders,
       
   836         database.NumUnPackStreamsVector,
       
   837         unPackSizes,
       
   838         digestsDefined,
       
   839         digests);
       
   840     database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
       
   841     type = ReadID();
       
   842   }
       
   843   else
       
   844   {
       
   845     for(int i = 0; i < database.Folders.Size(); i++)
       
   846     {
       
   847       database.NumUnPackStreamsVector.Add(1);
       
   848       CFolder &folder = database.Folders[i];
       
   849       unPackSizes.Add(folder.GetUnPackSize());
       
   850       digestsDefined.Add(folder.UnPackCRCDefined);
       
   851       digests.Add(folder.UnPackCRC);
       
   852     }
       
   853   }
       
   854 
       
   855   database.Files.Clear();
       
   856 
       
   857   if (type == NID::kEnd)
       
   858     return S_OK;
       
   859   if (type != NID::kFilesInfo)
       
   860     ThrowIncorrect();
       
   861   
       
   862   CNum numFiles = ReadNum();
       
   863   database.Files.Reserve(numFiles);
       
   864   CNum i;
       
   865   for(i = 0; i < numFiles; i++)
       
   866     database.Files.Add(CFileItem());
       
   867 
       
   868   database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
       
   869   if (!database.PackSizes.IsEmpty())
       
   870     database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
       
   871   if (numFiles > 0  && !digests.IsEmpty())
       
   872     database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
       
   873 
       
   874   CBoolVector emptyStreamVector;
       
   875   emptyStreamVector.Reserve((int)numFiles);
       
   876   for(i = 0; i < numFiles; i++)
       
   877     emptyStreamVector.Add(false);
       
   878   CBoolVector emptyFileVector;
       
   879   CBoolVector antiFileVector;
       
   880   CNum numEmptyStreams = 0;
       
   881 
       
   882   for (;;)
       
   883   {
       
   884     UInt64 type = ReadID();
       
   885     if (type == NID::kEnd)
       
   886       break;
       
   887     UInt64 size = ReadNumber();
       
   888     bool isKnownType = true;
       
   889     if (type > ((UInt32)1 << 30))
       
   890       isKnownType = false;
       
   891     else switch((UInt32)type)
       
   892     {
       
   893       case NID::kName:
       
   894       {
       
   895         CStreamSwitch streamSwitch;
       
   896         streamSwitch.Set(this, &dataVector);
       
   897         for(int i = 0; i < database.Files.Size(); i++)
       
   898           _inByteBack->ReadString(database.Files[i].Name);
       
   899         break;
       
   900       }
       
   901       case NID::kWinAttributes:
       
   902       {
       
   903         CBoolVector boolVector;
       
   904         ReadBoolVector2(database.Files.Size(), boolVector);
       
   905         CStreamSwitch streamSwitch;
       
   906         streamSwitch.Set(this, &dataVector);
       
   907         for(i = 0; i < numFiles; i++)
       
   908         {
       
   909           CFileItem &file = database.Files[i];
       
   910           file.AreAttributesDefined = boolVector[i];
       
   911           if (file.AreAttributesDefined)
       
   912             file.Attributes = ReadUInt32();
       
   913         }
       
   914         break;
       
   915       }
       
   916       case NID::kStartPos:
       
   917       {
       
   918         CBoolVector boolVector;
       
   919         ReadBoolVector2(database.Files.Size(), boolVector);
       
   920         CStreamSwitch streamSwitch;
       
   921         streamSwitch.Set(this, &dataVector);
       
   922         for(i = 0; i < numFiles; i++)
       
   923         {
       
   924           CFileItem &file = database.Files[i];
       
   925           file.IsStartPosDefined = boolVector[i];
       
   926           if (file.IsStartPosDefined)
       
   927             file.StartPos = ReadUInt64();
       
   928         }
       
   929         break;
       
   930       }
       
   931       case NID::kEmptyStream:
       
   932       {
       
   933         ReadBoolVector(numFiles, emptyStreamVector);
       
   934         for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
       
   935           if (emptyStreamVector[i])
       
   936             numEmptyStreams++;
       
   937         emptyFileVector.Reserve(numEmptyStreams);
       
   938         antiFileVector.Reserve(numEmptyStreams);
       
   939         for (i = 0; i < numEmptyStreams; i++)
       
   940         {
       
   941           emptyFileVector.Add(false);
       
   942           antiFileVector.Add(false);
       
   943         }
       
   944         break;
       
   945       }
       
   946       case NID::kEmptyFile:
       
   947       {
       
   948         ReadBoolVector(numEmptyStreams, emptyFileVector);
       
   949         break;
       
   950       }
       
   951       case NID::kAnti:
       
   952       {
       
   953         ReadBoolVector(numEmptyStreams, antiFileVector);
       
   954         break;
       
   955       }
       
   956       case NID::kCreationTime:
       
   957       case NID::kLastWriteTime:
       
   958       case NID::kLastAccessTime:
       
   959       {
       
   960         ReadTime(dataVector, database.Files, (UInt32)type);
       
   961         break;
       
   962       }
       
   963       default:
       
   964         isKnownType = false;
       
   965     }
       
   966     if (isKnownType)
       
   967       database.ArchiveInfo.FileInfoPopIDs.Add(type);
       
   968     else
       
   969       SkeepData(size);
       
   970   }
       
   971 
       
   972   CNum emptyFileIndex = 0;
       
   973   CNum sizeIndex = 0;
       
   974   for(i = 0; i < numFiles; i++)
       
   975   {
       
   976     CFileItem &file = database.Files[i];
       
   977     file.HasStream = !emptyStreamVector[i];
       
   978     if(file.HasStream)
       
   979     {
       
   980       file.IsDirectory = false;
       
   981       file.IsAnti = false;
       
   982       file.UnPackSize = unPackSizes[sizeIndex];
       
   983       file.FileCRC = digests[sizeIndex];
       
   984       file.IsFileCRCDefined = digestsDefined[sizeIndex];
       
   985       sizeIndex++;
       
   986     }
       
   987     else
       
   988     {
       
   989       file.IsDirectory = !emptyFileVector[emptyFileIndex];
       
   990       file.IsAnti = antiFileVector[emptyFileIndex];
       
   991       emptyFileIndex++;
       
   992       file.UnPackSize = 0;
       
   993       file.IsFileCRCDefined = false;
       
   994     }
       
   995   }
       
   996   return S_OK;
       
   997 }
       
   998 
       
   999 
       
  1000 void CArchiveDatabaseEx::FillFolderStartPackStream()
       
  1001 {
       
  1002   FolderStartPackStreamIndex.Clear();
       
  1003   FolderStartPackStreamIndex.Reserve(Folders.Size());
       
  1004   CNum startPos = 0;
       
  1005   for(int i = 0; i < Folders.Size(); i++)
       
  1006   {
       
  1007     FolderStartPackStreamIndex.Add(startPos);
       
  1008     startPos += (CNum)Folders[i].PackStreams.Size();
       
  1009   }
       
  1010 }
       
  1011 
       
  1012 void CArchiveDatabaseEx::FillStartPos()
       
  1013 {
       
  1014   PackStreamStartPositions.Clear();
       
  1015   PackStreamStartPositions.Reserve(PackSizes.Size());
       
  1016   UInt64 startPos = 0;
       
  1017   for(int i = 0; i < PackSizes.Size(); i++)
       
  1018   {
       
  1019     PackStreamStartPositions.Add(startPos);
       
  1020     startPos += PackSizes[i];
       
  1021   }
       
  1022 }
       
  1023 
       
  1024 void CArchiveDatabaseEx::FillFolderStartFileIndex()
       
  1025 {
       
  1026   FolderStartFileIndex.Clear();
       
  1027   FolderStartFileIndex.Reserve(Folders.Size());
       
  1028   FileIndexToFolderIndexMap.Clear();
       
  1029   FileIndexToFolderIndexMap.Reserve(Files.Size());
       
  1030   
       
  1031   int folderIndex = 0;
       
  1032   CNum indexInFolder = 0;
       
  1033   for (int i = 0; i < Files.Size(); i++)
       
  1034   {
       
  1035     const CFileItem &file = Files[i];
       
  1036     bool emptyStream = !file.HasStream;
       
  1037     if (emptyStream && indexInFolder == 0)
       
  1038     {
       
  1039       FileIndexToFolderIndexMap.Add(kNumNoIndex);
       
  1040       continue;
       
  1041     }
       
  1042     if (indexInFolder == 0)
       
  1043     {
       
  1044       // v3.13 incorrectly worked with empty folders
       
  1045       // v4.07: Loop for skipping empty folders
       
  1046       for (;;)
       
  1047       {
       
  1048         if (folderIndex >= Folders.Size())
       
  1049           ThrowIncorrect();
       
  1050         FolderStartFileIndex.Add(i); // check it
       
  1051         if (NumUnPackStreamsVector[folderIndex] != 0)
       
  1052           break;
       
  1053         folderIndex++;
       
  1054       }
       
  1055     }
       
  1056     FileIndexToFolderIndexMap.Add(folderIndex);
       
  1057     if (emptyStream)
       
  1058       continue;
       
  1059     indexInFolder++;
       
  1060     if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
       
  1061     {
       
  1062       folderIndex++;
       
  1063       indexInFolder = 0;
       
  1064     }
       
  1065   }
       
  1066 }
       
  1067 
       
  1068 HRESULT CInArchive::ReadDatabase2(
       
  1069     DECL_EXTERNAL_CODECS_LOC_VARS
       
  1070     CArchiveDatabaseEx &database
       
  1071     #ifndef _NO_CRYPTO
       
  1072     , ICryptoGetTextPassword *getTextPassword
       
  1073     #endif
       
  1074     )
       
  1075 {
       
  1076   database.Clear();
       
  1077   database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
       
  1078 
       
  1079   database.ArchiveInfo.Version.Major = _header[6];
       
  1080   database.ArchiveInfo.Version.Minor = _header[7];
       
  1081 
       
  1082   if (database.ArchiveInfo.Version.Major != kMajorVersion)
       
  1083     ThrowUnsupportedVersion();
       
  1084 
       
  1085   UInt32 crcFromArchive = GetUInt32FromMem(_header + 8);
       
  1086   UInt64 nextHeaderOffset = GetUInt64FromMem(_header + 0xC);
       
  1087   UInt64 nextHeaderSize = GetUInt64FromMem(_header + 0x14);
       
  1088   UInt32 nextHeaderCRC =  GetUInt32FromMem(_header + 0x1C);
       
  1089   UInt32 crc = CrcCalc(_header + 0xC, 20);
       
  1090 
       
  1091   #ifdef FORMAT_7Z_RECOVERY
       
  1092   if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
       
  1093   {
       
  1094     UInt64 cur, cur2;
       
  1095     RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
       
  1096     const int kCheckSize = 500;
       
  1097     Byte buf[kCheckSize];
       
  1098     RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
       
  1099     int checkSize = kCheckSize;
       
  1100     if (cur2 - cur < kCheckSize)
       
  1101       checkSize = (int)(cur2 - cur);
       
  1102     RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
       
  1103     
       
  1104     UInt32 realProcessedSize;
       
  1105     RINOK(_stream->Read(buf, (UInt32)kCheckSize, &realProcessedSize));
       
  1106 
       
  1107     int i;
       
  1108     for (i = (int)realProcessedSize - 2; i >= 0; i--)
       
  1109       if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
       
  1110         break;
       
  1111     if (i < 0)
       
  1112       return S_FALSE;
       
  1113     nextHeaderSize = realProcessedSize - i;
       
  1114     nextHeaderOffset = cur2 - cur + i;
       
  1115     nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
       
  1116     RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
       
  1117   }
       
  1118   #endif
       
  1119 
       
  1120   #ifdef FORMAT_7Z_RECOVERY
       
  1121   crcFromArchive = crc;
       
  1122   #endif
       
  1123 
       
  1124   database.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
       
  1125 
       
  1126   if (crc != crcFromArchive)
       
  1127     ThrowIncorrect();
       
  1128 
       
  1129   if (nextHeaderSize == 0)
       
  1130     return S_OK;
       
  1131 
       
  1132   if (nextHeaderSize > (UInt64)0xFFFFFFFF)
       
  1133     return S_FALSE;
       
  1134 
       
  1135   RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
       
  1136 
       
  1137   CByteBuffer buffer2;
       
  1138   buffer2.SetCapacity((size_t)nextHeaderSize);
       
  1139 
       
  1140   UInt32 realProcessedSize;
       
  1141   RINOK(_stream->Read(buffer2, (UInt32)nextHeaderSize, &realProcessedSize));
       
  1142   if (realProcessedSize != (UInt32)nextHeaderSize)
       
  1143     return S_FALSE;
       
  1144   if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
       
  1145     ThrowIncorrect();
       
  1146   
       
  1147   CStreamSwitch streamSwitch;
       
  1148   streamSwitch.Set(this, buffer2);
       
  1149   
       
  1150   CObjectVector<CByteBuffer> dataVector;
       
  1151   
       
  1152   for (;;)
       
  1153   {
       
  1154     UInt64 type = ReadID();
       
  1155     if (type == NID::kHeader)
       
  1156       break;
       
  1157     if (type != NID::kEncodedHeader)
       
  1158       ThrowIncorrect();
       
  1159     HRESULT result = ReadAndDecodePackedStreams(
       
  1160         EXTERNAL_CODECS_LOC_VARS
       
  1161         database.ArchiveInfo.StartPositionAfterHeader, 
       
  1162         database.ArchiveInfo.DataStartPosition2,
       
  1163         dataVector
       
  1164         #ifndef _NO_CRYPTO
       
  1165         , getTextPassword
       
  1166         #endif
       
  1167         );
       
  1168     RINOK(result);
       
  1169     if (dataVector.Size() == 0)
       
  1170       return S_OK;
       
  1171     if (dataVector.Size() > 1)
       
  1172       ThrowIncorrect();
       
  1173     streamSwitch.Remove();
       
  1174     streamSwitch.Set(this, dataVector.Front());
       
  1175   }
       
  1176 
       
  1177   return ReadHeader(
       
  1178     EXTERNAL_CODECS_LOC_VARS
       
  1179     database
       
  1180     #ifndef _NO_CRYPTO
       
  1181     , getTextPassword
       
  1182     #endif
       
  1183     );
       
  1184 }
       
  1185 
       
  1186 HRESULT CInArchive::ReadDatabase(
       
  1187     DECL_EXTERNAL_CODECS_LOC_VARS
       
  1188     CArchiveDatabaseEx &database
       
  1189     #ifndef _NO_CRYPTO
       
  1190     , ICryptoGetTextPassword *getTextPassword
       
  1191     #endif
       
  1192     )
       
  1193 {
       
  1194   try
       
  1195   {
       
  1196     return ReadDatabase2(
       
  1197       EXTERNAL_CODECS_LOC_VARS database
       
  1198       #ifndef _NO_CRYPTO
       
  1199       , getTextPassword
       
  1200       #endif
       
  1201       );
       
  1202   }
       
  1203   catch(CInArchiveException &) { return S_FALSE; }
       
  1204 }
       
  1205 
       
  1206 }}