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