misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zOut.cpp
changeset 12218 bb5522e88ab2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zOut.cpp	Mon Apr 10 12:06:43 2017 -0400
@@ -0,0 +1,1026 @@
+// 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);
+  }
+}
+
+}}