| OLD | NEW |
| (Empty) |
| 1 // 7zIn.cpp | |
| 2 | |
| 3 #include "StdAfx.h" | |
| 4 | |
| 5 extern "C" | |
| 6 { | |
| 7 #include "../../../../C/7zCrc.h" | |
| 8 #include "../../../../C/CpuArch.h" | |
| 9 } | |
| 10 | |
| 11 #include "../../Common/StreamObjects.h" | |
| 12 #include "../../Common/StreamUtils.h" | |
| 13 | |
| 14 #include "7zDecode.h" | |
| 15 #include "7zIn.h" | |
| 16 | |
| 17 #define Get16(p) GetUi16(p) | |
| 18 #define Get32(p) GetUi32(p) | |
| 19 #define Get64(p) GetUi64(p) | |
| 20 | |
| 21 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with em
pty StartHeader | |
| 22 #ifndef _SFX | |
| 23 #define FORMAT_7Z_RECOVERY | |
| 24 #endif | |
| 25 | |
| 26 namespace NArchive { | |
| 27 namespace N7z { | |
| 28 | |
| 29 static void BoolVector_Fill_False(CBoolVector &v, int size) | |
| 30 { | |
| 31 v.Clear(); | |
| 32 v.Reserve(size); | |
| 33 for (int i = 0; i < size; i++) | |
| 34 v.Add(false); | |
| 35 } | |
| 36 | |
| 37 static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) | |
| 38 { | |
| 39 if (index >= (UInt32)v.Size()) | |
| 40 return true; | |
| 41 bool res = v[index]; | |
| 42 v[index] = true; | |
| 43 return res; | |
| 44 } | |
| 45 | |
| 46 bool CFolder::CheckStructure() const | |
| 47 { | |
| 48 const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it | |
| 49 const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax | |
| 50 const int kNumBindsMax = 32; | |
| 51 | |
| 52 if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax) | |
| 53 return false; | |
| 54 | |
| 55 { | |
| 56 CBoolVector v; | |
| 57 BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); | |
| 58 | |
| 59 int i; | |
| 60 for (i = 0; i < BindPairs.Size(); i++) | |
| 61 if (BoolVector_GetAndSet(v, BindPairs[i].InIndex)) | |
| 62 return false; | |
| 63 for (i = 0; i < PackStreams.Size(); i++) | |
| 64 if (BoolVector_GetAndSet(v, PackStreams[i])) | |
| 65 return false; | |
| 66 | |
| 67 BoolVector_Fill_False(v, UnpackSizes.Size()); | |
| 68 for (i = 0; i < BindPairs.Size(); i++) | |
| 69 if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) | |
| 70 return false; | |
| 71 } | |
| 72 | |
| 73 UInt32 mask[kMaskSize]; | |
| 74 int i; | |
| 75 for (i = 0; i < kMaskSize; i++) | |
| 76 mask[i] = 0; | |
| 77 | |
| 78 { | |
| 79 CIntVector inStreamToCoder, outStreamToCoder; | |
| 80 for (i = 0; i < Coders.Size(); i++) | |
| 81 { | |
| 82 CNum j; | |
| 83 const CCoderInfo &coder = Coders[i]; | |
| 84 for (j = 0; j < coder.NumInStreams; j++) | |
| 85 inStreamToCoder.Add(i); | |
| 86 for (j = 0; j < coder.NumOutStreams; j++) | |
| 87 outStreamToCoder.Add(i); | |
| 88 } | |
| 89 | |
| 90 for (i = 0; i < BindPairs.Size(); i++) | |
| 91 { | |
| 92 const CBindPair &bp = BindPairs[i]; | |
| 93 mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 for (i = 0; i < kMaskSize; i++) | |
| 98 for (int j = 0; j < kMaskSize; j++) | |
| 99 if (((1 << j) & mask[i]) != 0) | |
| 100 mask[i] |= mask[j]; | |
| 101 | |
| 102 for (i = 0; i < kMaskSize; i++) | |
| 103 if (((1 << i) & mask[i]) != 0) | |
| 104 return false; | |
| 105 | |
| 106 return true; | |
| 107 } | |
| 108 | |
| 109 class CInArchiveException {}; | |
| 110 | |
| 111 static void ThrowException() { throw CInArchiveException(); } | |
| 112 static inline void ThrowEndOfData() { ThrowException(); } | |
| 113 static inline void ThrowUnsupported() { ThrowException(); } | |
| 114 static inline void ThrowIncorrect() { ThrowException(); } | |
| 115 static inline void ThrowUnsupportedVersion() { ThrowException(); } | |
| 116 | |
| 117 /* | |
| 118 class CInArchiveException | |
| 119 { | |
| 120 public: | |
| 121 enum CCauseType | |
| 122 { | |
| 123 kUnsupportedVersion = 0, | |
| 124 kUnsupported, | |
| 125 kIncorrect, | |
| 126 kEndOfData, | |
| 127 } Cause; | |
| 128 CInArchiveException(CCauseType cause): Cause(cause) {}; | |
| 129 }; | |
| 130 | |
| 131 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchive
Exception(c); } | |
| 132 static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData)
; } | |
| 133 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupporte
d); } | |
| 134 static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect)
; } | |
| 135 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUns
upportedVersion); } | |
| 136 */ | |
| 137 | |
| 138 class CStreamSwitch | |
| 139 { | |
| 140 CInArchive *_archive; | |
| 141 bool _needRemove; | |
| 142 public: | |
| 143 CStreamSwitch(): _needRemove(false) {} | |
| 144 ~CStreamSwitch() { Remove(); } | |
| 145 void Remove(); | |
| 146 void Set(CInArchive *archive, const Byte *data, size_t size); | |
| 147 void Set(CInArchive *archive, const CByteBuffer &byteBuffer); | |
| 148 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector); | |
| 149 }; | |
| 150 | |
| 151 void CStreamSwitch::Remove() | |
| 152 { | |
| 153 if (_needRemove) | |
| 154 { | |
| 155 _archive->DeleteByteStream(); | |
| 156 _needRemove = false; | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size) | |
| 161 { | |
| 162 Remove(); | |
| 163 _archive = archive; | |
| 164 _archive->AddByteStream(data, size); | |
| 165 _needRemove = true; | |
| 166 } | |
| 167 | |
| 168 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) | |
| 169 { | |
| 170 Set(archive, byteBuffer, byteBuffer.GetCapacity()); | |
| 171 } | |
| 172 | |
| 173 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *d
ataVector) | |
| 174 { | |
| 175 Remove(); | |
| 176 Byte external = archive->ReadByte(); | |
| 177 if (external != 0) | |
| 178 { | |
| 179 int dataIndex = (int)archive->ReadNum(); | |
| 180 if (dataIndex < 0 || dataIndex >= dataVector->Size()) | |
| 181 ThrowIncorrect(); | |
| 182 Set(archive, (*dataVector)[dataIndex]); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 Byte CInByte2::ReadByte() | |
| 187 { | |
| 188 if (_pos >= _size) | |
| 189 ThrowEndOfData(); | |
| 190 return _buffer[_pos++]; | |
| 191 } | |
| 192 | |
| 193 void CInByte2::ReadBytes(Byte *data, size_t size) | |
| 194 { | |
| 195 if (size > _size - _pos) | |
| 196 ThrowEndOfData(); | |
| 197 for (size_t i = 0; i < size; i++) | |
| 198 data[i] = _buffer[_pos++]; | |
| 199 } | |
| 200 | |
| 201 void CInByte2::SkeepData(UInt64 size) | |
| 202 { | |
| 203 if (size > _size - _pos) | |
| 204 ThrowEndOfData(); | |
| 205 _pos += (size_t)size; | |
| 206 } | |
| 207 | |
| 208 void CInByte2::SkeepData() | |
| 209 { | |
| 210 SkeepData(ReadNumber()); | |
| 211 } | |
| 212 | |
| 213 UInt64 CInByte2::ReadNumber() | |
| 214 { | |
| 215 if (_pos >= _size) | |
| 216 ThrowEndOfData(); | |
| 217 Byte firstByte = _buffer[_pos++]; | |
| 218 Byte mask = 0x80; | |
| 219 UInt64 value = 0; | |
| 220 for (int i = 0; i < 8; i++) | |
| 221 { | |
| 222 if ((firstByte & mask) == 0) | |
| 223 { | |
| 224 UInt64 highPart = firstByte & (mask - 1); | |
| 225 value += (highPart << (i * 8)); | |
| 226 return value; | |
| 227 } | |
| 228 if (_pos >= _size) | |
| 229 ThrowEndOfData(); | |
| 230 value |= ((UInt64)_buffer[_pos++] << (8 * i)); | |
| 231 mask >>= 1; | |
| 232 } | |
| 233 return value; | |
| 234 } | |
| 235 | |
| 236 CNum CInByte2::ReadNum() | |
| 237 { | |
| 238 UInt64 value = ReadNumber(); | |
| 239 if (value > kNumMax) | |
| 240 ThrowUnsupported(); | |
| 241 return (CNum)value; | |
| 242 } | |
| 243 | |
| 244 UInt32 CInByte2::ReadUInt32() | |
| 245 { | |
| 246 if (_pos + 4 > _size) | |
| 247 ThrowEndOfData(); | |
| 248 UInt32 res = Get32(_buffer + _pos); | |
| 249 _pos += 4; | |
| 250 return res; | |
| 251 } | |
| 252 | |
| 253 UInt64 CInByte2::ReadUInt64() | |
| 254 { | |
| 255 if (_pos + 8 > _size) | |
| 256 ThrowEndOfData(); | |
| 257 UInt64 res = Get64(_buffer + _pos); | |
| 258 _pos += 8; | |
| 259 return res; | |
| 260 } | |
| 261 | |
| 262 void CInByte2::ReadString(UString &s) | |
| 263 { | |
| 264 const Byte *buf = _buffer + _pos; | |
| 265 size_t rem = (_size - _pos) / 2 * 2; | |
| 266 { | |
| 267 size_t i; | |
| 268 for (i = 0; i < rem; i += 2) | |
| 269 if (buf[i] == 0 && buf[i + 1] == 0) | |
| 270 break; | |
| 271 if (i == rem) | |
| 272 ThrowEndOfData(); | |
| 273 rem = i; | |
| 274 } | |
| 275 int len = (int)(rem / 2); | |
| 276 if (len < 0 || (size_t)len * 2 != rem) | |
| 277 ThrowUnsupported(); | |
| 278 wchar_t *p = s.GetBuffer(len); | |
| 279 int i; | |
| 280 for (i = 0; i < len; i++, buf += 2) | |
| 281 p[i] = (wchar_t)Get16(buf); | |
| 282 s.ReleaseBuffer(len); | |
| 283 _pos += rem + 2; | |
| 284 } | |
| 285 | |
| 286 static inline bool TestSignatureCandidate(const Byte *p) | |
| 287 { | |
| 288 for (int i = 0; i < kSignatureSize; i++) | |
| 289 if (p[i] != kSignature[i]) | |
| 290 return false; | |
| 291 return (p[0x1A] == 0 && p[0x1B] == 0); | |
| 292 } | |
| 293 | |
| 294 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search
HeaderSizeLimit) | |
| 295 { | |
| 296 RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); | |
| 297 | |
| 298 if (TestSignatureCandidate(_header)) | |
| 299 return S_OK; | |
| 300 | |
| 301 CByteBuffer byteBuffer; | |
| 302 const UInt32 kBufferSize = (1 << 16); | |
| 303 byteBuffer.SetCapacity(kBufferSize); | |
| 304 Byte *buffer = byteBuffer; | |
| 305 UInt32 numPrevBytes = kHeaderSize - 1; | |
| 306 memcpy(buffer, _header + 1, numPrevBytes); | |
| 307 UInt64 curTestPos = _arhiveBeginStreamPosition + 1; | |
| 308 for (;;) | |
| 309 { | |
| 310 if (searchHeaderSizeLimit != NULL) | |
| 311 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) | |
| 312 break; | |
| 313 do | |
| 314 { | |
| 315 UInt32 numReadBytes = kBufferSize - numPrevBytes; | |
| 316 UInt32 processedSize; | |
| 317 RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize)); | |
| 318 numPrevBytes += processedSize; | |
| 319 if (processedSize == 0) | |
| 320 return S_FALSE; | |
| 321 } | |
| 322 while (numPrevBytes < kHeaderSize); | |
| 323 UInt32 numTests = numPrevBytes - kHeaderSize + 1; | |
| 324 for (UInt32 pos = 0; pos < numTests; pos++) | |
| 325 { | |
| 326 for (; buffer[pos] != '7' && pos < numTests; pos++); | |
| 327 if (pos == numTests) | |
| 328 break; | |
| 329 if (TestSignatureCandidate(buffer + pos)) | |
| 330 { | |
| 331 memcpy(_header, buffer + pos, kHeaderSize); | |
| 332 curTestPos += pos; | |
| 333 _arhiveBeginStreamPosition = curTestPos; | |
| 334 return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL); | |
| 335 } | |
| 336 } | |
| 337 curTestPos += numTests; | |
| 338 numPrevBytes -= numTests; | |
| 339 memmove(buffer, buffer + numTests, numPrevBytes); | |
| 340 } | |
| 341 return S_FALSE; | |
| 342 } | |
| 343 | |
| 344 // S_FALSE means that file is not archive | |
| 345 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) | |
| 346 { | |
| 347 HeadersSize = 0; | |
| 348 Close(); | |
| 349 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) | |
| 350 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); | |
| 351 _stream = stream; | |
| 352 return S_OK; | |
| 353 } | |
| 354 | |
| 355 void CInArchive::Close() | |
| 356 { | |
| 357 _stream.Release(); | |
| 358 } | |
| 359 | |
| 360 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) | |
| 361 { | |
| 362 for (;;) | |
| 363 { | |
| 364 if (ReadID() == NID::kEnd) | |
| 365 break; | |
| 366 SkeepData(); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 void CInArchive::GetNextFolderItem(CFolder &folder) | |
| 371 { | |
| 372 CNum numCoders = ReadNum(); | |
| 373 | |
| 374 folder.Coders.Clear(); | |
| 375 folder.Coders.Reserve((int)numCoders); | |
| 376 CNum numInStreams = 0; | |
| 377 CNum numOutStreams = 0; | |
| 378 CNum i; | |
| 379 for (i = 0; i < numCoders; i++) | |
| 380 { | |
| 381 folder.Coders.Add(CCoderInfo()); | |
| 382 CCoderInfo &coder = folder.Coders.Back(); | |
| 383 | |
| 384 { | |
| 385 Byte mainByte = ReadByte(); | |
| 386 int idSize = (mainByte & 0xF); | |
| 387 Byte longID[15]; | |
| 388 ReadBytes(longID, idSize); | |
| 389 if (idSize > 8) | |
| 390 ThrowUnsupported(); | |
| 391 UInt64 id = 0; | |
| 392 for (int j = 0; j < idSize; j++) | |
| 393 id |= (UInt64)longID[idSize - 1 - j] << (8 * j); | |
| 394 coder.MethodID = id; | |
| 395 | |
| 396 if ((mainByte & 0x10) != 0) | |
| 397 { | |
| 398 coder.NumInStreams = ReadNum(); | |
| 399 coder.NumOutStreams = ReadNum(); | |
| 400 } | |
| 401 else | |
| 402 { | |
| 403 coder.NumInStreams = 1; | |
| 404 coder.NumOutStreams = 1; | |
| 405 } | |
| 406 if ((mainByte & 0x20) != 0) | |
| 407 { | |
| 408 CNum propsSize = ReadNum(); | |
| 409 coder.Props.SetCapacity((size_t)propsSize); | |
| 410 ReadBytes((Byte *)coder.Props, (size_t)propsSize); | |
| 411 } | |
| 412 if ((mainByte & 0x80) != 0) | |
| 413 ThrowUnsupported(); | |
| 414 } | |
| 415 numInStreams += coder.NumInStreams; | |
| 416 numOutStreams += coder.NumOutStreams; | |
| 417 } | |
| 418 | |
| 419 CNum numBindPairs = numOutStreams - 1; | |
| 420 folder.BindPairs.Clear(); | |
| 421 folder.BindPairs.Reserve(numBindPairs); | |
| 422 for (i = 0; i < numBindPairs; i++) | |
| 423 { | |
| 424 CBindPair bp; | |
| 425 bp.InIndex = ReadNum(); | |
| 426 bp.OutIndex = ReadNum(); | |
| 427 folder.BindPairs.Add(bp); | |
| 428 } | |
| 429 | |
| 430 if (numInStreams < numBindPairs) | |
| 431 ThrowUnsupported(); | |
| 432 CNum numPackStreams = numInStreams - numBindPairs; | |
| 433 folder.PackStreams.Reserve(numPackStreams); | |
| 434 if (numPackStreams == 1) | |
| 435 { | |
| 436 for (i = 0; i < numInStreams; i++) | |
| 437 if (folder.FindBindPairForInStream(i) < 0) | |
| 438 { | |
| 439 folder.PackStreams.Add(i); | |
| 440 break; | |
| 441 } | |
| 442 if (folder.PackStreams.Size() != 1) | |
| 443 ThrowUnsupported(); | |
| 444 } | |
| 445 else | |
| 446 for (i = 0; i < numPackStreams; i++) | |
| 447 folder.PackStreams.Add(ReadNum()); | |
| 448 } | |
| 449 | |
| 450 void CInArchive::WaitAttribute(UInt64 attribute) | |
| 451 { | |
| 452 for (;;) | |
| 453 { | |
| 454 UInt64 type = ReadID(); | |
| 455 if (type == attribute) | |
| 456 return; | |
| 457 if (type == NID::kEnd) | |
| 458 ThrowIncorrect(); | |
| 459 SkeepData(); | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 void CInArchive::ReadHashDigests(int numItems, | |
| 464 CBoolVector &digestsDefined, | |
| 465 CRecordVector<UInt32> &digests) | |
| 466 { | |
| 467 ReadBoolVector2(numItems, digestsDefined); | |
| 468 digests.Clear(); | |
| 469 digests.Reserve(numItems); | |
| 470 for (int i = 0; i < numItems; i++) | |
| 471 { | |
| 472 UInt32 crc = 0; | |
| 473 if (digestsDefined[i]) | |
| 474 crc = ReadUInt32(); | |
| 475 digests.Add(crc); | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 void CInArchive::ReadPackInfo( | |
| 480 UInt64 &dataOffset, | |
| 481 CRecordVector<UInt64> &packSizes, | |
| 482 CBoolVector &packCRCsDefined, | |
| 483 CRecordVector<UInt32> &packCRCs) | |
| 484 { | |
| 485 dataOffset = ReadNumber(); | |
| 486 CNum numPackStreams = ReadNum(); | |
| 487 | |
| 488 WaitAttribute(NID::kSize); | |
| 489 packSizes.Clear(); | |
| 490 packSizes.Reserve(numPackStreams); | |
| 491 for (CNum i = 0; i < numPackStreams; i++) | |
| 492 packSizes.Add(ReadNumber()); | |
| 493 | |
| 494 UInt64 type; | |
| 495 for (;;) | |
| 496 { | |
| 497 type = ReadID(); | |
| 498 if (type == NID::kEnd) | |
| 499 break; | |
| 500 if (type == NID::kCRC) | |
| 501 { | |
| 502 ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); | |
| 503 continue; | |
| 504 } | |
| 505 SkeepData(); | |
| 506 } | |
| 507 if (packCRCsDefined.IsEmpty()) | |
| 508 { | |
| 509 BoolVector_Fill_False(packCRCsDefined, numPackStreams); | |
| 510 packCRCs.Reserve(numPackStreams); | |
| 511 packCRCs.Clear(); | |
| 512 for (CNum i = 0; i < numPackStreams; i++) | |
| 513 packCRCs.Add(0); | |
| 514 } | |
| 515 } | |
| 516 | |
| 517 void CInArchive::ReadUnpackInfo( | |
| 518 const CObjectVector<CByteBuffer> *dataVector, | |
| 519 CObjectVector<CFolder> &folders) | |
| 520 { | |
| 521 WaitAttribute(NID::kFolder); | |
| 522 CNum numFolders = ReadNum(); | |
| 523 | |
| 524 { | |
| 525 CStreamSwitch streamSwitch; | |
| 526 streamSwitch.Set(this, dataVector); | |
| 527 folders.Clear(); | |
| 528 folders.Reserve(numFolders); | |
| 529 for (CNum i = 0; i < numFolders; i++) | |
| 530 { | |
| 531 folders.Add(CFolder()); | |
| 532 GetNextFolderItem(folders.Back()); | |
| 533 } | |
| 534 } | |
| 535 | |
| 536 WaitAttribute(NID::kCodersUnpackSize); | |
| 537 | |
| 538 CNum i; | |
| 539 for (i = 0; i < numFolders; i++) | |
| 540 { | |
| 541 CFolder &folder = folders[i]; | |
| 542 CNum numOutStreams = folder.GetNumOutStreams(); | |
| 543 folder.UnpackSizes.Reserve(numOutStreams); | |
| 544 for (CNum j = 0; j < numOutStreams; j++) | |
| 545 folder.UnpackSizes.Add(ReadNumber()); | |
| 546 } | |
| 547 | |
| 548 for (;;) | |
| 549 { | |
| 550 UInt64 type = ReadID(); | |
| 551 if (type == NID::kEnd) | |
| 552 return; | |
| 553 if (type == NID::kCRC) | |
| 554 { | |
| 555 CBoolVector crcsDefined; | |
| 556 CRecordVector<UInt32> crcs; | |
| 557 ReadHashDigests(numFolders, crcsDefined, crcs); | |
| 558 for (i = 0; i < numFolders; i++) | |
| 559 { | |
| 560 CFolder &folder = folders[i]; | |
| 561 folder.UnpackCRCDefined = crcsDefined[i]; | |
| 562 folder.UnpackCRC = crcs[i]; | |
| 563 } | |
| 564 continue; | |
| 565 } | |
| 566 SkeepData(); | |
| 567 } | |
| 568 } | |
| 569 | |
| 570 void CInArchive::ReadSubStreamsInfo( | |
| 571 const CObjectVector<CFolder> &folders, | |
| 572 CRecordVector<CNum> &numUnpackStreamsInFolders, | |
| 573 CRecordVector<UInt64> &unpackSizes, | |
| 574 CBoolVector &digestsDefined, | |
| 575 CRecordVector<UInt32> &digests) | |
| 576 { | |
| 577 numUnpackStreamsInFolders.Clear(); | |
| 578 numUnpackStreamsInFolders.Reserve(folders.Size()); | |
| 579 UInt64 type; | |
| 580 for (;;) | |
| 581 { | |
| 582 type = ReadID(); | |
| 583 if (type == NID::kNumUnpackStream) | |
| 584 { | |
| 585 for (int i = 0; i < folders.Size(); i++) | |
| 586 numUnpackStreamsInFolders.Add(ReadNum()); | |
| 587 continue; | |
| 588 } | |
| 589 if (type == NID::kCRC || type == NID::kSize) | |
| 590 break; | |
| 591 if (type == NID::kEnd) | |
| 592 break; | |
| 593 SkeepData(); | |
| 594 } | |
| 595 | |
| 596 if (numUnpackStreamsInFolders.IsEmpty()) | |
| 597 for (int i = 0; i < folders.Size(); i++) | |
| 598 numUnpackStreamsInFolders.Add(1); | |
| 599 | |
| 600 int i; | |
| 601 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) | |
| 602 { | |
| 603 // v3.13 incorrectly worked with empty folders | |
| 604 // v4.07: we check that folder is empty | |
| 605 CNum numSubstreams = numUnpackStreamsInFolders[i]; | |
| 606 if (numSubstreams == 0) | |
| 607 continue; | |
| 608 UInt64 sum = 0; | |
| 609 for (CNum j = 1; j < numSubstreams; j++) | |
| 610 if (type == NID::kSize) | |
| 611 { | |
| 612 UInt64 size = ReadNumber(); | |
| 613 unpackSizes.Add(size); | |
| 614 sum += size; | |
| 615 } | |
| 616 unpackSizes.Add(folders[i].GetUnpackSize() - sum); | |
| 617 } | |
| 618 if (type == NID::kSize) | |
| 619 type = ReadID(); | |
| 620 | |
| 621 int numDigests = 0; | |
| 622 int numDigestsTotal = 0; | |
| 623 for (i = 0; i < folders.Size(); i++) | |
| 624 { | |
| 625 CNum numSubstreams = numUnpackStreamsInFolders[i]; | |
| 626 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) | |
| 627 numDigests += numSubstreams; | |
| 628 numDigestsTotal += numSubstreams; | |
| 629 } | |
| 630 | |
| 631 for (;;) | |
| 632 { | |
| 633 if (type == NID::kCRC) | |
| 634 { | |
| 635 CBoolVector digestsDefined2; | |
| 636 CRecordVector<UInt32> digests2; | |
| 637 ReadHashDigests(numDigests, digestsDefined2, digests2); | |
| 638 int digestIndex = 0; | |
| 639 for (i = 0; i < folders.Size(); i++) | |
| 640 { | |
| 641 CNum numSubstreams = numUnpackStreamsInFolders[i]; | |
| 642 const CFolder &folder = folders[i]; | |
| 643 if (numSubstreams == 1 && folder.UnpackCRCDefined) | |
| 644 { | |
| 645 digestsDefined.Add(true); | |
| 646 digests.Add(folder.UnpackCRC); | |
| 647 } | |
| 648 else | |
| 649 for (CNum j = 0; j < numSubstreams; j++, digestIndex++) | |
| 650 { | |
| 651 digestsDefined.Add(digestsDefined2[digestIndex]); | |
| 652 digests.Add(digests2[digestIndex]); | |
| 653 } | |
| 654 } | |
| 655 } | |
| 656 else if (type == NID::kEnd) | |
| 657 { | |
| 658 if (digestsDefined.IsEmpty()) | |
| 659 { | |
| 660 BoolVector_Fill_False(digestsDefined, numDigestsTotal); | |
| 661 digests.Clear(); | |
| 662 for (int i = 0; i < numDigestsTotal; i++) | |
| 663 digests.Add(0); | |
| 664 } | |
| 665 return; | |
| 666 } | |
| 667 else | |
| 668 SkeepData(); | |
| 669 type = ReadID(); | |
| 670 } | |
| 671 } | |
| 672 | |
| 673 void CInArchive::ReadStreamsInfo( | |
| 674 const CObjectVector<CByteBuffer> *dataVector, | |
| 675 UInt64 &dataOffset, | |
| 676 CRecordVector<UInt64> &packSizes, | |
| 677 CBoolVector &packCRCsDefined, | |
| 678 CRecordVector<UInt32> &packCRCs, | |
| 679 CObjectVector<CFolder> &folders, | |
| 680 CRecordVector<CNum> &numUnpackStreamsInFolders, | |
| 681 CRecordVector<UInt64> &unpackSizes, | |
| 682 CBoolVector &digestsDefined, | |
| 683 CRecordVector<UInt32> &digests) | |
| 684 { | |
| 685 for (;;) | |
| 686 { | |
| 687 UInt64 type = ReadID(); | |
| 688 if (type > ((UInt32)1 << 30)) | |
| 689 ThrowIncorrect(); | |
| 690 switch((UInt32)type) | |
| 691 { | |
| 692 case NID::kEnd: | |
| 693 return; | |
| 694 case NID::kPackInfo: | |
| 695 { | |
| 696 ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs); | |
| 697 break; | |
| 698 } | |
| 699 case NID::kUnpackInfo: | |
| 700 { | |
| 701 ReadUnpackInfo(dataVector, folders); | |
| 702 break; | |
| 703 } | |
| 704 case NID::kSubStreamsInfo: | |
| 705 { | |
| 706 ReadSubStreamsInfo(folders, numUnpackStreamsInFolders, | |
| 707 unpackSizes, digestsDefined, digests); | |
| 708 break; | |
| 709 } | |
| 710 default: | |
| 711 ThrowIncorrect(); | |
| 712 } | |
| 713 } | |
| 714 } | |
| 715 | |
| 716 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v) | |
| 717 { | |
| 718 v.Clear(); | |
| 719 v.Reserve(numItems); | |
| 720 Byte b = 0; | |
| 721 Byte mask = 0; | |
| 722 for (int i = 0; i < numItems; i++) | |
| 723 { | |
| 724 if (mask == 0) | |
| 725 { | |
| 726 b = ReadByte(); | |
| 727 mask = 0x80; | |
| 728 } | |
| 729 v.Add((b & mask) != 0); | |
| 730 mask >>= 1; | |
| 731 } | |
| 732 } | |
| 733 | |
| 734 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) | |
| 735 { | |
| 736 Byte allAreDefined = ReadByte(); | |
| 737 if (allAreDefined == 0) | |
| 738 { | |
| 739 ReadBoolVector(numItems, v); | |
| 740 return; | |
| 741 } | |
| 742 v.Clear(); | |
| 743 v.Reserve(numItems); | |
| 744 for (int i = 0; i < numItems; i++) | |
| 745 v.Add(true); | |
| 746 } | |
| 747 | |
| 748 void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVecto
r, | |
| 749 CUInt64DefVector &v, int numFiles) | |
| 750 { | |
| 751 ReadBoolVector2(numFiles, v.Defined); | |
| 752 | |
| 753 CStreamSwitch streamSwitch; | |
| 754 streamSwitch.Set(this, &dataVector); | |
| 755 v.Values.Reserve(numFiles); | |
| 756 | |
| 757 for (int i = 0; i < numFiles; i++) | |
| 758 { | |
| 759 UInt64 t = 0; | |
| 760 if (v.Defined[i]) | |
| 761 t = ReadUInt64(); | |
| 762 v.Values.Add(t); | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 HRESULT CInArchive::ReadAndDecodePackedStreams( | |
| 767 DECL_EXTERNAL_CODECS_LOC_VARS | |
| 768 UInt64 baseOffset, | |
| 769 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector | |
| 770 #ifndef _NO_CRYPTO | |
| 771 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined | |
| 772 #endif | |
| 773 ) | |
| 774 { | |
| 775 CRecordVector<UInt64> packSizes; | |
| 776 CBoolVector packCRCsDefined; | |
| 777 CRecordVector<UInt32> packCRCs; | |
| 778 CObjectVector<CFolder> folders; | |
| 779 | |
| 780 CRecordVector<CNum> numUnpackStreamsInFolders; | |
| 781 CRecordVector<UInt64> unpackSizes; | |
| 782 CBoolVector digestsDefined; | |
| 783 CRecordVector<UInt32> digests; | |
| 784 | |
| 785 ReadStreamsInfo(NULL, | |
| 786 dataOffset, | |
| 787 packSizes, | |
| 788 packCRCsDefined, | |
| 789 packCRCs, | |
| 790 folders, | |
| 791 numUnpackStreamsInFolders, | |
| 792 unpackSizes, | |
| 793 digestsDefined, | |
| 794 digests); | |
| 795 | |
| 796 // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeade
r; | |
| 797 | |
| 798 CNum packIndex = 0; | |
| 799 CDecoder decoder( | |
| 800 #ifdef _ST_MODE | |
| 801 false | |
| 802 #else | |
| 803 true | |
| 804 #endif | |
| 805 ); | |
| 806 UInt64 dataStartPos = baseOffset + dataOffset; | |
| 807 for (int i = 0; i < folders.Size(); i++) | |
| 808 { | |
| 809 const CFolder &folder = folders[i]; | |
| 810 dataVector.Add(CByteBuffer()); | |
| 811 CByteBuffer &data = dataVector.Back(); | |
| 812 UInt64 unpackSize64 = folder.GetUnpackSize(); | |
| 813 size_t unpackSize = (size_t)unpackSize64; | |
| 814 if (unpackSize != unpackSize64) | |
| 815 ThrowUnsupported(); | |
| 816 data.SetCapacity(unpackSize); | |
| 817 | |
| 818 CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2; | |
| 819 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; | |
| 820 outStreamSpec->Init(data, unpackSize); | |
| 821 | |
| 822 HRESULT result = decoder.Decode( | |
| 823 EXTERNAL_CODECS_LOC_VARS | |
| 824 _stream, dataStartPos, | |
| 825 &packSizes[packIndex], folder, outStream, NULL | |
| 826 #ifndef _NO_CRYPTO | |
| 827 , getTextPassword, passwordIsDefined | |
| 828 #endif | |
| 829 #ifdef COMPRESS_MT | |
| 830 , false, 1 | |
| 831 #endif | |
| 832 ); | |
| 833 RINOK(result); | |
| 834 | |
| 835 if (folder.UnpackCRCDefined) | |
| 836 if (CrcCalc(data, unpackSize) != folder.UnpackCRC) | |
| 837 ThrowIncorrect(); | |
| 838 for (int j = 0; j < folder.PackStreams.Size(); j++) | |
| 839 { | |
| 840 UInt64 packSize = packSizes[packIndex++]; | |
| 841 dataStartPos += packSize; | |
| 842 HeadersSize += packSize; | |
| 843 } | |
| 844 } | |
| 845 return S_OK; | |
| 846 } | |
| 847 | |
| 848 HRESULT CInArchive::ReadHeader( | |
| 849 DECL_EXTERNAL_CODECS_LOC_VARS | |
| 850 CArchiveDatabaseEx &db | |
| 851 #ifndef _NO_CRYPTO | |
| 852 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined | |
| 853 #endif | |
| 854 ) | |
| 855 { | |
| 856 UInt64 type = ReadID(); | |
| 857 | |
| 858 if (type == NID::kArchiveProperties) | |
| 859 { | |
| 860 ReadArchiveProperties(db.ArchiveInfo); | |
| 861 type = ReadID(); | |
| 862 } | |
| 863 | |
| 864 CObjectVector<CByteBuffer> dataVector; | |
| 865 | |
| 866 if (type == NID::kAdditionalStreamsInfo) | |
| 867 { | |
| 868 HRESULT result = ReadAndDecodePackedStreams( | |
| 869 EXTERNAL_CODECS_LOC_VARS | |
| 870 db.ArchiveInfo.StartPositionAfterHeader, | |
| 871 db.ArchiveInfo.DataStartPosition2, | |
| 872 dataVector | |
| 873 #ifndef _NO_CRYPTO | |
| 874 , getTextPassword, passwordIsDefined | |
| 875 #endif | |
| 876 ); | |
| 877 RINOK(result); | |
| 878 db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader
; | |
| 879 type = ReadID(); | |
| 880 } | |
| 881 | |
| 882 CRecordVector<UInt64> unpackSizes; | |
| 883 CBoolVector digestsDefined; | |
| 884 CRecordVector<UInt32> digests; | |
| 885 | |
| 886 if (type == NID::kMainStreamsInfo) | |
| 887 { | |
| 888 ReadStreamsInfo(&dataVector, | |
| 889 db.ArchiveInfo.DataStartPosition, | |
| 890 db.PackSizes, | |
| 891 db.PackCRCsDefined, | |
| 892 db.PackCRCs, | |
| 893 db.Folders, | |
| 894 db.NumUnpackStreamsVector, | |
| 895 unpackSizes, | |
| 896 digestsDefined, | |
| 897 digests); | |
| 898 db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader; | |
| 899 type = ReadID(); | |
| 900 } | |
| 901 else | |
| 902 { | |
| 903 for (int i = 0; i < db.Folders.Size(); i++) | |
| 904 { | |
| 905 db.NumUnpackStreamsVector.Add(1); | |
| 906 CFolder &folder = db.Folders[i]; | |
| 907 unpackSizes.Add(folder.GetUnpackSize()); | |
| 908 digestsDefined.Add(folder.UnpackCRCDefined); | |
| 909 digests.Add(folder.UnpackCRC); | |
| 910 } | |
| 911 } | |
| 912 | |
| 913 db.Files.Clear(); | |
| 914 | |
| 915 if (type == NID::kEnd) | |
| 916 return S_OK; | |
| 917 if (type != NID::kFilesInfo) | |
| 918 ThrowIncorrect(); | |
| 919 | |
| 920 CNum numFiles = ReadNum(); | |
| 921 db.Files.Reserve(numFiles); | |
| 922 CNum i; | |
| 923 for (i = 0; i < numFiles; i++) | |
| 924 db.Files.Add(CFileItem()); | |
| 925 | |
| 926 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); | |
| 927 if (!db.PackSizes.IsEmpty()) | |
| 928 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); | |
| 929 if (numFiles > 0 && !digests.IsEmpty()) | |
| 930 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); | |
| 931 | |
| 932 CBoolVector emptyStreamVector; | |
| 933 BoolVector_Fill_False(emptyStreamVector, (int)numFiles); | |
| 934 CBoolVector emptyFileVector; | |
| 935 CBoolVector antiFileVector; | |
| 936 CNum numEmptyStreams = 0; | |
| 937 | |
| 938 for (;;) | |
| 939 { | |
| 940 UInt64 type = ReadID(); | |
| 941 if (type == NID::kEnd) | |
| 942 break; | |
| 943 UInt64 size = ReadNumber(); | |
| 944 size_t ppp = _inByteBack->_pos; | |
| 945 bool addPropIdToList = true; | |
| 946 bool isKnownType = true; | |
| 947 if (type > ((UInt32)1 << 30)) | |
| 948 isKnownType = false; | |
| 949 else switch((UInt32)type) | |
| 950 { | |
| 951 case NID::kName: | |
| 952 { | |
| 953 CStreamSwitch streamSwitch; | |
| 954 streamSwitch.Set(this, &dataVector); | |
| 955 for (int i = 0; i < db.Files.Size(); i++) | |
| 956 _inByteBack->ReadString(db.Files[i].Name); | |
| 957 break; | |
| 958 } | |
| 959 case NID::kWinAttributes: | |
| 960 { | |
| 961 CBoolVector boolVector; | |
| 962 ReadBoolVector2(db.Files.Size(), boolVector); | |
| 963 CStreamSwitch streamSwitch; | |
| 964 streamSwitch.Set(this, &dataVector); | |
| 965 for (i = 0; i < numFiles; i++) | |
| 966 { | |
| 967 CFileItem &file = db.Files[i]; | |
| 968 file.AttribDefined = boolVector[i]; | |
| 969 if (file.AttribDefined) | |
| 970 file.Attrib = ReadUInt32(); | |
| 971 } | |
| 972 break; | |
| 973 } | |
| 974 case NID::kEmptyStream: | |
| 975 { | |
| 976 ReadBoolVector(numFiles, emptyStreamVector); | |
| 977 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) | |
| 978 if (emptyStreamVector[i]) | |
| 979 numEmptyStreams++; | |
| 980 | |
| 981 BoolVector_Fill_False(emptyFileVector, numEmptyStreams); | |
| 982 BoolVector_Fill_False(antiFileVector, numEmptyStreams); | |
| 983 | |
| 984 break; | |
| 985 } | |
| 986 case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); b
reak; | |
| 987 case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; | |
| 988 case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)nu
mFiles); break; | |
| 989 case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles
); break; | |
| 990 case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles
); break; | |
| 991 case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles
); break; | |
| 992 case NID::kDummy: | |
| 993 { | |
| 994 for (UInt64 j = 0; j < size; j++) | |
| 995 if (ReadByte() != 0) | |
| 996 ThrowIncorrect(); | |
| 997 addPropIdToList = false; | |
| 998 break; | |
| 999 } | |
| 1000 default: | |
| 1001 addPropIdToList = isKnownType = false; | |
| 1002 } | |
| 1003 if (isKnownType) | |
| 1004 { | |
| 1005 if(addPropIdToList) | |
| 1006 db.ArchiveInfo.FileInfoPopIDs.Add(type); | |
| 1007 } | |
| 1008 else | |
| 1009 SkeepData(size); | |
| 1010 bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 || | |
| 1011 db.ArchiveInfo.Version.Minor > 2); | |
| 1012 if (checkRecordsSize && _inByteBack->_pos - ppp != size) | |
| 1013 ThrowIncorrect(); | |
| 1014 } | |
| 1015 | |
| 1016 CNum emptyFileIndex = 0; | |
| 1017 CNum sizeIndex = 0; | |
| 1018 | |
| 1019 CNum numAntiItems = 0; | |
| 1020 for (i = 0; i < numEmptyStreams; i++) | |
| 1021 if (antiFileVector[i]) | |
| 1022 numAntiItems++; | |
| 1023 | |
| 1024 for (i = 0; i < numFiles; i++) | |
| 1025 { | |
| 1026 CFileItem &file = db.Files[i]; | |
| 1027 bool isAnti; | |
| 1028 file.HasStream = !emptyStreamVector[i]; | |
| 1029 if (file.HasStream) | |
| 1030 { | |
| 1031 file.IsDir = false; | |
| 1032 isAnti = false; | |
| 1033 file.Size = unpackSizes[sizeIndex]; | |
| 1034 file.Crc = digests[sizeIndex]; | |
| 1035 file.CrcDefined = digestsDefined[sizeIndex]; | |
| 1036 sizeIndex++; | |
| 1037 } | |
| 1038 else | |
| 1039 { | |
| 1040 file.IsDir = !emptyFileVector[emptyFileIndex]; | |
| 1041 isAnti = antiFileVector[emptyFileIndex]; | |
| 1042 emptyFileIndex++; | |
| 1043 file.Size = 0; | |
| 1044 file.CrcDefined = false; | |
| 1045 } | |
| 1046 if (numAntiItems != 0) | |
| 1047 db.IsAnti.Add(isAnti); | |
| 1048 } | |
| 1049 return S_OK; | |
| 1050 } | |
| 1051 | |
| 1052 | |
| 1053 void CArchiveDatabaseEx::FillFolderStartPackStream() | |
| 1054 { | |
| 1055 FolderStartPackStreamIndex.Clear(); | |
| 1056 FolderStartPackStreamIndex.Reserve(Folders.Size()); | |
| 1057 CNum startPos = 0; | |
| 1058 for (int i = 0; i < Folders.Size(); i++) | |
| 1059 { | |
| 1060 FolderStartPackStreamIndex.Add(startPos); | |
| 1061 startPos += (CNum)Folders[i].PackStreams.Size(); | |
| 1062 } | |
| 1063 } | |
| 1064 | |
| 1065 void CArchiveDatabaseEx::FillStartPos() | |
| 1066 { | |
| 1067 PackStreamStartPositions.Clear(); | |
| 1068 PackStreamStartPositions.Reserve(PackSizes.Size()); | |
| 1069 UInt64 startPos = 0; | |
| 1070 for (int i = 0; i < PackSizes.Size(); i++) | |
| 1071 { | |
| 1072 PackStreamStartPositions.Add(startPos); | |
| 1073 startPos += PackSizes[i]; | |
| 1074 } | |
| 1075 } | |
| 1076 | |
| 1077 void CArchiveDatabaseEx::FillFolderStartFileIndex() | |
| 1078 { | |
| 1079 FolderStartFileIndex.Clear(); | |
| 1080 FolderStartFileIndex.Reserve(Folders.Size()); | |
| 1081 FileIndexToFolderIndexMap.Clear(); | |
| 1082 FileIndexToFolderIndexMap.Reserve(Files.Size()); | |
| 1083 | |
| 1084 int folderIndex = 0; | |
| 1085 CNum indexInFolder = 0; | |
| 1086 for (int i = 0; i < Files.Size(); i++) | |
| 1087 { | |
| 1088 const CFileItem &file = Files[i]; | |
| 1089 bool emptyStream = !file.HasStream; | |
| 1090 if (emptyStream && indexInFolder == 0) | |
| 1091 { | |
| 1092 FileIndexToFolderIndexMap.Add(kNumNoIndex); | |
| 1093 continue; | |
| 1094 } | |
| 1095 if (indexInFolder == 0) | |
| 1096 { | |
| 1097 // v3.13 incorrectly worked with empty folders | |
| 1098 // v4.07: Loop for skipping empty folders | |
| 1099 for (;;) | |
| 1100 { | |
| 1101 if (folderIndex >= Folders.Size()) | |
| 1102 ThrowIncorrect(); | |
| 1103 FolderStartFileIndex.Add(i); // check it | |
| 1104 if (NumUnpackStreamsVector[folderIndex] != 0) | |
| 1105 break; | |
| 1106 folderIndex++; | |
| 1107 } | |
| 1108 } | |
| 1109 FileIndexToFolderIndexMap.Add(folderIndex); | |
| 1110 if (emptyStream) | |
| 1111 continue; | |
| 1112 indexInFolder++; | |
| 1113 if (indexInFolder >= NumUnpackStreamsVector[folderIndex]) | |
| 1114 { | |
| 1115 folderIndex++; | |
| 1116 indexInFolder = 0; | |
| 1117 } | |
| 1118 } | |
| 1119 } | |
| 1120 | |
| 1121 HRESULT CInArchive::ReadDatabase2( | |
| 1122 DECL_EXTERNAL_CODECS_LOC_VARS | |
| 1123 CArchiveDatabaseEx &db | |
| 1124 #ifndef _NO_CRYPTO | |
| 1125 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined | |
| 1126 #endif | |
| 1127 ) | |
| 1128 { | |
| 1129 db.Clear(); | |
| 1130 db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; | |
| 1131 | |
| 1132 db.ArchiveInfo.Version.Major = _header[6]; | |
| 1133 db.ArchiveInfo.Version.Minor = _header[7]; | |
| 1134 | |
| 1135 if (db.ArchiveInfo.Version.Major != kMajorVersion) | |
| 1136 ThrowUnsupportedVersion(); | |
| 1137 | |
| 1138 UInt32 crcFromArchive = Get32(_header + 8); | |
| 1139 UInt64 nextHeaderOffset = Get64(_header + 0xC); | |
| 1140 UInt64 nextHeaderSize = Get64(_header + 0x14); | |
| 1141 UInt32 nextHeaderCRC = Get32(_header + 0x1C); | |
| 1142 UInt32 crc = CrcCalc(_header + 0xC, 20); | |
| 1143 | |
| 1144 #ifdef FORMAT_7Z_RECOVERY | |
| 1145 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nex
tHeaderCRC == 0) | |
| 1146 { | |
| 1147 UInt64 cur, cur2; | |
| 1148 RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur)); | |
| 1149 const int kCheckSize = 500; | |
| 1150 Byte buf[kCheckSize]; | |
| 1151 RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2)); | |
| 1152 int checkSize = kCheckSize; | |
| 1153 if (cur2 - cur < kCheckSize) | |
| 1154 checkSize = (int)(cur2 - cur); | |
| 1155 RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2)); | |
| 1156 | |
| 1157 RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)); | |
| 1158 | |
| 1159 int i; | |
| 1160 for (i = (int)checkSize - 2; i >= 0; i--) | |
| 1161 if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] ==
0x04) | |
| 1162 break; | |
| 1163 if (i < 0) | |
| 1164 return S_FALSE; | |
| 1165 nextHeaderSize = checkSize - i; | |
| 1166 nextHeaderOffset = cur2 - cur + i; | |
| 1167 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); | |
| 1168 RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); | |
| 1169 } | |
| 1170 #endif | |
| 1171 | |
| 1172 #ifdef FORMAT_7Z_RECOVERY | |
| 1173 crcFromArchive = crc; | |
| 1174 #endif | |
| 1175 | |
| 1176 db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeader
Size; | |
| 1177 | |
| 1178 if (crc != crcFromArchive) | |
| 1179 ThrowIncorrect(); | |
| 1180 | |
| 1181 if (nextHeaderSize == 0) | |
| 1182 return S_OK; | |
| 1183 | |
| 1184 if (nextHeaderSize > (UInt64)0xFFFFFFFF) | |
| 1185 return S_FALSE; | |
| 1186 | |
| 1187 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); | |
| 1188 | |
| 1189 CByteBuffer buffer2; | |
| 1190 buffer2.SetCapacity((size_t)nextHeaderSize); | |
| 1191 | |
| 1192 RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize)); | |
| 1193 HeadersSize += kHeaderSize + nextHeaderSize; | |
| 1194 db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; | |
| 1195 | |
| 1196 if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC) | |
| 1197 ThrowIncorrect(); | |
| 1198 | |
| 1199 CStreamSwitch streamSwitch; | |
| 1200 streamSwitch.Set(this, buffer2); | |
| 1201 | |
| 1202 CObjectVector<CByteBuffer> dataVector; | |
| 1203 | |
| 1204 UInt64 type = ReadID(); | |
| 1205 if (type != NID::kHeader) | |
| 1206 { | |
| 1207 if (type != NID::kEncodedHeader) | |
| 1208 ThrowIncorrect(); | |
| 1209 HRESULT result = ReadAndDecodePackedStreams( | |
| 1210 EXTERNAL_CODECS_LOC_VARS | |
| 1211 db.ArchiveInfo.StartPositionAfterHeader, | |
| 1212 db.ArchiveInfo.DataStartPosition2, | |
| 1213 dataVector | |
| 1214 #ifndef _NO_CRYPTO | |
| 1215 , getTextPassword, passwordIsDefined | |
| 1216 #endif | |
| 1217 ); | |
| 1218 RINOK(result); | |
| 1219 if (dataVector.Size() == 0) | |
| 1220 return S_OK; | |
| 1221 if (dataVector.Size() > 1) | |
| 1222 ThrowIncorrect(); | |
| 1223 streamSwitch.Remove(); | |
| 1224 streamSwitch.Set(this, dataVector.Front()); | |
| 1225 if (ReadID() != NID::kHeader) | |
| 1226 ThrowIncorrect(); | |
| 1227 } | |
| 1228 | |
| 1229 db.HeadersSize = HeadersSize; | |
| 1230 | |
| 1231 return ReadHeader( | |
| 1232 EXTERNAL_CODECS_LOC_VARS | |
| 1233 db | |
| 1234 #ifndef _NO_CRYPTO | |
| 1235 , getTextPassword, passwordIsDefined | |
| 1236 #endif | |
| 1237 ); | |
| 1238 } | |
| 1239 | |
| 1240 HRESULT CInArchive::ReadDatabase( | |
| 1241 DECL_EXTERNAL_CODECS_LOC_VARS | |
| 1242 CArchiveDatabaseEx &db | |
| 1243 #ifndef _NO_CRYPTO | |
| 1244 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined | |
| 1245 #endif | |
| 1246 ) | |
| 1247 { | |
| 1248 try | |
| 1249 { | |
| 1250 return ReadDatabase2( | |
| 1251 EXTERNAL_CODECS_LOC_VARS db | |
| 1252 #ifndef _NO_CRYPTO | |
| 1253 , getTextPassword, passwordIsDefined | |
| 1254 #endif | |
| 1255 ); | |
| 1256 } | |
| 1257 catch(CInArchiveException &) { return S_FALSE; } | |
| 1258 } | |
| 1259 | |
| 1260 }} | |
| OLD | NEW |