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
Bv_GetSizeInBytes(const CBoolVector & v)505 static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
506
WriteAlignedBoolHeader(const CBoolVector & v,int numDefined,Byte type,unsigned itemSize)507 void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize)
508 {
509 const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
510 const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
511 SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
512
513 WriteByte(type);
514 WriteNumber(dataSize);
515 if (numDefined == v.Size())
516 WriteByte(1);
517 else
518 {
519 WriteByte(0);
520 WriteBoolVector(v);
521 }
522 WriteByte(0);
523 }
524
WriteUInt64DefVector(const CUInt64DefVector & v,Byte type)525 void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
526 {
527 int numDefined = 0;
528
529 int i;
530 for (i = 0; i < v.Defined.Size(); i++)
531 if (v.Defined[i])
532 numDefined++;
533
534 if (numDefined == 0)
535 return;
536
537 WriteAlignedBoolHeader(v.Defined, numDefined, type, 8);
538
539 for (i = 0; i < v.Defined.Size(); i++)
540 if (v.Defined[i])
541 WriteUInt64(v.Values[i]);
542 }
543
EncodeStream(DECL_EXTERNAL_CODECS_LOC_VARS CEncoder & encoder,const CByteBuffer & data,CRecordVector<UInt64> & packSizes,CObjectVector<CFolder> & folders)544 HRESULT COutArchive::EncodeStream(
545 DECL_EXTERNAL_CODECS_LOC_VARS
546 CEncoder &encoder, const CByteBuffer &data,
547 CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
548 {
549 CBufInStream *streamSpec = new CBufInStream;
550 CMyComPtr<ISequentialInStream> stream = streamSpec;
551 streamSpec->Init(data, data.GetCapacity());
552 CFolder folderItem;
553 folderItem.UnpackCRCDefined = true;
554 folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity());
555 UInt64 dataSize64 = data.GetCapacity();
556 RINOK(encoder.Encode(
557 EXTERNAL_CODECS_LOC_VARS
558 stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
559 folders.Add(folderItem);
560 return S_OK;
561 }
562
WriteHeader(const CArchiveDatabase & db,const CHeaderOptions & headerOptions,UInt64 & headerOffset)563 void COutArchive::WriteHeader(
564 const CArchiveDatabase &db,
565 const CHeaderOptions &headerOptions,
566 UInt64 &headerOffset)
567 {
568 int i;
569
570 UInt64 packedSize = 0;
571 for (i = 0; i < db.PackSizes.Size(); i++)
572 packedSize += db.PackSizes[i];
573
574 headerOffset = packedSize;
575
576 WriteByte(NID::kHeader);
577
578 // Archive Properties
579
580 if (db.Folders.Size() > 0)
581 {
582 WriteByte(NID::kMainStreamsInfo);
583 WritePackInfo(0, db.PackSizes,
584 db.PackCRCsDefined,
585 db.PackCRCs);
586
587 WriteUnpackInfo(db.Folders);
588
589 CRecordVector<UInt64> unpackSizes;
590 CRecordVector<bool> digestsDefined;
591 CRecordVector<UInt32> digests;
592 for (i = 0; i < db.Files.Size(); i++)
593 {
594 const CFileItem &file = db.Files[i];
595 if (!file.HasStream)
596 continue;
597 unpackSizes.Add(file.Size);
598 digestsDefined.Add(file.CrcDefined);
599 digests.Add(file.Crc);
600 }
601
602 WriteSubStreamsInfo(
603 db.Folders,
604 db.NumUnpackStreamsVector,
605 unpackSizes,
606 digestsDefined,
607 digests);
608 WriteByte(NID::kEnd);
609 }
610
611 if (db.Files.IsEmpty())
612 {
613 WriteByte(NID::kEnd);
614 return;
615 }
616
617 WriteByte(NID::kFilesInfo);
618 WriteNumber(db.Files.Size());
619
620 {
621 /* ---------- Empty Streams ---------- */
622 CBoolVector emptyStreamVector;
623 emptyStreamVector.Reserve(db.Files.Size());
624 int numEmptyStreams = 0;
625 for (i = 0; i < db.Files.Size(); i++)
626 if (db.Files[i].HasStream)
627 emptyStreamVector.Add(false);
628 else
629 {
630 emptyStreamVector.Add(true);
631 numEmptyStreams++;
632 }
633 if (numEmptyStreams > 0)
634 {
635 WriteByte(NID::kEmptyStream);
636 WriteNumber(Bv_GetSizeInBytes(emptyStreamVector));
637 WriteBoolVector(emptyStreamVector);
638
639 CBoolVector emptyFileVector, antiVector;
640 emptyFileVector.Reserve(numEmptyStreams);
641 antiVector.Reserve(numEmptyStreams);
642 CNum numEmptyFiles = 0, numAntiItems = 0;
643 for (i = 0; i < db.Files.Size(); i++)
644 {
645 const CFileItem &file = db.Files[i];
646 if (!file.HasStream)
647 {
648 emptyFileVector.Add(!file.IsDir);
649 if (!file.IsDir)
650 numEmptyFiles++;
651 bool isAnti = db.IsItemAnti(i);
652 antiVector.Add(isAnti);
653 if (isAnti)
654 numAntiItems++;
655 }
656 }
657
658 if (numEmptyFiles > 0)
659 {
660 WriteByte(NID::kEmptyFile);
661 WriteNumber(Bv_GetSizeInBytes(emptyFileVector));
662 WriteBoolVector(emptyFileVector);
663 }
664
665 if (numAntiItems > 0)
666 {
667 WriteByte(NID::kAnti);
668 WriteNumber(Bv_GetSizeInBytes(antiVector));
669 WriteBoolVector(antiVector);
670 }
671 }
672 }
673
674
675 {
676 /* ---------- Names ---------- */
677
678 int numDefined = 0;
679 size_t namesDataSize = 0;
680 for (int i = 0; i < db.Files.Size(); i++)
681 {
682 const UString &name = db.Files[i].Name;
683 if (!name.IsEmpty())
684 numDefined++;
685 namesDataSize += (name.Length() + 1) * 2;
686 }
687
688 if (numDefined > 0)
689 {
690 namesDataSize++;
691 SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
692
693 WriteByte(NID::kName);
694 WriteNumber(namesDataSize);
695 WriteByte(0);
696 for (int i = 0; i < db.Files.Size(); i++)
697 {
698 const UString &name = db.Files[i].Name;
699 for (int t = 0; t <= name.Length(); t++)
700 {
701 wchar_t c = name[t];
702 WriteByte((Byte)c);
703 WriteByte((Byte)(c >> 8));
704 }
705 }
706 }
707 }
708
709 if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime);
710 if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime);
711 if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime);
712 WriteUInt64DefVector(db.StartPos, NID::kStartPos);
713
714 {
715 /* ---------- Write Attrib ---------- */
716 CBoolVector boolVector;
717 boolVector.Reserve(db.Files.Size());
718 int numDefined = 0;
719 for (i = 0; i < db.Files.Size(); i++)
720 {
721 bool defined = db.Files[i].AttribDefined;
722 boolVector.Add(defined);
723 if (defined)
724 numDefined++;
725 }
726 if (numDefined > 0)
727 {
728 WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4);
729 for (i = 0; i < db.Files.Size(); i++)
730 {
731 const CFileItem &file = db.Files[i];
732 if (file.AttribDefined)
733 WriteUInt32(file.Attrib);
734 }
735 }
736 }
737
738 WriteByte(NID::kEnd); // for files
739 WriteByte(NID::kEnd); // for headers
740 }
741
WriteDatabase(DECL_EXTERNAL_CODECS_LOC_VARS const CArchiveDatabase & db,const CCompressionMethodMode * options,const CHeaderOptions & headerOptions)742 HRESULT COutArchive::WriteDatabase(
743 DECL_EXTERNAL_CODECS_LOC_VARS
744 const CArchiveDatabase &db,
745 const CCompressionMethodMode *options,
746 const CHeaderOptions &headerOptions)
747 {
748 if (!db.CheckNumFiles())
749 return E_FAIL;
750
751 UInt64 headerOffset;
752 UInt32 headerCRC;
753 UInt64 headerSize;
754 if (db.IsEmpty())
755 {
756 headerSize = 0;
757 headerOffset = 0;
758 headerCRC = CrcCalc(0, 0);
759 }
760 else
761 {
762 bool encodeHeaders = false;
763 if (options != 0)
764 if (options->IsEmpty())
765 options = 0;
766 if (options != 0)
767 if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
768 encodeHeaders = true;
769
770 _outByte.SetStream(SeqStream);
771 _outByte.Init();
772 _crc = CRC_INIT_VAL;
773 _countMode = encodeHeaders;
774 _writeToStream = true;
775 _countSize = 0;
776 WriteHeader(db, headerOptions, headerOffset);
777
778 if (encodeHeaders)
779 {
780 CByteBuffer buf;
781 buf.SetCapacity(_countSize);
782 _outByte2.Init((Byte *)buf, _countSize);
783
784 _countMode = false;
785 _writeToStream = false;
786 WriteHeader(db, headerOptions, headerOffset);
787
788 if (_countSize != _outByte2.GetPos())
789 return E_FAIL;
790
791 CCompressionMethodMode encryptOptions;
792 encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
793 encryptOptions.Password = options->Password;
794 CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
795 CRecordVector<UInt64> packSizes;
796 CObjectVector<CFolder> folders;
797 RINOK(EncodeStream(
798 EXTERNAL_CODECS_LOC_VARS
799 encoder, buf,
800 packSizes, folders));
801
802 _writeToStream = true;
803
804 if (folders.Size() == 0)
805 throw 1;
806
807 WriteID(NID::kEncodedHeader);
808 WritePackInfo(headerOffset, packSizes,
809 CRecordVector<bool>(), CRecordVector<UInt32>());
810 WriteUnpackInfo(folders);
811 WriteByte(NID::kEnd);
812 for (int i = 0; i < packSizes.Size(); i++)
813 headerOffset += packSizes[i];
814 }
815 RINOK(_outByte.Flush());
816 headerCRC = CRC_GET_DIGEST(_crc);
817 headerSize = _outByte.GetProcessedSize();
818 }
819 #ifdef _7Z_VOL
820 if (_endMarker)
821 {
822 CFinishHeader h;
823 h.NextHeaderSize = headerSize;
824 h.NextHeaderCRC = headerCRC;
825 h.NextHeaderOffset =
826 UInt64(0) - (headerSize +
827 4 + kFinishHeaderSize);
828 h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
829 h.AdditionalStartBlockSize = 0;
830 RINOK(WriteFinishHeader(h));
831 return WriteFinishSignature();
832 }
833 else
834 #endif
835 {
836 CStartHeader h;
837 h.NextHeaderSize = headerSize;
838 h.NextHeaderCRC = headerCRC;
839 h.NextHeaderOffset = headerOffset;
840 RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
841 return WriteStartHeader(h);
842 }
843 }
844
GetFile(int index,CFileItem & file,CFileItem2 & file2) const845 void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const
846 {
847 file = Files[index];
848 file2.CTimeDefined = CTime.GetItem(index, file2.CTime);
849 file2.ATimeDefined = ATime.GetItem(index, file2.ATime);
850 file2.MTimeDefined = MTime.GetItem(index, file2.MTime);
851 file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos);
852 file2.IsAnti = IsItemAnti(index);
853 }
854
AddFile(const CFileItem & file,const CFileItem2 & file2)855 void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2)
856 {
857 int index = Files.Size();
858 CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
859 ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
860 MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
861 StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
862 SetItemAnti(index, file2.IsAnti);
863 Files.Add(file);
864 }
865
866 }}
867