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 + -
显示快捷键?