diff options
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipIn.cpp')
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipIn.cpp | 373 |
1 files changed, 238 insertions, 135 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index f2b69a9..4236df7 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp | |||
@@ -11,8 +11,6 @@ | |||
11 | 11 | ||
12 | #include "../../../Windows/PropVariant.h" | 12 | #include "../../../Windows/PropVariant.h" |
13 | 13 | ||
14 | #include "../../Common/StreamUtils.h" | ||
15 | |||
16 | #include "../IArchive.h" | 14 | #include "../IArchive.h" |
17 | 15 | ||
18 | #include "ZipIn.h" | 16 | #include "ZipIn.h" |
@@ -28,9 +26,38 @@ | |||
28 | namespace NArchive { | 26 | namespace NArchive { |
29 | namespace NZip { | 27 | namespace NZip { |
30 | 28 | ||
31 | // (kBufferSize >= kDataDescriptorSize64 + 4) | 29 | /* we try to use same size of Buffer (1 << 17) for all tasks. |
30 | it allow to avoid reallocations and cache clearing. */ | ||
31 | |||
32 | static const size_t kSeqBufferSize = (size_t)1 << 17; | ||
32 | 33 | ||
33 | static const size_t kSeqBufferSize = (size_t)1 << 14; | 34 | /* |
35 | Open() | ||
36 | { | ||
37 | _inBufMode = false; | ||
38 | ReadVols() | ||
39 | FindCd(); | ||
40 | TryEcd64() | ||
41 | SeekToVol() | ||
42 | FindMarker() | ||
43 | _inBufMode = true; | ||
44 | ReadHeaders() | ||
45 | _inBufMode = false; | ||
46 | ReadCd() | ||
47 | FindCd() | ||
48 | TryEcd64() | ||
49 | TryReadCd() | ||
50 | { | ||
51 | SeekToVol(); | ||
52 | _inBufMode = true; | ||
53 | } | ||
54 | _inBufMode = true; | ||
55 | ReadLocals() | ||
56 | ReadCdItem() | ||
57 | .... | ||
58 | } | ||
59 | FindCd() writes to Buffer without touching (_inBufMode) | ||
60 | */ | ||
34 | 61 | ||
35 | /* | 62 | /* |
36 | if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE | 63 | if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE |
@@ -187,11 +214,14 @@ HRESULT CInArchive::Seek_SavePos(UInt64 offset) | |||
187 | return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos); | 214 | return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos); |
188 | } | 215 | } |
189 | 216 | ||
217 | |||
218 | /* SeekToVol() will keep the cached mode, if new volIndex is | ||
219 | same Vols.StreamIndex volume, and offset doesn't go out of cached region */ | ||
220 | |||
190 | HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) | 221 | HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) |
191 | { | 222 | { |
192 | if (volIndex != Vols.StreamIndex) | 223 | if (volIndex != Vols.StreamIndex) |
193 | { | 224 | { |
194 | InitBuf(); | ||
195 | if (IsMultiVol && volIndex >= 0) | 225 | if (IsMultiVol && volIndex >= 0) |
196 | { | 226 | { |
197 | if ((unsigned)volIndex >= Vols.Streams.Size()) | 227 | if ((unsigned)volIndex >= Vols.Streams.Size()) |
@@ -221,12 +251,29 @@ HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) | |||
221 | return S_OK; | 251 | return S_OK; |
222 | } | 252 | } |
223 | } | 253 | } |
224 | InitBuf(); | ||
225 | } | 254 | } |
255 | InitBuf(); | ||
226 | return Seek_SavePos(offset); | 256 | return Seek_SavePos(offset); |
227 | } | 257 | } |
228 | 258 | ||
229 | 259 | ||
260 | HRESULT CInArchive::AllocateBuffer(size_t size) | ||
261 | { | ||
262 | if (size <= Buffer.Size()) | ||
263 | return S_OK; | ||
264 | /* in cached mode virtual_pos is not equal to phy_pos (_streamPos) | ||
265 | so we change _streamPos and do Seek() to virtual_pos before cache clearing */ | ||
266 | if (_bufPos != _bufCached) | ||
267 | { | ||
268 | RINOK(Seek_SavePos(GetVirtStreamPos())) | ||
269 | } | ||
270 | InitBuf(); | ||
271 | Buffer.AllocAtLeast(size); | ||
272 | if (!Buffer.IsAllocated()) | ||
273 | return E_OUTOFMEMORY; | ||
274 | return S_OK; | ||
275 | } | ||
276 | |||
230 | // ---------- ReadFromCache ---------- | 277 | // ---------- ReadFromCache ---------- |
231 | // reads from cache and from Stream | 278 | // reads from cache and from Stream |
232 | // move to next volume can be allowed if (CanStartNewVol) and only before first byte reading | 279 | // move to next volume can be allowed if (CanStartNewVol) and only before first byte reading |
@@ -465,7 +512,7 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) | |||
465 | { | 512 | { |
466 | if (extraSize < 4) | 513 | if (extraSize < 4) |
467 | { | 514 | { |
468 | // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. | 515 | // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers. |
469 | // so we return k_IsArc_Res_YES to support such archives. | 516 | // so we return k_IsArc_Res_YES to support such archives. |
470 | // return k_IsArc_Res_NO; // do we need to support such extra ? | 517 | // return k_IsArc_Res_NO; // do we need to support such extra ? |
471 | return k_IsArc_Res_YES; | 518 | return k_IsArc_Res_YES; |
@@ -508,20 +555,46 @@ static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) | |||
508 | 555 | ||
509 | 556 | ||
510 | 557 | ||
511 | MY_NO_INLINE | 558 | /* FindPK_4() is allowed to access data up to and including &limit[3]. |
512 | static const Byte *FindPK(const Byte *p, const Byte *limit) | 559 | limit[4] access is not allowed. |
560 | return: | ||
561 | (return_ptr < limit) : "PK" was found at (return_ptr) | ||
562 | (return_ptr >= limit) : limit was reached or crossed. So no "PK" found before limit | ||
563 | */ | ||
564 | Z7_NO_INLINE | ||
565 | static const Byte *FindPK_4(const Byte *p, const Byte *limit) | ||
513 | { | 566 | { |
514 | for (;;) | 567 | for (;;) |
515 | { | 568 | { |
516 | for (;;) | 569 | for (;;) |
517 | { | 570 | { |
518 | Byte b0; | 571 | if (p >= limit) |
519 | b0 = p[0]; if (p >= limit) return p; p++; if (b0 == 0x50) break; | 572 | return limit; |
520 | b0 = p[0]; if (p >= limit) return p; p++; if (b0 == 0x50) break; | 573 | Byte b = p[1]; |
574 | if (b == 0x4B) { if (p[0] == 0x50) { return p; } p += 1; break; } | ||
575 | if (b == 0x50) { if (p[2] == 0x4B) { return p + 1; } p += 2; break; } | ||
576 | b = p[3]; | ||
577 | p += 4; | ||
578 | if (b == 0x4B) { if (p[-2]== 0x50) { return p - 2; } p -= 1; break; } | ||
579 | if (b == 0x50) { if (p[0] == 0x4B) { return p - 1; } break; } | ||
580 | } | ||
581 | } | ||
582 | /* | ||
583 | for (;;) | ||
584 | { | ||
585 | for (;;) | ||
586 | { | ||
587 | if (p >= limit) | ||
588 | return limit; | ||
589 | if (*p++ == 0x50) break; | ||
590 | if (*p++ == 0x50) break; | ||
591 | if (*p++ == 0x50) break; | ||
592 | if (*p++ == 0x50) break; | ||
521 | } | 593 | } |
522 | if (p[0] == 0x4B) | 594 | if (*p == 0x4B) |
523 | return p - 1; | 595 | return p - 1; |
524 | } | 596 | } |
597 | */ | ||
525 | } | 598 | } |
526 | 599 | ||
527 | 600 | ||
@@ -554,7 +627,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
554 | if (searchLimit && *searchLimit == 0) | 627 | if (searchLimit && *searchLimit == 0) |
555 | { | 628 | { |
556 | Byte startBuf[kMarkerSize]; | 629 | Byte startBuf[kMarkerSize]; |
557 | RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)); | 630 | RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)) |
558 | 631 | ||
559 | UInt32 marker = Get32(startBuf); | 632 | UInt32 marker = Get32(startBuf); |
560 | _signature = marker; | 633 | _signature = marker; |
@@ -562,7 +635,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
562 | if ( marker == NSignature::kNoSpan | 635 | if ( marker == NSignature::kNoSpan |
563 | || marker == NSignature::kSpan) | 636 | || marker == NSignature::kSpan) |
564 | { | 637 | { |
565 | RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)); | 638 | RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)) |
566 | _signature = Get32(startBuf); | 639 | _signature = Get32(startBuf); |
567 | } | 640 | } |
568 | 641 | ||
@@ -579,16 +652,12 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
579 | return S_OK; | 652 | return S_OK; |
580 | } | 653 | } |
581 | 654 | ||
582 | const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize | 655 | // zip specification: (_zip_header_size < (1 << 16)) |
583 | const size_t kBufSize = (size_t)1 << 17; // must be larger than kCheckSize | 656 | // so we need such size to check header |
657 | const size_t kCheckSize = (size_t)1 << 16; | ||
658 | const size_t kBufSize = (size_t)1 << 17; // (kBufSize must be > kCheckSize) | ||
584 | 659 | ||
585 | if (Buffer.Size() < kBufSize) | 660 | RINOK(AllocateBuffer(kBufSize)) |
586 | { | ||
587 | InitBuf(); | ||
588 | Buffer.AllocAtLeast(kBufSize); | ||
589 | if (!Buffer.IsAllocated()) | ||
590 | return E_OUTOFMEMORY; | ||
591 | } | ||
592 | 661 | ||
593 | _inBufMode = true; | 662 | _inBufMode = true; |
594 | 663 | ||
@@ -596,12 +665,13 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
596 | 665 | ||
597 | for (;;) | 666 | for (;;) |
598 | { | 667 | { |
599 | RINOK(LookAhead(kBufSize)); | 668 | RINOK(LookAhead(kBufSize)) |
600 | 669 | ||
601 | const size_t avail = GetAvail(); | 670 | const size_t avail = GetAvail(); |
602 | 671 | ||
603 | size_t limitPos; | 672 | size_t limitPos; |
604 | const bool isFinished = (avail != kBufSize); | 673 | // (avail > kBufSize) is possible, if (Buffer.Size() > kBufSize) |
674 | const bool isFinished = (avail < kBufSize); | ||
605 | if (isFinished) | 675 | if (isFinished) |
606 | { | 676 | { |
607 | const unsigned kMinAllowed = 4; | 677 | const unsigned kMinAllowed = 4; |
@@ -618,7 +688,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
618 | if (!s.Stream) | 688 | if (!s.Stream) |
619 | break; | 689 | break; |
620 | 690 | ||
621 | RINOK(s.SeekToStart()); | 691 | RINOK(s.SeekToStart()) |
622 | 692 | ||
623 | InitBuf(); | 693 | InitBuf(); |
624 | Vols.StreamIndex++; | 694 | Vols.StreamIndex++; |
@@ -651,11 +721,15 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
651 | 721 | ||
652 | for (;; p++) | 722 | for (;; p++) |
653 | { | 723 | { |
654 | p = FindPK(p, limit); | 724 | p = FindPK_4(p, limit); |
655 | if (p >= limit) | 725 | if (p >= limit) |
656 | break; | 726 | break; |
657 | const size_t rem = (size_t)(pStart + avail - p); | 727 | size_t rem = (size_t)(pStart + avail - p); |
658 | UInt32 res = IsArc_Zip_2(p, rem, isFinished); | 728 | /* 22.02 : we limit check size with kCheckSize to be consistent for |
729 | any different combination of _bufPos in Buffer and size of Buffer. */ | ||
730 | if (rem > kCheckSize) | ||
731 | rem = kCheckSize; | ||
732 | const UInt32 res = IsArc_Zip_2(p, rem, isFinished); | ||
659 | if (res != k_IsArc_Res_NO) | 733 | if (res != k_IsArc_Res_NO) |
660 | { | 734 | { |
661 | if (rem < kMarkerSize) | 735 | if (rem < kMarkerSize) |
@@ -689,7 +763,7 @@ HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) | |||
689 | { | 763 | { |
690 | progressPrev = _cnt; | 764 | progressPrev = _cnt; |
691 | // const UInt64 numFiles64 = 0; | 765 | // const UInt64 numFiles64 = 0; |
692 | RINOK(Callback->SetCompleted(NULL, &_cnt)); | 766 | RINOK(Callback->SetCompleted(NULL, &_cnt)) |
693 | } | 767 | } |
694 | } | 768 | } |
695 | 769 | ||
@@ -734,6 +808,8 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished) | |||
734 | return S_OK; | 808 | return S_OK; |
735 | } | 809 | } |
736 | 810 | ||
811 | // cache is empty | ||
812 | |||
737 | if (!IsMultiVol) | 813 | if (!IsMultiVol) |
738 | { | 814 | { |
739 | _cnt += offset; | 815 | _cnt += offset; |
@@ -767,7 +843,7 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished) | |||
767 | _cnt += offset; | 843 | _cnt += offset; |
768 | return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos); | 844 | return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos); |
769 | } | 845 | } |
770 | RINOK(Seek_SavePos(s.Size)); | 846 | RINOK(Seek_SavePos(s.Size)) |
771 | offset -= rem; | 847 | offset -= rem; |
772 | _cnt += rem; | 848 | _cnt += rem; |
773 | } | 849 | } |
@@ -787,7 +863,7 @@ HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished) | |||
787 | return S_OK; | 863 | return S_OK; |
788 | } | 864 | } |
789 | Stream = s2.Stream; | 865 | Stream = s2.Stream; |
790 | RINOK(Seek_SavePos(0)); | 866 | RINOK(Seek_SavePos(0)) |
791 | } | 867 | } |
792 | } | 868 | } |
793 | 869 | ||
@@ -847,7 +923,7 @@ HRESULT CInArchive::LookAhead(size_t minRequired) | |||
847 | if (!s.Stream) | 923 | if (!s.Stream) |
848 | return S_OK; | 924 | return S_OK; |
849 | 925 | ||
850 | RINOK(s.SeekToStart()); | 926 | RINOK(s.SeekToStart()) |
851 | 927 | ||
852 | Vols.StreamIndex++; | 928 | Vols.StreamIndex++; |
853 | _streamPos = 0; | 929 | _streamPos = 0; |
@@ -957,7 +1033,7 @@ HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles) | |||
957 | if (Callback) | 1033 | if (Callback) |
958 | { | 1034 | { |
959 | const UInt64 numFiles64 = numFiles; | 1035 | const UInt64 numFiles64 = numFiles; |
960 | RINOK(Callback->SetCompleted(&numFiles64, &_cnt)); | 1036 | RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) |
961 | } | 1037 | } |
962 | } | 1038 | } |
963 | } | 1039 | } |
@@ -1000,6 +1076,7 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo | |||
1000 | const UInt32 pair = ReadUInt32(); | 1076 | const UInt32 pair = ReadUInt32(); |
1001 | subBlock.ID = (pair & 0xFFFF); | 1077 | subBlock.ID = (pair & 0xFFFF); |
1002 | unsigned size = (unsigned)(pair >> 16); | 1078 | unsigned size = (unsigned)(pair >> 16); |
1079 | // const unsigned origSize = size; | ||
1003 | 1080 | ||
1004 | extraSize -= 4; | 1081 | extraSize -= 4; |
1005 | 1082 | ||
@@ -1068,13 +1145,15 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo | |||
1068 | } | 1145 | } |
1069 | } | 1146 | } |
1070 | 1147 | ||
1148 | // we can ignore errors, when some zip archiver still write all fields to zip64 extra in local header | ||
1149 | // if (&& (cdItem || !isOK || origSize != 8 * 3 + 4 || size != 8 * 1 + 4)) | ||
1071 | if (!isOK || size != 0) | 1150 | if (!isOK || size != 0) |
1072 | { | 1151 | { |
1073 | HeadersWarning = true; | 1152 | HeadersWarning = true; |
1074 | extra.Error = true; | 1153 | extra.Error = true; |
1075 | extra.IsZip64_Error = true; | 1154 | extra.IsZip64_Error = true; |
1076 | Skip(size); | ||
1077 | } | 1155 | } |
1156 | Skip(size); | ||
1078 | } | 1157 | } |
1079 | else | 1158 | else |
1080 | { | 1159 | { |
@@ -1092,7 +1171,7 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo | |||
1092 | { | 1171 | { |
1093 | ExtraMinorError = true; | 1172 | ExtraMinorError = true; |
1094 | extra.MinorError = true; | 1173 | extra.MinorError = true; |
1095 | // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. | 1174 | // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers. |
1096 | // so we don't return false, but just set warning flag | 1175 | // so we don't return false, but just set warning flag |
1097 | // return false; | 1176 | // return false; |
1098 | Skip(extraSize); | 1177 | Skip(extraSize); |
@@ -1184,9 +1263,10 @@ static bool FlagsAreSame(const CItem &i1, const CItem &i2_cd) | |||
1184 | mask &= 0x7FFF; | 1263 | mask &= 0x7FFF; |
1185 | } | 1264 | } |
1186 | 1265 | ||
1187 | // we can ignore utf8 flag, if name is ascii | 1266 | // we can ignore utf8 flag, if name is ascii, or if only cdItem has utf8 flag |
1188 | if (mask & NFileHeader::NFlags::kUtf8) | 1267 | if (mask & NFileHeader::NFlags::kUtf8) |
1189 | if (i1.Name.IsAscii() && i2_cd.Name.IsAscii()) | 1268 | if ((i1.Name.IsAscii() && i2_cd.Name.IsAscii()) |
1269 | || (i2_cd.Flags & NFileHeader::NFlags::kUtf8)) | ||
1190 | mask &= ~NFileHeader::NFlags::kUtf8; | 1270 | mask &= ~NFileHeader::NFlags::kUtf8; |
1191 | 1271 | ||
1192 | // some bad archive in rare case can use descriptor without descriptor flag in Central Dir | 1272 | // some bad archive in rare case can use descriptor without descriptor flag in Central Dir |
@@ -1270,11 +1350,8 @@ static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) | |||
1270 | } | 1350 | } |
1271 | 1351 | ||
1272 | 1352 | ||
1273 | HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError) | 1353 | HRESULT CInArchive::Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError) |
1274 | { | 1354 | { |
1275 | InitBuf(); | ||
1276 | _inBufMode = false; | ||
1277 | |||
1278 | isAvail = true; | 1355 | isAvail = true; |
1279 | headersError = false; | 1356 | headersError = false; |
1280 | if (item.FromLocal) | 1357 | if (item.FromLocal) |
@@ -1315,13 +1392,16 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool | |||
1315 | } | 1392 | } |
1316 | } | 1393 | } |
1317 | 1394 | ||
1318 | RINOK(Seek_SavePos(offset)); | 1395 | _inBufMode = false; |
1319 | 1396 | RINOK(Seek_SavePos(offset)) | |
1320 | /* | ||
1321 | // we can check buf mode | ||
1322 | InitBuf(); | 1397 | InitBuf(); |
1398 | /* | ||
1399 | // we can use buf mode with small buffer to reduce | ||
1400 | // the number of Read() calls in ReadLocalItem() | ||
1323 | _inBufMode = true; | 1401 | _inBufMode = true; |
1324 | Buffer.AllocAtLeast(1 << 10); | 1402 | Buffer.Alloc(1 << 10); |
1403 | if (!Buffer.IsAllocated()) | ||
1404 | return E_OUTOFMEMORY; | ||
1325 | */ | 1405 | */ |
1326 | 1406 | ||
1327 | CItemEx localItem; | 1407 | CItemEx localItem; |
@@ -1405,7 +1485,7 @@ HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles) | |||
1405 | 1485 | ||
1406 | // size_t processedSize; | 1486 | // size_t processedSize; |
1407 | CanStartNewVol = true; | 1487 | CanStartNewVol = true; |
1408 | RINOK(LookAhead(descriptorSize4)); | 1488 | RINOK(LookAhead(descriptorSize4)) |
1409 | const size_t avail = GetAvail(); | 1489 | const size_t avail = GetAvail(); |
1410 | 1490 | ||
1411 | if (avail < descriptorSize4) | 1491 | if (avail < descriptorSize4) |
@@ -1429,7 +1509,7 @@ HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles) | |||
1429 | // descriptor signature field is Info-ZIP's extension to pkware Zip specification. | 1509 | // descriptor signature field is Info-ZIP's extension to pkware Zip specification. |
1430 | // New ZIP specification also allows descriptorSignature. | 1510 | // New ZIP specification also allows descriptorSignature. |
1431 | 1511 | ||
1432 | p = FindPK(p, limit + 1); | 1512 | p = FindPK_4(p, limit + 1); |
1433 | if (p > limit) | 1513 | if (p > limit) |
1434 | break; | 1514 | break; |
1435 | 1515 | ||
@@ -1487,7 +1567,7 @@ HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles) | |||
1487 | { | 1567 | { |
1488 | progressPrev = _cnt; | 1568 | progressPrev = _cnt; |
1489 | const UInt64 numFiles64 = numFiles; | 1569 | const UInt64 numFiles64 = numFiles; |
1490 | RINOK(Callback->SetCompleted(&numFiles64, &_cnt)); | 1570 | RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) |
1491 | } | 1571 | } |
1492 | } | 1572 | } |
1493 | } | 1573 | } |
@@ -1501,7 +1581,7 @@ HRESULT CInArchive::CheckDescriptor(const CItemEx &item) | |||
1501 | // pkzip's version without descriptor signature is not supported | 1581 | // pkzip's version without descriptor signature is not supported |
1502 | 1582 | ||
1503 | bool isFinished = false; | 1583 | bool isFinished = false; |
1504 | RINOK(IncreaseRealPosition(item.PackSize, isFinished)); | 1584 | RINOK(IncreaseRealPosition(item.PackSize, isFinished)) |
1505 | if (isFinished) | 1585 | if (isFinished) |
1506 | return S_FALSE; | 1586 | return S_FALSE; |
1507 | 1587 | ||
@@ -1548,7 +1628,7 @@ HRESULT CInArchive::CheckDescriptor(const CItemEx &item) | |||
1548 | } | 1628 | } |
1549 | 1629 | ||
1550 | 1630 | ||
1551 | HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) | 1631 | HRESULT CInArchive::Read_LocalItem_After_CdItem_Full(CItemEx &item) |
1552 | { | 1632 | { |
1553 | if (item.FromLocal) | 1633 | if (item.FromLocal) |
1554 | return S_OK; | 1634 | return S_OK; |
@@ -1556,7 +1636,7 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) | |||
1556 | { | 1636 | { |
1557 | bool isAvail = true; | 1637 | bool isAvail = true; |
1558 | bool headersError = false; | 1638 | bool headersError = false; |
1559 | RINOK(ReadLocalItemAfterCdItem(item, isAvail, headersError)); | 1639 | RINOK(Read_LocalItem_After_CdItem(item, isAvail, headersError)) |
1560 | if (headersError) | 1640 | if (headersError) |
1561 | return S_FALSE; | 1641 | return S_FALSE; |
1562 | if (item.HasDescriptor()) | 1642 | if (item.HasDescriptor()) |
@@ -1606,14 +1686,22 @@ HRESULT CInArchive::ReadCdItem(CItemEx &item) | |||
1606 | } | 1686 | } |
1607 | 1687 | ||
1608 | 1688 | ||
1689 | /* | ||
1690 | TryEcd64() | ||
1691 | (_inBufMode == false) is expected here | ||
1692 | so TryEcd64() can't change the Buffer. | ||
1693 | if (Ecd64 is not covered by cached region), | ||
1694 | TryEcd64() can change cached region ranges (_bufCached, _bufPos) and _streamPos. | ||
1695 | */ | ||
1696 | |||
1609 | HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) | 1697 | HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) |
1610 | { | 1698 | { |
1611 | if (offset >= ((UInt64)1 << 63)) | 1699 | if (offset >= ((UInt64)1 << 63)) |
1612 | return S_FALSE; | 1700 | return S_FALSE; |
1613 | Byte buf[kEcd64_FullSize]; | 1701 | Byte buf[kEcd64_FullSize]; |
1614 | 1702 | ||
1615 | RINOK(SeekToVol(Vols.StreamIndex, offset)); | 1703 | RINOK(SeekToVol(Vols.StreamIndex, offset)) |
1616 | RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize)); | 1704 | RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize)) |
1617 | 1705 | ||
1618 | if (Get32(buf) != NSignature::kEcd64) | 1706 | if (Get32(buf) != NSignature::kEcd64) |
1619 | return S_FALSE; | 1707 | return S_FALSE; |
@@ -1625,6 +1713,9 @@ HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) | |||
1625 | } | 1713 | } |
1626 | 1714 | ||
1627 | 1715 | ||
1716 | /* FindCd() doesn't use previous cached region, | ||
1717 | but it uses Buffer. So it sets new cached region */ | ||
1718 | |||
1628 | HRESULT CInArchive::FindCd(bool checkOffsetMode) | 1719 | HRESULT CInArchive::FindCd(bool checkOffsetMode) |
1629 | { | 1720 | { |
1630 | CCdInfo &cdInfo = Vols.ecd; | 1721 | CCdInfo &cdInfo = Vols.ecd; |
@@ -1635,7 +1726,7 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode) | |||
1635 | // So here we don't use cache data from previous operations . | 1726 | // So here we don't use cache data from previous operations . |
1636 | 1727 | ||
1637 | InitBuf(); | 1728 | InitBuf(); |
1638 | RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPos)); | 1729 | RINOK(InStream_GetSize_SeekToEnd(Stream, endPos)) |
1639 | _streamPos = endPos; | 1730 | _streamPos = endPos; |
1640 | 1731 | ||
1641 | // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; | 1732 | // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; |
@@ -1646,15 +1737,9 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode) | |||
1646 | return S_FALSE; | 1737 | return S_FALSE; |
1647 | // CByteArr byteBuffer(bufSize); | 1738 | // CByteArr byteBuffer(bufSize); |
1648 | 1739 | ||
1649 | if (Buffer.Size() < kBufSizeMax) | 1740 | RINOK(AllocateBuffer(kBufSizeMax)) |
1650 | { | ||
1651 | // InitBuf(); | ||
1652 | Buffer.AllocAtLeast(kBufSizeMax); | ||
1653 | if (!Buffer.IsAllocated()) | ||
1654 | return E_OUTOFMEMORY; | ||
1655 | } | ||
1656 | 1741 | ||
1657 | RINOK(Seek_SavePos(endPos - bufSize)); | 1742 | RINOK(Seek_SavePos(endPos - bufSize)) |
1658 | 1743 | ||
1659 | size_t processed = bufSize; | 1744 | size_t processed = bufSize; |
1660 | HRESULT res = ReadStream(Stream, Buffer, &processed); | 1745 | HRESULT res = ReadStream(Stream, Buffer, &processed); |
@@ -1799,14 +1884,14 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn | |||
1799 | // _startLocalFromCd_Disk = (UInt32)(Int32)-1; | 1884 | // _startLocalFromCd_Disk = (UInt32)(Int32)-1; |
1800 | // _startLocalFromCd_Offset = (UInt64)(Int64)-1; | 1885 | // _startLocalFromCd_Offset = (UInt64)(Int64)-1; |
1801 | 1886 | ||
1802 | RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset)); | 1887 | RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset)) |
1803 | 1888 | ||
1804 | _inBufMode = true; | 1889 | _inBufMode = true; |
1805 | _cnt = 0; | 1890 | _cnt = 0; |
1806 | 1891 | ||
1807 | if (Callback) | 1892 | if (Callback) |
1808 | { | 1893 | { |
1809 | RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL)); | 1894 | RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL)) |
1810 | } | 1895 | } |
1811 | UInt64 numFileExpected = cdInfo.NumEntries; | 1896 | UInt64 numFileExpected = cdInfo.NumEntries; |
1812 | const UInt64 *totalFilesPtr = &numFileExpected; | 1897 | const UInt64 *totalFilesPtr = &numFileExpected; |
@@ -1820,7 +1905,7 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn | |||
1820 | CanStartNewVol = false; | 1905 | CanStartNewVol = false; |
1821 | { | 1906 | { |
1822 | CItemEx cdItem; | 1907 | CItemEx cdItem; |
1823 | RINOK(ReadCdItem(cdItem)); | 1908 | RINOK(ReadCdItem(cdItem)) |
1824 | 1909 | ||
1825 | /* | 1910 | /* |
1826 | if (cdItem.Disk < _startLocalFromCd_Disk || | 1911 | if (cdItem.Disk < _startLocalFromCd_Disk || |
@@ -1854,10 +1939,10 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn | |||
1854 | else | 1939 | else |
1855 | while (numFiles > numFileExpected) | 1940 | while (numFiles > numFileExpected) |
1856 | numFileExpected += (UInt32)1 << 16; | 1941 | numFileExpected += (UInt32)1 << 16; |
1857 | RINOK(Callback->SetTotal(totalFilesPtr, NULL)); | 1942 | RINOK(Callback->SetTotal(totalFilesPtr, NULL)) |
1858 | } | 1943 | } |
1859 | 1944 | ||
1860 | RINOK(Callback->SetCompleted(&numFiles, &_cnt)); | 1945 | RINOK(Callback->SetCompleted(&numFiles, &_cnt)) |
1861 | } | 1946 | } |
1862 | } | 1947 | } |
1863 | 1948 | ||
@@ -1900,7 +1985,7 @@ HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 | |||
1900 | 1985 | ||
1901 | if (!Vols.ecd_wasRead) | 1986 | if (!Vols.ecd_wasRead) |
1902 | { | 1987 | { |
1903 | RINOK(FindCd(checkOffsetMode)); | 1988 | RINOK(FindCd(checkOffsetMode)) |
1904 | } | 1989 | } |
1905 | 1990 | ||
1906 | CCdInfo &cdInfo = Vols.ecd; | 1991 | CCdInfo &cdInfo = Vols.ecd; |
@@ -2004,7 +2089,7 @@ HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items) | |||
2004 | 2089 | ||
2005 | if (Callback) | 2090 | if (Callback) |
2006 | { | 2091 | { |
2007 | RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL)); | 2092 | RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL)) |
2008 | } | 2093 | } |
2009 | 2094 | ||
2010 | while (_signature == NSignature::kLocalFileHeader) | 2095 | while (_signature == NSignature::kLocalFileHeader) |
@@ -2023,14 +2108,14 @@ HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items) | |||
2023 | 2108 | ||
2024 | if (item.HasDescriptor()) | 2109 | if (item.HasDescriptor()) |
2025 | { | 2110 | { |
2026 | RINOK(FindDescriptor(item, items.Size())); | 2111 | RINOK(FindDescriptor(item, items.Size())) |
2027 | isFinished = !item.DescriptorWasRead; | 2112 | isFinished = !item.DescriptorWasRead; |
2028 | } | 2113 | } |
2029 | else | 2114 | else |
2030 | { | 2115 | { |
2031 | if (item.PackSize >= ((UInt64)1 << 62)) | 2116 | if (item.PackSize >= ((UInt64)1 << 62)) |
2032 | throw CUnexpectEnd(); | 2117 | throw CUnexpectEnd(); |
2033 | RINOK(IncreaseRealPosition(item.PackSize, isFinished)); | 2118 | RINOK(IncreaseRealPosition(item.PackSize, isFinished)) |
2034 | } | 2119 | } |
2035 | 2120 | ||
2036 | items.Add(item); | 2121 | items.Add(item); |
@@ -2054,7 +2139,7 @@ HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items) | |||
2054 | { | 2139 | { |
2055 | progressPrev = _cnt; | 2140 | progressPrev = _cnt; |
2056 | const UInt64 numFiles = items.Size(); | 2141 | const UInt64 numFiles = items.Size(); |
2057 | RINOK(Callback->SetCompleted(&numFiles, &_cnt)); | 2142 | RINOK(Callback->SetCompleted(&numFiles, &_cnt)) |
2058 | } | 2143 | } |
2059 | } | 2144 | } |
2060 | 2145 | ||
@@ -2072,7 +2157,7 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) | |||
2072 | UString name; | 2157 | UString name; |
2073 | { | 2158 | { |
2074 | NWindows::NCOM::CPropVariant prop; | 2159 | NWindows::NCOM::CPropVariant prop; |
2075 | RINOK(volCallback->GetProperty(kpidName, &prop)); | 2160 | RINOK(volCallback->GetProperty(kpidName, &prop)) |
2076 | if (prop.vt != VT_BSTR) | 2161 | if (prop.vt != VT_BSTR) |
2077 | return S_OK; | 2162 | return S_OK; |
2078 | name = prop.bstrVal; | 2163 | name = prop.bstrVal; |
@@ -2235,11 +2320,8 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, | |||
2235 | } | 2320 | } |
2236 | } | 2321 | } |
2237 | 2322 | ||
2238 | UInt64 size; | 2323 | UInt64 pos, size; |
2239 | UInt64 pos; | 2324 | RINOK(InStream_GetPos_GetSize(stream, pos, size)) |
2240 | RINOK(stream->Seek(0, STREAM_SEEK_CUR, &pos)); | ||
2241 | RINOK(stream->Seek(0, STREAM_SEEK_END, &size)); | ||
2242 | RINOK(stream->Seek((Int64)pos, STREAM_SEEK_SET, NULL)); | ||
2243 | 2325 | ||
2244 | while (i >= Vols.Streams.Size()) | 2326 | while (i >= Vols.Streams.Size()) |
2245 | Vols.Streams.AddNew(); | 2327 | Vols.Streams.AddNew(); |
@@ -2270,7 +2352,7 @@ HRESULT CInArchive::ReadVols() | |||
2270 | if (!volCallback) | 2352 | if (!volCallback) |
2271 | return S_OK; | 2353 | return S_OK; |
2272 | 2354 | ||
2273 | RINOK(Vols.ParseArcName(volCallback)); | 2355 | RINOK(Vols.ParseArcName(volCallback)) |
2274 | 2356 | ||
2275 | // const int startZIndex = Vols.StartVolIndex; | 2357 | // const int startZIndex = Vols.StartVolIndex; |
2276 | 2358 | ||
@@ -2324,7 +2406,7 @@ HRESULT CInArchive::ReadVols() | |||
2324 | if (cdDisk != zipDisk) | 2406 | if (cdDisk != zipDisk) |
2325 | { | 2407 | { |
2326 | // get volumes required for cd. | 2408 | // get volumes required for cd. |
2327 | RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols)); | 2409 | RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols)) |
2328 | if (numMissingVols != 0) | 2410 | if (numMissingVols != 0) |
2329 | { | 2411 | { |
2330 | // cdOK = false; | 2412 | // cdOK = false; |
@@ -2352,7 +2434,7 @@ HRESULT CInArchive::ReadVols() | |||
2352 | { | 2434 | { |
2353 | // get volumes that were no requested still | 2435 | // get volumes that were no requested still |
2354 | const unsigned kNumMissingVolsMax = 1 << 12; | 2436 | const unsigned kNumMissingVolsMax = 1 << 12; |
2355 | RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols)); | 2437 | RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols)) |
2356 | } | 2438 | } |
2357 | 2439 | ||
2358 | // if (Vols.StartVolIndex >= 0) | 2440 | // if (Vols.StartVolIndex >= 0) |
@@ -2364,7 +2446,7 @@ HRESULT CInArchive::ReadVols() | |||
2364 | || !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream) | 2446 | || !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream) |
2365 | { | 2447 | { |
2366 | // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok) | 2448 | // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok) |
2367 | RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols)); | 2449 | RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols)) |
2368 | } | 2450 | } |
2369 | } | 2451 | } |
2370 | 2452 | ||
@@ -2377,7 +2459,7 @@ HRESULT CInArchive::ReadVols() | |||
2377 | if (zipDisk >= 0) | 2459 | if (zipDisk >= 0) |
2378 | { | 2460 | { |
2379 | // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok) | 2461 | // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok) |
2380 | RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols)); | 2462 | RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols)) |
2381 | } | 2463 | } |
2382 | } | 2464 | } |
2383 | 2465 | ||
@@ -2428,7 +2510,7 @@ HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) | |||
2428 | return S_FALSE; | 2510 | return S_FALSE; |
2429 | if (NeedSeek) | 2511 | if (NeedSeek) |
2430 | { | 2512 | { |
2431 | RINOK(s.SeekToStart()); | 2513 | RINOK(s.SeekToStart()) |
2432 | NeedSeek = false; | 2514 | NeedSeek = false; |
2433 | } | 2515 | } |
2434 | UInt32 realProcessedSize = 0; | 2516 | UInt32 realProcessedSize = 0; |
@@ -2444,7 +2526,7 @@ HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) | |||
2444 | } | 2526 | } |
2445 | } | 2527 | } |
2446 | 2528 | ||
2447 | STDMETHODIMP CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize) | 2529 | Z7_COM7F_IMF(CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize)) |
2448 | { | 2530 | { |
2449 | return Vols->Read(data, size, processedSize); | 2531 | return Vols->Read(data, size, processedSize); |
2450 | } | 2532 | } |
@@ -2458,14 +2540,10 @@ STDMETHODIMP CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize) | |||
2458 | 2540 | ||
2459 | HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | 2541 | HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) |
2460 | { | 2542 | { |
2461 | if (Buffer.Size() < kSeqBufferSize) | 2543 | // buffer that can be used for cd reading |
2462 | { | 2544 | RINOK(AllocateBuffer(kSeqBufferSize)) |
2463 | InitBuf(); | ||
2464 | Buffer.AllocAtLeast(kSeqBufferSize); | ||
2465 | if (!Buffer.IsAllocated()) | ||
2466 | return E_OUTOFMEMORY; | ||
2467 | } | ||
2468 | 2545 | ||
2546 | // here we can read small records. So we switch off _inBufMode. | ||
2469 | _inBufMode = false; | 2547 | _inBufMode = false; |
2470 | 2548 | ||
2471 | HRESULT res = S_OK; | 2549 | HRESULT res = S_OK; |
@@ -2488,6 +2566,13 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2488 | 2566 | ||
2489 | UInt64 cdAbsOffset = 0; // absolute cd offset, for LOCALS-CD-MODE only. | 2567 | UInt64 cdAbsOffset = 0; // absolute cd offset, for LOCALS-CD-MODE only. |
2490 | 2568 | ||
2569 | if (Force_ReadLocals_Mode) | ||
2570 | { | ||
2571 | IsArc = true; | ||
2572 | res = S_FALSE; // we will use LOCALS-CD-MODE mode | ||
2573 | } | ||
2574 | else | ||
2575 | { | ||
2491 | if (!MarkerIsFound || !MarkerIsSafe) | 2576 | if (!MarkerIsFound || !MarkerIsSafe) |
2492 | { | 2577 | { |
2493 | IsArc = true; | 2578 | IsArc = true; |
@@ -2497,7 +2582,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2497 | else if (res != S_FALSE) | 2582 | else if (res != S_FALSE) |
2498 | return res; | 2583 | return res; |
2499 | } | 2584 | } |
2500 | else | 2585 | else // (MarkerIsFound && MarkerIsSafe) |
2501 | { | 2586 | { |
2502 | 2587 | ||
2503 | // _signature must be kLocalFileHeader or kEcd or kEcd64 | 2588 | // _signature must be kLocalFileHeader or kEcd or kEcd64 |
@@ -2528,7 +2613,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2528 | return S_FALSE; | 2613 | return S_FALSE; |
2529 | } | 2614 | } |
2530 | 2615 | ||
2531 | RINOK(Skip64(recordSize - kEcd64_MainSize, 0)); | 2616 | RINOK(Skip64(recordSize - kEcd64_MainSize, 0)) |
2532 | } | 2617 | } |
2533 | 2618 | ||
2534 | ReadSignature(); | 2619 | ReadSignature(); |
@@ -2568,7 +2653,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2568 | ArcInfo.Base = (Int64)ArcInfo.MarkerPos; | 2653 | ArcInfo.Base = (Int64)ArcInfo.MarkerPos; |
2569 | IsArc = true; // check it: we need more tests? | 2654 | IsArc = true; // check it: we need more tests? |
2570 | 2655 | ||
2571 | RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)); | 2656 | RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)) |
2572 | ReadSignature(); | 2657 | ReadSignature(); |
2573 | } | 2658 | } |
2574 | else | 2659 | else |
@@ -2650,8 +2735,9 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2650 | } | 2735 | } |
2651 | } | 2736 | } |
2652 | } | 2737 | } |
2653 | } | 2738 | } // (MarkerIsFound && MarkerIsSafe) |
2654 | 2739 | ||
2740 | } // (!onlyLocalsMode) | ||
2655 | 2741 | ||
2656 | 2742 | ||
2657 | CObjectVector<CItemEx> cdItems; | 2743 | CObjectVector<CItemEx> cdItems; |
@@ -2676,17 +2762,20 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2676 | HeadersWarning = false; | 2762 | HeadersWarning = false; |
2677 | ExtraMinorError = false; | 2763 | ExtraMinorError = false; |
2678 | 2764 | ||
2679 | // we can use any mode: with buffer and without buffer | 2765 | /* we can use any mode: with buffer and without buffer |
2680 | // without buffer : skips packed data : fast for big files : slow for small files | 2766 | without buffer : skips packed data : fast for big files : slow for small files |
2681 | // with buffer : reads packed data : slow for big files : fast for small files | 2767 | with buffer : reads packed data : slow for big files : fast for small files |
2682 | 2768 | Buffer mode is more effective. */ | |
2683 | _inBufMode = false; | 2769 | // _inBufMode = false; |
2684 | // _inBufMode = true; | 2770 | _inBufMode = true; |
2685 | 2771 | // we could change the buffer size here, if we want smaller Buffer. | |
2686 | InitBuf(); | 2772 | // RINOK(ReAllocateBuffer(kSeqBufferSize)); |
2773 | // InitBuf() | ||
2687 | 2774 | ||
2688 | ArcInfo.Base = 0; | 2775 | ArcInfo.Base = 0; |
2689 | 2776 | ||
2777 | if (!Disable_FindMarker) | ||
2778 | { | ||
2690 | if (!MarkerIsFound) | 2779 | if (!MarkerIsFound) |
2691 | { | 2780 | { |
2692 | if (!IsMultiVol) | 2781 | if (!IsMultiVol) |
@@ -2695,7 +2784,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2695 | return S_FALSE; | 2784 | return S_FALSE; |
2696 | // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker. | 2785 | // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker. |
2697 | // so we suppose that there is no sfx stub | 2786 | // so we suppose that there is no sfx stub |
2698 | RINOK(SeekToVol(0, ArcInfo.MarkerPos2)); | 2787 | RINOK(SeekToVol(0, ArcInfo.MarkerPos2)) |
2699 | } | 2788 | } |
2700 | else | 2789 | else |
2701 | { | 2790 | { |
@@ -2710,17 +2799,16 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2710 | */ | 2799 | */ |
2711 | ArcInfo.Base = (Int64)ArcInfo.MarkerPos2; | 2800 | ArcInfo.Base = (Int64)ArcInfo.MarkerPos2; |
2712 | } | 2801 | } |
2713 | 2802 | RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)) | |
2714 | RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)); | ||
2715 | } | 2803 | } |
2716 | 2804 | } | |
2717 | _cnt = 0; | 2805 | _cnt = 0; |
2718 | 2806 | ||
2719 | ReadSignature(); | 2807 | ReadSignature(); |
2720 | 2808 | ||
2721 | LocalsWereRead = true; | 2809 | LocalsWereRead = true; |
2722 | 2810 | ||
2723 | RINOK(ReadLocals(items)); | 2811 | RINOK(ReadLocals(items)) |
2724 | 2812 | ||
2725 | if (_signature != NSignature::kCentralFileHeader) | 2813 | if (_signature != NSignature::kCentralFileHeader) |
2726 | { | 2814 | { |
@@ -2775,14 +2863,14 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2775 | { | 2863 | { |
2776 | CItemEx cdItem; | 2864 | CItemEx cdItem; |
2777 | 2865 | ||
2778 | RINOK(ReadCdItem(cdItem)); | 2866 | RINOK(ReadCdItem(cdItem)) |
2779 | 2867 | ||
2780 | cdItems.Add(cdItem); | 2868 | cdItems.Add(cdItem); |
2781 | if (Callback && (cdItems.Size() & 0xFFF) == 0) | 2869 | if (Callback && (cdItems.Size() & 0xFFF) == 0) |
2782 | { | 2870 | { |
2783 | const UInt64 numFiles = items.Size(); | 2871 | const UInt64 numFiles = items.Size(); |
2784 | const UInt64 numBytes = _cnt; | 2872 | const UInt64 numBytes = _cnt; |
2785 | RINOK(Callback->SetCompleted(&numFiles, &numBytes)); | 2873 | RINOK(Callback->SetCompleted(&numFiles, &numBytes)) |
2786 | } | 2874 | } |
2787 | ReadSignature(); | 2875 | ReadSignature(); |
2788 | if (_signature != NSignature::kCentralFileHeader) | 2876 | if (_signature != NSignature::kCentralFileHeader) |
@@ -2842,7 +2930,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2842 | cdInfo.ParseEcd64e(buf); | 2930 | cdInfo.ParseEcd64e(buf); |
2843 | } | 2931 | } |
2844 | 2932 | ||
2845 | RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size())); | 2933 | RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size())) |
2846 | } | 2934 | } |
2847 | 2935 | ||
2848 | 2936 | ||
@@ -2886,12 +2974,12 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
2886 | ecd.Parse(buf); | 2974 | ecd.Parse(buf); |
2887 | } | 2975 | } |
2888 | 2976 | ||
2889 | COPY_ECD_ITEM_16(ThisDisk); | 2977 | COPY_ECD_ITEM_16(ThisDisk) |
2890 | COPY_ECD_ITEM_16(CdDisk); | 2978 | COPY_ECD_ITEM_16(CdDisk) |
2891 | COPY_ECD_ITEM_16(NumEntries_in_ThisDisk); | 2979 | COPY_ECD_ITEM_16(NumEntries_in_ThisDisk) |
2892 | COPY_ECD_ITEM_16(NumEntries); | 2980 | COPY_ECD_ITEM_16(NumEntries) |
2893 | COPY_ECD_ITEM_32(Size); | 2981 | COPY_ECD_ITEM_32(Size) |
2894 | COPY_ECD_ITEM_32(Offset); | 2982 | COPY_ECD_ITEM_32(Offset) |
2895 | 2983 | ||
2896 | bool cdOK = true; | 2984 | bool cdOK = true; |
2897 | 2985 | ||
@@ -3040,7 +3128,7 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
3040 | if ((i & 0x3FFF) == 0) | 3128 | if ((i & 0x3FFF) == 0) |
3041 | { | 3129 | { |
3042 | const UInt64 numFiles64 = items.Size() + items2.Size(); | 3130 | const UInt64 numFiles64 = items.Size() + items2.Size(); |
3043 | RINOK(Callback->SetCompleted(&numFiles64, &_cnt)); | 3131 | RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) |
3044 | } | 3132 | } |
3045 | 3133 | ||
3046 | const CItemEx &cdItem = cdItems[i]; | 3134 | const CItemEx &cdItem = cdItems[i]; |
@@ -3093,6 +3181,9 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) | |||
3093 | item.ExternalAttrib = cdItem.ExternalAttrib; | 3181 | item.ExternalAttrib = cdItem.ExternalAttrib; |
3094 | item.Comment = cdItem.Comment; | 3182 | item.Comment = cdItem.Comment; |
3095 | item.FromCentral = cdItem.FromCentral; | 3183 | item.FromCentral = cdItem.FromCentral; |
3184 | // 22.02: we force utf8 flag, if central header has utf8 flag | ||
3185 | if (cdItem.Flags & NFileHeader::NFlags::kUtf8) | ||
3186 | item.Flags |= NFileHeader::NFlags::kUtf8; | ||
3096 | } | 3187 | } |
3097 | 3188 | ||
3098 | FOR_VECTOR (k, items2) | 3189 | FOR_VECTOR (k, items2) |
@@ -3175,8 +3266,8 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3175 | Close(); | 3266 | Close(); |
3176 | 3267 | ||
3177 | UInt64 startPos; | 3268 | UInt64 startPos; |
3178 | RINOK(stream->Seek(0, STREAM_SEEK_CUR, &startPos)); | 3269 | RINOK(InStream_GetPos(stream, startPos)) |
3179 | RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos)); | 3270 | RINOK(InStream_GetSize_SeekToEnd(stream, ArcInfo.FileEndPos)) |
3180 | _streamPos = ArcInfo.FileEndPos; | 3271 | _streamPos = ArcInfo.FileEndPos; |
3181 | 3272 | ||
3182 | StartStream = stream; | 3273 | StartStream = stream; |
@@ -3187,18 +3278,30 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3187 | 3278 | ||
3188 | bool volWasRequested = false; | 3279 | bool volWasRequested = false; |
3189 | 3280 | ||
3281 | if (!Disable_VolsRead) | ||
3190 | if (callback | 3282 | if (callback |
3191 | && (startPos == 0 || !searchLimit || *searchLimit != 0)) | 3283 | && (startPos == 0 || !searchLimit || *searchLimit != 0)) |
3192 | { | 3284 | { |
3193 | // we try to read volumes only if it's first call (offset == 0) or scan is allowed. | 3285 | // we try to read volumes only if it's first call (offset == 0) or scan is allowed. |
3194 | volWasRequested = true; | 3286 | volWasRequested = true; |
3195 | RINOK(ReadVols()); | 3287 | RINOK(ReadVols()) |
3196 | } | 3288 | } |
3197 | 3289 | ||
3290 | if (Disable_FindMarker) | ||
3291 | { | ||
3292 | RINOK(SeekToVol(-1, startPos)) | ||
3293 | StreamRef = stream; | ||
3294 | Stream = stream; | ||
3295 | MarkerIsFound = true; | ||
3296 | MarkerIsSafe = true; | ||
3297 | ArcInfo.MarkerPos = startPos; | ||
3298 | ArcInfo.MarkerPos2 = startPos; | ||
3299 | } | ||
3300 | else | ||
3198 | if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()) | 3301 | if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()) |
3199 | { | 3302 | { |
3200 | // only StartParsingVol = 0 is safe search. | 3303 | // only StartParsingVol = 0 is safe search. |
3201 | RINOK(SeekToVol(0, 0)); | 3304 | RINOK(SeekToVol(0, 0)) |
3202 | // if (Stream) | 3305 | // if (Stream) |
3203 | { | 3306 | { |
3204 | // UInt64 limit = 1 << 22; // for sfx | 3307 | // UInt64 limit = 1 << 22; // for sfx |
@@ -3222,11 +3325,11 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3222 | && (unsigned)Vols.StartParsingVol < Vols.Streams.Size() | 3325 | && (unsigned)Vols.StartParsingVol < Vols.Streams.Size() |
3223 | && Vols.Streams[(unsigned)Vols.StartParsingVol].Stream) | 3326 | && Vols.Streams[(unsigned)Vols.StartParsingVol].Stream) |
3224 | { | 3327 | { |
3225 | RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0)); | 3328 | RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0)) |
3226 | } | 3329 | } |
3227 | else | 3330 | else |
3228 | { | 3331 | { |
3229 | RINOK(SeekToVol(-1, startPos)); | 3332 | RINOK(SeekToVol(-1, startPos)) |
3230 | } | 3333 | } |
3231 | 3334 | ||
3232 | // UInt64 limit = 1 << 22; | 3335 | // UInt64 limit = 1 << 22; |
@@ -3242,8 +3345,8 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3242 | else if (!IsMultiVol) | 3345 | else if (!IsMultiVol) |
3243 | { | 3346 | { |
3244 | /* | 3347 | /* |
3245 | // if (startPos != 0), probably CD copuld be already tested with another call with (startPos == 0). | 3348 | // if (startPos != 0), probably CD could be already tested with another call with (startPos == 0). |
3246 | // so we don't want to try to open CD again in that ase. | 3349 | // so we don't want to try to open CD again in that case. |
3247 | if (startPos != 0) | 3350 | if (startPos != 0) |
3248 | return res; | 3351 | return res; |
3249 | // we can try to open CD, if there is no Marker and (startPos == 0). | 3352 | // we can try to open CD, if there is no Marker and (startPos == 0). |
@@ -3254,7 +3357,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3254 | 3357 | ||
3255 | if (ArcInfo.IsSpanMode && !volWasRequested) | 3358 | if (ArcInfo.IsSpanMode && !volWasRequested) |
3256 | { | 3359 | { |
3257 | RINOK(ReadVols()); | 3360 | RINOK(ReadVols()) |
3258 | if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0) | 3361 | if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0) |
3259 | ArcInfo.MarkerVolIndex = Vols.StartVolIndex; | 3362 | ArcInfo.MarkerVolIndex = Vols.StartVolIndex; |
3260 | } | 3363 | } |
@@ -3271,7 +3374,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3271 | Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream; | 3374 | Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream; |
3272 | if (Stream) | 3375 | if (Stream) |
3273 | { | 3376 | { |
3274 | RINOK(Seek_SavePos(curPos)); | 3377 | RINOK(Seek_SavePos(curPos)) |
3275 | } | 3378 | } |
3276 | else | 3379 | else |
3277 | IsMultiVol = false; | 3380 | IsMultiVol = false; |
@@ -3287,7 +3390,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, | |||
3287 | Stream = StartStream; | 3390 | Stream = StartStream; |
3288 | Vols.StreamIndex = -1; | 3391 | Vols.StreamIndex = -1; |
3289 | InitBuf(); | 3392 | InitBuf(); |
3290 | RINOK(Seek_SavePos(curPos)); | 3393 | RINOK(Seek_SavePos(curPos)) |
3291 | } | 3394 | } |
3292 | 3395 | ||
3293 | ArcInfo.MarkerVolIndex = -1; | 3396 | ArcInfo.MarkerVolIndex = -1; |
@@ -3356,7 +3459,7 @@ HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyCom | |||
3356 | if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex) | 3459 | if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex) |
3357 | return S_OK; | 3460 | return S_OK; |
3358 | pos = (UInt64)((Int64)pos + ArcInfo.Base); | 3461 | pos = (UInt64)((Int64)pos + ArcInfo.Base); |
3359 | RINOK(StreamRef->Seek((Int64)pos, STREAM_SEEK_SET, NULL)); | 3462 | RINOK(InStream_SeekSet(StreamRef, pos)) |
3360 | stream = StreamRef; | 3463 | stream = StreamRef; |
3361 | return S_OK; | 3464 | return S_OK; |
3362 | } | 3465 | } |
@@ -3367,7 +3470,7 @@ HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyCom | |||
3367 | IInStream *str2 = Vols.Streams[item.Disk].Stream; | 3470 | IInStream *str2 = Vols.Streams[item.Disk].Stream; |
3368 | if (!str2) | 3471 | if (!str2) |
3369 | return S_OK; | 3472 | return S_OK; |
3370 | RINOK(str2->Seek((Int64)pos, STREAM_SEEK_SET, NULL)); | 3473 | RINOK(InStream_SeekSet(str2, pos)) |
3371 | 3474 | ||
3372 | Vols.NeedSeek = false; | 3475 | Vols.NeedSeek = false; |
3373 | Vols.StreamIndex = (int)item.Disk; | 3476 | Vols.StreamIndex = (int)item.Disk; |