7zin.cpp

来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 1,295 行 · 第 1/3 页

CPP
1,295
字号
    dataVector.Add(CByteBuffer());    CByteBuffer &data = dataVector.Back();    UInt64 unPackSize = folder.GetUnPackSize();    if (unPackSize > kNumMax)      return E_FAIL;    if (unPackSize > 0xFFFFFFFF)      return E_FAIL;    data.SetCapacity((size_t)unPackSize);        CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;    CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;    outStreamSpec->Init(data, (size_t)unPackSize);        HRESULT result = decoder.Decode(_stream, dataStartPos,       &packSizes[packIndex], folder, outStream, NULL      #ifndef _NO_CRYPTO      , getTextPassword      #endif      #ifdef COMPRESS_MT      , false, 1      #endif      );    RINOK(result);        if (folder.UnPackCRCDefined)      if (!CCRC::VerifyDigest(folder.UnPackCRC, data, (UInt32)unPackSize))        throw CInArchiveException(CInArchiveException::kIncorrectHeader);      for (int j = 0; j < folder.PackStreams.Size(); j++)        dataStartPos += packSizes[packIndex++];  }  return S_OK;}HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database    #ifndef _NO_CRYPTO    , ICryptoGetTextPassword *getTextPassword    #endif    ){  UInt64 type;  RINOK(ReadID(type));  if (type == NID::kArchiveProperties)  {    RINOK(ReadArchiveProperties(database.ArchiveInfo));    RINOK(ReadID(type));  }   CObjectVector<CByteBuffer> dataVector;    if (type == NID::kAdditionalStreamsInfo)  {    HRESULT result = ReadAndDecodePackedStreams(        database.ArchiveInfo.StartPositionAfterHeader,         database.ArchiveInfo.DataStartPosition2,        dataVector        #ifndef _NO_CRYPTO        , getTextPassword        #endif        );    RINOK(result);    database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;    RINOK(ReadID(type));  }  CRecordVector<UInt64> unPackSizes;  CRecordVector<bool> digestsDefined;  CRecordVector<UInt32> digests;    if (type == NID::kMainStreamsInfo)  {    RINOK(ReadStreamsInfo(&dataVector,        database.ArchiveInfo.DataStartPosition,        database.PackSizes,         database.PackCRCsDefined,         database.PackCRCs,         database.Folders,        database.NumUnPackStreamsVector,        unPackSizes,        digestsDefined,        digests));    database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;    RINOK(ReadID(type));  }  else  {    for(int i = 0; i < database.Folders.Size(); i++)    {      database.NumUnPackStreamsVector.Add(1);      CFolder &folder = database.Folders[i];      unPackSizes.Add(folder.GetUnPackSize());      digestsDefined.Add(folder.UnPackCRCDefined);      digests.Add(folder.UnPackCRC);    }  }  database.Files.Clear();  if (type == NID::kEnd)    return S_OK;  if (type != NID::kFilesInfo)    throw CInArchiveException(CInArchiveException::kIncorrectHeader);    CNum numFiles;  RINOK(ReadNum(numFiles));  database.Files.Reserve(numFiles);  CNum i;  for(i = 0; i < numFiles; i++)    database.Files.Add(CFileItem());  database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);  if (!database.PackSizes.IsEmpty())    database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);  if (numFiles > 0  && !digests.IsEmpty())    database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);  CBoolVector emptyStreamVector;  emptyStreamVector.Reserve((int)numFiles);  for(i = 0; i < numFiles; i++)    emptyStreamVector.Add(false);  CBoolVector emptyFileVector;  CBoolVector antiFileVector;  CNum numEmptyStreams = 0;  // int sizePrev = -1;  // int posPrev = 0;  while(true)  {    /*    if (sizePrev >= 0)      if (sizePrev != _inByteBack->GetProcessedSize() - posPrev)        throw 2;    */    UInt64 type;    RINOK(ReadID(type));    if (type == NID::kEnd)      break;    UInt64 size;    RINOK(ReadNumber(size));        // sizePrev = size;    // posPrev = _inByteBack->GetProcessedSize();    database.ArchiveInfo.FileInfoPopIDs.Add(type);    switch(type)    {      case NID::kName:      {        CStreamSwitch streamSwitch;        RINOK(streamSwitch.Set(this, &dataVector));        RINOK(ReadFileNames(database.Files))        break;      }      case NID::kWinAttributes:      {        CBoolVector boolVector;        RINOK(ReadBoolVector2(database.Files.Size(), boolVector))        CStreamSwitch streamSwitch;        RINOK(streamSwitch.Set(this, &dataVector));        for(i = 0; i < numFiles; i++)        {          CFileItem &file = database.Files[i];          if (file.AreAttributesDefined = boolVector[i])          {            RINOK(ReadUInt32(file.Attributes));          }        }        break;      }      case NID::kStartPos:      {        CBoolVector boolVector;        RINOK(ReadBoolVector2(database.Files.Size(), boolVector))        CStreamSwitch streamSwitch;        RINOK(streamSwitch.Set(this, &dataVector));        for(i = 0; i < numFiles; i++)        {          CFileItem &file = database.Files[i];          if (file.IsStartPosDefined = boolVector[i])          {            RINOK(ReadUInt64(file.StartPos));          }        }        break;      }      case NID::kEmptyStream:      {        RINOK(ReadBoolVector(numFiles, emptyStreamVector))        for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)          if (emptyStreamVector[i])            numEmptyStreams++;        emptyFileVector.Reserve(numEmptyStreams);        antiFileVector.Reserve(numEmptyStreams);        for (i = 0; i < numEmptyStreams; i++)        {          emptyFileVector.Add(false);          antiFileVector.Add(false);        }        break;      }      case NID::kEmptyFile:      {        RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector))        break;      }      case NID::kAnti:      {        RINOK(ReadBoolVector(numEmptyStreams, antiFileVector))        break;      }      case NID::kCreationTime:      case NID::kLastWriteTime:      case NID::kLastAccessTime:      {        RINOK(ReadTime(dataVector, database.Files, type))        break;      }      default:      {        database.ArchiveInfo.FileInfoPopIDs.DeleteBack();        RINOK(SkeepData(size));      }    }  }  CNum emptyFileIndex = 0;  CNum sizeIndex = 0;  for(i = 0; i < numFiles; i++)  {    CFileItem &file = database.Files[i];    file.HasStream = !emptyStreamVector[i];    if(file.HasStream)    {      file.IsDirectory = false;      file.IsAnti = false;      file.UnPackSize = unPackSizes[sizeIndex];      file.FileCRC = digests[sizeIndex];      file.IsFileCRCDefined = digestsDefined[sizeIndex];      sizeIndex++;    }    else    {      file.IsDirectory = !emptyFileVector[emptyFileIndex];      file.IsAnti = antiFileVector[emptyFileIndex];      emptyFileIndex++;      file.UnPackSize = 0;      file.IsFileCRCDefined = false;    }  }  return S_OK;}void CArchiveDatabaseEx::FillFolderStartPackStream(){  FolderStartPackStreamIndex.Clear();  FolderStartPackStreamIndex.Reserve(Folders.Size());  CNum startPos = 0;  for(int i = 0; i < Folders.Size(); i++)  {    FolderStartPackStreamIndex.Add(startPos);    startPos += (CNum)Folders[i].PackStreams.Size();  }}void CArchiveDatabaseEx::FillStartPos(){  PackStreamStartPositions.Clear();  PackStreamStartPositions.Reserve(PackSizes.Size());  UInt64 startPos = 0;  for(int i = 0; i < PackSizes.Size(); i++)  {    PackStreamStartPositions.Add(startPos);    startPos += PackSizes[i];  }}void CArchiveDatabaseEx::FillFolderStartFileIndex(){  FolderStartFileIndex.Clear();  FolderStartFileIndex.Reserve(Folders.Size());  FileIndexToFolderIndexMap.Clear();  FileIndexToFolderIndexMap.Reserve(Files.Size());    int folderIndex = 0;  CNum indexInFolder = 0;  for (int i = 0; i < Files.Size(); i++)  {    const CFileItem &file = Files[i];    bool emptyStream = !file.HasStream;    if (emptyStream && indexInFolder == 0)    {      FileIndexToFolderIndexMap.Add(kNumNoIndex);      continue;    }    if (indexInFolder == 0)    {      // v3.13 incorrectly worked with empty folders      // v4.07: Loop for skipping empty folders      while(true)      {        if (folderIndex >= Folders.Size())          throw CInArchiveException(CInArchiveException::kIncorrectHeader);        FolderStartFileIndex.Add(i); // check it        if (NumUnPackStreamsVector[folderIndex] != 0)          break;        folderIndex++;      }    }    FileIndexToFolderIndexMap.Add(folderIndex);    if (emptyStream)      continue;    indexInFolder++;    if (indexInFolder >= NumUnPackStreamsVector[folderIndex])    {      folderIndex++;      indexInFolder = 0;    }  }}HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database    #ifndef _NO_CRYPTO    , ICryptoGetTextPassword *getTextPassword    #endif    ){  database.Clear();  database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;  RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Major, 1));  RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Minor, 1));  if (database.ArchiveInfo.Version.Major != kMajorVersion)    throw  CInArchiveException(CInArchiveException::kUnsupportedVersion);  #ifdef _7Z_VOL  if (_finishSignature)  {    RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) -         (kSignatureSize + 2), STREAM_SEEK_SET, &_position));  }  #endif  UInt32 crcFromArchive;  RINOK(SafeReadDirectUInt32(crcFromArchive));  UInt64 nextHeaderOffset;  UInt64 nextHeaderSize;  UInt32 nextHeaderCRC;  CCRC crc;  RINOK(SafeReadDirectUInt64(nextHeaderOffset));  crc.UpdateUInt64(nextHeaderOffset);  RINOK(SafeReadDirectUInt64(nextHeaderSize));  crc.UpdateUInt64(nextHeaderSize);  RINOK(SafeReadDirectUInt32(nextHeaderCRC));  crc.UpdateUInt32(nextHeaderCRC);  #ifdef _7Z_VOL  UInt64 archiveStartOffset;  // data offset from end if that struct  UInt64 additionalStartBlockSize; // start  signature & start header size  if (_finishSignature)  {    RINOK(SafeReadDirectUInt64(archiveStartOffset));    crc.UpdateUInt64(archiveStartOffset);    RINOK(SafeReadDirectUInt64(additionalStartBlockSize));    crc.UpdateUInt64(additionalStartBlockSize);    database.ArchiveInfo.StartPositionAfterHeader = _position + archiveStartOffset;  }  else  #endif  {    database.ArchiveInfo.StartPositionAfterHeader = _position;  }  if (crc.GetDigest() != crcFromArchive)    throw CInArchiveException(CInArchiveException::kIncorrectHeader);  if (nextHeaderSize == 0)    return S_OK;  if (nextHeaderSize >= 0xFFFFFFFF)    return E_FAIL;  RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, &_position));  CByteBuffer buffer2;  buffer2.SetCapacity((size_t)nextHeaderSize);  RINOK(SafeReadDirect(buffer2, (UInt32)nextHeaderSize));  if (!CCRC::VerifyDigest(nextHeaderCRC, buffer2, (UInt32)nextHeaderSize))    throw CInArchiveException(CInArchiveException::kIncorrectHeader);    CStreamSwitch streamSwitch;  streamSwitch.Set(this, buffer2);    CObjectVector<CByteBuffer> dataVector;    while (true)  {    UInt64 type;    RINOK(ReadID(type));    if (type == NID::kHeader)      break;    if (type != NID::kEncodedHeader)      throw CInArchiveException(CInArchiveException::kIncorrectHeader);    HRESULT result = ReadAndDecodePackedStreams(        database.ArchiveInfo.StartPositionAfterHeader,         database.ArchiveInfo.DataStartPosition2,        dataVector        #ifndef _NO_CRYPTO        , getTextPassword        #endif        );    RINOK(result);    if (dataVector.Size() == 0)      return S_OK;    if (dataVector.Size() > 1)      throw CInArchiveException(CInArchiveException::kIncorrectHeader);    streamSwitch.Remove();    streamSwitch.Set(this, dataVector.Front());  }  return ReadHeader(database    #ifndef _NO_CRYPTO    , getTextPassword    #endif    );}}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?