7zout.cpp

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

CPP
1,124
字号
// 7zOut.cpp#include "StdAfx.h"#include "../../../Common/AutoPtr.h"#include "../../Common/StreamObjects.h"#include "7zOut.h"static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size){  while (size > 0)  {    UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);    UInt32 processedSize;    RINOK(stream->Write(data, curSize, &processedSize));    if(processedSize == 0)      return E_FAIL;    data = (const void *)((const Byte *)data + processedSize);    size -= processedSize;  }  return S_OK;}namespace NArchive {namespace N7z {HRESULT COutArchive::WriteDirect(const void *data, UInt32 size){  return ::WriteBytes(SeqStream, data, size);}HRESULT COutArchive::WriteDirectUInt32(UInt32 value){  for (int i = 0; i < 4; i++)  {    RINOK(WriteDirectByte((Byte)value));    value >>= 8;  }  return S_OK;}HRESULT COutArchive::WriteDirectUInt64(UInt64 value){  for (int i = 0; i < 8; i++)  {    RINOK(WriteDirectByte((Byte)value));    value >>= 8;  }  return S_OK;}HRESULT COutArchive::WriteSignature(){  RINOK(WriteDirect(kSignature, kSignatureSize));  RINOK(WriteDirectByte(kMajorVersion));  return WriteDirectByte(2);}#ifdef _7Z_VOLHRESULT COutArchive::WriteFinishSignature(){  RINOK(WriteDirect(kFinishSignature, kSignatureSize));  CArchiveVersion av;  av.Major = kMajorVersion;  av.Minor = 2;  RINOK(WriteDirectByte(av.Major));  return WriteDirectByte(av.Minor);}#endifHRESULT COutArchive::WriteStartHeader(const CStartHeader &h){  CCRC crc;  crc.UpdateUInt64(h.NextHeaderOffset);  crc.UpdateUInt64(h.NextHeaderSize);  crc.UpdateUInt32(h.NextHeaderCRC);  RINOK(WriteDirectUInt32(crc.GetDigest()));  RINOK(WriteDirectUInt64(h.NextHeaderOffset));  RINOK(WriteDirectUInt64(h.NextHeaderSize));  return WriteDirectUInt32(h.NextHeaderCRC);}#ifdef _7Z_VOLHRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h){  CCRC crc;  crc.UpdateUInt64(h.NextHeaderOffset);  crc.UpdateUInt64(h.NextHeaderSize);  crc.UpdateUInt32(h.NextHeaderCRC);  crc.UpdateUInt64(h.ArchiveStartOffset);  crc.UpdateUInt64(h.AdditionalStartBlockSize);  RINOK(WriteDirectUInt32(crc.GetDigest()));  RINOK(WriteDirectUInt64(h.NextHeaderOffset));  RINOK(WriteDirectUInt64(h.NextHeaderSize));  RINOK(WriteDirectUInt32(h.NextHeaderCRC));  RINOK(WriteDirectUInt64(h.ArchiveStartOffset));  return WriteDirectUInt64(h.AdditionalStartBlockSize);}#endifHRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker){  Close();  #ifdef _7Z_VOL  // endMarker = false;  _endMarker = endMarker;  #endif  SeqStream = stream;  if (!endMarker)  {    SeqStream.QueryInterface(IID_IOutStream, &Stream);    if (!Stream)    {      return E_NOTIMPL;      // endMarker = true;    }  }  #ifdef _7Z_VOL  if (endMarker)  {    /*    CStartHeader sh;    sh.NextHeaderOffset = (UInt32)(Int32)-1;    sh.NextHeaderSize = (UInt32)(Int32)-1;    sh.NextHeaderCRC = 0;    WriteStartHeader(sh);    */  }  else  #endif  {    if (!Stream)      return E_FAIL;    WriteSignature();    RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));  }  return S_OK;}void COutArchive::Close(){  SeqStream.Release();  Stream.Release();}HRESULT COutArchive::SkeepPrefixArchiveHeader(){  #ifdef _7Z_VOL  if (_endMarker)    return S_OK;  #endif  return Stream->Seek(24, STREAM_SEEK_CUR, NULL);}HRESULT COutArchive::WriteBytes(const void *data, size_t 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::WriteBytes(const CByteBuffer &data){  return WriteBytes(data, data.GetCapacity());}HRESULT COutArchive::WriteByte(Byte b){  return WriteBytes(&b, 1);}HRESULT COutArchive::WriteUInt32(UInt32 value){  for (int i = 0; i < 4; i++)  {    RINOK(WriteByte((Byte)value));    value >>= 8;  }  return S_OK;}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(WriteByte(firstByte));  for (;i > 0; i--)  {    RINOK(WriteByte((Byte)value));    value >>= 8;  }  return S_OK;}static UInt32 GetBigNumberSize(UInt64 value){  int i;  for (i = 0; i < 8; i++)    if (value < ((UInt64(1) << ( 7  * (i + 1)))))      break;  return 1 + i;}#ifdef _7Z_VOLUInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props){  UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;  if (nameLength != 0)  {    nameLength = (nameLength + 1) * 2;    result += nameLength + GetBigNumberSize(nameLength) + 2;  }  if (props)  {    result += 20;  }  if (result >= 128)    result++;  result += kSignatureSize + 2 + kFinishHeaderSize;  return result;}UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props){  UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);  int testSize;  if (volSize > headersSizeBase)    testSize = volSize - headersSizeBase;  else    testSize = 1;  UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);  UInt64 pureSize = 1;  if (volSize > headersSize)    pureSize = volSize - headersSize;  return pureSize;}#endifHRESULT COutArchive::WriteFolder(const CFolder &folder){  RINOK(WriteNumber(folder.Coders.Size()));  int i;  for (i = 0; i < folder.Coders.Size(); i++)  {    const CCoderInfo &coder = folder.Coders[i];    for (int j = 0; j < coder.AltCoders.Size(); j++)    {      const CAltCoderInfo &altCoder = coder.AltCoders[j];      size_t propertiesSize = altCoder.Properties.GetCapacity();            Byte b;      b = altCoder.MethodID.IDSize & 0xF;      bool isComplex = !coder.IsSimpleCoder();      b |= (isComplex ? 0x10 : 0);      b |= ((propertiesSize != 0) ? 0x20 : 0 );      b |= ((j == coder.AltCoders.Size() - 1) ? 0 : 0x80 );      RINOK(WriteByte(b));      RINOK(WriteBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize));      if (isComplex)      {        RINOK(WriteNumber(coder.NumInStreams));        RINOK(WriteNumber(coder.NumOutStreams));      }      if (propertiesSize == 0)        continue;      RINOK(WriteNumber(propertiesSize));      RINOK(WriteBytes(altCoder.Properties, propertiesSize));    }  }  for (i = 0; i < folder.BindPairs.Size(); i++)  {    const CBindPair &bindPair = folder.BindPairs[i];    RINOK(WriteNumber(bindPair.InIndex));    RINOK(WriteNumber(bindPair.OutIndex));  }  if (folder.PackStreams.Size() > 1)    for (i = 0; i < folder.PackStreams.Size(); i++)    {      RINOK(WriteNumber(folder.PackStreams[i]));    }  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(WriteByte(b));      mask = 0x80;      b = 0;    }  }  if (mask != 0x80)  {    RINOK(WriteByte(b));  }  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(WriteByte(NID::kCRC));  if (numDefined == digestsDefined.Size())  {    RINOK(WriteByte(1));  }  else  {    RINOK(WriteByte(0));    RINOK(WriteBoolVector(digestsDefined));  }  for(i = 0; i < digests.Size(); i++)  {    if(digestsDefined[i])      RINOK(WriteUInt32(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(WriteByte(NID::kPackInfo));  RINOK(WriteNumber(dataOffset));  RINOK(WriteNumber(packSizes.Size()));  RINOK(WriteByte(NID::kSize));  for(int i = 0; i < packSizes.Size(); i++)    RINOK(WriteNumber(packSizes[i]));  RINOK(WriteHashDigests(packCRCsDefined, packCRCs));    return WriteByte(NID::kEnd);}HRESULT COutArchive::WriteUnPackInfo(    bool externalFolders,    CNum externalFoldersStreamIndex,    const CObjectVector<CFolder> &folders){  if (folders.IsEmpty())    return S_OK;  RINOK(WriteByte(NID::kUnPackInfo));  RINOK(WriteByte(NID::kFolder));  RINOK(WriteNumber(folders.Size()));  if (externalFolders)  {    RINOK(WriteByte(1));    RINOK(WriteNumber(externalFoldersStreamIndex));  }  else  {    RINOK(WriteByte(0));    for(int i = 0; i < folders.Size(); i++)      RINOK(WriteFolder(folders[i]));  }    RINOK(WriteByte(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 WriteByte(NID::kEnd);}HRESULT COutArchive::WriteSubStreamsInfo(    const CObjectVector<CFolder> &folders,    const CRecordVector<CNum> &numUnPackStreamsInFolders,    const CRecordVector<UInt64> &unPackSizes,    const CRecordVector<bool> &digestsDefined,    const CRecordVector<UInt32> &digests){  RINOK(WriteByte(NID::kSubStreamsInfo));  int i;  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)  {    if (numUnPackStreamsInFolders[i] != 1)    {      RINOK(WriteByte(NID::kNumUnPackStream));      for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)        RINOK(WriteNumber(numUnPackStreamsInFolders[i]));      break;    }  }   bool needFlag = true;  CNum index = 0;  for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)    for (CNum j = 0; j < numUnPackStreamsInFolders[i]; j++)    {      if (j + 1 != numUnPackStreamsInFolders[i])      {        if (needFlag)          RINOK(WriteByte(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 WriteByte(NID::kEnd);}HRESULT COutArchive::WriteTime(    const CObjectVector<CFileItem> &files, Byte type,    bool isExternal, CNum 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(WriteByte(type));  size_t dataSize = 1 + 1;  if (isExternal)    dataSize += GetBigNumberSize(externalDataIndex);  else    dataSize += files.Size() * 8;  if (allDefined)  {    RINOK(WriteNumber(dataSize));    WriteByte(1);  }  else  {    RINOK(WriteNumber(1 + (boolVector.Size() + 7) / 8 + dataSize));    WriteByte(0);    RINOK(WriteBoolVector(boolVector));  }  if (isExternal)  {    RINOK(WriteByte(1));    RINOK(WriteNumber(externalDataIndex));    return S_OK;  }  RINOK(WriteByte(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;      }

⌨️ 快捷键说明

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