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