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