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
13static 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
28namespace NArchive {
29namespace N7z {
30
31HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
32{
33  return ::WriteBytes(SeqStream, data, size);
34}
35
36HRESULT 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
46HRESULT 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
57static void SetUInt32(Byte *p, UInt32 d)
58{
59  for (int i = 0; i < 4; i++, d >>= 8)
60    p[i] = (Byte)d;
61}
62
63static void SetUInt64(Byte *p, UInt64 d)
64{
65  for (int i = 0; i < 8; i++, d >>= 8)
66    p[i] = (Byte)d;
67}
68
69HRESULT 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
80HRESULT 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
97HRESULT 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
136void COutArchive::Close()
137{
138  SeqStream.Release();
139  Stream.Release();
140}
141
142HRESULT 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
151UInt64 COutArchive::GetPos() const
152{
153  if (_countMode)
154    return _countSize;
155  if (_writeToStream)
156    return _outByte.GetProcessedSize();
157  return _outByte2.GetPos();
158}
159
160void 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
173void 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
186void COutArchive::WriteUInt32(UInt32 value)
187{
188  for (int i = 0; i < 4; i++)
189  {
190    WriteByte((Byte)value);
191    value >>= 8;
192  }
193}
194
195void COutArchive::WriteUInt64(UInt64 value)
196{
197  for (int i = 0; i < 8; i++)
198  {
199    WriteByte((Byte)value);
200    value >>= 8;
201  }
202}
203
204void 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
227static 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
237UInt32 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
255UInt64 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
271void 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
320void 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
341void 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
366void 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
386void 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
423void 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
480void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */)
481{
482  return;
483}
484
485/*
4867-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
487
488void 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
505static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
506
507void 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
525void 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
544HRESULT 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
563void 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
742HRESULT 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
845void 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
855void 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