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