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 
WriteBytes(ISequentialOutStream * stream,const void * data,size_t size)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 
WriteDirect(const void * data,UInt32 size)31 HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
32 {
33   return ::WriteBytes(SeqStream, data, size);
34 }
35 
WriteSignature()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
WriteFinishSignature()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 
SetUInt32(Byte * p,UInt32 d)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 
SetUInt64(Byte * p,UInt64 d)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 
WriteStartHeader(const CStartHeader & h)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
WriteFinishHeader(const CFinishHeader & h)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 
Create(ISequentialOutStream * stream,bool endMarker)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 
Close()136 void COutArchive::Close()
137 {
138   SeqStream.Release();
139   Stream.Release();
140 }
141 
SkipPrefixArchiveHeader()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 
GetPos() const151 UInt64 COutArchive::GetPos() const
152 {
153   if (_countMode)
154     return _countSize;
155   if (_writeToStream)
156     return _outByte.GetProcessedSize();
157   return _outByte2.GetPos();
158 }
159 
WriteBytes(const void * data,size_t size)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 
WriteByte(Byte b)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 
WriteUInt32(UInt32 value)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 
WriteUInt64(UInt64 value)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 
WriteNumber(UInt64 value)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 
GetBigNumberSize(UInt64 value)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
GetVolHeadersSize(UInt64 dataSize,int nameLength,bool props)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 
GetVolPureSize(UInt64 volSize,int nameLength,bool props)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 
WriteFolder(const CFolder & folder)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 
WriteBoolVector(const CBoolVector & boolVector)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 
WriteHashDigests(const CRecordVector<bool> & digestsDefined,const CRecordVector<UInt32> & digests)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 
WritePackInfo(UInt64 dataOffset,const CRecordVector<UInt64> & packSizes,const CRecordVector<bool> & packCRCsDefined,const CRecordVector<UInt32> & packCRCs)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 
WriteUnpackInfo(const CObjectVector<CFolder> & folders)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 
WriteSubStreamsInfo(const CObjectVector<CFolder> & folders,const CRecordVector<CNum> & numUnpackStreamsInFolders,const CRecordVector<UInt64> & unpackSizes,const CRecordVector<bool> & digestsDefined,const CRecordVector<UInt32> & digests)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 
SkipAlign(unsigned,unsigned)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 
Bv_GetSizeInBytes(const CBoolVector & v)505 static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
506 
WriteAlignedBoolHeader(const CBoolVector & v,int numDefined,Byte type,unsigned itemSize)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 
WriteUInt64DefVector(const CUInt64DefVector & v,Byte type)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 
EncodeStream(DECL_EXTERNAL_CODECS_LOC_VARS CEncoder & encoder,const CByteBuffer & data,CRecordVector<UInt64> & packSizes,CObjectVector<CFolder> & folders)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 
WriteHeader(const CArchiveDatabase & db,const CHeaderOptions & headerOptions,UInt64 & headerOffset)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 
WriteDatabase(DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabase & db,const CCompressionMethodMode * options,const CHeaderOptions & headerOptions)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 
GetFile(int index,CFileItem & file,CFileItem2 & file2) const845 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 
AddFile(const CFileItem & file,const CFileItem2 & file2)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