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