other-licenses/7zstub/src/7zip/Archive/7z/7zIn.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 // 7zIn.cpp
     3 #include "StdAfx.h"
     5 #include "7zIn.h"
     6 #include "7zMethods.h"
     7 #include "7zDecode.h"
     8 #include "../../Common/StreamObjects.h"
     9 #include "../../Common/StreamUtils.h"
    10 #include "../../../Common/CRC.h"
    12 namespace NArchive {
    13 namespace N7z {
    15 class CStreamSwitch
    16 {
    17   CInArchive *_archive;
    18   bool _needRemove;
    19 public:
    20   CStreamSwitch(): _needRemove(false) {}
    21   ~CStreamSwitch() { Remove(); }
    22   void Remove();
    23   void Set(CInArchive *archive, const Byte *data, size_t size);
    24   void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
    25   HRESULT Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
    26 };
    28 void CStreamSwitch::Remove()
    29 {
    30   if (_needRemove)
    31   {
    32     _archive->DeleteByteStream();
    33     _needRemove = false;
    34   }
    35 }
    37 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
    38 {
    39   Remove();
    40   _archive = archive;
    41   _archive->AddByteStream(data, size);
    42   _needRemove = true;
    43 }
    45 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
    46 {
    47   Set(archive, byteBuffer, byteBuffer.GetCapacity());
    48 }
    50 HRESULT CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
    51 {
    52   Remove();
    53   Byte external;
    54   RINOK(archive->ReadByte(external));
    55   if (external != 0)
    56   {
    57     CNum dataIndex;
    58     RINOK(archive->ReadNum(dataIndex));
    59     Set(archive, (*dataVector)[dataIndex]);
    60   }
    61   return S_OK;
    62 }
    65 CInArchiveException::CInArchiveException(CCauseType cause):
    66   Cause(cause)
    67 {}
    69 HRESULT CInArchive::ReadDirect(IInStream *stream, void *data, UInt32 size, 
    70     UInt32 *processedSize)
    71 {
    72   UInt32 realProcessedSize;
    73   HRESULT result = ReadStream(stream, data, size, &realProcessedSize);
    74   if(processedSize != NULL)
    75     *processedSize = realProcessedSize;
    76   _position += realProcessedSize;
    77   return result;
    78 }
    80 HRESULT CInArchive::ReadDirect(void *data, UInt32 size, UInt32 *processedSize)
    81 {
    82   return ReadDirect(_stream, data, size, processedSize);
    83 }
    85 HRESULT CInArchive::SafeReadDirect(void *data, UInt32 size)
    86 {
    87   UInt32 realProcessedSize;
    88   RINOK(ReadDirect(data, size, &realProcessedSize));
    89   if (realProcessedSize != size)
    90     throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
    91   return S_OK;
    92 }
    94 HRESULT CInArchive::SafeReadDirectByte(Byte &b)
    95 {
    96   return SafeReadDirect(&b, 1);
    97 }
    99 HRESULT CInArchive::SafeReadDirectUInt32(UInt32 &value)
   100 {
   101   value = 0;
   102   for (int i = 0; i < 4; i++)
   103   {
   104     Byte b;
   105     RINOK(SafeReadDirectByte(b));
   106     value |= (UInt32(b) << (8 * i));
   107   }
   108   return S_OK;
   109 }
   111 HRESULT CInArchive::SafeReadDirectUInt64(UInt64 &value)
   112 {
   113   value = 0;
   114   for (int i = 0; i < 8; i++)
   115   {
   116     Byte b;
   117     RINOK(SafeReadDirectByte(b));
   118     value |= (UInt64(b) << (8 * i));
   119   }
   120   return S_OK;
   121 }
   123 HRESULT CInArchive::ReadNumber(UInt64 &value)
   124 {
   125   Byte firstByte;
   126   RINOK(ReadByte(firstByte));
   127   Byte mask = 0x80;
   128   value = 0;
   129   for (int i = 0; i < 8; i++)
   130   {
   131     if ((firstByte & mask) == 0)
   132     {
   133       UInt64 highPart = firstByte & (mask - 1);
   134       value += (highPart << (i * 8));
   135       return S_OK;
   136     }
   137     Byte b;
   138     RINOK(ReadByte(b));
   139     value |= (UInt64(b) << (8 * i));
   140     mask >>= 1;
   141   }
   142   return S_OK;
   143 }
   145 HRESULT CInArchive::ReadNum(CNum &value)
   146 { 
   147   UInt64 value64;
   148   RINOK(ReadNumber(value64)); 
   149   if (value64 > kNumMax)
   150     return E_FAIL;
   151   value = (CNum)value64;
   152   return S_OK;
   153 }
   155 HRESULT CInArchive::ReadUInt32(UInt32 &value)
   156 {
   157   value = 0;
   158   for (int i = 0; i < 4; i++)
   159   {
   160     Byte b;
   161     RINOK(ReadByte(b));
   162     value |= (UInt32(b) << (8 * i));
   163   }
   164   return S_OK;
   165 }
   167 HRESULT CInArchive::ReadUInt64(UInt64 &value)
   168 {
   169   value = 0;
   170   for (int i = 0; i < 8; i++)
   171   {
   172     Byte b;
   173     RINOK(ReadByte(b));
   174     value |= (UInt64(b) << (8 * i));
   175   }
   176   return S_OK;
   177 }
   179 static inline bool TestSignatureCandidate(const void *testBytes)
   180 {
   181   for (int i = 0; i < kSignatureSize; i++)
   182     if (((const Byte *)testBytes)[i] != kSignature[i])
   183       return false;
   184   return true;
   185 }
   187 #ifdef _7Z_VOL
   188 static inline bool TestFinishSignatureCandidate(const void *testBytes)
   189 {
   190   for (int i = 0; i < kSignatureSize; i++)
   191     if (((const Byte *)testBytes)[i] != kFinishSignature[i])
   192       return false;
   193   return true;
   194 }
   195 #endif
   197 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
   198 {
   199   _position = _arhiveBeginStreamPosition;
   200   RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL));
   202   Byte signature[kSignatureSize];
   203   UInt32 processedSize; 
   204   RINOK(ReadDirect(stream, signature, kSignatureSize, &processedSize));
   205   if(processedSize != kSignatureSize)
   206     return S_FALSE;
   207   if (TestSignatureCandidate(signature))
   208     return S_OK;
   210   CByteBuffer byteBuffer;
   211   const UInt32 kBufferSize = (1 << 16);
   212   byteBuffer.SetCapacity(kBufferSize);
   213   Byte *buffer = byteBuffer;
   214   UInt32 numPrevBytes = kSignatureSize - 1;
   215   memmove(buffer, signature + 1, numPrevBytes);
   216   UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
   217   while(true)
   218   {
   219     if (searchHeaderSizeLimit != NULL)
   220       if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
   221         return S_FALSE;
   222     UInt32 numReadBytes = kBufferSize - numPrevBytes;
   223     RINOK(ReadDirect(stream, buffer + numPrevBytes, numReadBytes, &processedSize));
   224     UInt32 numBytesInBuffer = numPrevBytes + processedSize;
   225     if (numBytesInBuffer < kSignatureSize)
   226       return S_FALSE;
   227     UInt32 numTests = numBytesInBuffer - kSignatureSize + 1;
   228     for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++)
   229     { 
   230       if (TestSignatureCandidate(buffer + pos))
   231       {
   232         _arhiveBeginStreamPosition = curTestPos;
   233         _position = curTestPos + kSignatureSize;
   234         return stream->Seek(_position, STREAM_SEEK_SET, NULL);
   235       }
   236     }
   237     numPrevBytes = numBytesInBuffer - numTests;
   238     memmove(buffer, buffer + numTests, numPrevBytes);
   239   }
   240 }
   242 // Out: _position must point to end of signature
   244 #ifdef _7Z_VOL
   245 HRESULT CInArchive::FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
   246 {
   247   RINOK(stream->Seek(0, STREAM_SEEK_END, &_position));
   248   if (_position < kSignatureSize)
   249     return S_FALSE;
   251   CByteBuffer byteBuffer;
   252   const UInt32 kBufferSize = (1 << 18);
   253   byteBuffer.SetCapacity(kBufferSize);
   254   Byte *buffer = byteBuffer;
   255   UInt32 numPrevBytes = 0;
   256   UInt64 limitPos = 0;
   257   if (searchHeaderSizeLimit != NULL)
   258     if (*searchHeaderSizeLimit < _position)
   259       limitPos = _position - *searchHeaderSizeLimit;
   261   while(_position >= limitPos)
   262   {
   263     UInt32 numReadBytes = kBufferSize - numPrevBytes;
   264     if (numReadBytes > _position)
   265       numReadBytes = (UInt32)_position;
   266     UInt32 numBytesInBuffer = numPrevBytes + numReadBytes;
   267     if (numBytesInBuffer < kSignatureSize)
   268       return S_FALSE;
   269     _position -= numReadBytes;
   270     RINOK(stream->Seek(_position, STREAM_SEEK_SET, &_position));
   271     UInt32 startPos = kBufferSize - numBytesInBuffer;
   272     UInt32 processedSize;
   273     RINOK(ReadDirect(stream, buffer + startPos, numReadBytes, &processedSize));
   274     if (processedSize != numReadBytes)
   275       return S_FALSE;
   276     _position -= processedSize;
   277     for(UInt32 pos = kBufferSize; pos >= startPos + kSignatureSize; pos--)
   278     { 
   279       if (TestFinishSignatureCandidate(buffer + pos - kSignatureSize))
   280       {
   281         _position += pos - startPos;
   282         return stream->Seek(_position, STREAM_SEEK_SET, NULL);
   283       }
   284     }
   285     numPrevBytes = kSignatureSize - 1;
   286     memmove(buffer + kBufferSize - numPrevBytes, buffer + startPos + 1, numPrevBytes);
   287   }
   288   return S_FALSE;
   289 }
   290 #endif
   292 // S_FALSE means that file is not archive
   293 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
   294 {
   295   Close();
   296   RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
   297   _position = _arhiveBeginStreamPosition;
   298   #ifdef _7Z_VOL
   299   HRESULT result = FindFinishSignature(stream, searchHeaderSizeLimit);
   300   if (result == S_OK)
   301     _finishSignature = true;
   302   else
   303   {
   304     if (result != S_FALSE)
   305       return result;
   306     _finishSignature = false;
   307     RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
   308   }
   309   #else
   310   RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
   311   #endif
   312   _stream = stream;
   313   return S_OK;
   314 }
   316 void CInArchive::Close()
   317 {
   318   _stream.Release();
   319 }
   321 HRESULT CInArchive::SkeepData(UInt64 size)
   322 {
   323   for (UInt64 i = 0; i < size; i++)
   324   {
   325     Byte temp;
   326     RINOK(ReadByte(temp));
   327   }
   328   return S_OK;
   329 }
   331 HRESULT CInArchive::SkeepData()
   332 {
   333   UInt64 size;
   334   RINOK(ReadNumber(size));
   335   return SkeepData(size);
   336 }
   338 HRESULT CInArchive::ReadArchiveProperties(CInArchiveInfo &archiveInfo)
   339 {
   340   while(true)
   341   {
   342     UInt64 type;
   343     RINOK(ReadID(type));
   344     if (type == NID::kEnd)
   345       break;
   346     SkeepData();
   347   }
   348   return S_OK;
   349 }
   351 HRESULT CInArchive::GetNextFolderItem(CFolder &folder)
   352 {
   353   CNum numCoders;
   354   RINOK(ReadNum(numCoders));
   356   folder.Coders.Clear();
   357   folder.Coders.Reserve((int)numCoders);
   358   CNum numInStreams = 0;
   359   CNum numOutStreams = 0;
   360   CNum i;
   361   for (i = 0; i < numCoders; i++)
   362   {
   363     folder.Coders.Add(CCoderInfo());
   364     CCoderInfo &coder = folder.Coders.Back();
   366     while (true)
   367     {
   368       coder.AltCoders.Add(CAltCoderInfo());
   369       CAltCoderInfo &altCoder = coder.AltCoders.Back();
   370       Byte mainByte;
   371       RINOK(ReadByte(mainByte));
   372       altCoder.MethodID.IDSize = mainByte & 0xF;
   373       RINOK(ReadBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize));
   374       if ((mainByte & 0x10) != 0)
   375       {
   376         RINOK(ReadNum(coder.NumInStreams));
   377         RINOK(ReadNum(coder.NumOutStreams));
   378       }
   379       else
   380       {
   381         coder.NumInStreams = 1;
   382         coder.NumOutStreams = 1;
   383       }
   384       if ((mainByte & 0x20) != 0)
   385       {
   386         CNum propertiesSize = 0;
   387         RINOK(ReadNum(propertiesSize));
   388         altCoder.Properties.SetCapacity((size_t)propertiesSize);
   389         RINOK(ReadBytes((Byte *)altCoder.Properties, (size_t)propertiesSize));
   390       }
   391       if ((mainByte & 0x80) == 0)
   392         break;
   393     }
   394     numInStreams += coder.NumInStreams;
   395     numOutStreams += coder.NumOutStreams;
   396   }
   398   CNum numBindPairs;
   399   // RINOK(ReadNumber(numBindPairs));
   400   numBindPairs = numOutStreams - 1;
   401   folder.BindPairs.Clear();
   402   folder.BindPairs.Reserve(numBindPairs);
   403   for (i = 0; i < numBindPairs; i++)
   404   {
   405     CBindPair bindPair;
   406     RINOK(ReadNum(bindPair.InIndex));
   407     RINOK(ReadNum(bindPair.OutIndex)); 
   408     folder.BindPairs.Add(bindPair);
   409   }
   411   CNum numPackedStreams = numInStreams - numBindPairs;
   412   folder.PackStreams.Reserve(numPackedStreams);
   413   if (numPackedStreams == 1)
   414   {
   415     for (CNum j = 0; j < numInStreams; j++)
   416       if (folder.FindBindPairForInStream(j) < 0)
   417       {
   418         folder.PackStreams.Add(j);
   419         break;
   420       }
   421   }
   422   else
   423     for(i = 0; i < numPackedStreams; i++)
   424     {
   425       CNum packStreamInfo;
   426       RINOK(ReadNum(packStreamInfo));
   427       folder.PackStreams.Add(packStreamInfo);
   428     }
   430   return S_OK;
   431 }
   433 HRESULT CInArchive::WaitAttribute(UInt64 attribute)
   434 {
   435   while(true)
   436   {
   437     UInt64 type;
   438     RINOK(ReadID(type));
   439     if (type == attribute)
   440       return S_OK;
   441     if (type == NID::kEnd)
   442       return S_FALSE;
   443     RINOK(SkeepData());
   444   }
   445 }
   447 HRESULT CInArchive::ReadHashDigests(int numItems,
   448     CRecordVector<bool> &digestsDefined, 
   449     CRecordVector<UInt32> &digests)
   450 {
   451   RINOK(ReadBoolVector2(numItems, digestsDefined));
   452   digests.Clear();
   453   digests.Reserve(numItems);
   454   for(int i = 0; i < numItems; i++)
   455   {
   456     UInt32 crc;
   457     if (digestsDefined[i])
   458       RINOK(ReadUInt32(crc));
   459     digests.Add(crc);
   460   }
   461   return S_OK;
   462 }
   464 HRESULT CInArchive::ReadPackInfo(
   465     UInt64 &dataOffset,
   466     CRecordVector<UInt64> &packSizes,
   467     CRecordVector<bool> &packCRCsDefined,
   468     CRecordVector<UInt32> &packCRCs)
   469 {
   470   RINOK(ReadNumber(dataOffset));
   471   CNum numPackStreams;
   472   RINOK(ReadNum(numPackStreams));
   474   RINOK(WaitAttribute(NID::kSize));
   475   packSizes.Clear();
   476   packSizes.Reserve(numPackStreams);
   477   for(CNum i = 0; i < numPackStreams; i++)
   478   {
   479     UInt64 size;
   480     RINOK(ReadNumber(size));
   481     packSizes.Add(size);
   482   }
   484   UInt64 type;
   485   while(true)
   486   {
   487     RINOK(ReadID(type));
   488     if (type == NID::kEnd)
   489       break;
   490     if (type == NID::kCRC)
   491     {
   492       RINOK(ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs)); 
   493       continue;
   494     }
   495     RINOK(SkeepData());
   496   }
   497   if (packCRCsDefined.IsEmpty())
   498   {
   499     packCRCsDefined.Reserve(numPackStreams);
   500     packCRCsDefined.Clear();
   501     packCRCs.Reserve(numPackStreams);
   502     packCRCs.Clear();
   503     for(CNum i = 0; i < numPackStreams; i++)
   504     {
   505       packCRCsDefined.Add(false);
   506       packCRCs.Add(0);
   507     }
   508   }
   509   return S_OK;
   510 }
   512 HRESULT CInArchive::ReadUnPackInfo(
   513     const CObjectVector<CByteBuffer> *dataVector,
   514     CObjectVector<CFolder> &folders)
   515 {
   516   RINOK(WaitAttribute(NID::kFolder));
   517   CNum numFolders;
   518   RINOK(ReadNum(numFolders));
   520   {
   521     CStreamSwitch streamSwitch;
   522     RINOK(streamSwitch.Set(this, dataVector));
   523     folders.Clear();
   524     folders.Reserve((UInt32)numFolders);
   525     for(CNum i = 0; i < numFolders; i++)
   526     {
   527       folders.Add(CFolder());
   528       RINOK(GetNextFolderItem(folders.Back()));
   529     }
   530   }
   532   RINOK(WaitAttribute(NID::kCodersUnPackSize));
   534   CNum i;
   535   for(i = 0; i < numFolders; i++)
   536   {
   537     CFolder &folder = folders[i];
   538     CNum numOutStreams = folder.GetNumOutStreams();
   539     folder.UnPackSizes.Reserve(numOutStreams);
   540     for(CNum j = 0; j < numOutStreams; j++)
   541     {
   542       UInt64 unPackSize;
   543       RINOK(ReadNumber(unPackSize));
   544       folder.UnPackSizes.Add(unPackSize);
   545     }
   546   }
   548   while(true)
   549   {
   550     UInt64 type;
   551     RINOK(ReadID(type));
   552     if (type == NID::kEnd)
   553       return S_OK;
   554     if (type == NID::kCRC)
   555     {
   556       CRecordVector<bool> crcsDefined;
   557       CRecordVector<UInt32> crcs;
   558       RINOK(ReadHashDigests(numFolders, crcsDefined, crcs)); 
   559       for(i = 0; i < numFolders; i++)
   560       {
   561         CFolder &folder = folders[i];
   562         folder.UnPackCRCDefined = crcsDefined[i];
   563         folder.UnPackCRC = crcs[i];
   564       }
   565       continue;
   566     }
   567     RINOK(SkeepData());
   568   }
   569 }
   571 HRESULT CInArchive::ReadSubStreamsInfo(
   572     const CObjectVector<CFolder> &folders,
   573     CRecordVector<CNum> &numUnPackStreamsInFolders,
   574     CRecordVector<UInt64> &unPackSizes,
   575     CRecordVector<bool> &digestsDefined, 
   576     CRecordVector<UInt32> &digests)
   577 {
   578   numUnPackStreamsInFolders.Clear();
   579   numUnPackStreamsInFolders.Reserve(folders.Size());
   580   UInt64 type;
   581   while(true)
   582   {
   583     RINOK(ReadID(type));
   584     if (type == NID::kNumUnPackStream)
   585     {
   586       for(int i = 0; i < folders.Size(); i++)
   587       {
   588         CNum value;
   589         RINOK(ReadNum(value));
   590         numUnPackStreamsInFolders.Add(value);
   591       }
   592       continue;
   593     }
   594     if (type == NID::kCRC || type == NID::kSize)
   595       break;
   596     if (type == NID::kEnd)
   597       break;
   598     RINOK(SkeepData());
   599   }
   601   if (numUnPackStreamsInFolders.IsEmpty())
   602     for(int i = 0; i < folders.Size(); i++)
   603       numUnPackStreamsInFolders.Add(1);
   605   int i;
   606   for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
   607   {
   608     // v3.13 incorrectly worked with empty folders
   609     // v4.07: we check that folder is empty
   610     CNum numSubstreams = numUnPackStreamsInFolders[i];
   611     if (numSubstreams == 0)
   612       continue;
   613     UInt64 sum = 0;
   614     for (CNum j = 1; j < numSubstreams; j++)
   615     {
   616       UInt64 size;
   617       if (type == NID::kSize)
   618       {
   619         RINOK(ReadNumber(size));
   620         unPackSizes.Add(size);
   621         sum += size;
   622       }
   623     }
   624     unPackSizes.Add(folders[i].GetUnPackSize() - sum);
   625   }
   626   if (type == NID::kSize)
   627   {
   628     RINOK(ReadID(type));
   629   }
   631   int numDigests = 0;
   632   int numDigestsTotal = 0;
   633   for(i = 0; i < folders.Size(); i++)
   634   {
   635     CNum numSubstreams = numUnPackStreamsInFolders[i];
   636     if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
   637       numDigests += numSubstreams;
   638     numDigestsTotal += numSubstreams;
   639   }
   641   while(true)
   642   {
   643     if (type == NID::kCRC)
   644     {
   645       CRecordVector<bool> digestsDefined2; 
   646       CRecordVector<UInt32> digests2;
   647       RINOK(ReadHashDigests(numDigests, digestsDefined2, digests2));
   648       int digestIndex = 0;
   649       for (i = 0; i < folders.Size(); i++)
   650       {
   651         CNum numSubstreams = numUnPackStreamsInFolders[i];
   652         const CFolder &folder = folders[i];
   653         if (numSubstreams == 1 && folder.UnPackCRCDefined)
   654         {
   655           digestsDefined.Add(true);
   656           digests.Add(folder.UnPackCRC);
   657         }
   658         else
   659           for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
   660           {
   661             digestsDefined.Add(digestsDefined2[digestIndex]);
   662             digests.Add(digests2[digestIndex]);
   663           }
   664       }
   665     }
   666     else if (type == NID::kEnd)
   667     {
   668       if (digestsDefined.IsEmpty())
   669       {
   670         digestsDefined.Clear();
   671         digests.Clear();
   672         for (int i = 0; i < numDigestsTotal; i++)
   673         {
   674           digestsDefined.Add(false);
   675           digests.Add(0);
   676         }
   677       }
   678       return S_OK;
   679     }
   680     else
   681     {
   682       RINOK(SkeepData());
   683     }
   684     RINOK(ReadID(type));
   685   }
   686 }
   688 HRESULT CInArchive::ReadStreamsInfo(
   689     const CObjectVector<CByteBuffer> *dataVector,
   690     UInt64 &dataOffset,
   691     CRecordVector<UInt64> &packSizes,
   692     CRecordVector<bool> &packCRCsDefined,
   693     CRecordVector<UInt32> &packCRCs,
   694     CObjectVector<CFolder> &folders,
   695     CRecordVector<CNum> &numUnPackStreamsInFolders,
   696     CRecordVector<UInt64> &unPackSizes,
   697     CRecordVector<bool> &digestsDefined, 
   698     CRecordVector<UInt32> &digests)
   699 {
   700   while(true)
   701   {
   702     UInt64 type;
   703     RINOK(ReadID(type));
   704     switch(type)
   705     {
   706       case NID::kEnd:
   707         return S_OK;
   708       case NID::kPackInfo:
   709       {
   710         RINOK(ReadPackInfo(dataOffset, packSizes,
   711             packCRCsDefined, packCRCs));
   712         break;
   713       }
   714       case NID::kUnPackInfo:
   715       {
   716         RINOK(ReadUnPackInfo(dataVector, folders));
   717         break;
   718       }
   719       case NID::kSubStreamsInfo:
   720       {
   721         RINOK(ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
   722           unPackSizes, digestsDefined, digests));
   723         break;
   724       }
   725     }
   726   }
   727 }
   729 HRESULT CInArchive::ReadFileNames(CObjectVector<CFileItem> &files)
   730 {
   731   for(int i = 0; i < files.Size(); i++)
   732   {
   733     UString &name = files[i].Name;
   734     name.Empty();
   735     while (true)
   736     {
   737       wchar_t c;
   738       RINOK(ReadWideCharLE(c));
   739       if (c == L'\0')
   740         break;
   741       name += c;
   742     }
   743   }
   744   return S_OK;
   745 }
   747 HRESULT CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
   748 {
   749   v.Clear();
   750   v.Reserve(numItems);
   751   Byte b;
   752   Byte mask = 0;
   753   for(int i = 0; i < numItems; i++)
   754   {
   755     if (mask == 0)
   756     {
   757       RINOK(ReadByte(b));
   758       mask = 0x80;
   759     }
   760     v.Add((b & mask) != 0);
   761     mask >>= 1;
   762   }
   763   return S_OK;
   764 }
   766 HRESULT CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
   767 {
   768   Byte allAreDefined;
   769   RINOK(ReadByte(allAreDefined));
   770   if (allAreDefined == 0)
   771     return ReadBoolVector(numItems, v);
   772   v.Clear();
   773   v.Reserve(numItems);
   774   for (int i = 0; i < numItems; i++)
   775     v.Add(true);
   776   return S_OK;
   777 }
   779 HRESULT CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector,
   780     CObjectVector<CFileItem> &files, UInt64 type)
   781 {
   782   CBoolVector boolVector;
   783   RINOK(ReadBoolVector2(files.Size(), boolVector))
   785   CStreamSwitch streamSwitch;
   786   RINOK(streamSwitch.Set(this, &dataVector));
   788   for(int i = 0; i < files.Size(); i++)
   789   {
   790     CFileItem &file = files[i];
   791     CArchiveFileTime fileTime;
   792     bool defined = boolVector[i];
   793     if (defined)
   794     {
   795       UInt32 low, high;
   796       RINOK(ReadUInt32(low));
   797       RINOK(ReadUInt32(high));
   798       fileTime.dwLowDateTime = low;
   799       fileTime.dwHighDateTime = high;
   800     }
   801     switch(type)
   802     {
   803       case NID::kCreationTime:
   804         file.IsCreationTimeDefined = defined;
   805         if (defined)
   806           file.CreationTime = fileTime;
   807         break;
   808       case NID::kLastWriteTime:
   809         file.IsLastWriteTimeDefined = defined;
   810         if (defined)
   811           file.LastWriteTime = fileTime;
   812         break;
   813       case NID::kLastAccessTime:
   814         file.IsLastAccessTimeDefined = defined;
   815         if (defined)
   816           file.LastAccessTime = fileTime;
   817         break;
   818     }
   819   }
   820   return S_OK;
   821 }
   823 HRESULT CInArchive::ReadAndDecodePackedStreams(UInt64 baseOffset, 
   824     UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
   825     #ifndef _NO_CRYPTO
   826     , ICryptoGetTextPassword *getTextPassword
   827     #endif
   828     )
   829 {
   830   CRecordVector<UInt64> packSizes;
   831   CRecordVector<bool> packCRCsDefined;
   832   CRecordVector<UInt32> packCRCs;
   833   CObjectVector<CFolder> folders;
   835   CRecordVector<CNum> numUnPackStreamsInFolders;
   836   CRecordVector<UInt64> unPackSizes;
   837   CRecordVector<bool> digestsDefined;
   838   CRecordVector<UInt32> digests;
   840   RINOK(ReadStreamsInfo(NULL, 
   841     dataOffset,
   842     packSizes, 
   843     packCRCsDefined, 
   844     packCRCs, 
   845     folders,
   846     numUnPackStreamsInFolders,
   847     unPackSizes,
   848     digestsDefined, 
   849     digests));
   851   // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
   853   CNum packIndex = 0;
   854   CDecoder decoder(
   855     #ifdef _ST_MODE
   856     false
   857     #else
   858     true
   859     #endif
   860     );
   861   UInt64 dataStartPos = baseOffset + dataOffset;
   862   for(int i = 0; i < folders.Size(); i++)
   863   {
   864     const CFolder &folder = folders[i];
   865     dataVector.Add(CByteBuffer());
   866     CByteBuffer &data = dataVector.Back();
   867     UInt64 unPackSize = folder.GetUnPackSize();
   868     if (unPackSize > kNumMax)
   869       return E_FAIL;
   870     if (unPackSize > 0xFFFFFFFF)
   871       return E_FAIL;
   872     data.SetCapacity((size_t)unPackSize);
   874     CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
   875     CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
   876     outStreamSpec->Init(data, (size_t)unPackSize);
   878     HRESULT result = decoder.Decode(_stream, dataStartPos, 
   879       &packSizes[packIndex], folder, outStream, NULL
   880       #ifndef _NO_CRYPTO
   881       , getTextPassword
   882       #endif
   883       #ifdef COMPRESS_MT
   884       , false, 1
   885       #endif
   886       );
   887     RINOK(result);
   889     if (folder.UnPackCRCDefined)
   890       if (!CCRC::VerifyDigest(folder.UnPackCRC, data, (UInt32)unPackSize))
   891         throw CInArchiveException(CInArchiveException::kIncorrectHeader);
   892       for (int j = 0; j < folder.PackStreams.Size(); j++)
   893         dataStartPos += packSizes[packIndex++];
   894   }
   895   return S_OK;
   896 }
   898 HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database
   899     #ifndef _NO_CRYPTO
   900     , ICryptoGetTextPassword *getTextPassword
   901     #endif
   902     )
   903 {
   904   UInt64 type;
   905   RINOK(ReadID(type));
   907   if (type == NID::kArchiveProperties)
   908   {
   909     RINOK(ReadArchiveProperties(database.ArchiveInfo));
   910     RINOK(ReadID(type));
   911   }
   913   CObjectVector<CByteBuffer> dataVector;
   915   if (type == NID::kAdditionalStreamsInfo)
   916   {
   917     HRESULT result = ReadAndDecodePackedStreams(
   918         database.ArchiveInfo.StartPositionAfterHeader, 
   919         database.ArchiveInfo.DataStartPosition2,
   920         dataVector
   921         #ifndef _NO_CRYPTO
   922         , getTextPassword
   923         #endif
   924         );
   925     RINOK(result);
   926     database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
   927     RINOK(ReadID(type));
   928   }
   930   CRecordVector<UInt64> unPackSizes;
   931   CRecordVector<bool> digestsDefined;
   932   CRecordVector<UInt32> digests;
   934   if (type == NID::kMainStreamsInfo)
   935   {
   936     RINOK(ReadStreamsInfo(&dataVector,
   937         database.ArchiveInfo.DataStartPosition,
   938         database.PackSizes, 
   939         database.PackCRCsDefined, 
   940         database.PackCRCs, 
   941         database.Folders,
   942         database.NumUnPackStreamsVector,
   943         unPackSizes,
   944         digestsDefined,
   945         digests));
   946     database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
   947     RINOK(ReadID(type));
   948   }
   949   else
   950   {
   951     for(int i = 0; i < database.Folders.Size(); i++)
   952     {
   953       database.NumUnPackStreamsVector.Add(1);
   954       CFolder &folder = database.Folders[i];
   955       unPackSizes.Add(folder.GetUnPackSize());
   956       digestsDefined.Add(folder.UnPackCRCDefined);
   957       digests.Add(folder.UnPackCRC);
   958     }
   959   }
   961   database.Files.Clear();
   963   if (type == NID::kEnd)
   964     return S_OK;
   965   if (type != NID::kFilesInfo)
   966     throw CInArchiveException(CInArchiveException::kIncorrectHeader);
   968   CNum numFiles;
   969   RINOK(ReadNum(numFiles));
   970   database.Files.Reserve(numFiles);
   971   CNum i;
   972   for(i = 0; i < numFiles; i++)
   973     database.Files.Add(CFileItem());
   975   database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
   976   if (!database.PackSizes.IsEmpty())
   977     database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
   978   if (numFiles > 0  && !digests.IsEmpty())
   979     database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
   981   CBoolVector emptyStreamVector;
   982   emptyStreamVector.Reserve((int)numFiles);
   983   for(i = 0; i < numFiles; i++)
   984     emptyStreamVector.Add(false);
   985   CBoolVector emptyFileVector;
   986   CBoolVector antiFileVector;
   987   CNum numEmptyStreams = 0;
   989   // int sizePrev = -1;
   990   // int posPrev = 0;
   992   while(true)
   993   {
   994     /*
   995     if (sizePrev >= 0)
   996       if (sizePrev != _inByteBack->GetProcessedSize() - posPrev)
   997         throw 2;
   998     */
   999     UInt64 type;
  1000     RINOK(ReadID(type));
  1001     if (type == NID::kEnd)
  1002       break;
  1003     UInt64 size;
  1004     RINOK(ReadNumber(size));
  1006     // sizePrev = size;
  1007     // posPrev = _inByteBack->GetProcessedSize();
  1009     database.ArchiveInfo.FileInfoPopIDs.Add(type);
  1010     switch(type)
  1012       case NID::kName:
  1014         CStreamSwitch streamSwitch;
  1015         RINOK(streamSwitch.Set(this, &dataVector));
  1016         RINOK(ReadFileNames(database.Files))
  1017         break;
  1019       case NID::kWinAttributes:
  1021         CBoolVector boolVector;
  1022         RINOK(ReadBoolVector2(database.Files.Size(), boolVector))
  1023         CStreamSwitch streamSwitch;
  1024         RINOK(streamSwitch.Set(this, &dataVector));
  1025         for(i = 0; i < numFiles; i++)
  1027           CFileItem &file = database.Files[i];
  1028           if (file.AreAttributesDefined = boolVector[i])
  1030             RINOK(ReadUInt32(file.Attributes));
  1033         break;
  1035       case NID::kStartPos:
  1037         CBoolVector boolVector;
  1038         RINOK(ReadBoolVector2(database.Files.Size(), boolVector))
  1039         CStreamSwitch streamSwitch;
  1040         RINOK(streamSwitch.Set(this, &dataVector));
  1041         for(i = 0; i < numFiles; i++)
  1043           CFileItem &file = database.Files[i];
  1044           if (file.IsStartPosDefined = boolVector[i])
  1046             RINOK(ReadUInt64(file.StartPos));
  1049         break;
  1051       case NID::kEmptyStream:
  1053         RINOK(ReadBoolVector(numFiles, emptyStreamVector))
  1054         for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
  1055           if (emptyStreamVector[i])
  1056             numEmptyStreams++;
  1057         emptyFileVector.Reserve(numEmptyStreams);
  1058         antiFileVector.Reserve(numEmptyStreams);
  1059         for (i = 0; i < numEmptyStreams; i++)
  1061           emptyFileVector.Add(false);
  1062           antiFileVector.Add(false);
  1064         break;
  1066       case NID::kEmptyFile:
  1068         RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector))
  1069         break;
  1071       case NID::kAnti:
  1073         RINOK(ReadBoolVector(numEmptyStreams, antiFileVector))
  1074         break;
  1076       case NID::kCreationTime:
  1077       case NID::kLastWriteTime:
  1078       case NID::kLastAccessTime:
  1080         RINOK(ReadTime(dataVector, database.Files, type))
  1081         break;
  1083       default:
  1085         database.ArchiveInfo.FileInfoPopIDs.DeleteBack();
  1086         RINOK(SkeepData(size));
  1091   CNum emptyFileIndex = 0;
  1092   CNum sizeIndex = 0;
  1093   for(i = 0; i < numFiles; i++)
  1095     CFileItem &file = database.Files[i];
  1096     file.HasStream = !emptyStreamVector[i];
  1097     if(file.HasStream)
  1099       file.IsDirectory = false;
  1100       file.IsAnti = false;
  1101       file.UnPackSize = unPackSizes[sizeIndex];
  1102       file.FileCRC = digests[sizeIndex];
  1103       file.IsFileCRCDefined = digestsDefined[sizeIndex];
  1104       sizeIndex++;
  1106     else
  1108       file.IsDirectory = !emptyFileVector[emptyFileIndex];
  1109       file.IsAnti = antiFileVector[emptyFileIndex];
  1110       emptyFileIndex++;
  1111       file.UnPackSize = 0;
  1112       file.IsFileCRCDefined = false;
  1115   return S_OK;
  1119 void CArchiveDatabaseEx::FillFolderStartPackStream()
  1121   FolderStartPackStreamIndex.Clear();
  1122   FolderStartPackStreamIndex.Reserve(Folders.Size());
  1123   CNum startPos = 0;
  1124   for(int i = 0; i < Folders.Size(); i++)
  1126     FolderStartPackStreamIndex.Add(startPos);
  1127     startPos += (CNum)Folders[i].PackStreams.Size();
  1131 void CArchiveDatabaseEx::FillStartPos()
  1133   PackStreamStartPositions.Clear();
  1134   PackStreamStartPositions.Reserve(PackSizes.Size());
  1135   UInt64 startPos = 0;
  1136   for(int i = 0; i < PackSizes.Size(); i++)
  1138     PackStreamStartPositions.Add(startPos);
  1139     startPos += PackSizes[i];
  1143 void CArchiveDatabaseEx::FillFolderStartFileIndex()
  1145   FolderStartFileIndex.Clear();
  1146   FolderStartFileIndex.Reserve(Folders.Size());
  1147   FileIndexToFolderIndexMap.Clear();
  1148   FileIndexToFolderIndexMap.Reserve(Files.Size());
  1150   int folderIndex = 0;
  1151   CNum indexInFolder = 0;
  1152   for (int i = 0; i < Files.Size(); i++)
  1154     const CFileItem &file = Files[i];
  1155     bool emptyStream = !file.HasStream;
  1156     if (emptyStream && indexInFolder == 0)
  1158       FileIndexToFolderIndexMap.Add(kNumNoIndex);
  1159       continue;
  1161     if (indexInFolder == 0)
  1163       // v3.13 incorrectly worked with empty folders
  1164       // v4.07: Loop for skipping empty folders
  1165       while(true)
  1167         if (folderIndex >= Folders.Size())
  1168           throw CInArchiveException(CInArchiveException::kIncorrectHeader);
  1169         FolderStartFileIndex.Add(i); // check it
  1170         if (NumUnPackStreamsVector[folderIndex] != 0)
  1171           break;
  1172         folderIndex++;
  1175     FileIndexToFolderIndexMap.Add(folderIndex);
  1176     if (emptyStream)
  1177       continue;
  1178     indexInFolder++;
  1179     if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
  1181       folderIndex++;
  1182       indexInFolder = 0;
  1187 HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database
  1188     #ifndef _NO_CRYPTO
  1189     , ICryptoGetTextPassword *getTextPassword
  1190     #endif
  1193   database.Clear();
  1194   database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
  1197   RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Major, 1));
  1198   RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Minor, 1));
  1199   if (database.ArchiveInfo.Version.Major != kMajorVersion)
  1200     throw  CInArchiveException(CInArchiveException::kUnsupportedVersion);
  1202   #ifdef _7Z_VOL
  1203   if (_finishSignature)
  1205     RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) - 
  1206         (kSignatureSize + 2), STREAM_SEEK_SET, &_position));
  1208   #endif
  1210   UInt32 crcFromArchive;
  1211   RINOK(SafeReadDirectUInt32(crcFromArchive));
  1213   UInt64 nextHeaderOffset;
  1214   UInt64 nextHeaderSize;
  1215   UInt32 nextHeaderCRC;
  1216   CCRC crc;
  1217   RINOK(SafeReadDirectUInt64(nextHeaderOffset));
  1218   crc.UpdateUInt64(nextHeaderOffset);
  1219   RINOK(SafeReadDirectUInt64(nextHeaderSize));
  1220   crc.UpdateUInt64(nextHeaderSize);
  1221   RINOK(SafeReadDirectUInt32(nextHeaderCRC));
  1222   crc.UpdateUInt32(nextHeaderCRC);
  1224   #ifdef _7Z_VOL
  1225   UInt64 archiveStartOffset;  // data offset from end if that struct
  1226   UInt64 additionalStartBlockSize; // start  signature & start header size
  1227   if (_finishSignature)
  1229     RINOK(SafeReadDirectUInt64(archiveStartOffset));
  1230     crc.UpdateUInt64(archiveStartOffset);
  1231     RINOK(SafeReadDirectUInt64(additionalStartBlockSize));
  1232     crc.UpdateUInt64(additionalStartBlockSize);
  1233     database.ArchiveInfo.StartPositionAfterHeader = _position + archiveStartOffset;
  1235   else
  1236   #endif
  1238     database.ArchiveInfo.StartPositionAfterHeader = _position;
  1240   if (crc.GetDigest() != crcFromArchive)
  1241     throw CInArchiveException(CInArchiveException::kIncorrectHeader);
  1243   if (nextHeaderSize == 0)
  1244     return S_OK;
  1246   if (nextHeaderSize >= 0xFFFFFFFF)
  1247     return E_FAIL;
  1249   RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, &_position));
  1251   CByteBuffer buffer2;
  1252   buffer2.SetCapacity((size_t)nextHeaderSize);
  1253   RINOK(SafeReadDirect(buffer2, (UInt32)nextHeaderSize));
  1254   if (!CCRC::VerifyDigest(nextHeaderCRC, buffer2, (UInt32)nextHeaderSize))
  1255     throw CInArchiveException(CInArchiveException::kIncorrectHeader);
  1257   CStreamSwitch streamSwitch;
  1258   streamSwitch.Set(this, buffer2);
  1260   CObjectVector<CByteBuffer> dataVector;
  1262   while (true)
  1264     UInt64 type;
  1265     RINOK(ReadID(type));
  1266     if (type == NID::kHeader)
  1267       break;
  1268     if (type != NID::kEncodedHeader)
  1269       throw CInArchiveException(CInArchiveException::kIncorrectHeader);
  1270     HRESULT result = ReadAndDecodePackedStreams(
  1271         database.ArchiveInfo.StartPositionAfterHeader, 
  1272         database.ArchiveInfo.DataStartPosition2,
  1273         dataVector
  1274         #ifndef _NO_CRYPTO
  1275         , getTextPassword
  1276         #endif
  1277         );
  1278     RINOK(result);
  1279     if (dataVector.Size() == 0)
  1280       return S_OK;
  1281     if (dataVector.Size() > 1)
  1282       throw CInArchiveException(CInArchiveException::kIncorrectHeader);
  1283     streamSwitch.Remove();
  1284     streamSwitch.Set(this, dataVector.Front());
  1287   return ReadHeader(database
  1288     #ifndef _NO_CRYPTO
  1289     , getTextPassword
  1290     #endif
  1291     );
  1294 }}

mercurial