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 
WriteAlignedBoolHeader(const CBoolVector & v,int numDefined,Byte type,unsigned itemSize)505 void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize)
506 {
507   const UInt64 bvSize = (numDefined == v.Size()) ? 0 : (v.Size() + 7) / 8;
508   const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
509   SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
510 
511   WriteByte(type);
512   WriteNumber(dataSize);
513   if (numDefined == v.Size())
514     WriteByte(1);
515   else
516   {
517     WriteByte(0);
518     WriteBoolVector(v);
519   }
520   WriteByte(0);
521 }
522 
WriteUInt64DefVector(const CUInt64DefVector & v,Byte type)523 void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
524 {
525   int numDefined = 0;
526 
527   int i;
528   for (i = 0; i < v.Defined.Size(); i++)
529     if (v.Defined[i])
530       numDefined++;
531 
532   if (numDefined == 0)
533     return;
534 
535   WriteAlignedBoolHeader(v.Defined, numDefined, type, 8);
536 
537   for (i = 0; i < v.Defined.Size(); i++)
538     if (v.Defined[i])
539       WriteUInt64(v.Values[i]);
540 }
541 
EncodeStream(DECL_EXTERNAL_CODECS_LOC_VARS CEncoder & encoder,const Byte * data,size_t dataSize,CRecordVector<UInt64> & packSizes,CObjectVector<CFolder> & folders)542 HRESULT COutArchive::EncodeStream(
543     DECL_EXTERNAL_CODECS_LOC_VARS
544     CEncoder &encoder, const Byte *data, size_t dataSize,
545     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
546 {
547   CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp;
548   CMyComPtr<ISequentialInStream> stream = streamSpec;
549   streamSpec->Init(data, dataSize);
550   CFolder folderItem;
551   folderItem.UnpackCRCDefined = true;
552   folderItem.UnpackCRC = CrcCalc(data, dataSize);
553   UInt64 dataSize64 = dataSize;
554   RINOK(encoder.Encode(
555       EXTERNAL_CODECS_LOC_VARS
556       stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
557   folders.Add(folderItem);
558   return S_OK;
559 }
560 
EncodeStream(DECL_EXTERNAL_CODECS_LOC_VARS CEncoder & encoder,const CByteBuffer & data,CRecordVector<UInt64> & packSizes,CObjectVector<CFolder> & folders)561 HRESULT COutArchive::EncodeStream(
562     DECL_EXTERNAL_CODECS_LOC_VARS
563     CEncoder &encoder, const CByteBuffer &data,
564     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
565 {
566   return EncodeStream(
567       EXTERNAL_CODECS_LOC_VARS
568       encoder, data, data.GetCapacity(), packSizes, folders);
569 }
570 
WriteHeader(const CArchiveDatabase & db,const CHeaderOptions & headerOptions,UInt64 & headerOffset)571 void COutArchive::WriteHeader(
572     const CArchiveDatabase &db,
573     const CHeaderOptions &headerOptions,
574     UInt64 &headerOffset)
575 {
576   int i;
577 
578   UInt64 packedSize = 0;
579   for (i = 0; i < db.PackSizes.Size(); i++)
580     packedSize += db.PackSizes[i];
581 
582   headerOffset = packedSize;
583 
584   WriteByte(NID::kHeader);
585 
586   // Archive Properties
587 
588   if (db.Folders.Size() > 0)
589   {
590     WriteByte(NID::kMainStreamsInfo);
591     WritePackInfo(0, db.PackSizes,
592         db.PackCRCsDefined,
593         db.PackCRCs);
594 
595     WriteUnpackInfo(db.Folders);
596 
597     CRecordVector<UInt64> unpackSizes;
598     CRecordVector<bool> digestsDefined;
599     CRecordVector<UInt32> digests;
600     for (i = 0; i < db.Files.Size(); i++)
601     {
602       const CFileItem &file = db.Files[i];
603       if (!file.HasStream)
604         continue;
605       unpackSizes.Add(file.Size);
606       digestsDefined.Add(file.CrcDefined);
607       digests.Add(file.Crc);
608     }
609 
610     WriteSubStreamsInfo(
611         db.Folders,
612         db.NumUnpackStreamsVector,
613         unpackSizes,
614         digestsDefined,
615         digests);
616     WriteByte(NID::kEnd);
617   }
618 
619   if (db.Files.IsEmpty())
620   {
621     WriteByte(NID::kEnd);
622     return;
623   }
624 
625   WriteByte(NID::kFilesInfo);
626   WriteNumber(db.Files.Size());
627 
628   {
629   /* ---------- Empty Streams ---------- */
630   CBoolVector emptyStreamVector;
631   emptyStreamVector.Reserve(db.Files.Size());
632   int numEmptyStreams = 0;
633   for (i = 0; i < db.Files.Size(); i++)
634     if (db.Files[i].HasStream)
635       emptyStreamVector.Add(false);
636     else
637     {
638       emptyStreamVector.Add(true);
639       numEmptyStreams++;
640     }
641   if (numEmptyStreams > 0)
642   {
643     WriteByte(NID::kEmptyStream);
644     WriteNumber((emptyStreamVector.Size() + 7) / 8);
645     WriteBoolVector(emptyStreamVector);
646 
647     CBoolVector emptyFileVector, antiVector;
648     emptyFileVector.Reserve(numEmptyStreams);
649     antiVector.Reserve(numEmptyStreams);
650     CNum numEmptyFiles = 0, numAntiItems = 0;
651     for (i = 0; i < db.Files.Size(); i++)
652     {
653       const CFileItem &file = db.Files[i];
654       if (!file.HasStream)
655       {
656         emptyFileVector.Add(!file.IsDir);
657         if (!file.IsDir)
658           numEmptyFiles++;
659         bool isAnti = db.IsItemAnti(i);
660         antiVector.Add(isAnti);
661         if (isAnti)
662           numAntiItems++;
663       }
664     }
665 
666     if (numEmptyFiles > 0)
667     {
668       WriteByte(NID::kEmptyFile);
669       WriteNumber((emptyFileVector.Size() + 7) / 8);
670       WriteBoolVector(emptyFileVector);
671     }
672 
673     if (numAntiItems > 0)
674     {
675       WriteByte(NID::kAnti);
676       WriteNumber((antiVector.Size() + 7) / 8);
677       WriteBoolVector(antiVector);
678     }
679   }
680   }
681 
682 
683   {
684     /* ---------- Names ---------- */
685 
686     int numDefined = 0;
687     size_t namesDataSize = 0;
688     for (int i = 0; i < db.Files.Size(); i++)
689     {
690       const UString &name = db.Files[i].Name;
691       if (!name.IsEmpty())
692         numDefined++;
693       namesDataSize += (name.Length() + 1) * 2;
694     }
695 
696     if (numDefined > 0)
697     {
698       namesDataSize++;
699       SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
700 
701       WriteByte(NID::kName);
702       WriteNumber(namesDataSize);
703       WriteByte(0);
704       for (int i = 0; i < db.Files.Size(); i++)
705       {
706         const UString &name = db.Files[i].Name;
707         for (int t = 0; t <= name.Length(); t++)
708         {
709           wchar_t c = name[t];
710           WriteByte((Byte)c);
711           WriteByte((Byte)(c >> 8));
712         }
713       }
714     }
715   }
716 
717   if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime);
718   if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime);
719   if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime);
720   WriteUInt64DefVector(db.StartPos, NID::kStartPos);
721 
722   {
723     /* ---------- Write Attrib ---------- */
724     CBoolVector boolVector;
725     boolVector.Reserve(db.Files.Size());
726     int numDefined = 0;
727     for (i = 0; i < db.Files.Size(); i++)
728     {
729       bool defined = db.Files[i].AttribDefined;
730       boolVector.Add(defined);
731       if (defined)
732         numDefined++;
733     }
734     if (numDefined > 0)
735     {
736       WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4);
737       for (i = 0; i < db.Files.Size(); i++)
738       {
739         const CFileItem &file = db.Files[i];
740         if (file.AttribDefined)
741           WriteUInt32(file.Attrib);
742       }
743     }
744   }
745 
746   WriteByte(NID::kEnd); // for files
747   WriteByte(NID::kEnd); // for headers
748 }
749 
WriteDatabase(DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabase & db,const CCompressionMethodMode * options,const CHeaderOptions & headerOptions)750 HRESULT COutArchive::WriteDatabase(
751     DECL_EXTERNAL_CODECS_LOC_VARS
752     const CArchiveDatabase &db,
753     const CCompressionMethodMode *options,
754     const CHeaderOptions &headerOptions)
755 {
756   if (!db.CheckNumFiles())
757     return E_FAIL;
758 
759   UInt64 headerOffset;
760   UInt32 headerCRC;
761   UInt64 headerSize;
762   if (db.IsEmpty())
763   {
764     headerSize = 0;
765     headerOffset = 0;
766     headerCRC = CrcCalc(0, 0);
767   }
768   else
769   {
770     bool encodeHeaders = false;
771     if (options != 0)
772       if (options->IsEmpty())
773         options = 0;
774     if (options != 0)
775       if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
776         encodeHeaders = true;
777 
778     _outByte.SetStream(SeqStream);
779     _outByte.Init();
780     _crc = CRC_INIT_VAL;
781     _countMode = encodeHeaders;
782     _writeToStream = true;
783     _countSize = 0;
784     WriteHeader(db, headerOptions, headerOffset);
785 
786     if (encodeHeaders)
787     {
788       CByteBuffer buf;
789       buf.SetCapacity(_countSize);
790       _outByte2.Init((Byte *)buf, _countSize);
791 
792       _countMode = false;
793       _writeToStream = false;
794       WriteHeader(db, headerOptions, headerOffset);
795 
796       if (_countSize != _outByte2.GetPos())
797         return E_FAIL;
798 
799       CCompressionMethodMode encryptOptions;
800       encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
801       encryptOptions.Password = options->Password;
802       CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
803       CRecordVector<UInt64> packSizes;
804       CObjectVector<CFolder> folders;
805       RINOK(EncodeStream(
806           EXTERNAL_CODECS_LOC_VARS
807           encoder, (const Byte *)buf,
808           _countSize, packSizes, folders));
809 
810       _writeToStream = true;
811 
812       if (folders.Size() == 0)
813         throw 1;
814 
815       WriteID(NID::kEncodedHeader);
816       WritePackInfo(headerOffset, packSizes,
817         CRecordVector<bool>(), CRecordVector<UInt32>());
818       WriteUnpackInfo(folders);
819       WriteByte(NID::kEnd);
820       for (int i = 0; i < packSizes.Size(); i++)
821         headerOffset += packSizes[i];
822     }
823     RINOK(_outByte.Flush());
824     headerCRC = CRC_GET_DIGEST(_crc);
825     headerSize = _outByte.GetProcessedSize();
826   }
827   #ifdef _7Z_VOL
828   if (_endMarker)
829   {
830     CFinishHeader h;
831     h.NextHeaderSize = headerSize;
832     h.NextHeaderCRC = headerCRC;
833     h.NextHeaderOffset =
834         UInt64(0) - (headerSize +
835         4 + kFinishHeaderSize);
836     h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
837     h.AdditionalStartBlockSize = 0;
838     RINOK(WriteFinishHeader(h));
839     return WriteFinishSignature();
840   }
841   else
842   #endif
843   {
844     CStartHeader h;
845     h.NextHeaderSize = headerSize;
846     h.NextHeaderCRC = headerCRC;
847     h.NextHeaderOffset = headerOffset;
848     RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
849     return WriteStartHeader(h);
850   }
851 }
852 
GetFile(int index,CFileItem & file,CFileItem2 & file2) const853 void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const
854 {
855   file = Files[index];
856   file2.CTimeDefined = CTime.GetItem(index, file2.CTime);
857   file2.ATimeDefined = ATime.GetItem(index, file2.ATime);
858   file2.MTimeDefined = MTime.GetItem(index, file2.MTime);
859   file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos);
860   file2.IsAnti = IsItemAnti(index);
861 }
862 
AddFile(const CFileItem & file,const CFileItem2 & file2)863 void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2)
864 {
865   int index = Files.Size();
866   CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
867   ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
868   MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
869   StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
870   SetItemAnti(index, file2.IsAnti);
871   Files.Add(file);
872 }
873 
874 }}
875