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