7zout.cpp

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

CPP
1,124
字号
      RINOK(WriteUInt32(timeValue.dwLowDateTime));      RINOK(WriteUInt32(timeValue.dwHighDateTime));    }  }  return S_OK;}HRESULT COutArchive::EncodeStream(CEncoder &encoder, const Byte *data, size_t dataSize,    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders){  CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp;  CMyComPtr<ISequentialInStream> stream = streamSpec;  streamSpec->Init(data, dataSize);  CFolder folderItem;  folderItem.UnPackCRCDefined = true;  folderItem.UnPackCRC = CCRC::CalculateDigest(data, dataSize);  UInt64 dataSize64 = dataSize;  RINOK(encoder.Encode(stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL));  folders.Add(folderItem);  return S_OK;}HRESULT COutArchive::EncodeStream(CEncoder &encoder, const CByteBuffer &data,     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders){  return EncodeStream(encoder, data, data.GetCapacity(), packSizes, folders);}static void WriteUInt32ToBuffer(Byte *data, UInt32 value){  for (int i = 0; i < 4; i++)  {    *data++ = (Byte)value;    value >>= 8;  }}static void WriteUInt64ToBuffer(Byte *data, UInt64 value){  for (int i = 0; i < 8; i++)  {    *data++ = (Byte)value;    value >>= 8;  }}HRESULT COutArchive::WriteHeader(const CArchiveDatabase &database,    const CCompressionMethodMode *options, UInt64 &headerOffset){  CObjectVector<CFolder> folders;  bool compressHeaders = (options != NULL);  CMyAutoPtr<CEncoder> encoder;  if (compressHeaders)  {    // it's for gcc2.95.2    CMyAutoPtr<CEncoder> tmp(new CEncoder(*options));    encoder = tmp;  }  CRecordVector<UInt64> packSizes;  CNum dataIndex = 0;  //////////////////////////  // Folders  CNum externalFoldersStreamIndex;  bool externalFolders = (compressHeaders && database.Folders.Size() > 8);  if (externalFolders)  {    _mainMode = false;    _countMode = true;    _countSize = 0;    int i;    for(i = 0; i < database.Folders.Size(); i++)    {      RINOK(WriteFolder(database.Folders[i]));    }        _countMode = false;        CByteBuffer foldersData;    foldersData.SetCapacity(_countSize);    _outByte2.Init(foldersData, foldersData.GetCapacity());        for(i = 0; i < database.Folders.Size(); i++)    {      RINOK(WriteFolder(database.Folders[i]));    }        {      externalFoldersStreamIndex = dataIndex++;      RINOK(EncodeStream(*encoder, foldersData, packSizes, folders));    }  }  int i;  /////////////////////////////////  // Names  CNum numDefinedNames = 0;  size_t namesDataSize = 0;  for(i = 0; i < database.Files.Size(); i++)  {    const UString &name = database.Files[i].Name;    if (!name.IsEmpty())      numDefinedNames++;    namesDataSize += (name.Length() + 1) * 2;  }  CByteBuffer namesData;  CNum externalNamesStreamIndex;  bool externalNames = (compressHeaders && database.Files.Size() > 8);  if (numDefinedNames > 0)  {    namesData.SetCapacity((size_t)namesDataSize);    size_t pos = 0;    for(int i = 0; i < database.Files.Size(); i++)    {      const UString &name = database.Files[i].Name;      for (int t = 0; t < name.Length(); t++)      {        wchar_t c = name[t];        namesData[pos++] = Byte(c);        namesData[pos++] = Byte(c >> 8);      }      namesData[pos++] = 0;      namesData[pos++] = 0;    }    if (externalNames)    {      externalNamesStreamIndex = dataIndex++;      RINOK(EncodeStream(*encoder, namesData, packSizes, folders));    }  }  /////////////////////////////////  // Write Attributes  CBoolVector attributesBoolVector;  attributesBoolVector.Reserve(database.Files.Size());  int numDefinedAttributes = 0;  for(i = 0; i < database.Files.Size(); i++)  {    bool defined = database.Files[i].AreAttributesDefined;    attributesBoolVector.Add(defined);    if (defined)      numDefinedAttributes++;  }  CByteBuffer attributesData;  CNum externalAttributesStreamIndex;  bool externalAttributes = (compressHeaders && numDefinedAttributes > 8);  if (numDefinedAttributes > 0)  {    attributesData.SetCapacity(numDefinedAttributes * 4);    size_t pos = 0;    for(i = 0; i < database.Files.Size(); i++)    {      const CFileItem &file = database.Files[i];      if (file.AreAttributesDefined)      {        WriteUInt32ToBuffer(attributesData + pos, file.Attributes);        pos += 4;      }    }    if (externalAttributes)    {      externalAttributesStreamIndex = dataIndex++;      RINOK(EncodeStream(*encoder, attributesData, packSizes, folders));    }  }  /////////////////////////////////  // Write StartPos  CBoolVector startsBoolVector;  startsBoolVector.Reserve(database.Files.Size());  int numDefinedStarts = 0;  for(i = 0; i < database.Files.Size(); i++)  {    bool defined = database.Files[i].IsStartPosDefined;    startsBoolVector.Add(defined);    if (defined)      numDefinedStarts++;  }  CByteBuffer startsData;  CNum externalStartStreamIndex;  bool externalStarts = (compressHeaders && numDefinedStarts > 8);  if (numDefinedStarts > 0)  {    startsData.SetCapacity(numDefinedStarts * 8);    size_t pos = 0;    for(i = 0; i < database.Files.Size(); i++)    {      const CFileItem &file = database.Files[i];      if (file.IsStartPosDefined)      {        WriteUInt64ToBuffer(startsData + pos, file.StartPos);        pos += 8;      }    }    if (externalStarts)    {      externalStartStreamIndex = dataIndex++;      RINOK(EncodeStream(*encoder, startsData, packSizes, folders));    }  }    /////////////////////////////////  // Write Last Write Time  CNum externalLastWriteTimeStreamIndex;  bool externalLastWriteTime = false;  // /*  CNum numDefinedLastWriteTimes = 0;  for(i = 0; i < database.Files.Size(); i++)    if (database.Files[i].IsLastWriteTimeDefined)      numDefinedLastWriteTimes++;  externalLastWriteTime = (compressHeaders && numDefinedLastWriteTimes > 64);  if (numDefinedLastWriteTimes > 0)  {    CByteBuffer lastWriteTimeData;    lastWriteTimeData.SetCapacity(numDefinedLastWriteTimes * 8);    size_t pos = 0;    for(i = 0; i < database.Files.Size(); i++)    {      const CFileItem &file = database.Files[i];      if (file.IsLastWriteTimeDefined)      {        WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwLowDateTime);        pos += 4;        WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwHighDateTime);        pos += 4;      }    }    if (externalLastWriteTime)    {      externalLastWriteTimeStreamIndex = dataIndex++;      RINOK(EncodeStream(*encoder, lastWriteTimeData, packSizes, folders));    }  }  // */    UInt64 packedSize = 0;  for(i = 0; i < database.PackSizes.Size(); i++)    packedSize += database.PackSizes[i];  UInt64 headerPackSize = 0;  for (i = 0; i < packSizes.Size(); i++)    headerPackSize += packSizes[i];  headerOffset = packedSize + headerPackSize;  _mainMode = true;  _outByte.SetStream(SeqStream);  _outByte.Init();  _crc.Init();  RINOK(WriteByte(NID::kHeader));  // Archive Properties  if (folders.Size() > 0)  {    RINOK(WriteByte(NID::kAdditionalStreamsInfo));    RINOK(WritePackInfo(packedSize, packSizes,         CRecordVector<bool>(), CRecordVector<UInt32>()));    RINOK(WriteUnPackInfo(false, 0, folders));    RINOK(WriteByte(NID::kEnd));  }  ////////////////////////////////////////////////////   if (database.Folders.Size() > 0)  {    RINOK(WriteByte(NID::kMainStreamsInfo));    RINOK(WritePackInfo(0, database.PackSizes,         database.PackCRCsDefined,        database.PackCRCs));    RINOK(WriteUnPackInfo(externalFolders, externalFoldersStreamIndex, database.Folders));    CRecordVector<UInt64> unPackSizes;    CRecordVector<bool> digestsDefined;    CRecordVector<UInt32> digests;    for (i = 0; i < database.Files.Size(); i++)    {      const CFileItem &file = database.Files[i];      if (!file.HasStream)        continue;      unPackSizes.Add(file.UnPackSize);      digestsDefined.Add(file.IsFileCRCDefined);      digests.Add(file.FileCRC);    }    RINOK(WriteSubStreamsInfo(        database.Folders,        database.NumUnPackStreamsVector,        unPackSizes,        digestsDefined,        digests));    RINOK(WriteByte(NID::kEnd));  }  if (database.Files.IsEmpty())  {    RINOK(WriteByte(NID::kEnd));    return _outByte.Flush();  }  RINOK(WriteByte(NID::kFilesInfo));  RINOK(WriteNumber(database.Files.Size()));  CBoolVector emptyStreamVector;  emptyStreamVector.Reserve(database.Files.Size());  int numEmptyStreams = 0;  for(i = 0; i < database.Files.Size(); i++)    if (database.Files[i].HasStream)      emptyStreamVector.Add(false);    else    {      emptyStreamVector.Add(true);      numEmptyStreams++;    }  if (numEmptyStreams > 0)  {    RINOK(WriteByte(NID::kEmptyStream));    RINOK(WriteNumber((emptyStreamVector.Size() + 7) / 8));    RINOK(WriteBoolVector(emptyStreamVector));    CBoolVector emptyFileVector, antiVector;    emptyFileVector.Reserve(numEmptyStreams);    antiVector.Reserve(numEmptyStreams);    CNum numEmptyFiles = 0, numAntiItems = 0;    for(i = 0; i < database.Files.Size(); i++)    {      const CFileItem &file = database.Files[i];      if (!file.HasStream)      {        emptyFileVector.Add(!file.IsDirectory);        if (!file.IsDirectory)          numEmptyFiles++;        antiVector.Add(file.IsAnti);        if (file.IsAnti)          numAntiItems++;      }    }    if (numEmptyFiles > 0)    {      RINOK(WriteByte(NID::kEmptyFile));      RINOK(WriteNumber((emptyFileVector.Size() + 7) / 8));      RINOK(WriteBoolVector(emptyFileVector));    }    if (numAntiItems > 0)    {      RINOK(WriteByte(NID::kAnti));      RINOK(WriteNumber((antiVector.Size() + 7) / 8));      RINOK(WriteBoolVector(antiVector));    }  }  if (numDefinedNames > 0)  {    /////////////////////////////////////////////////    RINOK(WriteByte(NID::kName));    if (externalNames)    {      RINOK(WriteNumber(1 + GetBigNumberSize(externalNamesStreamIndex)));      RINOK(WriteByte(1));      RINOK(WriteNumber(externalNamesStreamIndex));    }    else    {      RINOK(WriteNumber(1 + namesData.GetCapacity()));      RINOK(WriteByte(0));      RINOK(WriteBytes(namesData));    }  }  RINOK(WriteTime(database.Files, NID::kCreationTime, false, 0));  RINOK(WriteTime(database.Files, NID::kLastAccessTime, false, 0));  RINOK(WriteTime(database.Files, NID::kLastWriteTime,       // false, 0));      externalLastWriteTime, externalLastWriteTimeStreamIndex));  if (numDefinedAttributes > 0)  {    RINOK(WriteByte(NID::kWinAttributes));    size_t size = 2;    if (numDefinedAttributes != database.Files.Size())      size += (attributesBoolVector.Size() + 7) / 8 + 1;    if (externalAttributes)      size += GetBigNumberSize(externalAttributesStreamIndex);    else      size += attributesData.GetCapacity();    RINOK(WriteNumber(size));    if (numDefinedAttributes == database.Files.Size())    {      RINOK(WriteByte(1));    }    else    {      RINOK(WriteByte(0));      RINOK(WriteBoolVector(attributesBoolVector));    }    if (externalAttributes)    {      RINOK(WriteByte(1));      RINOK(WriteNumber(externalAttributesStreamIndex));    }    else    {      RINOK(WriteByte(0));      RINOK(WriteBytes(attributesData));    }  }  if (numDefinedStarts > 0)  {    RINOK(WriteByte(NID::kStartPos));    size_t size = 2;    if (numDefinedStarts != database.Files.Size())      size += (startsBoolVector.Size() + 7) / 8 + 1;    if (externalStarts)      size += GetBigNumberSize(externalStartStreamIndex);    else      size += startsData.GetCapacity();    RINOK(WriteNumber(size));    if (numDefinedStarts == database.Files.Size())    {      RINOK(WriteByte(1));    }    else    {      RINOK(WriteByte(0));      RINOK(WriteBoolVector(startsBoolVector));    }    if (externalAttributes)    {      RINOK(WriteByte(1));      RINOK(WriteNumber(externalStartStreamIndex));    }    else    {      RINOK(WriteByte(0));      RINOK(WriteBytes(startsData));    }  }  RINOK(WriteByte(NID::kEnd)); // for files  RINOK(WriteByte(NID::kEnd)); // for headers  return _outByte.Flush();}HRESULT COutArchive::WriteDatabase(const CArchiveDatabase &database,    const CCompressionMethodMode *options,     bool useAdditionalStreams, bool compressMainHeader){  UInt64 headerOffset;  UInt32 headerCRC;  UInt64 headerSize;  if (database.IsEmpty())  {    headerSize = 0;    headerOffset = 0;    headerCRC = CCRC::CalculateDigest(0, 0);  }  else  {    _dynamicBuffer.Init();    _dynamicMode = false;    if (options != 0)      if (options->IsEmpty())        options = 0;    const CCompressionMethodMode *additionalStreamsOptions = options;    if (!useAdditionalStreams)      additionalStreamsOptions = 0;    /*    if (database.Files.Size() < 2)      compressMainHeader = false;    */    if (options != 0)      if (options->PasswordIsDefined || compressMainHeader)        _dynamicMode = true;    RINOK(WriteHeader(database, additionalStreamsOptions, headerOffset));    if (_dynamicMode)    {      CCompressionMethodMode encryptOptions;      encryptOptions.PasswordIsDefined = options->PasswordIsDefined;      encryptOptions.Password = options->Password;      CEncoder encoder(compressMainHeader ? *options : encryptOptions);      CRecordVector<UInt64> packSizes;      CObjectVector<CFolder> folders;      RINOK(EncodeStream(encoder, _dynamicBuffer,           _dynamicBuffer.GetSize(), packSizes, folders));      _dynamicMode = false;      _mainMode = true;            _outByte.SetStream(SeqStream);      _outByte.Init();      _crc.Init();            if (folders.Size() == 0)        throw 1;      RINOK(WriteID(NID::kEncodedHeader));      RINOK(WritePackInfo(headerOffset, packSizes,         CRecordVector<bool>(), CRecordVector<UInt32>()));      RINOK(WriteUnPackInfo(false, 0, folders));      RINOK(WriteByte(NID::kEnd));      for (int i = 0; i < packSizes.Size(); i++)        headerOffset += packSizes[i];      RINOK(_outByte.Flush());    }    headerCRC = _crc.GetDigest();    headerSize = _outByte.GetProcessedSize();  }  #ifdef _7Z_VOL  if (_endMarker)  {    CFinishHeader h;    h.NextHeaderSize = headerSize;    h.NextHeaderCRC = headerCRC;    h.NextHeaderOffset =         UInt64(0) - (headerSize +         4 + kFinishHeaderSize);    h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;    h.AdditionalStartBlockSize = 0;    RINOK(WriteFinishHeader(h));    return WriteFinishSignature();  }  else  #endif  {    CStartHeader h;    h.NextHeaderSize = headerSize;    h.NextHeaderCRC = headerCRC;    h.NextHeaderOffset = headerOffset;    RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));    return WriteStartHeader(h);  }}}}

⌨️ 快捷键说明

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