⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 7zout.cpp

📁 压缩软件源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    }
  }
  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);
  RINOK(encoder.Encode(stream, NULL, 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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -