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