aboutsummaryrefslogtreecommitdiff
path: root/CPP/7zip/Archive/Zip/ZipIn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipIn.cpp')
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp373
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 @@
28namespace NArchive { 26namespace NArchive {
29namespace NZip { 27namespace 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
32static const size_t kSeqBufferSize = (size_t)1 << 17;
32 33
33static const size_t kSeqBufferSize = (size_t)1 << 14; 34/*
35Open()
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}
59FindCd() 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
190HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) 221HRESULT 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
260HRESULT 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
511MY_NO_INLINE 558/* FindPK_4() is allowed to access data up to and including &limit[3].
512static 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*/
564Z7_NO_INLINE
565static 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
1273HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError) 1353HRESULT 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
1551HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) 1631HRESULT 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/*
1690TryEcd64()
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
1609HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) 1697HRESULT 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
1628HRESULT CInArchive::FindCd(bool checkOffsetMode) 1719HRESULT 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
2447STDMETHODIMP CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize) 2529Z7_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
2459HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) 2541HRESULT 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
2569if (Force_ReadLocals_Mode)
2570{
2571 IsArc = true;
2572 res = S_FALSE; // we will use LOCALS-CD-MODE mode
2573}
2574else
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;