Home | History | Annotate | Download | only in 7z
      1 // 7zOut.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../../C/7zCrc.h"
      6 
      7 #include "../../../Common/AutoPtr.h"
      8 
      9 #include "../../Common/StreamObjects.h"
     10 
     11 #include "7zOut.h"
     12 
     13 static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
     14 {
     15   while (size > 0)
     16   {
     17     UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
     18     UInt32 processedSize;
     19     RINOK(stream->Write(data, curSize, &processedSize));
     20     if (processedSize == 0)
     21       return E_FAIL;
     22     data = (const void *)((const Byte *)data + processedSize);
     23     size -= processedSize;
     24   }
     25   return S_OK;
     26 }
     27 
     28 namespace NArchive {
     29 namespace N7z {
     30 
     31 HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
     32 {
     33   return ::WriteBytes(SeqStream, data, size);
     34 }
     35 
     36 HRESULT COutArchive::WriteSignature()
     37 {
     38   Byte buf[8];
     39   memcpy(buf, kSignature, kSignatureSize);
     40   buf[kSignatureSize] = kMajorVersion;
     41   buf[kSignatureSize + 1] = 3;
     42   return WriteDirect(buf, 8);
     43 }
     44 
     45 #ifdef _7Z_VOL
     46 HRESULT COutArchive::WriteFinishSignature()
     47 {
     48   RINOK(WriteDirect(kFinishSignature, kSignatureSize));
     49   CArchiveVersion av;
     50   av.Major = kMajorVersion;
     51   av.Minor = 2;
     52   RINOK(WriteDirectByte(av.Major));
     53   return WriteDirectByte(av.Minor);
     54 }
     55 #endif
     56 
     57 static void SetUInt32(Byte *p, UInt32 d)
     58 {
     59   for (int i = 0; i < 4; i++, d >>= 8)
     60     p[i] = (Byte)d;
     61 }
     62 
     63 static void SetUInt64(Byte *p, UInt64 d)
     64 {
     65   for (int i = 0; i < 8; i++, d >>= 8)
     66     p[i] = (Byte)d;
     67 }
     68 
     69 HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
     70 {
     71   Byte buf[24];
     72   SetUInt64(buf + 4, h.NextHeaderOffset);
     73   SetUInt64(buf + 12, h.NextHeaderSize);
     74   SetUInt32(buf + 20, h.NextHeaderCRC);
     75   SetUInt32(buf, CrcCalc(buf + 4, 20));
     76   return WriteDirect(buf, 24);
     77 }
     78 
     79 #ifdef _7Z_VOL
     80 HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
     81 {
     82   CCRC crc;
     83   crc.UpdateUInt64(h.NextHeaderOffset);
     84   crc.UpdateUInt64(h.NextHeaderSize);
     85   crc.UpdateUInt32(h.NextHeaderCRC);
     86   crc.UpdateUInt64(h.ArchiveStartOffset);
     87   crc.UpdateUInt64(h.AdditionalStartBlockSize);
     88   RINOK(WriteDirectUInt32(crc.GetDigest()));
     89   RINOK(WriteDirectUInt64(h.NextHeaderOffset));
     90   RINOK(WriteDirectUInt64(h.NextHeaderSize));
     91   RINOK(WriteDirectUInt32(h.NextHeaderCRC));
     92   RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
     93   return WriteDirectUInt64(h.AdditionalStartBlockSize);
     94 }
     95 #endif
     96 
     97 HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
     98 {
     99   Close();
    100   #ifdef _7Z_VOL
    101   // endMarker = false;
    102   _endMarker = endMarker;
    103   #endif
    104   SeqStream = stream;
    105   if (!endMarker)
    106   {
    107     SeqStream.QueryInterface(IID_IOutStream, &Stream);
    108     if (!Stream)
    109     {
    110       return E_NOTIMPL;
    111       // endMarker = true;
    112     }
    113   }
    114   #ifdef _7Z_VOL
    115   if (endMarker)
    116   {
    117     /*
    118     CStartHeader sh;
    119     sh.NextHeaderOffset = (UInt32)(Int32)-1;
    120     sh.NextHeaderSize = (UInt32)(Int32)-1;
    121     sh.NextHeaderCRC = 0;
    122     WriteStartHeader(sh);
    123     */
    124   }
    125   else
    126   #endif
    127   {
    128     if (!Stream)
    129       return E_FAIL;
    130     RINOK(WriteSignature());
    131     RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
    132   }
    133   return S_OK;
    134 }
    135 
    136 void COutArchive::Close()
    137 {
    138   SeqStream.Release();
    139   Stream.Release();
    140 }
    141 
    142 HRESULT COutArchive::SkipPrefixArchiveHeader()
    143 {
    144   #ifdef _7Z_VOL
    145   if (_endMarker)
    146     return S_OK;
    147   #endif
    148   return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
    149 }
    150 
    151 UInt64 COutArchive::GetPos() const
    152 {
    153   if (_countMode)
    154     return _countSize;
    155   if (_writeToStream)
    156     return _outByte.GetProcessedSize();
    157   return _outByte2.GetPos();
    158 }
    159 
    160 void COutArchive::WriteBytes(const void *data, size_t size)
    161 {
    162   if (_countMode)
    163     _countSize += size;
    164   else if (_writeToStream)
    165   {
    166     _outByte.WriteBytes(data, size);
    167     _crc = CrcUpdate(_crc, data, size);
    168   }
    169   else
    170     _outByte2.WriteBytes(data, size);
    171 }
    172 
    173 void COutArchive::WriteByte(Byte b)
    174 {
    175   if (_countMode)
    176     _countSize++;
    177   else if (_writeToStream)
    178   {
    179     _outByte.WriteByte(b);
    180     _crc = CRC_UPDATE_BYTE(_crc, b);
    181   }
    182   else
    183     _outByte2.WriteByte(b);
    184 }
    185 
    186 void COutArchive::WriteUInt32(UInt32 value)
    187 {
    188   for (int i = 0; i < 4; i++)
    189   {
    190     WriteByte((Byte)value);
    191     value >>= 8;
    192   }
    193 }
    194 
    195 void COutArchive::WriteUInt64(UInt64 value)
    196 {
    197   for (int i = 0; i < 8; i++)
    198   {
    199     WriteByte((Byte)value);
    200     value >>= 8;
    201   }
    202 }
    203 
    204 void COutArchive::WriteNumber(UInt64 value)
    205 {
    206   Byte firstByte = 0;
    207   Byte mask = 0x80;
    208   int i;
    209   for (i = 0; i < 8; i++)
    210   {
    211     if (value < ((UInt64(1) << ( 7  * (i + 1)))))
    212     {
    213       firstByte |= Byte(value >> (8 * i));
    214       break;
    215     }
    216     firstByte |= mask;
    217     mask >>= 1;
    218   }
    219   WriteByte(firstByte);
    220   for (;i > 0; i--)
    221   {
    222     WriteByte((Byte)value);
    223     value >>= 8;
    224   }
    225 }
    226 
    227 static UInt32 GetBigNumberSize(UInt64 value)
    228 {
    229   int i;
    230   for (i = 1; i < 9; i++)
    231     if (value < (((UInt64)1 << (i * 7))))
    232       break;
    233   return i;
    234 }
    235 
    236 #ifdef _7Z_VOL
    237 UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
    238 {
    239   UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
    240   if (nameLength != 0)
    241   {
    242     nameLength = (nameLength + 1) * 2;
    243     result += nameLength + GetBigNumberSize(nameLength) + 2;
    244   }
    245   if (props)
    246   {
    247     result += 20;
    248   }
    249   if (result >= 128)
    250     result++;
    251   result += kSignatureSize + 2 + kFinishHeaderSize;
    252   return result;
    253 }
    254 
    255 UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
    256 {
    257   UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
    258   int testSize;
    259   if (volSize > headersSizeBase)
    260     testSize = volSize - headersSizeBase;
    261   else
    262     testSize = 1;
    263   UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
    264   UInt64 pureSize = 1;
    265   if (volSize > headersSize)
    266     pureSize = volSize - headersSize;
    267   return pureSize;
    268 }
    269 #endif
    270 
    271 void COutArchive::WriteFolder(const CFolder &folder)
    272 {
    273   WriteNumber(folder.Coders.Size());
    274   int i;
    275   for (i = 0; i < folder.Coders.Size(); i++)
    276   {
    277     const CCoderInfo &coder = folder.Coders[i];
    278     {
    279       size_t propsSize = coder.Props.GetCapacity();
    280 
    281       UInt64 id = coder.MethodID;
    282       int idSize;
    283       for (idSize = 1; idSize < sizeof(id); idSize++)
    284         if ((id >> (8 * idSize)) == 0)
    285           break;
    286       BYTE longID[15];
    287       for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
    288         longID[t] = (Byte)(id & 0xFF);
    289       Byte b;
    290       b = (Byte)(idSize & 0xF);
    291       bool isComplex = !coder.IsSimpleCoder();
    292       b |= (isComplex ? 0x10 : 0);
    293       b |= ((propsSize != 0) ? 0x20 : 0 );
    294       WriteByte(b);
    295       WriteBytes(longID, idSize);
    296       if (isComplex)
    297       {
    298         WriteNumber(coder.NumInStreams);
    299         WriteNumber(coder.NumOutStreams);
    300       }
    301       if (propsSize == 0)
    302         continue;
    303       WriteNumber(propsSize);
    304       WriteBytes(coder.Props, propsSize);
    305     }
    306   }
    307   for (i = 0; i < folder.BindPairs.Size(); i++)
    308   {
    309     const CBindPair &bindPair = folder.BindPairs[i];
    310     WriteNumber(bindPair.InIndex);
    311     WriteNumber(bindPair.OutIndex);
    312   }
    313   if (folder.PackStreams.Size() > 1)
    314     for (i = 0; i < folder.PackStreams.Size(); i++)
    315     {
    316       WriteNumber(folder.PackStreams[i]);
    317     }
    318 }
    319 
    320 void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
    321 {
    322   Byte b = 0;
    323   Byte mask = 0x80;
    324   for (int i = 0; i < boolVector.Size(); i++)
    325   {
    326     if (boolVector[i])
    327       b |= mask;
    328     mask >>= 1;
    329     if (mask == 0)
    330     {
    331       WriteByte(b);
    332       mask = 0x80;
    333       b = 0;
    334     }
    335   }
    336   if (mask != 0x80)
    337     WriteByte(b);
    338 }
    339 
    340 
    341 void COutArchive::WriteHashDigests(
    342     const CRecordVector<bool> &digestsDefined,
    343     const CRecordVector<UInt32> &digests)
    344 {
    345   int numDefined = 0;
    346   int i;
    347   for (i = 0; i < digestsDefined.Size(); i++)
    348     if (digestsDefined[i])
    349       numDefined++;
    350   if (numDefined == 0)
    351     return;
    352 
    353   WriteByte(NID::kCRC);
    354   if (numDefined == digestsDefined.Size())
    355     WriteByte(1);
    356   else
    357   {
    358     WriteByte(0);
    359     WriteBoolVector(digestsDefined);
    360   }
    361   for (i = 0; i < digests.Size(); i++)
    362     if (digestsDefined[i])
    363       WriteUInt32(digests[i]);
    364 }
    365 
    366 void COutArchive::WritePackInfo(
    367     UInt64 dataOffset,
    368     const CRecordVector<UInt64> &packSizes,
    369     const CRecordVector<bool> &packCRCsDefined,
    370     const CRecordVector<UInt32> &packCRCs)
    371 {
    372   if (packSizes.IsEmpty())
    373     return;
    374   WriteByte(NID::kPackInfo);
    375   WriteNumber(dataOffset);
    376   WriteNumber(packSizes.Size());
    377   WriteByte(NID::kSize);
    378   for (int i = 0; i < packSizes.Size(); i++)
    379     WriteNumber(packSizes[i]);
    380 
    381   WriteHashDigests(packCRCsDefined, packCRCs);
    382 
    383   WriteByte(NID::kEnd);
    384 }
    385 
    386 void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders)
    387 {
    388   if (folders.IsEmpty())
    389     return;
    390 
    391   WriteByte(NID::kUnpackInfo);
    392 
    393   WriteByte(NID::kFolder);
    394   WriteNumber(folders.Size());
    395   {
    396     WriteByte(0);
    397     for (int i = 0; i < folders.Size(); i++)
    398       WriteFolder(folders[i]);
    399   }
    400 
    401   WriteByte(NID::kCodersUnpackSize);
    402   int i;
    403   for (i = 0; i < folders.Size(); i++)
    404   {
    405     const CFolder &folder = folders[i];
    406     for (int j = 0; j < folder.UnpackSizes.Size(); j++)
    407       WriteNumber(folder.UnpackSizes[j]);
    408   }
    409 
    410   CRecordVector<bool> unpackCRCsDefined;
    411   CRecordVector<UInt32> unpackCRCs;
    412   for (i = 0; i < folders.Size(); i++)
    413   {
    414     const CFolder &folder = folders[i];
    415     unpackCRCsDefined.Add(folder.UnpackCRCDefined);
    416     unpackCRCs.Add(folder.UnpackCRC);
    417   }
    418   WriteHashDigests(unpackCRCsDefined, unpackCRCs);
    419 
    420   WriteByte(NID::kEnd);
    421 }
    422 
    423 void COutArchive::WriteSubStreamsInfo(
    424     const CObjectVector<CFolder> &folders,
    425     const CRecordVector<CNum> &numUnpackStreamsInFolders,
    426     const CRecordVector<UInt64> &unpackSizes,
    427     const CRecordVector<bool> &digestsDefined,
    428     const CRecordVector<UInt32> &digests)
    429 {
    430   WriteByte(NID::kSubStreamsInfo);
    431 
    432   int i;
    433   for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
    434   {
    435     if (numUnpackStreamsInFolders[i] != 1)
    436     {
    437       WriteByte(NID::kNumUnpackStream);
    438       for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
    439         WriteNumber(numUnpackStreamsInFolders[i]);
    440       break;
    441     }
    442   }
    443 
    444 
    445   bool needFlag = true;
    446   CNum index = 0;
    447   for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
    448     for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++)
    449     {
    450       if (j + 1 != numUnpackStreamsInFolders[i])
    451       {
    452         if (needFlag)
    453           WriteByte(NID::kSize);
    454         needFlag = false;
    455         WriteNumber(unpackSizes[index]);
    456       }
    457       index++;
    458     }
    459 
    460   CRecordVector<bool> digestsDefined2;
    461   CRecordVector<UInt32> digests2;
    462 
    463   int digestIndex = 0;
    464   for (i = 0; i < folders.Size(); i++)
    465   {
    466     int numSubStreams = (int)numUnpackStreamsInFolders[i];
    467     if (numSubStreams == 1 && folders[i].UnpackCRCDefined)
    468       digestIndex++;
    469     else
    470       for (int j = 0; j < numSubStreams; j++, digestIndex++)
    471       {
    472         digestsDefined2.Add(digestsDefined[digestIndex]);
    473         digests2.Add(digests[digestIndex]);
    474       }
    475   }
    476   WriteHashDigests(digestsDefined2, digests2);
    477   WriteByte(NID::kEnd);
    478 }
    479 
    480 void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */)
    481 {
    482   return;
    483 }
    484 
    485 /*
    486 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
    487 
    488 void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
    489 {
    490   pos += (unsigned)GetPos();
    491   pos &= (alignSize - 1);
    492   if (pos == 0)
    493     return;
    494   unsigned skip = alignSize - pos;
    495   if (skip < 2)
    496     skip += alignSize;
    497   skip -= 2;
    498   WriteByte(NID::kDummy);
    499   WriteByte((Byte)skip);
    500   for (unsigned i = 0; i < skip; i++)
    501     WriteByte(0);
    502 }
    503 */
    504 
    505 static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
    506 
    507 void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize)
    508 {
    509   const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
    510   const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
    511   SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
    512 
    513   WriteByte(type);
    514   WriteNumber(dataSize);
    515   if (numDefined == v.Size())
    516     WriteByte(1);
    517   else
    518   {
    519     WriteByte(0);
    520     WriteBoolVector(v);
    521   }
    522   WriteByte(0);
    523 }
    524 
    525 void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
    526 {
    527   int numDefined = 0;
    528 
    529   int i;
    530   for (i = 0; i < v.Defined.Size(); i++)
    531     if (v.Defined[i])
    532       numDefined++;
    533 
    534   if (numDefined == 0)
    535     return;
    536 
    537   WriteAlignedBoolHeader(v.Defined, numDefined, type, 8);
    538 
    539   for (i = 0; i < v.Defined.Size(); i++)
    540     if (v.Defined[i])
    541       WriteUInt64(v.Values[i]);
    542 }
    543 
    544 HRESULT COutArchive::EncodeStream(
    545     DECL_EXTERNAL_CODECS_LOC_VARS
    546     CEncoder &encoder, const CByteBuffer &data,
    547     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
    548 {
    549   CBufInStream *streamSpec = new CBufInStream;
    550   CMyComPtr<ISequentialInStream> stream = streamSpec;
    551   streamSpec->Init(data, data.GetCapacity());
    552   CFolder folderItem;
    553   folderItem.UnpackCRCDefined = true;
    554   folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity());
    555   UInt64 dataSize64 = data.GetCapacity();
    556   RINOK(encoder.Encode(
    557       EXTERNAL_CODECS_LOC_VARS
    558       stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
    559   folders.Add(folderItem);
    560   return S_OK;
    561 }
    562 
    563 void COutArchive::WriteHeader(
    564     const CArchiveDatabase &db,
    565     const CHeaderOptions &headerOptions,
    566     UInt64 &headerOffset)
    567 {
    568   int i;
    569 
    570   UInt64 packedSize = 0;
    571   for (i = 0; i < db.PackSizes.Size(); i++)
    572     packedSize += db.PackSizes[i];
    573 
    574   headerOffset = packedSize;
    575 
    576   WriteByte(NID::kHeader);
    577 
    578   // Archive Properties
    579 
    580   if (db.Folders.Size() > 0)
    581   {
    582     WriteByte(NID::kMainStreamsInfo);
    583     WritePackInfo(0, db.PackSizes,
    584         db.PackCRCsDefined,
    585         db.PackCRCs);
    586 
    587     WriteUnpackInfo(db.Folders);
    588 
    589     CRecordVector<UInt64> unpackSizes;
    590     CRecordVector<bool> digestsDefined;
    591     CRecordVector<UInt32> digests;
    592     for (i = 0; i < db.Files.Size(); i++)
    593     {
    594       const CFileItem &file = db.Files[i];
    595       if (!file.HasStream)
    596         continue;
    597       unpackSizes.Add(file.Size);
    598       digestsDefined.Add(file.CrcDefined);
    599       digests.Add(file.Crc);
    600     }
    601 
    602     WriteSubStreamsInfo(
    603         db.Folders,
    604         db.NumUnpackStreamsVector,
    605         unpackSizes,
    606         digestsDefined,
    607         digests);
    608     WriteByte(NID::kEnd);
    609   }
    610 
    611   if (db.Files.IsEmpty())
    612   {
    613     WriteByte(NID::kEnd);
    614     return;
    615   }
    616 
    617   WriteByte(NID::kFilesInfo);
    618   WriteNumber(db.Files.Size());
    619 
    620   {
    621   /* ---------- Empty Streams ---------- */
    622   CBoolVector emptyStreamVector;
    623   emptyStreamVector.Reserve(db.Files.Size());
    624   int numEmptyStreams = 0;
    625   for (i = 0; i < db.Files.Size(); i++)
    626     if (db.Files[i].HasStream)
    627       emptyStreamVector.Add(false);
    628     else
    629     {
    630       emptyStreamVector.Add(true);
    631       numEmptyStreams++;
    632     }
    633   if (numEmptyStreams > 0)
    634   {
    635     WriteByte(NID::kEmptyStream);
    636     WriteNumber(Bv_GetSizeInBytes(emptyStreamVector));
    637     WriteBoolVector(emptyStreamVector);
    638 
    639     CBoolVector emptyFileVector, antiVector;
    640     emptyFileVector.Reserve(numEmptyStreams);
    641     antiVector.Reserve(numEmptyStreams);
    642     CNum numEmptyFiles = 0, numAntiItems = 0;
    643     for (i = 0; i < db.Files.Size(); i++)
    644     {
    645       const CFileItem &file = db.Files[i];
    646       if (!file.HasStream)
    647       {
    648         emptyFileVector.Add(!file.IsDir);
    649         if (!file.IsDir)
    650           numEmptyFiles++;
    651         bool isAnti = db.IsItemAnti(i);
    652         antiVector.Add(isAnti);
    653         if (isAnti)
    654           numAntiItems++;
    655       }
    656     }
    657 
    658     if (numEmptyFiles > 0)
    659     {
    660       WriteByte(NID::kEmptyFile);
    661       WriteNumber(Bv_GetSizeInBytes(emptyFileVector));
    662       WriteBoolVector(emptyFileVector);
    663     }
    664 
    665     if (numAntiItems > 0)
    666     {
    667       WriteByte(NID::kAnti);
    668       WriteNumber(Bv_GetSizeInBytes(antiVector));
    669       WriteBoolVector(antiVector);
    670     }
    671   }
    672   }
    673 
    674 
    675   {
    676     /* ---------- Names ---------- */
    677 
    678     int numDefined = 0;
    679     size_t namesDataSize = 0;
    680     for (int i = 0; i < db.Files.Size(); i++)
    681     {
    682       const UString &name = db.Files[i].Name;
    683       if (!name.IsEmpty())
    684         numDefined++;
    685       namesDataSize += (name.Length() + 1) * 2;
    686     }
    687 
    688     if (numDefined > 0)
    689     {
    690       namesDataSize++;
    691       SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
    692 
    693       WriteByte(NID::kName);
    694       WriteNumber(namesDataSize);
    695       WriteByte(0);
    696       for (int i = 0; i < db.Files.Size(); i++)
    697       {
    698         const UString &name = db.Files[i].Name;
    699         for (int t = 0; t <= name.Length(); t++)
    700         {
    701           wchar_t c = name[t];
    702           WriteByte((Byte)c);
    703           WriteByte((Byte)(c >> 8));
    704         }
    705       }
    706     }
    707   }
    708 
    709   if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime);
    710   if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime);
    711   if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime);
    712   WriteUInt64DefVector(db.StartPos, NID::kStartPos);
    713 
    714   {
    715     /* ---------- Write Attrib ---------- */
    716     CBoolVector boolVector;
    717     boolVector.Reserve(db.Files.Size());
    718     int numDefined = 0;
    719     for (i = 0; i < db.Files.Size(); i++)
    720     {
    721       bool defined = db.Files[i].AttribDefined;
    722       boolVector.Add(defined);
    723       if (defined)
    724         numDefined++;
    725     }
    726     if (numDefined > 0)
    727     {
    728       WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4);
    729       for (i = 0; i < db.Files.Size(); i++)
    730       {
    731         const CFileItem &file = db.Files[i];
    732         if (file.AttribDefined)
    733           WriteUInt32(file.Attrib);
    734       }
    735     }
    736   }
    737 
    738   WriteByte(NID::kEnd); // for files
    739   WriteByte(NID::kEnd); // for headers
    740 }
    741 
    742 HRESULT COutArchive::WriteDatabase(
    743     DECL_EXTERNAL_CODECS_LOC_VARS
    744     const CArchiveDatabase &db,
    745     const CCompressionMethodMode *options,
    746     const CHeaderOptions &headerOptions)
    747 {
    748   if (!db.CheckNumFiles())
    749     return E_FAIL;
    750 
    751   UInt64 headerOffset;
    752   UInt32 headerCRC;
    753   UInt64 headerSize;
    754   if (db.IsEmpty())
    755   {
    756     headerSize = 0;
    757     headerOffset = 0;
    758     headerCRC = CrcCalc(0, 0);
    759   }
    760   else
    761   {
    762     bool encodeHeaders = false;
    763     if (options != 0)
    764       if (options->IsEmpty())
    765         options = 0;
    766     if (options != 0)
    767       if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
    768         encodeHeaders = true;
    769 
    770     _outByte.SetStream(SeqStream);
    771     _outByte.Init();
    772     _crc = CRC_INIT_VAL;
    773     _countMode = encodeHeaders;
    774     _writeToStream = true;
    775     _countSize = 0;
    776     WriteHeader(db, headerOptions, headerOffset);
    777 
    778     if (encodeHeaders)
    779     {
    780       CByteBuffer buf;
    781       buf.SetCapacity(_countSize);
    782       _outByte2.Init((Byte *)buf, _countSize);
    783 
    784       _countMode = false;
    785       _writeToStream = false;
    786       WriteHeader(db, headerOptions, headerOffset);
    787 
    788       if (_countSize != _outByte2.GetPos())
    789         return E_FAIL;
    790 
    791       CCompressionMethodMode encryptOptions;
    792       encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
    793       encryptOptions.Password = options->Password;
    794       CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
    795       CRecordVector<UInt64> packSizes;
    796       CObjectVector<CFolder> folders;
    797       RINOK(EncodeStream(
    798           EXTERNAL_CODECS_LOC_VARS
    799           encoder, buf,
    800           packSizes, folders));
    801 
    802       _writeToStream = true;
    803 
    804       if (folders.Size() == 0)
    805         throw 1;
    806 
    807       WriteID(NID::kEncodedHeader);
    808       WritePackInfo(headerOffset, packSizes,
    809         CRecordVector<bool>(), CRecordVector<UInt32>());
    810       WriteUnpackInfo(folders);
    811       WriteByte(NID::kEnd);
    812       for (int i = 0; i < packSizes.Size(); i++)
    813         headerOffset += packSizes[i];
    814     }
    815     RINOK(_outByte.Flush());
    816     headerCRC = CRC_GET_DIGEST(_crc);
    817     headerSize = _outByte.GetProcessedSize();
    818   }
    819   #ifdef _7Z_VOL
    820   if (_endMarker)
    821   {
    822     CFinishHeader h;
    823     h.NextHeaderSize = headerSize;
    824     h.NextHeaderCRC = headerCRC;
    825     h.NextHeaderOffset =
    826         UInt64(0) - (headerSize +
    827         4 + kFinishHeaderSize);
    828     h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
    829     h.AdditionalStartBlockSize = 0;
    830     RINOK(WriteFinishHeader(h));
    831     return WriteFinishSignature();
    832   }
    833   else
    834   #endif
    835   {
    836     CStartHeader h;
    837     h.NextHeaderSize = headerSize;
    838     h.NextHeaderCRC = headerCRC;
    839     h.NextHeaderOffset = headerOffset;
    840     RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
    841     return WriteStartHeader(h);
    842   }
    843 }
    844 
    845 void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const
    846 {
    847   file = Files[index];
    848   file2.CTimeDefined = CTime.GetItem(index, file2.CTime);
    849   file2.ATimeDefined = ATime.GetItem(index, file2.ATime);
    850   file2.MTimeDefined = MTime.GetItem(index, file2.MTime);
    851   file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos);
    852   file2.IsAnti = IsItemAnti(index);
    853 }
    854 
    855 void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2)
    856 {
    857   int index = Files.Size();
    858   CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
    859   ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
    860   MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
    861   StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
    862   SetItemAnti(index, file2.IsAnti);
    863   Files.Add(file);
    864 }
    865 
    866 }}
    867