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