| 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 |