• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace NArchive {
14 namespace N7z {
15 
WriteSignature()16 HRESULT COutArchive::WriteSignature()
17 {
18   Byte buf[8];
19   memcpy(buf, kSignature, kSignatureSize);
20   buf[kSignatureSize] = kMajorVersion;
21   buf[kSignatureSize + 1] = 4;
22   return WriteDirect(buf, 8);
23 }
24 
25 #ifdef _7Z_VOL
WriteFinishSignature()26 HRESULT COutArchive::WriteFinishSignature()
27 {
28   RINOK(WriteDirect(kFinishSignature, kSignatureSize));
29   CArchiveVersion av;
30   av.Major = kMajorVersion;
31   av.Minor = 2;
32   RINOK(WriteDirectByte(av.Major));
33   return WriteDirectByte(av.Minor);
34 }
35 #endif
36 
SetUInt32(Byte * p,UInt32 d)37 static void SetUInt32(Byte *p, UInt32 d)
38 {
39   for (int i = 0; i < 4; i++, d >>= 8)
40     p[i] = (Byte)d;
41 }
42 
SetUInt64(Byte * p,UInt64 d)43 static void SetUInt64(Byte *p, UInt64 d)
44 {
45   for (int i = 0; i < 8; i++, d >>= 8)
46     p[i] = (Byte)d;
47 }
48 
WriteStartHeader(const CStartHeader & h)49 HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
50 {
51   Byte buf[24];
52   SetUInt64(buf + 4, h.NextHeaderOffset);
53   SetUInt64(buf + 12, h.NextHeaderSize);
54   SetUInt32(buf + 20, h.NextHeaderCRC);
55   SetUInt32(buf, CrcCalc(buf + 4, 20));
56   return WriteDirect(buf, 24);
57 }
58 
59 #ifdef _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(ISequentialOutStream * stream,bool endMarker)77 HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
78 {
79   Close();
80   #ifdef _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   }
94   #ifdef _7Z_VOL
95   if (endMarker)
96   {
97     /*
98     CStartHeader sh;
99     sh.NextHeaderOffset = (UInt32)(Int32)-1;
100     sh.NextHeaderSize = (UInt32)(Int32)-1;
101     sh.NextHeaderCRC = 0;
102     WriteStartHeader(sh);
103     */
104   }
105   else
106   #endif
107   {
108     if (!Stream)
109       return E_FAIL;
110     RINOK(WriteSignature());
111     RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
112   }
113   return S_OK;
114 }
115 
Close()116 void COutArchive::Close()
117 {
118   SeqStream.Release();
119   Stream.Release();
120 }
121 
SkipPrefixArchiveHeader()122 HRESULT COutArchive::SkipPrefixArchiveHeader()
123 {
124   #ifdef _7Z_VOL
125   if (_endMarker)
126     return S_OK;
127   #endif
128   Byte buf[24];
129   memset(buf, 0, 24);
130   return WriteDirect(buf, 24);
131 }
132 
GetPos() const133 UInt64 COutArchive::GetPos() const
134 {
135   if (_countMode)
136     return _countSize;
137   if (_writeToStream)
138     return _outByte.GetProcessedSize();
139   return _outByte2.GetPos();
140 }
141 
WriteBytes(const void * data,size_t size)142 void COutArchive::WriteBytes(const void *data, size_t size)
143 {
144   if (_countMode)
145     _countSize += size;
146   else if (_writeToStream)
147   {
148     _outByte.WriteBytes(data, size);
149     _crc = CrcUpdate(_crc, data, size);
150   }
151   else
152     _outByte2.WriteBytes(data, size);
153 }
154 
WriteByte(Byte b)155 void COutArchive::WriteByte(Byte b)
156 {
157   if (_countMode)
158     _countSize++;
159   else if (_writeToStream)
160   {
161     _outByte.WriteByte(b);
162     _crc = CRC_UPDATE_BYTE(_crc, b);
163   }
164   else
165     _outByte2.WriteByte(b);
166 }
167 
WriteUInt32(UInt32 value)168 void COutArchive::WriteUInt32(UInt32 value)
169 {
170   for (int i = 0; i < 4; i++)
171   {
172     WriteByte((Byte)value);
173     value >>= 8;
174   }
175 }
176 
WriteUInt64(UInt64 value)177 void COutArchive::WriteUInt64(UInt64 value)
178 {
179   for (int i = 0; i < 8; i++)
180   {
181     WriteByte((Byte)value);
182     value >>= 8;
183   }
184 }
185 
WriteNumber(UInt64 value)186 void COutArchive::WriteNumber(UInt64 value)
187 {
188   Byte firstByte = 0;
189   Byte mask = 0x80;
190   int i;
191   for (i = 0; i < 8; i++)
192   {
193     if (value < ((UInt64(1) << ( 7  * (i + 1)))))
194     {
195       firstByte |= Byte(value >> (8 * i));
196       break;
197     }
198     firstByte |= mask;
199     mask >>= 1;
200   }
201   WriteByte(firstByte);
202   for (; i > 0; i--)
203   {
204     WriteByte((Byte)value);
205     value >>= 8;
206   }
207 }
208 
GetBigNumberSize(UInt64 value)209 static UInt32 GetBigNumberSize(UInt64 value)
210 {
211   int i;
212   for (i = 1; i < 9; i++)
213     if (value < (((UInt64)1 << (i * 7))))
214       break;
215   return i;
216 }
217 
218 #ifdef _7Z_VOL
GetVolHeadersSize(UInt64 dataSize,int nameLength,bool props)219 UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
220 {
221   UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
222   if (nameLength != 0)
223   {
224     nameLength = (nameLength + 1) * 2;
225     result += nameLength + GetBigNumberSize(nameLength) + 2;
226   }
227   if (props)
228   {
229     result += 20;
230   }
231   if (result >= 128)
232     result++;
233   result += kSignatureSize + 2 + kFinishHeaderSize;
234   return result;
235 }
236 
GetVolPureSize(UInt64 volSize,int nameLength,bool props)237 UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
238 {
239   UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
240   int testSize;
241   if (volSize > headersSizeBase)
242     testSize = volSize - headersSizeBase;
243   else
244     testSize = 1;
245   UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
246   UInt64 pureSize = 1;
247   if (volSize > headersSize)
248     pureSize = volSize - headersSize;
249   return pureSize;
250 }
251 #endif
252 
WriteFolder(const CFolder & folder)253 void COutArchive::WriteFolder(const CFolder &folder)
254 {
255   WriteNumber(folder.Coders.Size());
256   unsigned i;
257 
258   for (i = 0; i < folder.Coders.Size(); i++)
259   {
260     const CCoderInfo &coder = folder.Coders[i];
261     {
262       UInt64 id = coder.MethodID;
263       unsigned idSize;
264       for (idSize = 1; idSize < sizeof(id); idSize++)
265         if ((id >> (8 * idSize)) == 0)
266           break;
267       idSize &= 0xF;
268       Byte temp[16];
269       for (unsigned t = idSize; t != 0; t--, id >>= 8)
270         temp[t] = (Byte)(id & 0xFF);
271 
272       Byte b = (Byte)(idSize);
273       bool isComplex = !coder.IsSimpleCoder();
274       b |= (isComplex ? 0x10 : 0);
275 
276       size_t propsSize = coder.Props.Size();
277       b |= ((propsSize != 0) ? 0x20 : 0);
278       temp[0] = b;
279       WriteBytes(temp, idSize + 1);
280       if (isComplex)
281       {
282         WriteNumber(coder.NumStreams);
283         WriteNumber(1); // NumOutStreams;
284       }
285       if (propsSize == 0)
286         continue;
287       WriteNumber(propsSize);
288       WriteBytes(coder.Props, propsSize);
289     }
290   }
291 
292   for (i = 0; i < folder.Bonds.Size(); i++)
293   {
294     const CBond &bond = folder.Bonds[i];
295     WriteNumber(bond.PackIndex);
296     WriteNumber(bond.UnpackIndex);
297   }
298 
299   if (folder.PackStreams.Size() > 1)
300     for (i = 0; i < folder.PackStreams.Size(); i++)
301       WriteNumber(folder.PackStreams[i]);
302 }
303 
WriteBoolVector(const CBoolVector & boolVector)304 void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
305 {
306   Byte b = 0;
307   Byte mask = 0x80;
308   FOR_VECTOR (i, boolVector)
309   {
310     if (boolVector[i])
311       b |= mask;
312     mask >>= 1;
313     if (mask == 0)
314     {
315       WriteByte(b);
316       mask = 0x80;
317       b = 0;
318     }
319   }
320   if (mask != 0x80)
321     WriteByte(b);
322 }
323 
Bv_GetSizeInBytes(const CBoolVector & v)324 static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
325 
WritePropBoolVector(Byte id,const CBoolVector & boolVector)326 void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector)
327 {
328   WriteByte(id);
329   WriteNumber(Bv_GetSizeInBytes(boolVector));
330   WriteBoolVector(boolVector);
331 }
332 
WriteHashDigests(const CUInt32DefVector & digests)333 void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
334 {
335   unsigned numDefined = 0;
336   unsigned i;
337   for (i = 0; i < digests.Defs.Size(); i++)
338     if (digests.Defs[i])
339       numDefined++;
340   if (numDefined == 0)
341     return;
342 
343   WriteByte(NID::kCRC);
344   if (numDefined == digests.Defs.Size())
345     WriteByte(1);
346   else
347   {
348     WriteByte(0);
349     WriteBoolVector(digests.Defs);
350   }
351   for (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 
SkipAlign(unsigned pos,unsigned alignSize)456 void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
457 {
458   if (!_useAlign)
459     return;
460   pos += (unsigned)GetPos();
461   pos &= (alignSize - 1);
462   if (pos == 0)
463     return;
464   unsigned skip = alignSize - pos;
465   if (skip < 2)
466     skip += alignSize;
467   skip -= 2;
468   WriteByte(NID::kDummy);
469   WriteByte((Byte)skip);
470   for (unsigned i = 0; i < skip; i++)
471     WriteByte(0);
472 }
473 
WriteAlignedBoolHeader(const CBoolVector & v,unsigned numDefined,Byte type,unsigned itemSize)474 void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize)
475 {
476   const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
477   const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
478   SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
479 
480   WriteByte(type);
481   WriteNumber(dataSize);
482   if (numDefined == v.Size())
483     WriteByte(1);
484   else
485   {
486     WriteByte(0);
487     WriteBoolVector(v);
488   }
489   WriteByte(0);
490 }
491 
WriteUInt64DefVector(const CUInt64DefVector & v,Byte type)492 void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
493 {
494   unsigned numDefined = 0;
495 
496   unsigned i;
497   for (i = 0; i < v.Defs.Size(); i++)
498     if (v.Defs[i])
499       numDefined++;
500 
501   if (numDefined == 0)
502     return;
503 
504   WriteAlignedBoolHeader(v.Defs, numDefined, type, 8);
505 
506   for (i = 0; i < v.Defs.Size(); i++)
507     if (v.Defs[i])
508       WriteUInt64(v.Vals[i]);
509 }
510 
EncodeStream(DECL_EXTERNAL_CODECS_LOC_VARS CEncoder & encoder,const CByteBuffer & data,CRecordVector<UInt64> & packSizes,CObjectVector<CFolder> & folders,COutFolders & outFolders)511 HRESULT COutArchive::EncodeStream(
512     DECL_EXTERNAL_CODECS_LOC_VARS
513     CEncoder &encoder, const CByteBuffer &data,
514     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)
515 {
516   CBufInStream *streamSpec = new CBufInStream;
517   CMyComPtr<ISequentialInStream> stream = streamSpec;
518   streamSpec->Init(data, data.Size());
519   outFolders.FolderUnpackCRCs.Defs.Add(true);
520   outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size()));
521   // outFolders.NumUnpackStreamsVector.Add(1);
522   UInt64 dataSize64 = data.Size();
523   UInt64 unpackSize;
524   RINOK(encoder.Encode(
525       EXTERNAL_CODECS_LOC_VARS
526       stream,
527       // NULL,
528       &dataSize64,
529       folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL))
530   return S_OK;
531 }
532 
WriteHeader(const CArchiveDatabaseOut & db,UInt64 & headerOffset)533 void COutArchive::WriteHeader(
534     const CArchiveDatabaseOut &db,
535     // const CHeaderOptions &headerOptions,
536     UInt64 &headerOffset)
537 {
538   /*
539   bool thereIsSecure = (db.SecureBuf.Size() != 0);
540   */
541   _useAlign = true;
542 
543   {
544     UInt64 packSize = 0;
545     FOR_VECTOR (i, db.PackSizes)
546       packSize += db.PackSizes[i];
547     headerOffset = packSize;
548   }
549 
550 
551   WriteByte(NID::kHeader);
552 
553   // Archive Properties
554 
555   if (db.Folders.Size() > 0)
556   {
557     WriteByte(NID::kMainStreamsInfo);
558     WritePackInfo(0, db.PackSizes, db.PackCRCs);
559     WriteUnpackInfo(db.Folders, (const COutFolders &)db);
560 
561     CRecordVector<UInt64> unpackSizes;
562     CUInt32DefVector digests;
563     FOR_VECTOR (i, db.Files)
564     {
565       const CFileItem &file = db.Files[i];
566       if (!file.HasStream)
567         continue;
568       unpackSizes.Add(file.Size);
569       digests.Defs.Add(file.CrcDefined);
570       digests.Vals.Add(file.Crc);
571     }
572 
573     WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests);
574     WriteByte(NID::kEnd);
575   }
576 
577   if (db.Files.IsEmpty())
578   {
579     WriteByte(NID::kEnd);
580     return;
581   }
582 
583   WriteByte(NID::kFilesInfo);
584   WriteNumber(db.Files.Size());
585 
586   {
587     /* ---------- Empty Streams ---------- */
588     CBoolVector emptyStreamVector;
589     emptyStreamVector.ClearAndSetSize(db.Files.Size());
590     unsigned numEmptyStreams = 0;
591     {
592       FOR_VECTOR (i, db.Files)
593         if (db.Files[i].HasStream)
594           emptyStreamVector[i] = false;
595         else
596         {
597           emptyStreamVector[i] = true;
598           numEmptyStreams++;
599         }
600     }
601 
602     if (numEmptyStreams != 0)
603     {
604       WritePropBoolVector(NID::kEmptyStream, emptyStreamVector);
605 
606       CBoolVector emptyFileVector, antiVector;
607       emptyFileVector.ClearAndSetSize(numEmptyStreams);
608       antiVector.ClearAndSetSize(numEmptyStreams);
609       bool thereAreEmptyFiles = false, thereAreAntiItems = false;
610       unsigned cur = 0;
611 
612       FOR_VECTOR (i, db.Files)
613       {
614         const CFileItem &file = db.Files[i];
615         if (file.HasStream)
616           continue;
617         emptyFileVector[cur] = !file.IsDir;
618         if (!file.IsDir)
619           thereAreEmptyFiles = true;
620         bool isAnti = db.IsItemAnti(i);
621         antiVector[cur] = isAnti;
622         if (isAnti)
623           thereAreAntiItems = true;
624         cur++;
625       }
626 
627       if (thereAreEmptyFiles)
628         WritePropBoolVector(NID::kEmptyFile, emptyFileVector);
629       if (thereAreAntiItems)
630         WritePropBoolVector(NID::kAnti, antiVector);
631     }
632   }
633 
634 
635   {
636     /* ---------- Names ---------- */
637 
638     unsigned numDefined = 0;
639     size_t namesDataSize = 0;
640     FOR_VECTOR (i, db.Files)
641     {
642       const UString &name = db.Names[i];
643       if (!name.IsEmpty())
644         numDefined++;
645       namesDataSize += (name.Len() + 1) * 2;
646     }
647 
648     if (numDefined > 0)
649     {
650       namesDataSize++;
651       SkipAlign(2 + GetBigNumberSize(namesDataSize), 16);
652 
653       WriteByte(NID::kName);
654       WriteNumber(namesDataSize);
655       WriteByte(0);
656       FOR_VECTOR (i, db.Files)
657       {
658         const UString &name = db.Names[i];
659         for (unsigned t = 0; t <= name.Len(); t++)
660         {
661           wchar_t c = name[t];
662           WriteByte((Byte)c);
663           WriteByte((Byte)(c >> 8));
664         }
665       }
666     }
667   }
668 
669   /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime);
670   /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime);
671   /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime);
672   WriteUInt64DefVector(db.StartPos, NID::kStartPos);
673 
674   {
675     /* ---------- Write Attrib ---------- */
676     CBoolVector boolVector;
677     boolVector.ClearAndSetSize(db.Files.Size());
678     unsigned numDefined = 0;
679 
680     {
681       FOR_VECTOR (i, db.Files)
682       {
683         bool defined = db.Files[i].AttribDefined;
684         boolVector[i] = defined;
685         if (defined)
686           numDefined++;
687       }
688     }
689 
690     if (numDefined != 0)
691     {
692       WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4);
693       FOR_VECTOR (i, db.Files)
694       {
695         const CFileItem &file = db.Files[i];
696         if (file.AttribDefined)
697           WriteUInt32(file.Attrib);
698       }
699     }
700   }
701 
702   /*
703   {
704     // ---------- Write IsAux ----------
705     unsigned numAux = 0;
706     const CBoolVector &isAux = db.IsAux;
707     for (i = 0; i < isAux.Size(); i++)
708       if (isAux[i])
709         numAux++;
710     if (numAux > 0)
711     {
712       const unsigned bvSize = Bv_GetSizeInBytes(isAux);
713       WriteByte(NID::kIsAux);
714       WriteNumber(bvSize);
715       WriteBoolVector(isAux);
716     }
717   }
718 
719   {
720     // ---------- Write Parent ----------
721     CBoolVector boolVector;
722     boolVector.Reserve(db.Files.Size());
723     unsigned numIsDir = 0;
724     unsigned numParentLinks = 0;
725     for (i = 0; i < db.Files.Size(); i++)
726     {
727       const CFileItem &file = db.Files[i];
728       bool defined = !file.IsAltStream;
729       boolVector.Add(defined);
730       if (defined)
731         numIsDir++;
732       if (file.Parent >= 0)
733         numParentLinks++;
734     }
735     if (numParentLinks > 0)
736     {
737       // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4);
738       const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector);
739       const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1;
740       SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4);
741 
742       WriteByte(NID::kParent);
743       WriteNumber(dataSize);
744       if (numIsDir == boolVector.Size())
745         WriteByte(1);
746       else
747       {
748         WriteByte(0);
749         WriteBoolVector(boolVector);
750       }
751       for (i = 0; i < db.Files.Size(); i++)
752       {
753         const CFileItem &file = db.Files[i];
754         // if (file.Parent >= 0)
755           WriteUInt32(file.Parent);
756       }
757     }
758   }
759 
760   if (thereIsSecure)
761   {
762     UInt64 secureDataSize = 1 + 4 +
763        db.SecureBuf.Size() +
764        db.SecureSizes.Size() * 4;
765     // secureDataSize += db.SecureIDs.Size() * 4;
766     for (i = 0; i < db.SecureIDs.Size(); i++)
767       secureDataSize += GetBigNumberSize(db.SecureIDs[i]);
768     SkipAlign(2 + GetBigNumberSize(secureDataSize), 4);
769     WriteByte(NID::kNtSecure);
770     WriteNumber(secureDataSize);
771     WriteByte(0);
772     WriteUInt32(db.SecureSizes.Size());
773     for (i = 0; i < db.SecureSizes.Size(); i++)
774       WriteUInt32(db.SecureSizes[i]);
775     WriteBytes(db.SecureBuf, db.SecureBuf.Size());
776     for (i = 0; i < db.SecureIDs.Size(); i++)
777     {
778       WriteNumber(db.SecureIDs[i]);
779       // WriteUInt32(db.SecureIDs[i]);
780     }
781   }
782   */
783 
784   WriteByte(NID::kEnd); // for files
785   WriteByte(NID::kEnd); // for headers
786 }
787 
WriteDatabase(DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabaseOut & db,const CCompressionMethodMode * options,const CHeaderOptions & headerOptions)788 HRESULT COutArchive::WriteDatabase(
789     DECL_EXTERNAL_CODECS_LOC_VARS
790     const CArchiveDatabaseOut &db,
791     const CCompressionMethodMode *options,
792     const CHeaderOptions &headerOptions)
793 {
794   if (!db.CheckNumFiles())
795     return E_FAIL;
796 
797   UInt64 headerOffset;
798   UInt32 headerCRC;
799   UInt64 headerSize;
800   if (db.IsEmpty())
801   {
802     headerSize = 0;
803     headerOffset = 0;
804     headerCRC = CrcCalc(0, 0);
805   }
806   else
807   {
808     bool encodeHeaders = false;
809     if (options != 0)
810       if (options->IsEmpty())
811         options = 0;
812     if (options != 0)
813       if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
814         encodeHeaders = true;
815 
816     _outByte.SetStream(SeqStream);
817     _outByte.Init();
818     _crc = CRC_INIT_VAL;
819     _countMode = encodeHeaders;
820     _writeToStream = true;
821     _countSize = 0;
822     WriteHeader(db, /* headerOptions, */ headerOffset);
823 
824     if (encodeHeaders)
825     {
826       CByteBuffer buf(_countSize);
827       _outByte2.Init((Byte *)buf, _countSize);
828 
829       _countMode = false;
830       _writeToStream = false;
831       WriteHeader(db, /* headerOptions, */ headerOffset);
832 
833       if (_countSize != _outByte2.GetPos())
834         return E_FAIL;
835 
836       CCompressionMethodMode encryptOptions;
837       encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
838       encryptOptions.Password = options->Password;
839       CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
840       CRecordVector<UInt64> packSizes;
841       CObjectVector<CFolder> folders;
842       COutFolders outFolders;
843 
844       RINOK(EncodeStream(
845           EXTERNAL_CODECS_LOC_VARS
846           encoder, buf,
847           packSizes, folders, outFolders));
848 
849       _writeToStream = true;
850 
851       if (folders.Size() == 0)
852         throw 1;
853 
854       WriteID(NID::kEncodedHeader);
855       WritePackInfo(headerOffset, packSizes, CUInt32DefVector());
856       WriteUnpackInfo(folders, outFolders);
857       WriteByte(NID::kEnd);
858       FOR_VECTOR (i, packSizes)
859         headerOffset += packSizes[i];
860     }
861     RINOK(_outByte.Flush());
862     headerCRC = CRC_GET_DIGEST(_crc);
863     headerSize = _outByte.GetProcessedSize();
864   }
865   #ifdef _7Z_VOL
866   if (_endMarker)
867   {
868     CFinishHeader h;
869     h.NextHeaderSize = headerSize;
870     h.NextHeaderCRC = headerCRC;
871     h.NextHeaderOffset =
872         UInt64(0) - (headerSize +
873         4 + kFinishHeaderSize);
874     h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
875     h.AdditionalStartBlockSize = 0;
876     RINOK(WriteFinishHeader(h));
877     return WriteFinishSignature();
878   }
879   else
880   #endif
881   {
882     CStartHeader h;
883     h.NextHeaderSize = headerSize;
884     h.NextHeaderCRC = headerCRC;
885     h.NextHeaderOffset = headerOffset;
886     RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
887     return WriteStartHeader(h);
888   }
889 }
890 
SetItem(unsigned index,bool defined,UInt64 value)891 void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value)
892 {
893   while (index >= Defs.Size())
894     Defs.Add(false);
895   Defs[index] = defined;
896   if (!defined)
897     return;
898   while (index >= Vals.Size())
899     Vals.Add(0);
900   Vals[index] = value;
901 }
902 
AddFile(const CFileItem & file,const CFileItem2 & file2,const UString & name)903 void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name)
904 {
905   unsigned index = Files.Size();
906   CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
907   ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
908   MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
909   StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
910   SetItem_Anti(index, file2.IsAnti);
911   // SetItem_Aux(index, file2.IsAux);
912   Names.Add(name);
913   Files.Add(file);
914 }
915 
916 }}
917