// 7zOut.cpp #include "StdAfx.h" #include "../../../Common/AutoPtr.h" #include "../../Common/StreamObjects.h" #include "7zOut.h" extern "C" { #include "../../../../C/7zCrc.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); } UInt32 CrcUpdateUInt32(UInt32 crc, UInt32 value) { for (int i = 0; i < 4; i++, value >>= 8) crc = CRC_UPDATE_BYTE(crc, (Byte)value); return crc; } UInt32 CrcUpdateUInt64(UInt32 crc, UInt64 value) { for (int i = 0; i < 8; i++, value >>= 8) crc = CRC_UPDATE_BYTE(crc, (Byte)value); return crc; } 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_VOL HRESULT COutArchive::WriteFinishSignature() { RINOK(WriteDirect(kFinishSignature, kSignatureSize)); CArchiveVersion av; av.Major = kMajorVersion; av.Minor = 2; RINOK(WriteDirectByte(av.Major)); return WriteDirectByte(av.Minor); } #endif HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) { UInt32 crc = CRC_INIT_VAL; crc = CrcUpdateUInt64(crc, h.NextHeaderOffset); crc = CrcUpdateUInt64(crc, h.NextHeaderSize); crc = CrcUpdateUInt32(crc, h.NextHeaderCRC); RINOK(WriteDirectUInt32(CRC_GET_DIGEST(crc))); RINOK(WriteDirectUInt64(h.NextHeaderOffset)); RINOK(WriteDirectUInt64(h.NextHeaderSize)); return WriteDirectUInt32(h.NextHeaderCRC); } #ifdef _7Z_VOL HRESULT 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); } #endif HRESULT 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; RINOK(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 = CrcUpdate(_crc, 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; } #ifdef _7Z_VOL static UInt32 GetBigNumberSize(UInt64 value) { int i; for (i = 0; i < 8; i++) if (value < ((UInt64(1) << ( 7 * (i + 1))))) break; return 1 + i; } UInt32 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; } #endif HRESULT 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]; { size_t propertiesSize = coder.Properties.GetCapacity(); UInt64 id = coder.MethodID; int idSize; for (idSize = 1; idSize < sizeof(id); idSize++) if ((id >> (8 * idSize)) == 0) break; BYTE longID[15]; for (int t = idSize - 1; t >= 0 ; t--, id >>= 8) longID[t] = (Byte)(id & 0xFF); Byte b; b = (Byte)(idSize & 0xF); bool isComplex = !coder.IsSimpleCoder(); b |= (isComplex ? 0x10 : 0); b |= ((propertiesSize != 0) ? 0x20 : 0 ); RINOK(WriteByte(b)); RINOK(WriteBytes(longID, idSize)); if (isComplex) { RINOK(WriteNumber(coder.NumInStreams)); RINOK(WriteNumber(coder.NumOutStreams)); } if (propertiesSize == 0) continue; RINOK(WriteNumber(propertiesSize)); RINOK(WriteBytes(coder.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 &digestsDefined, const CRecordVector &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 &packSizes, const CRecordVector &packCRCsDefined, const CRecordVector &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(const CObjectVector &folders) { if (folders.IsEmpty()) return S_OK; RINOK(WriteByte(NID::kUnPackInfo)); RINOK(WriteByte(NID::kFolder)); RINOK(WriteNumber(folders.Size())); { 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 unPackCRCsDefined; CRecordVector 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 &folders, const CRecordVector &numUnPackStreamsInFolders, const CRecordVector &unPackSizes, const CRecordVector &digestsDefined, const CRecordVector &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 digestsDefined2; CRecordVector 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 &files, Byte type) { ///////////////////////////////////////////////// // 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; 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)); } RINOK(WriteByte(0)); for(i = 0; i < files.Size(); i++) { if (boolVector[i]) { const CFileItem &item = files[i]; CArchiveFileTime timeValue; timeValue.dwLowDateTime = 0; timeValue.dwHighDateTime = 0; switch(type) { case NID::kCreationTime: timeValue = item.CreationTime; break; case NID::kLastWriteTime: timeValue = item.LastWriteTime; break; case NID::kLastAccessTime: timeValue = item.LastAccessTime; break; } RINOK(WriteUInt32(timeValue.dwLowDateTime)); RINOK(WriteUInt32(timeValue.dwHighDateTime)); } } return S_OK; } HRESULT COutArchive::EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const Byte *data, size_t dataSize, CRecordVector &packSizes, CObjectVector &folders) { CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp; CMyComPtr stream = streamSpec; streamSpec->Init(data, dataSize); CFolder folderItem; folderItem.UnPackCRCDefined = true; folderItem.UnPackCRC = CrcCalc(data, dataSize); UInt64 dataSize64 = dataSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL)) folders.Add(folderItem); return S_OK; } HRESULT COutArchive::EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, CRecordVector &packSizes, CObjectVector &folders) { return EncodeStream( EXTERNAL_CODECS_LOC_VARS 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 CHeaderOptions &headerOptions, UInt64 &headerOffset) { 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; 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; } } ///////////////////////////////// // 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; 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; } } } ///////////////////////////////// // 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; 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; } } } ///////////////////////////////// // Write Last Write Time // /* CNum numDefinedLastWriteTimes = 0; for(i = 0; i < database.Files.Size(); i++) if (database.Files[i].IsLastWriteTimeDefined) numDefinedLastWriteTimes++; 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; } } } // */ UInt64 packedSize = 0; for(i = 0; i < database.PackSizes.Size(); i++) packedSize += database.PackSizes[i]; headerOffset = packedSize; _mainMode = true; _outByte.SetStream(SeqStream); _outByte.Init(); _crc = CRC_INIT_VAL; RINOK(WriteByte(NID::kHeader)); // Archive Properties if (database.Folders.Size() > 0) { RINOK(WriteByte(NID::kMainStreamsInfo)); RINOK(WritePackInfo(0, database.PackSizes, database.PackCRCsDefined, database.PackCRCs)); RINOK(WriteUnPackInfo(database.Folders)); CRecordVector unPackSizes; CRecordVector digestsDefined; CRecordVector 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)); { RINOK(WriteNumber(1 + namesData.GetCapacity())); RINOK(WriteByte(0)); RINOK(WriteBytes(namesData)); } } if (headerOptions.WriteCreated) { RINOK(WriteTime(database.Files, NID::kCreationTime)); } if (headerOptions.WriteModified) { RINOK(WriteTime(database.Files, NID::kLastWriteTime)); } if (headerOptions.WriteAccessed) { RINOK(WriteTime(database.Files, NID::kLastAccessTime)); } if (numDefinedAttributes > 0) { RINOK(WriteByte(NID::kWinAttributes)); size_t size = 2; if (numDefinedAttributes != database.Files.Size()) size += (attributesBoolVector.Size() + 7) / 8 + 1; size += attributesData.GetCapacity(); RINOK(WriteNumber(size)); if (numDefinedAttributes == database.Files.Size()) { RINOK(WriteByte(1)); } else { RINOK(WriteByte(0)); RINOK(WriteBoolVector(attributesBoolVector)); } { 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; size += startsData.GetCapacity(); RINOK(WriteNumber(size)); if (numDefinedStarts == database.Files.Size()) { RINOK(WriteByte(1)); } else { RINOK(WriteByte(0)); RINOK(WriteBoolVector(startsBoolVector)); } { RINOK(WriteByte(0)); RINOK(WriteBytes(startsData)); } } RINOK(WriteByte(NID::kEnd)); // for files RINOK(WriteByte(NID::kEnd)); // for headers return _outByte.Flush(); } HRESULT COutArchive::WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabase &database, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions) { UInt64 headerOffset; UInt32 headerCRC; UInt64 headerSize; if (database.IsEmpty()) { headerSize = 0; headerOffset = 0; headerCRC = CrcCalc(0, 0); } else { _dynamicBuffer.Init(); _dynamicMode = false; if (options != 0) if (options->IsEmpty()) options = 0; if (options != 0) if (options->PasswordIsDefined || headerOptions.CompressMainHeader) _dynamicMode = true; RINOK(WriteHeader(database, headerOptions, headerOffset)); if (_dynamicMode) { CCompressionMethodMode encryptOptions; encryptOptions.PasswordIsDefined = options->PasswordIsDefined; encryptOptions.Password = options->Password; CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); CRecordVector packSizes; CObjectVector folders; RINOK(EncodeStream( EXTERNAL_CODECS_LOC_VARS encoder, _dynamicBuffer, _dynamicBuffer.GetSize(), packSizes, folders)); _dynamicMode = false; _mainMode = true; _outByte.SetStream(SeqStream); _outByte.Init(); _crc = CRC_INIT_VAL; if (folders.Size() == 0) throw 1; RINOK(WriteID(NID::kEncodedHeader)); RINOK(WritePackInfo(headerOffset, packSizes, CRecordVector(), CRecordVector())); RINOK(WriteUnPackInfo(folders)); RINOK(WriteByte(NID::kEnd)); for (int i = 0; i < packSizes.Size(); i++) headerOffset += packSizes[i]; RINOK(_outByte.Flush()); } headerCRC = CRC_GET_DIGEST(_crc); 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); } } }}