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