bulk copy of latest physfs to our misc/libphysfs since this seems to fix an off-by-1 error reliably hit in readln read of 1 byte probably introduced in the addition of the buffered read. Whether this is excessive or whether libphysfs should even be maintained by us is another matter. But at least we shouldn't crash
// 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<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(const CObjectVector<CFolder> &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<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)
{
/////////////////////////////////////////////////
// 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<UInt64> &packSizes, CObjectVector<CFolder> &folders)
{
CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp;
CMyComPtr<ISequentialInStream> 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<UInt64> &packSizes, CObjectVector<CFolder> &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<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));
{
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<UInt64> packSizes;
CObjectVector<CFolder> 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<bool>(), CRecordVector<UInt32>()));
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);
}
}
}}