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