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

📄 7zout.cpp

📁 7-Zip 3.11的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 7zOut.cpp

#include "StdAfx.h"

#include "7zOut.h"
#include "../../Common/StreamObjects.h"

static HRESULT WriteBytes(IOutStream *stream, const void *data, UINT32 size)
{
  UINT32 processedSize;
  RINOK(stream->Write(data, size, &processedSize));
  if(processedSize != size)
    return E_FAIL;
  return S_OK;
}

namespace NArchive {
namespace N7z {

HRESULT COutArchive::Create(IOutStream *stream)
{
  Close();
  RINOK(::WriteBytes(stream, kSignature, kSignatureSize));
  CArchiveVersion archiveVersion;
  archiveVersion.Major = kMajorVersion;
  archiveVersion.Minor = 2;
  RINOK(::WriteBytes(stream, &archiveVersion, sizeof(archiveVersion)));
  RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
  Stream = stream;
  return S_OK;
}

void COutArchive::Close()
{
  Stream.Release();
}

HRESULT COutArchive::SkeepPrefixArchiveHeader()
{
  return Stream->Seek(sizeof(CStartHeader) + sizeof(UINT32), STREAM_SEEK_CUR, NULL);
}

HRESULT COutArchive::WriteBytes(const void *data, UINT32 size)
{
  return ::WriteBytes(Stream, data, size);
}


HRESULT COutArchive::WriteBytes2(const void *data, UINT32 size)
{
  if (_mainMode)
  {
    if (_dynamicMode)
      _dynamicBuffer.Write(data, size);
    else
      _outByte.WriteBytes(data, size);
    _crc.Update(data, size);
  }
  else
  {
    if (_countMode)
      _countSize += size;
    else
      RINOK(_outByte2.Write(data, size));
  }
  return S_OK;
}

HRESULT COutArchive::WriteBytes2(const CByteBuffer &data)
{
  return  WriteBytes2(data, data.GetCapacity());
}

HRESULT COutArchive::WriteByte2(BYTE b)
{
  return WriteBytes2(&b, 1);
}

HRESULT COutArchive::WriteNumber(UINT64 value)
{
  BYTE firstByte = 0;
  BYTE mask = 0x80;
  int i;
  for (i = 0; i < 8; i++)
  {
    if (value < ((UINT64(1) << ( 7  * (i + 1)))))
    {
      firstByte |= BYTE(value >> (8 * i));
      break;
    }
    firstByte |= mask;
    mask >>= 1;
  }
  RINOK(WriteByte2(firstByte));
  return WriteBytes2(&value, i);
}

static UINT32 GetBigNumberSize(UINT64 value)
{
  int i;
  for (i = 0; i < 8; i++)
    if (value < ((UINT64(1) << ( 7  * (i + 1)))))
      break;
  return 1 + i;
}

HRESULT COutArchive::WriteFolderHeader(const CFolder &itemInfo)
{
  RINOK(WriteNumber(itemInfo.Coders.Size()));
  int i;
  for (i = 0; i < itemInfo.Coders.Size(); i++)
  {
    const CCoderInfo &coderInfo = itemInfo.Coders[i];
    for (int j = 0; j < coderInfo.AltCoders.Size(); j++)
    {
      const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders[j];
      UINT64 propertiesSize = altCoderInfo.Properties.GetCapacity();
      
      BYTE b;
      b = altCoderInfo.MethodID.IDSize & 0xF;
      bool isComplex = (coderInfo.NumInStreams != 1) ||  
        (coderInfo.NumOutStreams != 1);
      b |= (isComplex ? 0x10 : 0);
      b |= ((propertiesSize != 0) ? 0x20 : 0 );
      b |= ((j == coderInfo.AltCoders.Size() - 1) ? 0 : 0x80 );
      RINOK(WriteByte2(b));
      RINOK(WriteBytes2(&altCoderInfo.MethodID.ID[0], 
        altCoderInfo.MethodID.IDSize));
      if (isComplex)
      {
        RINOK(WriteNumber(coderInfo.NumInStreams));
        RINOK(WriteNumber(coderInfo.NumOutStreams));
      }
      if (propertiesSize == 0)
        continue;
      RINOK(WriteNumber(propertiesSize));
      RINOK(WriteBytes2(altCoderInfo.Properties, (UINT32)propertiesSize));
    }
  }
  // RINOK(WriteNumber(itemInfo.BindPairs.Size()));
  for (i = 0; i < itemInfo.BindPairs.Size(); i++)
  {
    const CBindPair &bindPair = itemInfo.BindPairs[i];
    RINOK(WriteNumber(bindPair.InIndex));
    RINOK(WriteNumber(bindPair.OutIndex));
  }
  if (itemInfo.PackStreams.Size() > 1)
    for (i = 0; i < itemInfo.PackStreams.Size(); i++)
    {
      const CPackStreamInfo &packStreamInfo = itemInfo.PackStreams[i];
      RINOK(WriteNumber(packStreamInfo.Index));
    }
  return S_OK;
}

HRESULT COutArchive::WriteBoolVector(const CBoolVector &boolVector)
{
  BYTE b = 0;
  BYTE mask = 0x80;
  for(int i = 0; i < boolVector.Size(); i++)
  {
    if (boolVector[i])
      b |= mask;
    mask >>= 1;
    if (mask == 0)
    {
      RINOK(WriteBytes2(&b, 1));
      mask = 0x80;
      b = 0;
    }
  }
  if (mask != 0x80)
  {
    RINOK(WriteBytes2(&b, 1));
  }
  return S_OK;
}


HRESULT COutArchive::WriteHashDigests(
    const CRecordVector<bool> &digestsDefined,
    const CRecordVector<UINT32> &digests)
{
  int numDefined = 0;
  int i;
  for(i = 0; i < digestsDefined.Size(); i++)
    if (digestsDefined[i])
      numDefined++;
  if (numDefined == 0)
    return S_OK;

  RINOK(WriteByte2(NID::kCRC));
  if (numDefined == digestsDefined.Size())
  {
    RINOK(WriteByte2(1));
  }
  else
  {
    RINOK(WriteByte2(0));
    RINOK(WriteBoolVector(digestsDefined));
  }
  for(i = 0; i < digests.Size(); i++)
  {
    if(digestsDefined[i])
      RINOK(WriteBytes2(&digests[i], sizeof(digests[i])));
  }
  return S_OK;
}

HRESULT COutArchive::WritePackInfo(
    UINT64 dataOffset,
    const CRecordVector<UINT64> &packSizes,
    const CRecordVector<bool> &packCRCsDefined,
    const CRecordVector<UINT32> &packCRCs)
{
  if (packSizes.IsEmpty())
    return S_OK;
  RINOK(WriteByte2(NID::kPackInfo));
  RINOK(WriteNumber(dataOffset));
  RINOK(WriteNumber(packSizes.Size()));
  RINOK(WriteByte2(NID::kSize));
  for(int i = 0; i < packSizes.Size(); i++)
    RINOK(WriteNumber(packSizes[i]));

  RINOK(WriteHashDigests(packCRCsDefined, packCRCs));
  
  return WriteByte2(NID::kEnd);
}

HRESULT COutArchive::WriteUnPackInfo(
    bool externalFolders,
    UINT64 externalFoldersStreamIndex,
    const CObjectVector<CFolder> &folders)
{
  if (folders.IsEmpty())
    return S_OK;

  RINOK(WriteByte2(NID::kUnPackInfo));

  RINOK(WriteByte2(NID::kFolder));
  RINOK(WriteNumber(folders.Size()));
  if (externalFolders)
  {
    RINOK(WriteByte2(1));
    RINOK(WriteNumber(externalFoldersStreamIndex));
  }
  else
  {
    RINOK(WriteByte2(0));
    for(int i = 0; i < folders.Size(); i++)
      RINOK(WriteFolderHeader(folders[i]));
  }
  
  RINOK(WriteByte2(NID::kCodersUnPackSize));
  int i;
  for(i = 0; i < folders.Size(); i++)
  {
    const CFolder &folder = folders[i];
    for (int j = 0; j < folder.UnPackSizes.Size(); j++)
      RINOK(WriteNumber(folder.UnPackSizes[j]));
  }

  CRecordVector<bool> unPackCRCsDefined;
  CRecordVector<UINT32> unPackCRCs;
  for(i = 0; i < folders.Size(); i++)
  {
    const CFolder &folder = folders[i];
    unPackCRCsDefined.Add(folder.UnPackCRCDefined);
    unPackCRCs.Add(folder.UnPackCRC);
  }
  RINOK(WriteHashDigests(unPackCRCsDefined, unPackCRCs));

  return WriteByte2(NID::kEnd);
}

HRESULT COutArchive::WriteSubStreamsInfo(
    const CObjectVector<CFolder> &folders,
    const CRecordVector<UINT64> &numUnPackStreamsInFolders,
    const CRecordVector<UINT64> &unPackSizes,
    const CRecordVector<bool> &digestsDefined,
    const CRecordVector<UINT32> &digests)
{
  RINOK(WriteByte2(NID::kSubStreamsInfo));

  int i;
  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
  {
    if (numUnPackStreamsInFolders[i] != 1)
    {
      RINOK(WriteByte2(NID::kNumUnPackStream));
      for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
        RINOK(WriteNumber(numUnPackStreamsInFolders[i]));
      break;
    }
  }
 

  UINT32 needFlag = true;
  UINT32 index = 0;
  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
    for (UINT32 j = 0; j < numUnPackStreamsInFolders[i]; j++)
    {
      if (j + 1 != numUnPackStreamsInFolders[i])
      {
        if (needFlag)
          RINOK(WriteByte2(NID::kSize));
        needFlag = false;
        RINOK(WriteNumber(unPackSizes[index]));
      }
      index++;
    }

  CRecordVector<bool> digestsDefined2;
  CRecordVector<UINT32> digests2;

  int digestIndex = 0;
  for (i = 0; i < folders.Size(); i++)
  {
    int numSubStreams = (int)numUnPackStreamsInFolders[i];
    if (numSubStreams == 1 && folders[i].UnPackCRCDefined)
      digestIndex++;
    else
      for (int j = 0; j < numSubStreams; j++, digestIndex++)
      {
        digestsDefined2.Add(digestsDefined[digestIndex]);
        digests2.Add(digests[digestIndex]);
      }
  }
  RINOK(WriteHashDigests(digestsDefined2, digests2));
  return WriteByte2(NID::kEnd);
}

HRESULT COutArchive::WriteTime(
    const CObjectVector<CFileItem> &files, BYTE type,
    bool isExternal, int externalDataIndex)
{
  /////////////////////////////////////////////////
  // CreationTime
  CBoolVector boolVector;
  boolVector.Reserve(files.Size());
  bool thereAreDefined = false;
  bool allDefined = true;
  int i;
  for(i = 0; i < files.Size(); i++)
  {
    const CFileItem &item = files[i];
    bool defined;
    switch(type)
    {
      case NID::kCreationTime:
        defined = item.IsCreationTimeDefined;
        break;
      case NID::kLastWriteTime:
        defined = item.IsLastWriteTimeDefined;
        break;
      case NID::kLastAccessTime:
        defined = item.IsLastAccessTimeDefined;
        break;
      default:
        throw 1;
    }
    boolVector.Add(defined);
    thereAreDefined = (thereAreDefined || defined);
    allDefined = (allDefined && defined);
  }
  if (!thereAreDefined)
    return S_OK;
  RINOK(WriteByte2(type));
  UINT32 dataSize = 1 + 1;
  if (isExternal)
    dataSize += GetBigNumberSize(externalDataIndex);
  else
    dataSize += files.Size() * sizeof(CArchiveFileTime);
  if (allDefined)
  {
    RINOK(WriteNumber(dataSize));
    WriteByte2(1);
  }
  else
  {
    RINOK(WriteNumber(1 + (boolVector.Size() + 7) / 8 + dataSize));
    WriteByte2(0);
    RINOK(WriteBoolVector(boolVector));
  }
  if (isExternal)
  {
    RINOK(WriteByte2(1));
    RINOK(WriteNumber(externalDataIndex));
    return S_OK;
  }
  RINOK(WriteByte2(0));
  for(i = 0; i < files.Size(); i++)
  {
    if (boolVector[i])
    {
      const CFileItem &item = files[i];
      CArchiveFileTime timeValue;
      switch(type)
      {
        case NID::kCreationTime:
          timeValue = item.CreationTime;
          break;
        case NID::kLastWriteTime:
          timeValue = item.LastWriteTime;
          break;
        case NID::kLastAccessTime:
          timeValue = item.LastAccessTime;
          break;
      }
      RINOK(WriteBytes2(&timeValue, sizeof(timeValue)));
    }
  }
  return S_OK;
}

HRESULT COutArchive::EncodeStream(CEncoder &encoder, const BYTE *data, UINT32 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, Stream,
      packSizes, NULL));

⌨️ 快捷键说明

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