aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2026-09-04 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2026-09-04 12:17:40 +0500
commit0766b733fe3e06dd2a7f9a3cfbf2108ac73abd17 (patch)
tree3a8ca8ef8e855c41476499484ae3f3596e842ac2
parentf9d78aff31a5f2521ae7ddbdc97c4a8855808959 (diff)
download7zip-26.03.tar.gz
7zip-26.03.tar.bz2
7zip-26.03.zip
-rw-r--r--.gitattributes2
-rw-r--r--C/7zDec.c73
-rw-r--r--C/7zTypes.h1
-rw-r--r--C/7zVersion.h6
-rw-r--r--C/Bcj2Enc.c7
-rw-r--r--C/BwtSort.c6
-rw-r--r--C/Compiler.h30
-rw-r--r--C/CpuArch.h11
-rw-r--r--C/Lzma2Enc.c22
-rw-r--r--C/LzmaDec.c18
-rw-r--r--C/LzmaEnc.c13
-rw-r--r--C/Ppmd7Enc.c7
-rw-r--r--C/Ppmd8.c4
-rw-r--r--C/Util/7z/7zMain.c2
-rw-r--r--CPP/7zip/Archive/7z/7zEncode.cpp29
-rw-r--r--CPP/7zip/Archive/7z/7zHandler.cpp7
-rw-r--r--CPP/7zip/Archive/ApfsHandler.cpp2
-rw-r--r--CPP/7zip/Archive/ApmHandler.cpp5
-rw-r--r--CPP/7zip/Archive/ArHandler.cpp2
-rw-r--r--CPP/7zip/Archive/ArjHandler.cpp5
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.cpp50
-rw-r--r--CPP/7zip/Archive/Cab/CabIn.cpp83
-rw-r--r--CPP/7zip/Archive/Cab/CabIn.h29
-rw-r--r--CPP/7zip/Archive/Cab/CabItem.h35
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp21
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.cpp2
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp4
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp5
-rw-r--r--CPP/7zip/Archive/GzHandler.cpp2
-rw-r--r--CPP/7zip/Archive/HfsHandler.cpp5
-rw-r--r--CPP/7zip/Archive/Iso/IsoHandler.cpp6
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.cpp127
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.h24
-rw-r--r--CPP/7zip/Archive/Iso/IsoItem.h8
-rw-r--r--CPP/7zip/Archive/LzmaHandler.cpp10
-rw-r--r--CPP/7zip/Archive/Nsis/NsisHandler.cpp12
-rw-r--r--CPP/7zip/Archive/Nsis/NsisIn.cpp149
-rw-r--r--CPP/7zip/Archive/Nsis/NsisIn.h12
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp8
-rw-r--r--CPP/7zip/Archive/PeHandler.cpp8
-rw-r--r--CPP/7zip/Archive/PpmdHandler.cpp80
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp6
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp63
-rw-r--r--CPP/7zip/Archive/SquashfsHandler.cpp19
-rw-r--r--CPP/7zip/Archive/SwfHandler.cpp2
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.cpp6
-rw-r--r--CPP/7zip/Archive/VhdHandler.cpp11
-rw-r--r--CPP/7zip/Archive/VhdxHandler.cpp2
-rw-r--r--CPP/7zip/Archive/Wim/WimHandler.cpp129
-rw-r--r--CPP/7zip/Archive/Wim/WimHandler.h15
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.cpp21
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.h30
-rw-r--r--CPP/7zip/Archive/Zip/ZipAddCommon.cpp2
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp5
-rw-r--r--CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp6
-rw-r--r--CPP/7zip/Common/FileStreams.cpp6
-rw-r--r--CPP/7zip/Common/LimitedStreams.cpp14
-rw-r--r--CPP/7zip/Common/LimitedStreams.h16
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.cpp2
-rw-r--r--CPP/7zip/Compress/HuffmanDecoder.h29
-rw-r--r--CPP/7zip/Compress/LzmaEncoder.cpp2
-rw-r--r--CPP/7zip/Compress/Rar3Decoder.cpp2
-rw-r--r--CPP/7zip/Crypto/Rar5Aes.cpp1
-rw-r--r--CPP/7zip/UI/Agent/Agent.cpp230
-rw-r--r--CPP/7zip/UI/Agent/Agent.h7
-rw-r--r--CPP/7zip/UI/Agent/AgentOut.cpp164
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.cpp848
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.h96
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp14
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolderOut.cpp3
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp319
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.h21
-rw-r--r--CPP/7zip/UI/Common/ArchiveOpenCallback.cpp7
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp7
-rw-r--r--CPP/7zip/UI/Common/ExtractingFilePath.cpp5
-rw-r--r--CPP/7zip/UI/Common/OpenArchive.cpp100
-rw-r--r--CPP/7zip/UI/Common/PropIDUtils.cpp27
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp13
-rw-r--r--CPP/7zip/UI/FileManager/AltStreamsFolder.cpp87
-rw-r--r--CPP/7zip/UI/FileManager/EnumFormatEtc.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.cpp60
-rw-r--r--CPP/7zip/UI/FileManager/PanelItemOpen.cpp53
-rw-r--r--CPP/7zip/UI/FileManager/PanelItems.cpp57
-rw-r--r--CPP/7zip/UI/FileManager/PanelMenu.cpp6
-rw-r--r--CPP/7zip/UI/FileManager/SysIconUtils.cpp3
-rw-r--r--CPP/Build.mak19
-rw-r--r--CPP/Common/MyCom.h2
-rw-r--r--CPP/Common/MyVector.h15
-rw-r--r--CPP/Windows/FileDir.cpp102
-rw-r--r--CPP/Windows/FileDir.h1
-rw-r--r--CPP/Windows/FileIO.cpp248
-rw-r--r--CPP/Windows/FileIO.h45
-rw-r--r--DOC/7zC.txt4
-rw-r--r--DOC/7zFormat.txt4
-rw-r--r--DOC/7zip.wxs2
-rw-r--r--DOC/Methods.txt2
-rw-r--r--DOC/readme.txt10
-rw-r--r--DOC/src-history.txt50
98 files changed, 2545 insertions, 1409 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a4a2554
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
1*.dsp text eol=crlf
2*.dsw text eol=crlf
diff --git a/C/7zDec.c b/C/7zDec.c
index 520cbfd..1149d06 100644
--- a/C/7zDec.c
+++ b/C/7zDec.c
@@ -99,62 +99,61 @@ static Byte ReadByte(IByteInPtr pp)
99static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, 99static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
100 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) 100 Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
101{ 101{
102 CPpmd7 ppmd; 102 CPpmd7 *ppmd;
103 CByteInToLook s; 103 SRes res;
104 SRes res = SZ_OK; 104 unsigned order;
105 105 UInt32 memSize;
106 s.vt.Read = ReadByte;
107 s.inStream = inStream;
108 s.begin = s.end = s.cur = NULL;
109 s.extra = False;
110 s.res = SZ_OK;
111 s.processed = 0;
112 106
113 if (propsSize != 5) 107 if (propsSize != 5)
114 return SZ_ERROR_UNSUPPORTED; 108 return SZ_ERROR_UNSUPPORTED;
115 109 order = props[0];
116 { 110 memSize = GetUi32(props + 1);
117 unsigned order = props[0]; 111 if (order < PPMD7_MIN_ORDER ||
118 UInt32 memSize = GetUi32(props + 1); 112 order > PPMD7_MAX_ORDER ||
119 if (order < PPMD7_MIN_ORDER || 113 memSize < PPMD7_MIN_MEM_SIZE ||
120 order > PPMD7_MAX_ORDER || 114 memSize > PPMD7_MAX_MEM_SIZE)
121 memSize < PPMD7_MIN_MEM_SIZE || 115 return SZ_ERROR_UNSUPPORTED;
122 memSize > PPMD7_MAX_MEM_SIZE) 116 if ((ppmd = (CPpmd7 *)ISzAlloc_Alloc(allocMain, sizeof(CPpmd7))) == NULL)
123 return SZ_ERROR_UNSUPPORTED; 117 return SZ_ERROR_MEM;
124 Ppmd7_Construct(&ppmd); 118 Ppmd7_Construct(ppmd);
125 if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) 119 res = SZ_ERROR_MEM;
126 return SZ_ERROR_MEM; 120 if (Ppmd7_Alloc(ppmd, memSize, allocMain))
127 Ppmd7_Init(&ppmd, order);
128 }
129 { 121 {
130 ppmd.rc.dec.Stream = &s.vt; 122 CByteInToLook s;
131 if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec)) 123 s.vt.Read = ReadByte;
132 res = SZ_ERROR_DATA; 124 s.inStream = inStream;
133 else if (!s.extra) 125 s.begin = s.end = s.cur = NULL;
126 s.extra = False;
127 s.res = SZ_OK;
128 s.processed = 0;
129
130 Ppmd7_Init(ppmd, order);
131 ppmd->rc.dec.Stream = &s.vt;
132 res = SZ_ERROR_DATA;
133 if (Ppmd7z_RangeDec_Init(&ppmd->rc.dec) && !s.extra)
134 { 134 {
135 Byte *buf = outBuffer; 135 Byte *buf = outBuffer;
136 const Byte *lim = buf + outSize; 136 const Byte *lim = buf + outSize;
137 for (; buf != lim; buf++) 137 for (; buf != lim; buf++)
138 { 138 {
139 int sym = Ppmd7z_DecodeSymbol(&ppmd); 139 int sym = Ppmd7z_DecodeSymbol(ppmd);
140 if (s.extra || sym < 0) 140 if (s.extra || sym < 0)
141 break; 141 break;
142 *buf = (Byte)sym; 142 *buf = (Byte)sym;
143 } 143 }
144 if (buf != lim) 144 if (buf == lim)
145 res = SZ_ERROR_DATA; 145 if (Ppmd7z_RangeDec_IsFinishedOK(&ppmd->rc.dec)
146 else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) 146 // || (Ppmd7z_DecodeSymbol(&ppmd) == PPMD7_SYM_END && Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
147 { 147 )
148 /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */ 148 res = SZ_OK;
149 res = SZ_ERROR_DATA;
150 }
151 } 149 }
152 if (s.extra) 150 if (s.extra)
153 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); 151 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
154 else if (s.processed + (size_t)(s.cur - s.begin) != inSize) 152 else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
155 res = SZ_ERROR_DATA; 153 res = SZ_ERROR_DATA;
154 Ppmd7_Free(ppmd, allocMain);
156 } 155 }
157 Ppmd7_Free(&ppmd, allocMain); 156 ISzAlloc_Free(allocMain, ppmd);
158 return res; 157 return res;
159} 158}
160 159
diff --git a/C/7zTypes.h b/C/7zTypes.h
index 8aaabc8..af47668 100644
--- a/C/7zTypes.h
+++ b/C/7zTypes.h
@@ -556,6 +556,7 @@ struct ISzAlloc
556 556
557 557
558#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) 558#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a))
559#define Z7_memset_0_VAR(a) memset(&(a), 0, sizeof(a))
559 560
560#ifndef Z7_ARRAY_SIZE 561#ifndef Z7_ARRAY_SIZE
561#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 562#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
diff --git a/C/7zVersion.h b/C/7zVersion.h
index 50ccebb..de7efb8 100644
--- a/C/7zVersion.h
+++ b/C/7zVersion.h
@@ -1,7 +1,7 @@
1#define MY_VER_MAJOR 26 1#define MY_VER_MAJOR 26
2#define MY_VER_MINOR 2 2#define MY_VER_MINOR 3
3#define MY_VER_BUILD 0 3#define MY_VER_BUILD 0
4#define MY_VERSION_NUMBERS "26.02" 4#define MY_VERSION_NUMBERS "26.03"
5#define MY_VERSION MY_VERSION_NUMBERS 5#define MY_VERSION MY_VERSION_NUMBERS
6 6
7#ifdef MY_CPU_NAME 7#ifdef MY_CPU_NAME
@@ -10,7 +10,7 @@
10 #define MY_VERSION_CPU MY_VERSION 10 #define MY_VERSION_CPU MY_VERSION
11#endif 11#endif
12 12
13#define MY_DATE "2026-06-25" 13#define MY_DATE "2026-09-03"
14#undef MY_COPYRIGHT 14#undef MY_COPYRIGHT
15#undef MY_VERSION_COPYRIGHT_DATE 15#undef MY_VERSION_COPYRIGHT_DATE
16#define MY_AUTHOR_NAME "Igor Pavlov" 16#define MY_AUTHOR_NAME "Igor Pavlov"
diff --git a/C/Bcj2Enc.c b/C/Bcj2Enc.c
index 79460bb..5727cbb 100644
--- a/C/Bcj2Enc.c
+++ b/C/Bcj2Enc.c
@@ -1,5 +1,5 @@
1/* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2) 1/* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2)
22023-04-02 : Igor Pavlov : Public domain */ 2: Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
@@ -75,7 +75,10 @@ static BoolInt Bcj2_RangeEnc_ShiftLow(CBcj2Enc *p)
75 p->cache = (Byte)(low >> 24); 75 p->cache = (Byte)(low >> 24);
76 } 76 }
77 p->cacheSize++; 77 p->cacheSize++;
78 p->low = low << 8; 78 {
79 const UInt32 low2 = low << 8;
80 p->low = low2;
81 }
79 return False; 82 return False;
80} 83}
81 84
diff --git a/C/BwtSort.c b/C/BwtSort.c
index 8f64f9d..c8f9135 100644
--- a/C/BwtSort.c
+++ b/C/BwtSort.c
@@ -564,7 +564,8 @@ UInt32 BlockSort(UInt32 *Indices, const Byte *data, size_t blockSize)
564 const BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); 564 const BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0);
565 if (Indices[i] & 0x40000000) 565 if (Indices[i] & 0x40000000)
566 { 566 {
567 groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); 567 const UInt32 temp = ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
568 groupSize += temp;
568 Indices[(size_t)i + 1] &= kIndexMask; 569 Indices[(size_t)i + 1] &= kIndexMask;
569 } 570 }
570 Indices[i] &= kIndexMask; 571 Indices[i] &= kIndexMask;
@@ -616,7 +617,8 @@ UInt32 BlockSort(UInt32 *Indices, const Byte *data, size_t blockSize)
616 size_t groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax; 617 size_t groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax;
617 if (Indices[i] & 0x40000000) 618 if (Indices[i] & 0x40000000)
618 { 619 {
619 groupSize += (Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits; 620 const UInt32 temp = (Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits;
621 groupSize += temp;
620 Indices[(size_t)i + 1] &= kIndexMask; 622 Indices[(size_t)i + 1] &= kIndexMask;
621 } 623 }
622 Indices[i] &= kIndexMask; 624 Indices[i] &= kIndexMask;
diff --git a/C/Compiler.h b/C/Compiler.h
index c06b883..707e46d 100644
--- a/C/Compiler.h
+++ b/C/Compiler.h
@@ -125,6 +125,36 @@ typedef void (*Z7_void_Function)(void);
125#pragma warning(disable : 4464) // relative include path contains '..' 125#pragma warning(disable : 4464) // relative include path contains '..'
126#endif 126#endif
127 127
128// #define Z7_ANALYZE_MODE
129#if defined(Z7_ANALYZE_MODE) // && defined(Z7_MSC_VER_ORIGINAL)
130// for -analyze switch:
131#if _MSC_VER >= 1900
132#pragma warning(disable : 6001) // Using uninitialized memory 'ps'.
133#pragma warning(disable : 6031) // Return value ignored: 'CoInitialize'
134#pragma warning(disable : 6553) // The annotation for function 'RegOpenKeyExW' on _Param_(3) does not apply to a value type.
135#pragma warning(disable : 28159) // Random.cpp(21) : Consider using 'GetTickCount64' instead of 'GetTickCount'
136#pragma warning(disable : 28160) // ProcessUtils.h(92) : Error annotation: Passing MEM_RELEASE and a non-zero dwSize parameter to VirtualFree is not allowed. This results in the failure of this call
137#pragma warning(disable : 28251) // Inconsistent annotation for 'WinMain': this instance has no annotations. See c:\program files (x86)\windows kits\10\include\10.0.26100.0\um\winbase.h(1062).
138#pragma warning(disable : 28286) // um\consoleapi.h(236) : For function 'ReadConsoleW', error near the end of 'SAL_readableTo(byteCount(*__formal(3,lpNumberOfCharsRead) * sizeof(TCHAR%)))'.
139#pragma warning(disable : 28301) // No annotations for first declaration of 'PNTSTATUS'. See c:\program files (x86)\windows kits\10\include\10.0.26100.0\shared\bcrypt.h(40).
140#endif
141#if _MSC_VER >= 1600
142#pragma warning(disable : 6011) // Dereferencing NULL pointer 'p->IsDirs'
143#pragma warning(disable : 6255) // `_alloca` indicates failure by raising a stack overflow exception. Consider using _malloca instead.
144#pragma warning(disable : 6258) // Using TerminateThread does not allow proper thread clean up.
145// #pragma warning(disable : 6262) // SfxSetup.c : Function uses '32808' bytes of stack.
146#pragma warning(disable : 6320) // Threads.c : Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled.
147#pragma warning(disable : 6385) // createcoder.cpp : Invalid data: accessing 'struct CCodecInfo const * * g_Codecs', the readable size is '256' bytes, but '4194244' bytes might be read: Lines: 338, 339, 340, 342, 344
148#pragma warning(disable : 6387) // MyString.cpp : 's' could be '0': this does not adhere to the specification for the function 'wmemcpy'
149#endif
150#if _MSC_VER == 1600
151#pragma warning(disable : 6200) // compressdialog.cpp : Index '31' is out of valid index range '0' to '9' for non-stack buffer 'g_Levels'
152#pragma warning(disable : 6204) // Possible buffer overrun in call to 'memset': use of unchecked parameter 'size'
153#pragma warning(disable : 6309) // Argument '1' is null: this does not adhere to function specification of 'GetProcAddress'
154#pragma warning(disable : 6386) // myvector.h : Buffer overrun: accessing 'argument 1', the writable size is 'newCapacity*4' bytes, but '8' bytes might be written
155#endif
156#endif // Z7_ANALYZE_MODE
157
128// == 1200 : -O1 : for __forceinline 158// == 1200 : -O1 : for __forceinline
129// >= 1900 : -O1 : for printf 159// >= 1900 : -O1 : for printf
130#pragma warning(disable : 4710) // function not inlined 160#pragma warning(disable : 4710) // function not inlined
diff --git a/C/CpuArch.h b/C/CpuArch.h
index 348db0a..e6698d8 100644
--- a/C/CpuArch.h
+++ b/C/CpuArch.h
@@ -209,6 +209,17 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
209#endif 209#endif
210 210
211 211
212#if defined(__s390__)
213#if defined(__s390x__) || defined(__LP64__) || (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8)
214 #define MY_CPU_NAME "s390x"
215 #define MY_CPU_SIZEOF_POINTER 8
216#else
217 #define MY_CPU_NAME "s390"
218 #define MY_CPU_SIZEOF_POINTER 4
219#endif
220#endif
221
222
212// #undef MY_CPU_NAME 223// #undef MY_CPU_NAME
213// #undef MY_CPU_SIZEOF_POINTER 224// #undef MY_CPU_SIZEOF_POINTER
214// #define __e2k__ 225// #define __e2k__
diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c
index 72aec69..5d64828 100644
--- a/C/Lzma2Enc.c
+++ b/C/Lzma2Enc.c
@@ -129,11 +129,10 @@ UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p);
129static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, 129static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
130 size_t *packSizeRes, ISeqOutStreamPtr outStream) 130 size_t *packSizeRes, ISeqOutStreamPtr outStream)
131{ 131{
132 size_t packSizeLimit = *packSizeRes; 132 const size_t packSizeLimit = *packSizeRes;
133 size_t packSize = packSizeLimit; 133 size_t packSize = packSizeLimit;
134 UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; 134 UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX;
135 unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); 135 const unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0);
136 BoolInt useCopyBlock;
137 SRes res; 136 SRes res;
138 137
139 *packSizeRes = 0; 138 *packSizeRes = 0;
@@ -150,22 +149,13 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
150 if (unpackSize == 0) 149 if (unpackSize == 0)
151 return res; 150 return res;
152 151
153 if (res == SZ_OK) 152 if (res == SZ_ERROR_OUTPUT_EOF
154 useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); 153 || (res == SZ_OK && (packSize + 2 >= unpackSize || packSize > (1 << 16))))
155 else
156 {
157 if (res != SZ_ERROR_OUTPUT_EOF)
158 return res;
159 res = SZ_OK;
160 useCopyBlock = True;
161 }
162
163 if (useCopyBlock)
164 { 154 {
165 size_t destPos = 0; 155 size_t destPos = 0;
166 PRF(printf("################# COPY ")); 156 PRF(printf("################# COPY "));
167 157
168 while (unpackSize > 0) 158 while (unpackSize)
169 { 159 {
170 const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; 160 const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;
171 if (packSizeLimit - destPos < u + 3) 161 if (packSizeLimit - destPos < u + 3)
@@ -194,6 +184,8 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
194 return SZ_OK; 184 return SZ_OK;
195 } 185 }
196 186
187 if (res != SZ_OK)
188 return res;
197 { 189 {
198 size_t destPos = 0; 190 size_t destPos = 0;
199 const UInt32 u = unpackSize - 1; 191 const UInt32 u = unpackSize - 1;
diff --git a/C/LzmaDec.c b/C/LzmaDec.c
index 69bb8bb..5bc5094 100644
--- a/C/LzmaDec.c
+++ b/C/LzmaDec.c
@@ -1,5 +1,5 @@
1/* LzmaDec.c -- LZMA Decoder 1/* LzmaDec.c -- LZMA Decoder
22023-04-07 : Igor Pavlov : Public domain */ 2: Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
@@ -462,8 +462,10 @@ int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
462 if (state >= kNumStates) 462 if (state >= kNumStates)
463 { 463 {
464 UInt32 distance; 464 UInt32 distance;
465 prob = probs + PosSlot + 465 {
466 ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); 466 const unsigned temp = (len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits;
467 prob = probs + PosSlot + temp;
468 }
467 TREE_6_DECODE(prob, distance) 469 TREE_6_DECODE(prob, distance)
468 if (distance >= kStartPosModelIndex) 470 if (distance >= kStartPosModelIndex)
469 { 471 {
@@ -857,9 +859,10 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byt
857 if (state < 4) 859 if (state < 4)
858 { 860 {
859 unsigned posSlot; 861 unsigned posSlot;
860 prob = probs + PosSlot + 862 {
861 ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << 863 const unsigned temp = (len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << kNumPosSlotBits;
862 kNumPosSlotBits); 864 prob = probs + PosSlot + temp;
865 }
863 TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot) 866 TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot)
864 if (posSlot >= kStartPosModelIndex) 867 if (posSlot >= kStartPosModelIndex)
865 { 868 {
@@ -867,7 +870,8 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byt
867 870
868 if (posSlot < kEndPosModelIndex) 871 if (posSlot < kEndPosModelIndex)
869 { 872 {
870 prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); 873 const unsigned temp = (2 | (posSlot & 1)) << numDirectBits;
874 prob = probs + SpecPos + temp;
871 } 875 }
872 else 876 else
873 { 877 {
diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c
index 60f1d21..f54e670 100644
--- a/C/LzmaEnc.c
+++ b/C/LzmaEnc.c
@@ -692,7 +692,10 @@ Z7_NO_INLINE static void Z7_FASTCALL RangeEnc_ShiftLow(CRangeEnc *p)
692{ 692{
693 UInt32 low = (UInt32)p->low; 693 UInt32 low = (UInt32)p->low;
694 unsigned high = (unsigned)(p->low >> 32); 694 unsigned high = (unsigned)(p->low >> 32);
695 p->low = (UInt32)(low << 8); 695 {
696 const UInt32 low2 = low << 8;
697 p->low = low2;
698 }
696 if (low < (UInt32)0xFF000000 || high != 0) 699 if (low < (UInt32)0xFF000000 || high != 0)
697 { 700 {
698 { 701 {
@@ -958,7 +961,8 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posS
958 unsigned m; 961 unsigned m;
959 unsigned bit; 962 unsigned bit;
960 RC_BIT_0(rc, probs) 963 RC_BIT_0(rc, probs)
961 probs += (posState << (1 + kLenNumLowBits)); 964 posState <<= (1 + kLenNumLowBits);
965 probs += posState;
962 bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit; 966 bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit;
963 bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit; 967 bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit;
964 bit = sym & 1; RC_BIT(rc, probs + m, bit) 968 bit = sym & 1; RC_BIT(rc, probs + m, bit)
@@ -1000,7 +1004,8 @@ Z7_NO_INLINE static void Z7_FASTCALL LenPriceEnc_UpdateTables(
1000 for (posState = 0; posState < numPosStates; posState++) 1004 for (posState = 0; posState < numPosStates; posState++)
1001 { 1005 {
1002 UInt32 *prices = p->prices[posState]; 1006 UInt32 *prices = p->prices[posState];
1003 const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); 1007 const unsigned posState2 = posState << (1 + kLenNumLowBits);
1008 const CLzmaProb *probs = enc->low + posState2;
1004 SetPrices_3(probs, a, prices, ProbPrices); 1009 SetPrices_3(probs, a, prices, ProbPrices);
1005 SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); 1010 SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
1006 } 1011 }
@@ -2220,7 +2225,7 @@ Z7_NO_INLINE static void FillAlignPrices(CLzmaEnc *p)
2220 UInt32 prob; 2225 UInt32 prob;
2221 bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; 2226 bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
2222 bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; 2227 bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
2223 bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; 2228 bit = sym & 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
2224 prob = probs[m]; 2229 prob = probs[m];
2225 p->alignPrices[i ] = price + GET_PRICEa_0(prob); 2230 p->alignPrices[i ] = price + GET_PRICEa_0(prob);
2226 p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); 2231 p->alignPrices[i + 8] = price + GET_PRICEa_1(prob);
diff --git a/C/Ppmd7Enc.c b/C/Ppmd7Enc.c
index 49cbbe6..975157c 100644
--- a/C/Ppmd7Enc.c
+++ b/C/Ppmd7Enc.c
@@ -1,5 +1,5 @@
1/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder 1/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder
22023-09-07 : Igor Pavlov : Public domain 2: Igor Pavlov : Public domain
3This code is based on: 3This code is based on:
4 PPMd var.H (2001): Dmitry Shkarin : Public domain */ 4 PPMd var.H (2001): Dmitry Shkarin : Public domain */
5 5
@@ -35,7 +35,10 @@ static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p)
35 R->Cache = (Byte)((UInt32)R->Low >> 24); 35 R->Cache = (Byte)((UInt32)R->Low >> 24);
36 } 36 }
37 R->CacheSize++; 37 R->CacheSize++;
38 R->Low = (UInt32)((UInt32)R->Low << 8); 38 {
39 const UInt32 low2 = (UInt32)R->Low << 8;
40 R->Low = low2;
41 }
39} 42}
40 43
41#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p); 44#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p);
diff --git a/C/Ppmd8.c b/C/Ppmd8.c
index 774b30c..bd56480 100644
--- a/C/Ppmd8.c
+++ b/C/Ppmd8.c
@@ -885,9 +885,9 @@ static PPMD8_CTX_PTR Ppmd8_CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State
885 if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; } 885 if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; }
886 } 886 }
887 else 887 else
888 { 888 { const unsigned temp = !SUFFIX(c)->NumStats;
889 s = ONE_STATE(c); 889 s = ONE_STATE(c);
890 s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); 890 s->Freq = (Byte)(s->Freq + (temp & (s->Freq < 24)));
891 } 891 }
892 successor = SUCCESSOR(s); 892 successor = SUCCESSOR(s);
893 if (successor != upBranch) 893 if (successor != upBranch)
diff --git a/C/Util/7z/7zMain.c b/C/Util/7z/7zMain.c
index 300c363..e49c230 100644
--- a/C/Util/7z/7zMain.c
+++ b/C/Util/7z/7zMain.c
@@ -967,7 +967,7 @@ int Z7_CDECL main(int numargs, char *args[])
967 break; 967 break;
968 } 968 }
969 969
970 if (len > tempSize) 970 if (len > tempSize || !temp)
971 { 971 {
972 SzFree(NULL, temp); 972 SzFree(NULL, temp);
973 tempSize = len; 973 tempSize = len;
diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp
index 71d1ddb..049cc17 100644
--- a/CPP/7zip/Archive/7z/7zEncode.cpp
+++ b/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -323,20 +323,16 @@ HRESULT CEncoder::Encode1(
323 ICompressProgressInfo *compressProgress) 323 ICompressProgressInfo *compressProgress)
324{ 324{
325 RINOK(EncoderConstr()) 325 RINOK(EncoderConstr())
326
327 if (!_mixerRef) 326 if (!_mixerRef)
328 { 327 {
329 RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)) 328 RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce))
330 } 329 }
331
332 RINOK(_mixer->ReInit2()) 330 RINOK(_mixer->ReInit2())
333 331
334 CMyComPtr2<ICompressProgressInfo, CMtEncMultiProgress> mtProgress; 332 CMyComPtr2<ICompressProgressInfo, CMtEncMultiProgress> mtProgress;
335 CMyComPtr2<ISequentialOutStream, CSequentialOutMtNotify> mtOutStreamNotify; 333 CMyComPtr2<ISequentialOutStream, CSequentialOutMtNotify> mtOutStreamNotify;
336
337 CRecordVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs; 334 CRecordVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
338 CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers; 335 CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
339
340 unsigned i; 336 unsigned i;
341 337
342 for (i = 1; i < _bindInfo.PackStreams.Size(); i++) 338 for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
@@ -348,34 +344,21 @@ HRESULT CEncoder::Encode1(
348 } 344 }
349 345
350 const unsigned numMethods = _bindInfo.Coders.Size(); 346 const unsigned numMethods = _bindInfo.Coders.Size();
351
352 for (i = 0; i < numMethods; i++) 347 for (i = 0; i < numMethods; i++)
353 _mixer->SetCoderInfo(i, NULL, NULL, false); 348 _mixer->SetCoderInfo(i, NULL, NULL, false);
354 349
355
356 /* inStreamSize can be used by BCJ2 to set optimal range of conversion. 350 /* inStreamSize can be used by BCJ2 to set optimal range of conversion.
357 But current BCJ2 encoder uses also another way to check exact size of current file. 351 But current BCJ2 encoder uses also another way to check exact size of current file.
358 So inStreamSize is not required. */ 352 So inStreamSize is not required. */
359
360 /* 353 /*
361 if (inStreamSize) 354 if (inStreamSize)
362 _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL); 355 _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
363 */ 356 */
364 357 // CMyComPtr2_Create<ISequentialInStream, CSequentialInStreamSizeCount2> inStreamSizeCount;
365 358 CMyComPtr2_Create<ISequentialOutStream, CSequentialOutStreamSizeCount> outStreamSizeCount;
366 /*
367 CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
368 CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
369 */
370
371 CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
372 CMyComPtr<ISequentialOutStream> outStreamSizeCount;
373
374 // inStreamSizeCountSpec->Init(inStream); 359 // inStreamSizeCountSpec->Init(inStream);
375
376 // ISequentialInStream *inStreamPointer = inStreamSizeCount; 360 // ISequentialInStream *inStreamPointer = inStreamSizeCount;
377 ISequentialInStream *inStreamPointer = inStream; 361 ISequentialInStream *inStreamPointer = inStream;
378
379 CRecordVector<ISequentialOutStream *> outStreamPointers; 362 CRecordVector<ISequentialOutStream *> outStreamPointers;
380 363
381 SetFolder(folderItem); 364 SetFolder(folderItem);
@@ -466,11 +449,9 @@ HRESULT CEncoder::Encode1(
466 449
467 if (_bindInfo.PackStreams.Size() != 0) 450 if (_bindInfo.PackStreams.Size() != 0)
468 { 451 {
469 outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; 452 outStreamSizeCount->SetStream(mtOutStreamNotify.IsDefined() ?
470 outStreamSizeCount = outStreamSizeCountSpec;
471 outStreamSizeCountSpec->SetStream(mtOutStreamNotify.IsDefined() ?
472 mtOutStreamNotify.Interface() : outStream); 453 mtOutStreamNotify.Interface() : outStream);
473 outStreamSizeCountSpec->Init(); 454 outStreamSizeCount->Init();
474 outStreamPointers.Add(outStreamSizeCount); 455 outStreamPointers.Add(outStreamSizeCount);
475 } 456 }
476 457
@@ -486,7 +467,7 @@ HRESULT CEncoder::Encode1(
486 compressProgress, dataAfterEnd_Error)) 467 compressProgress, dataAfterEnd_Error))
487 468
488 if (_bindInfo.PackStreams.Size() != 0) 469 if (_bindInfo.PackStreams.Size() != 0)
489 packSizes.Add(outStreamSizeCountSpec->GetSize()); 470 packSizes.Add(outStreamSizeCount->GetSize());
490 471
491 for (i = 1; i < _bindInfo.PackStreams.Size(); i++) 472 for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
492 { 473 {
diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp
index 81dd966..a81f5df 100644
--- a/CPP/7zip/Archive/7z/7zHandler.cpp
+++ b/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -309,6 +309,11 @@ bool CHandler::IsFolderEncrypted(CNum folderIndex) const
309 inByte.SkipDataNoCheck(idSize); 309 inByte.SkipDataNoCheck(idSize);
310 if (id64 == k_AES) 310 if (id64 == k_AES)
311 return true; 311 return true;
312 if ((mainByte & 0x10) != 0)
313 {
314 inByte.ReadNum(); // NumInStreams
315 inByte.ReadNum(); // NumOutStreams
316 }
312 if ((mainByte & 0x20) != 0) 317 if ((mainByte & 0x20) != 0)
313 inByte.SkipDataNoCheck(inByte.ReadNum()); 318 inByte.SkipDataNoCheck(inByte.ReadNum());
314 } 319 }
@@ -455,7 +460,7 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
455 const UInt32 lp = d % 5; 460 const UInt32 lp = d % 5;
456 if (lc != 3) dest = AddProp32(dest, "lc", lc); 461 if (lc != 3) dest = AddProp32(dest, "lc", lc);
457 if (lp != 0) dest = AddProp32(dest, "lp", lp); 462 if (lp != 0) dest = AddProp32(dest, "lp", lp);
458 if (pb != 2) dest = AddProp32(dest, "pb", pb); 463 if (pb != 2) /* dest = */ AddProp32(dest, "pb", pb);
459 } 464 }
460 } 465 }
461 } 466 }
diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp
index 2876991..0f367f9 100644
--- a/CPP/7zip/Archive/ApfsHandler.cpp
+++ b/CPP/7zip/Archive/ApfsHandler.cpp
@@ -3829,7 +3829,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3829 #ifdef APFS_SHOW_ALT_STREAMS 3829 #ifdef APFS_SHOW_ALT_STREAMS
3830 if (ref.IsAltStream()) 3830 if (ref.IsAltStream())
3831 { 3831 {
3832 // if (inode) 3832 if (inode)
3833 { 3833 {
3834 const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex]; 3834 const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex];
3835 ConvertUTF8ToUnicode(attr.Name, s); 3835 ConvertUTF8ToUnicode(attr.Name, s);
diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp
index e88d2fe..ca46eb1 100644
--- a/CPP/7zip/Archive/ApmHandler.cpp
+++ b/CPP/7zip/Archive/ApmHandler.cpp
@@ -253,9 +253,10 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
253 numBlocks = finish; 253 numBlocks = finish;
254 254
255 _items.Add(item); 255 _items.Add(item);
256 if (numPadSectors != 0)
257 { 256 {
258 RINOK(stream->Seek(numPadSectors << 9, STREAM_SEEK_CUR, NULL)) 257 const unsigned offset = numPadSectors << 9;
258 if (offset)
259 RINOK(stream->Seek(offset, STREAM_SEEK_CUR, NULL))
259 } 260 }
260 if (++i == numBlocksInMap) 261 if (++i == numBlocksInMap)
261 break; 262 break;
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp
index 9f672a9..e9afb1b 100644
--- a/CPP/7zip/Archive/ArHandler.cpp
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -249,7 +249,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, bool &filled)
249 RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize; 249 RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize;
250 RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize; 250 RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize;
251 RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize; 251 RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize;
252 RIF(DecimalToNumber(cur, kSizeSize, item.Size)) cur += kSizeSize; 252 RIF(DecimalToNumber(cur, kSizeSize, item.Size)) // cur += kSizeSize;
253 253
254 if (longNameLen != 0 && longNameLen <= item.Size) 254 if (longNameLen != 0 && longNameLen <= item.Size)
255 { 255 {
diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp
index 1d641e4..1a06781 100644
--- a/CPP/7zip/Archive/ArjHandler.cpp
+++ b/CPP/7zip/Archive/ArjHandler.cpp
@@ -352,7 +352,7 @@ HRESULT CArcHeader::Parse(const Byte *p, unsigned size)
352 pos += size1; 352 pos += size1;
353 size1 = size - pos; 353 size1 = size - pos;
354 RINOK(ReadString(p + pos, size1, Comment)) 354 RINOK(ReadString(p + pos, size1, Comment))
355 pos += size1; 355 // pos += size1;
356 return S_OK; 356 return S_OK;
357} 357}
358 358
@@ -462,8 +462,7 @@ HRESULT CItem::Parse(const Byte *p, unsigned size)
462 pos += size1; 462 pos += size1;
463 size1 = size - pos; 463 size1 = size - pos;
464 RINOK(ReadString(p + pos, size1, Comment)) 464 RINOK(ReadString(p + pos, size1, Comment))
465 pos += size1; 465 // pos += size1;
466
467 return S_OK; 466 return S_OK;
468} 467}
469 468
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
index 0ad2a0e..f97c686 100644
--- a/CPP/7zip/Archive/Cab/CabHandler.cpp
+++ b/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -145,10 +145,13 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
145 // case kpidSolid: prop = _database.IsSolid(); break; 145 // case kpidSolid: prop = _database.IsSolid(); break;
146 case kpidNumBlocks: 146 case kpidNumBlocks:
147 { 147 {
148 /*
148 UInt32 numFolders = 0; 149 UInt32 numFolders = 0;
149 FOR_VECTOR (v, m_Database.Volumes) 150 FOR_VECTOR (v, m_Database.Volumes)
150 numFolders += m_Database.Volumes[v].Folders.Size(); 151 numFolders += m_Database.Volumes[v].Folders.Size();
151 prop = numFolders; 152 prop = numFolders;
153 */
154 prop = (UInt32)m_Database.FolderStartFileIndex.Size();
152 break; 155 break;
153 } 156 }
154 157
@@ -292,7 +295,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
292 break; 295 break;
293 } 296 }
294 297
295 case kpidIsDir: prop = item.IsDir(); break; 298 // case kpidIsDir: prop = false; break;
296 case kpidSize: prop = item.Size; break; 299 case kpidSize: prop = item.Size; break;
297 case kpidAttrib: prop = item.GetWinAttrib(); break; 300 case kpidAttrib: prop = item.GetWinAttrib(); break;
298 301
@@ -315,7 +318,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
315 break; 318 break;
316 } 319 }
317 320
318 case kpidBlock: prop.Set_Int32((Int32)m_Database.GetFolderIndex(&mvItem)); break; 321 case kpidBlock: prop.Set_Int32((Int32)m_Database.GetGlobalFolderIndex(mvItem)); break;
319 322
320 #ifdef CAB_DETAILS 323 #ifdef CAB_DETAILS
321 324
@@ -516,8 +519,7 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
516 return S_FALSE; 519 return S_FALSE;
517 else 520 else
518 { 521 {
519 m_Database.FillSortAndShrink(); 522 if (!m_Database.Fill_Sort_Shrink_and_Check())
520 if (!m_Database.Check())
521 return S_FALSE; 523 return S_FALSE;
522 } 524 }
523 } 525 }
@@ -921,9 +923,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
921 const unsigned index = allFilesMode ? i : indices[i]; 923 const unsigned index = allFilesMode ? i : indices[i];
922 const CMvItem &mvItem = m_Database.Items[index]; 924 const CMvItem &mvItem = m_Database.Items[index];
923 const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; 925 const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
924 if (item.IsDir()) 926 const int folderIndex = m_Database.GetGlobalFolderIndex(mvItem);
925 continue;
926 const int folderIndex = m_Database.GetFolderIndex(&mvItem);
927 if (folderIndex != lastFolder) 927 if (folderIndex != lastFolder)
928 totalUnPacked += lastFolderSize; 928 totalUnPacked += lastFolderSize;
929 lastFolder = folderIndex; 929 lastFolder = folderIndex;
@@ -967,20 +967,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
967 const CItem &item = db.Items[itemIndex]; 967 const CItem &item = db.Items[itemIndex];
968 968
969 i++; 969 i++;
970 if (item.IsDir())
971 {
972 const Int32 askMode = testMode ?
973 NExtract::NAskMode::kTest :
974 NExtract::NAskMode::kExtract;
975 CMyComPtr<ISequentialOutStream> realOutStream;
976 RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
977 RINOK(extractCallback->PrepareOperation(askMode))
978 realOutStream.Release();
979 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
980 continue;
981 }
982 970
983 const int folderIndex = m_Database.GetFolderIndex(&mvItem); 971 const int folderIndex = m_Database.GetGlobalFolderIndex(mvItem);
984 972
985 if (folderIndex < 0) 973 if (folderIndex < 0)
986 { 974 {
@@ -992,7 +980,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
992 RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) 980 RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
993 RINOK(extractCallback->PrepareOperation(askMode)) 981 RINOK(extractCallback->PrepareOperation(askMode))
994 realOutStream.Release(); 982 realOutStream.Release();
995 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)) 983 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable))
996 continue; 984 continue;
997 } 985 }
998 986
@@ -1010,9 +998,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1010 const unsigned indexNext = allFilesMode ? i : indices[i]; 998 const unsigned indexNext = allFilesMode ? i : indices[i];
1011 const CMvItem &mvItem2 = m_Database.Items[indexNext]; 999 const CMvItem &mvItem2 = m_Database.Items[indexNext];
1012 const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; 1000 const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex];
1013 if (item2.IsDir()) 1001 const int newFolderIndex = m_Database.GetGlobalFolderIndex(mvItem2);
1014 continue;
1015 const int newFolderIndex = m_Database.GetFolderIndex(&mvItem2);
1016 1002
1017 if (newFolderIndex != folderIndex) 1003 if (newFolderIndex != folderIndex)
1018 break; 1004 break;
@@ -1073,6 +1059,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1073 bool keepHistory = false; 1059 bool keepHistory = false;
1074 bool keepInputBuffer = false; 1060 bool keepInputBuffer = false;
1075 bool thereWasNotAlignedChunk = false; 1061 bool thereWasNotAlignedChunk = false;
1062
1063 // printf(" -locFolderIndex=%5i\n", locFolderIndex);
1076 1064
1077 for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();) 1065 for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();)
1078 { 1066 {
@@ -1085,6 +1073,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1085 const CDatabaseEx &db2 = m_Database.Volumes[volIndex]; 1073 const CDatabaseEx &db2 = m_Database.Volumes[volIndex];
1086 if (locFolderIndex < 0) 1074 if (locFolderIndex < 0)
1087 return E_FAIL; 1075 return E_FAIL;
1076 if ((unsigned)locFolderIndex >= db2.Folders.Size())
1077 {
1078 res = S_FALSE;
1079 break;
1080 }
1088 const CFolder &folder2 = db2.Folders[(unsigned)locFolderIndex]; 1081 const CFolder &folder2 = db2.Folders[(unsigned)locFolderIndex];
1089 1082
1090 if (bl == 0) 1083 if (bl == 0)
@@ -1092,7 +1085,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1092 RINOK(InStream_SeekSet(db2.Stream, db2.StartPosition + folder2.DataStart)) 1085 RINOK(InStream_SeekSet(db2.Stream, db2.StartPosition + folder2.DataStart))
1093 } 1086 }
1094 1087
1095 if (bl == folder2.NumDataBlocks) 1088 if (bl >= folder2.NumDataBlocks)
1096 { 1089 {
1097 /* 1090 /*
1098 CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit. 1091 CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit.
@@ -1105,13 +1098,14 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1105 if (m_Database.Volumes.Size() > 1) 1098 if (m_Database.Volumes.Size() > 1)
1106 { 1099 {
1107 volIndex++; 1100 volIndex++;
1101 // printf(" -volIndex=%5u\n", volIndex);
1108 locFolderIndex = 0; 1102 locFolderIndex = 0;
1109 bl = 0; 1103 bl = 0;
1110 continue; 1104 continue;
1111 } 1105 }
1112 } 1106 }
1113 1107 else
1114 bl++; 1108 bl++;
1115 1109
1116 if (!keepInputBuffer) 1110 if (!keepInputBuffer)
1117 blockPackData.InitForNewBlock(); 1111 blockPackData.InitForNewBlock();
@@ -1120,6 +1114,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1120 res = blockPackData.Read(db2.Stream, db2.ArcInfo.GetDataBlockReserveSize(), packSize, unpackSize); 1114 res = blockPackData.Read(db2.Stream, db2.ArcInfo.GetDataBlockReserveSize(), packSize, unpackSize);
1121 if (res == S_FALSE) 1115 if (res == S_FALSE)
1122 break; 1116 break;
1117 // if folder is Continued_To_Next volume, then (unpackSize == 0) in last chunk of volume, but (packSize != 0)
1118 // printf(" -block=%5u unpackSize=%5u packSize=%5u\n", bl - 1, unpackSize, packSize);
1123 RINOK(res) 1119 RINOK(res)
1124 keepInputBuffer = (unpackSize == 0); 1120 keepInputBuffer = (unpackSize == 0);
1125 if (keepInputBuffer) 1121 if (keepInputBuffer)
diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp
index bd6969a..a20d3b0 100644
--- a/CPP/7zip/Archive/Cab/CabIn.cpp
+++ b/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -31,9 +31,11 @@ void CInArchive::Read(Byte *data, unsigned size)
31 throw CUnexpectedEndException(); 31 throw CUnexpectedEndException();
32} 32}
33 33
34static const size_t k_Name_Size_Limit = 1 << 13;
35
34void CInArchive::ReadName(AString &s) 36void CInArchive::ReadName(AString &s)
35{ 37{
36 for (size_t i = 0; i < ((size_t)1 << 13); i++) 38 for (size_t i = 0; i < k_Name_Size_Limit; i++)
37 { 39 {
38 Byte b; 40 Byte b;
39 if (!_inBuffer.ReadByte(b)) 41 if (!_inBuffer.ReadByte(b))
@@ -43,8 +45,6 @@ void CInArchive::ReadName(AString &s)
43 s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i); 45 s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i);
44 return; 46 return;
45 } 47 }
46 if (_tempBuf.Size() == i)
47 _tempBuf.ChangeSize_KeepData(i * 2, i);
48 _tempBuf[i] = b; 48 _tempBuf[i] = b;
49 } 49 }
50 50
@@ -58,7 +58,7 @@ void CInArchive::ReadName(AString &s)
58 } 58 }
59 59
60 ErrorInNames = true; 60 ErrorInNames = true;
61 s = "[ERROR-LONG-PATH]"; 61 s = "[LONG_PATH_FILE]";
62} 62}
63 63
64void CInArchive::ReadOtherArc(COtherArc &oa) 64void CInArchive::ReadOtherArc(COtherArc &oa)
@@ -268,14 +268,14 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
268 IsArc = true; 268 IsArc = true;
269 269
270 _inBuffer.SetStream(limitedStream); 270 _inBuffer.SetStream(limitedStream);
271 if (_tempBuf.Size() == 0) 271 _tempBuf.Alloc(k_Name_Size_Limit);
272 _tempBuf.Alloc(1 << 12);
273 272
274 Byte p[16]; 273 Byte p[16];
275 const unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0); 274 const unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0);
276 Read(p, nextSize); 275 Read(p, nextSize);
277 ai.SetID = Get16(p); 276 ai.SetID = Get16(p);
278 ai.CabinetNumber = Get16(p + 2); 277 ai.CabinetNumber = Get16(p + 2);
278 // printf("CabinetNumber=%5u \n", ai.CabinetNumber);
279 279
280 if (ai.ReserveBlockPresent()) 280 if (ai.ReserveBlockPresent())
281 { 281 {
@@ -302,10 +302,9 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
302 folder.MethodMinor = p[7]; 302 folder.MethodMinor = p[7];
303 Skip(ai.PerFolder_AreaSize); 303 Skip(ai.PerFolder_AreaSize);
304 db.Folders.AddInReserved(folder); 304 db.Folders.AddInReserved(folder);
305 // printf("folder=%5u DataStart=%8u numBlocks=%8u\n", i, folder.DataStart, folder.NumDataBlocks);
305 } 306 }
306 307
307 // for (int iii = 0; iii < 10000; iii++) {
308
309 if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset) 308 if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset)
310 { 309 {
311 // printf("\n!!! Seek Error !!!!\n"); 310 // printf("\n!!! Seek Error !!!!\n");
@@ -315,8 +314,14 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
315 _inBuffer.Init(); 314 _inBuffer.Init();
316 } 315 }
317 316
317/*
318 if (FolderIndex == kContinuedFromPrev || FolderIndex == kContinuedPrevAndNext),
319 then there are no (FolderIndex == 0) items in that cab volume.
320 But (FolderIndex == kContinuedToNext) and (FolderIndex == numFolders - 1) items are possible in same volume.
321 if there are multiple files with (FolderIndex == kContinuedToNext), then they are duplicated
322 in next volume with (FolderIndex == kContinuedFromPrev or kContinuedPrevAndNext).
323*/
318 db.Items.ClearAndReserve(ai.NumFiles); 324 db.Items.ClearAndReserve(ai.NumFiles);
319
320 for (i = 0; i < ai.NumFiles; i++) 325 for (i = 0; i < ai.NumFiles; i++)
321 { 326 {
322 Read(p, 16); 327 Read(p, 16);
@@ -328,18 +333,15 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
328 const UInt16 pureTime = Get16(p + 12); 333 const UInt16 pureTime = Get16(p + 12);
329 item.Time = (((UInt32)pureDate << 16)) | pureTime; 334 item.Time = (((UInt32)pureDate << 16)) | pureTime;
330 item.Attributes = Get16(p + 14); 335 item.Attributes = Get16(p + 14);
331
332 ReadName(item.Name); 336 ReadName(item.Name);
333 337 // printf(" -file=%5u Folder=%5x Offset=%10u size=%10u %s\n", i, item.FolderIndex, item.Offset, item.Size, item.Name.Ptr());
334 if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) 338 const unsigned numFolders = db.Folders.Size();
339 if (numFolders == 0 || item.GetFolderIndex(numFolders) >= (int)numFolders)
335 { 340 {
336 HeaderError = true; 341 HeaderError = true;
337 return S_FALSE; 342 return S_FALSE;
338 } 343 }
339 } 344 }
340
341 // }
342
343 return S_OK; 345 return S_OK;
344} 346}
345 347
@@ -365,12 +367,8 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
365 const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex]; 367 const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
366 const CItem &item1 = db1.Items[p1->ItemIndex]; 368 const CItem &item1 = db1.Items[p1->ItemIndex];
367 const CItem &item2 = db2.Items[p2->ItemIndex]; 369 const CItem &item2 = db2.Items[p2->ItemIndex];
368 const bool isDir1 = item1.IsDir(); 370 const int f1 = mvDb.GetGlobalFolderIndex(*p1);
369 const bool isDir2 = item2.IsDir(); 371 const int f2 = mvDb.GetGlobalFolderIndex(*p2);
370 if (isDir1 && !isDir2) return -1;
371 if (isDir2 && !isDir1) return 1;
372 const int f1 = mvDb.GetFolderIndex(p1);
373 const int f2 = mvDb.GetFolderIndex(p2);
374 RINOZ(MyCompare(f1, f2)) 372 RINOZ(MyCompare(f1, f2))
375 RINOZ(MyCompare(item1.Offset, item2.Offset)) 373 RINOZ(MyCompare(item1.Offset, item2.Offset))
376 RINOZ(MyCompare(item1.Size, item2.Size)) 374 RINOZ(MyCompare(item1.Size, item2.Size))
@@ -379,37 +377,39 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
379} 377}
380 378
381 379
382bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) 380bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) const
383{ 381{
384 const CMvItem *p1 = &Items[i1]; 382 const CMvItem &p1 = Items[i1];
385 const CMvItem *p2 = &Items[i2]; 383 const CMvItem &p2 = Items[i2];
386 const CDatabaseEx &db1 = Volumes[p1->VolumeIndex]; 384 const CDatabaseEx &db1 = Volumes[p1.VolumeIndex];
387 const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; 385 const CDatabaseEx &db2 = Volumes[p2.VolumeIndex];
388 const CItem &item1 = db1.Items[p1->ItemIndex]; 386 const CItem &item1 = db1.Items[p1.ItemIndex];
389 const CItem &item2 = db2.Items[p2->ItemIndex]; 387 const CItem &item2 = db2.Items[p2.ItemIndex];
390 return GetFolderIndex(p1) == GetFolderIndex(p2) 388 return GetGlobalFolderIndex(p1) == GetGlobalFolderIndex(p2)
391 && item1.Offset == item2.Offset 389 && item1.Offset == item2.Offset
392 && item1.Size == item2.Size 390 && item1.Size == item2.Size
393 && item1.Name == item2.Name; 391 && item1.Name == item2.Name;
394} 392}
395 393
396 394
397void CMvDatabaseEx::FillSortAndShrink() 395bool CMvDatabaseEx::Fill_Sort_Shrink_and_Check()
396{
398{ 397{
399 Items.Clear(); 398 Items.Clear();
400 StartFolderOfVol.Clear();
401 FolderStartFileIndex.Clear(); 399 FolderStartFileIndex.Clear();
402 400
403 int offset = 0; 401 int offset = 0;
404 402
405 FOR_VECTOR (v, Volumes) 403 FOR_VECTOR (v, Volumes)
406 { 404 {
407 const CDatabaseEx &db = Volumes[v]; 405 CDatabaseEx &db = Volumes[v];
408 int curOffset = offset;
409 if (db.IsTherePrevFolder()) 406 if (db.IsTherePrevFolder())
410 curOffset--; 407 offset--;
411 StartFolderOfVol.Add(curOffset); 408 db.StartGlobalFolderIndex = offset;
412 offset += db.GetNumberOfNewFolders(); 409 // printf("vol=%5u StartGlobalFolderIndex=%8d\n", v, offset);
410 offset += (int)db.Folders.Size();
411 if (offset < -1) // overflow
412 return false;
413 413
414 CMvItem mvItem; 414 CMvItem mvItem;
415 mvItem.VolumeIndex = v; 415 mvItem.VolumeIndex = v;
@@ -433,15 +433,12 @@ void CMvDatabaseEx::FillSortAndShrink()
433 433
434 FOR_VECTOR (i, Items) 434 FOR_VECTOR (i, Items)
435 { 435 {
436 const int folderIndex = GetFolderIndex(&Items[i]); 436 const int folderIndex = GetGlobalFolderIndex(Items[i]);
437 while (folderIndex >= (int)FolderStartFileIndex.Size()) 437 while (folderIndex >= (int)FolderStartFileIndex.Size())
438 FolderStartFileIndex.Add(i); 438 FolderStartFileIndex.Add(i);
439 } 439 }
440} 440}
441 441
442
443bool CMvDatabaseEx::Check()
444{
445 for (unsigned v = 1; v < Volumes.Size(); v++) 442 for (unsigned v = 1; v < Volumes.Size(); v++)
446 { 443 {
447 const CDatabaseEx &db1 = Volumes[v]; 444 const CDatabaseEx &db1 = Volumes[v];
@@ -465,14 +462,12 @@ bool CMvDatabaseEx::Check()
465 FOR_VECTOR (i, Items) 462 FOR_VECTOR (i, Items)
466 { 463 {
467 const CMvItem &mvItem = Items[i]; 464 const CMvItem &mvItem = Items[i];
468 const int fIndex = GetFolderIndex(&mvItem); 465 const int fIndex = GetGlobalFolderIndex(mvItem);
469 if (fIndex >= (int)FolderStartFileIndex.Size()) 466 if (fIndex >= (int)FolderStartFileIndex.Size())
470 return false; 467 return false;
471 const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; 468 const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
472 if (item.IsDir())
473 continue;
474 469
475 const int folderIndex = GetFolderIndex(&mvItem); 470 const int folderIndex = GetGlobalFolderIndex(mvItem);
476 471
477 if (folderIndex != prevFolder) 472 if (folderIndex != prevFolder)
478 prevFolder = folderIndex; 473 prevFolder = folderIndex;
diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h
index 06aa34c..1c22bef 100644
--- a/CPP/7zip/Archive/Cab/CabIn.h
+++ b/CPP/7zip/Archive/Cab/CabIn.h
@@ -97,20 +97,15 @@ struct CDatabase
97 return true; 97 return true;
98 return false; 98 return false;
99 } 99 }
100
101 int GetNumberOfNewFolders() const
102 {
103 int res = (int)Folders.Size();
104 if (IsTherePrevFolder())
105 res--;
106 return res;
107 }
108}; 100};
109 101
110 102
111struct CDatabaseEx: public CDatabase 103struct CDatabaseEx: public CDatabase
112{ 104{
113 CMyComPtr<IInStream> Stream; 105 CMyComPtr<IInStream> Stream;
106 int StartGlobalFolderIndex; // == (-1), if there are links to a previous volume that is missing or contains an error
107
108 CDatabaseEx(): StartGlobalFolderIndex(-1) {}
114}; 109};
115 110
116 111
@@ -123,31 +118,29 @@ struct CMvItem
123 118
124class CMvDatabaseEx 119class CMvDatabaseEx
125{ 120{
126 bool AreItemsEqual(unsigned i1, unsigned i2); 121 bool AreItemsEqual(unsigned i1, unsigned i2) const;
127 122
128public: 123public:
129 CObjectVector<CDatabaseEx> Volumes; 124 CObjectVector<CDatabaseEx> Volumes;
130 CRecordVector<CMvItem> Items; 125 CRecordVector<CMvItem> Items;
131 CRecordVector<int> StartFolderOfVol; // can be negative 126 CRecordVector<unsigned> FolderStartFileIndex; // GlobalFolderIndex to Items[] index
132 CRecordVector<unsigned> FolderStartFileIndex;
133 127
134 int GetFolderIndex(const CMvItem *mvi) const 128 // out: (returned_value == -1) is possible, if (mvi) refers to a previous volume that is missing or contains an error
129 int GetGlobalFolderIndex(const CMvItem &mvi) const
135 { 130 {
136 const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; 131 const CDatabaseEx &db = Volumes[mvi.VolumeIndex];
137 return StartFolderOfVol[mvi->VolumeIndex] + 132 return db.StartGlobalFolderIndex +
138 db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); 133 db.Items[mvi.ItemIndex].GetFolderIndex(db.Folders.Size());
139 } 134 }
140 135
141 void Clear() 136 void Clear()
142 { 137 {
143 Volumes.Clear(); 138 Volumes.Clear();
144 Items.Clear(); 139 Items.Clear();
145 StartFolderOfVol.Clear();
146 FolderStartFileIndex.Clear(); 140 FolderStartFileIndex.Clear();
147 } 141 }
148 142
149 void FillSortAndShrink(); 143 bool Fill_Sort_Shrink_and_Check();
150 bool Check();
151}; 144};
152 145
153 146
diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h
index b7e07d1..8f24ed7 100644
--- a/CPP/7zip/Archive/Cab/CabItem.h
+++ b/CPP/7zip/Archive/Cab/CabItem.h
@@ -28,14 +28,17 @@ struct CItem
28 UInt32 Offset; 28 UInt32 Offset;
29 UInt32 Size; 29 UInt32 Size;
30 UInt32 Time; 30 UInt32 Time;
31 UInt32 FolderIndex; 31 unsigned FolderIndex;
32 UInt16 Flags; 32 UInt16 Flags;
33 UInt16 Attributes; 33 UInt16 Attributes;
34 34
35 UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } 35 UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
36 UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; } 36 /* v26.03: we show all items as files, as original cab extracting software does.
37 Also we disable FILE_ATTRIBUTE_DIRECTORY in GetWinAttrib(), because some client
38 software of 7zip still can parse FILE_ATTRIBUTE_DIRECTORY flag from returned Attributes. */
39 UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~((UInt32)NHeader::kFileNameIsUtf8_Mask | (UInt32)FILE_ATTRIBUTE_DIRECTORY); }
37 bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; } 40 bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; }
38 bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } 41 // bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; }
39 42
40 bool ContinuedFromPrev() const 43 bool ContinuedFromPrev() const
41 { 44 {
@@ -43,21 +46,21 @@ struct CItem
43 FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev || 46 FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev ||
44 FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; 47 FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext;
45 } 48 }
46 49 // in: (numFolders > 0) is expected
47 bool ContinuedToNext() const 50 // out: (returned_value >= 0) is expected
48 {
49 return
50 FolderIndex == NHeader::NFolderIndex::kContinuedToNext ||
51 FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext;
52 }
53
54 int GetFolderIndex(unsigned numFolders) const 51 int GetFolderIndex(unsigned numFolders) const
55 { 52 {
56 if (ContinuedFromPrev()) 53 const unsigned folderIndex = FolderIndex;
57 return 0; 54 switch (folderIndex)
58 if (ContinuedToNext()) 55 {
59 return (int)numFolders - 1; 56 case NHeader::NFolderIndex::kContinuedFromPrev:
60 return (int)FolderIndex; 57 case NHeader::NFolderIndex::kContinuedPrevAndNext:
58 return 0;
59 case NHeader::NFolderIndex::kContinuedToNext:
60 return (int)numFolders - 1;
61 default:
62 return (int)folderIndex;
63 }
61 } 64 }
62}; 65};
63 66
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
index 5bbdf07..7706e5d 100644
--- a/CPP/7zip/Archive/ComHandler.cpp
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -579,7 +579,7 @@ HRESULT CDatabase::Check_Item(unsigned index)
579 const unsigned subBits = SectorSizeBits - k_MiniSectorSizeBits; 579 const unsigned subBits = SectorSizeBits - k_MiniSectorSizeBits;
580 const UInt32 fid = sid >> subBits; 580 const UInt32 fid = sid >> subBits;
581 if (fid >= NumSectors_in_MiniStream) 581 if (fid >= NumSectors_in_MiniStream)
582 return false; 582 return S_FALSE;
583 sid = Mat[sid]; 583 sid = Mat[sid];
584 if (size <= clusterSize) 584 if (size <= clusterSize)
585 break; 585 break;
@@ -887,12 +887,16 @@ HRESULT CDatabase::Open(IInStream *inStream)
887 } 887 }
888 else if (item.IsStorage()) 888 else if (item.IsStorage())
889 { 889 {
890 if (item.Size != 0) // by specification 890 /* some old compound archives don't comply specification for (Size) and (Sid) fields for kStorage items.
891 return S_FALSE; 891 But original Windows code ignores these errors.
892 if (item.Sid != 0 // by specification 892 We also ignore these errors: */
893#if 0
894 if (item.Size != 0 // by specification
895 || ( item.Sid != 0 // by specification
893 && item.Sid != NFatID::kFree // NFatID::kFree is used in some AAF files 896 && item.Sid != NFatID::kFree // NFatID::kFree is used in some AAF files
894 && item.Sid != NFatID::kEndOfChain) // NFatID::kEndOfChain is used in QuickSet (selinc) file 897 && item.Sid != NFatID::kEndOfChain)) // NFatID::kEndOfChain is used in QuickSet (selinc) file
895 return S_FALSE; 898 HeadersWarning = true;
899#endif
896 } 900 }
897 // else if (item.Type == NItemType::kRootStorage) return S_FALSE; 901 // else if (item.Type == NItemType::kRootStorage) return S_FALSE;
898 else if (item.IsEmptyType()) 902 else if (item.IsEmptyType())
@@ -1375,9 +1379,10 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
1375 const unsigned subBits = _db.SectorSizeBits - k_MiniSectorSizeBits; 1379 const unsigned subBits = _db.SectorSizeBits - k_MiniSectorSizeBits;
1376 const UInt32 fid = sid >> subBits; 1380 const UInt32 fid = sid >> subBits;
1377 if (fid >= _db.NumSectors_in_MiniStream) 1381 if (fid >= _db.NumSectors_in_MiniStream)
1378 return false; 1382 return S_FALSE;
1383 const UInt32 temp = ((sid & ((1u << subBits) - 1)) << k_MiniSectorSizeBits);
1379 const UInt64 offset = (((UInt64)_db.MiniSids[fid] + 1) << _db.SectorSizeBits) + 1384 const UInt64 offset = (((UInt64)_db.MiniSids[fid] + 1) << _db.SectorSizeBits) +
1380 ((sid & ((1u << subBits) - 1)) << k_MiniSectorSizeBits); 1385 temp;
1381 if (phyPos != offset) 1386 if (phyPos != offset)
1382 { 1387 {
1383 RINOK(InStream_SeekSet(_stream, offset)) 1388 RINOK(InStream_SeekSet(_stream, offset))
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 5a11e30..58770f8 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -98,7 +98,7 @@ bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIAN
98 98
99 if (name.IsPrefixedBy_Ascii_NoCase("memuse")) 99 if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
100 { 100 {
101 UInt64 v; 101 UInt64 v = 0;
102 if (!ParseSizeString(name.Ptr(6), value, _memAvail, v)) 102 if (!ParseSizeString(name.Ptr(6), value, _memAvail, v))
103 hres = E_INVALIDARG; 103 hres = E_INVALIDARG;
104 _memUsage_Decompress = v; 104 _memUsage_Decompress = v;
diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp
index d379373..27ae94e 100644
--- a/CPP/7zip/Archive/ExtHandler.cpp
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -2167,9 +2167,9 @@ public:
2167 _curRem = 0; 2167 _curRem = 0;
2168 _virtPos = 0; 2168 _virtPos = 0;
2169 _physPos = 0; 2169 _physPos = 0;
2170 if (Vector.Size() > 0) 2170 if (Vector.Size())
2171 { 2171 {
2172 _physPos = (Vector[0] << BlockBits); 2172 _physPos = (UInt64)Vector[0] << BlockBits;
2173 return SeekToPhys(); 2173 return SeekToPhys();
2174 } 2174 }
2175 return S_OK; 2175 return S_OK;
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index 18fce91..7a0774c 100644
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -497,7 +497,8 @@ HRESULT CDatabase::OpenProgressFat(bool changeTotal)
497 return S_OK; 497 return S_OK;
498 if (changeTotal) 498 if (changeTotal)
499 { 499 {
500 const UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + 500 const UInt32 fatBytes = Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
501 const UInt64 numTotalBytes = fatBytes +
501 ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); 502 ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog);
502 RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)) 503 RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes))
503 } 504 }
@@ -938,7 +939,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
938 CClusterInStream *streamSpec = new CClusterInStream; 939 CClusterInStream *streamSpec = new CClusterInStream;
939 CMyComPtr<ISequentialInStream> streamTemp = streamSpec; 940 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
940 streamSpec->Stream = InStream; 941 streamSpec->Stream = InStream;
941 streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog; 942 streamSpec->StartOffset = (UInt64)Header.DataSector << Header.SectorSizeLog;
942 streamSpec->BlockSizeLog = Header.ClusterSizeLog; 943 streamSpec->BlockSizeLog = Header.ClusterSizeLog;
943 streamSpec->Size = item.Size; 944 streamSpec->Size = item.Size;
944 945
diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp
index ca9d246..9c85bf3 100644
--- a/CPP/7zip/Archive/GzHandler.cpp
+++ b/CPP/7zip/Archive/GzHandler.cpp
@@ -838,8 +838,6 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
838 838
839 // outStream.Release(); 839 // outStream.Release();
840 840
841 retResult = NExtract::NOperationResult::kDataError;
842
843 if (!_isArc) 841 if (!_isArc)
844 retResult = NExtract::NOperationResult::kIsNotArc; 842 retResult = NExtract::NOperationResult::kIsNotArc;
845 else if (_needMoreInput) 843 else if (_needMoreInput)
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
index 5df00ed..1d6492e 100644
--- a/CPP/7zip/Archive/HfsHandler.cpp
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -1429,7 +1429,10 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
1429 const unsigned sector_of_FirstBlock = Get16a(p + 0x1c); // drAlBlSt : first allocation block in volume 1429 const unsigned sector_of_FirstBlock = Get16a(p + 0x1c); // drAlBlSt : first allocation block in volume
1430 const UInt32 startBlock = Get16a(p + 0x7c + 2); 1430 const UInt32 startBlock = Get16a(p + 0x7c + 2);
1431 const UInt32 blockCount = Get16a(p + 0x7c + 4); 1431 const UInt32 blockCount = Get16a(p + 0x7c + 4);
1432 SpecOffset = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here 1432 {
1433 const UInt32 temp = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here
1434 SpecOffset = temp;
1435 }
1433 PhySize2 = SpecOffset + (UInt64)numBlocks * blockSize; 1436 PhySize2 = SpecOffset + (UInt64)numBlocks * blockSize;
1434 SpecOffset += (UInt64)startBlock * blockSize; 1437 SpecOffset += (UInt64)startBlock * blockSize;
1435 // before v24.09: // SpecOffset = (UInt64)(1 + startBlock) * blockSize; 1438 // before v24.09: // SpecOffset = (UInt64)(1 + startBlock) * blockSize;
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp
index c085386..20937bb 100644
--- a/CPP/7zip/Archive/Iso/IsoHandler.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -51,12 +51,12 @@ IMP_IInArchive_ArcProps
51 51
52Z7_COM7F_IMF(CHandler::Open(IInStream *stream, 52Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
53 const UInt64 * /* maxCheckStartPosition */, 53 const UInt64 * /* maxCheckStartPosition */,
54 IArchiveOpenCallback * /* openArchiveCallback */)) 54 IArchiveOpenCallback *openCallback))
55{ 55{
56 COM_TRY_BEGIN 56 COM_TRY_BEGIN
57 Close(); 57 Close();
58 { 58 {
59 RINOK(_archive.Open(stream)) 59 RINOK(_archive.Open(stream, openCallback))
60 _stream = stream; 60 _stream = stream;
61 } 61 }
62 return S_OK; 62 return S_OK;
@@ -165,6 +165,8 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
165 AddErrorMessage(s, "Self-linked directory"); 165 AddErrorMessage(s, "Self-linked directory");
166 if (_archive.TooDeepDirs) 166 if (_archive.TooDeepDirs)
167 AddErrorMessage(s, "Too deep directory levels"); 167 AddErrorMessage(s, "Too deep directory levels");
168 if (_archive.TooBigMetadata)
169 AddErrorMessage(s, "Too big headers");
168 if (!s.IsEmpty()) 170 if (!s.IsEmpty())
169 prop = s; 171 prop = s;
170 break; 172 break;
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
index 0054abf..b775dfc 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.cpp
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -94,7 +94,8 @@ Byte CInArchive::ReadByte()
94 throw CSystemException(res); 94 throw CSystemException(res);
95 if (processed != kBlockSize) 95 if (processed != kBlockSize)
96 throw CUnexpectedEndException(); 96 throw CUnexpectedEndException();
97 UInt64 end = _position + processed; 97 _processedBytes += processed;
98 const UInt64 end = _position + processed;
98 if (PhySize < end) 99 if (PhySize < end)
99 PhySize = end; 100 PhySize = end;
100 } 101 }
@@ -172,22 +173,30 @@ UInt32 CInArchive::ReadUInt32()
172 return val; 173 return val;
173} 174}
174 175
175UInt32 CInArchive::ReadDigits(int numDigits) 176unsigned CInArchive::ReadDigits(unsigned numDigits)
176{ 177{
177 UInt32 res = 0; 178 unsigned res = 0;
178 for (int i = 0; i < numDigits; i++) 179 unsigned mode = 0;
180 for (unsigned i = 0; i < numDigits; i++)
179 { 181 {
180 Byte b = ReadByte(); 182 const Byte b = ReadByte();
181 if (b < '0' || b > '9') 183 if (mode == 2)
184 continue;
185 const unsigned d = (unsigned)b - (unsigned)'0';
186 if (d > 9)
182 { 187 {
183 if (b == 0 || b == ' ') // it's bug in some CD's 188 // what exact cases are possible here?
184 b = '0'; 189 if (b != 0 && b != ' ')
185 else
186 throw CHeaderErrorException(); 190 throw CHeaderErrorException();
191 if (mode == 1)
192 mode = 2;
193 }
194 else
195 {
196 mode = 1;
197 res *= 10;
198 res += d;
187 } 199 }
188 UInt32 d = (UInt32)(b - '0');
189 res *= 10;
190 res += d;
191 } 200 }
192 return res; 201 return res;
193} 202}
@@ -222,7 +231,7 @@ void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t)
222 t.GmtOffset = (signed char)ReadByte(); 231 t.GmtOffset = (signed char)ReadByte();
223} 232}
224 233
225void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) 234void CInArchive::ReadDirRecord(CDirRecord &r, unsigned len, bool isJolietDescriptor)
226{ 235{
227 r.ExtendedAttributeRecordLen = ReadByte(); 236 r.ExtendedAttributeRecordLen = ReadByte();
228 if (r.ExtendedAttributeRecordLen != 0) 237 if (r.ExtendedAttributeRecordLen != 0)
@@ -234,29 +243,28 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
234 r.FileUnitSize = ReadByte(); 243 r.FileUnitSize = ReadByte();
235 r.InterleaveGapSize = ReadByte(); 244 r.InterleaveGapSize = ReadByte();
236 r.VolSequenceNumber = ReadUInt16(); 245 r.VolSequenceNumber = ReadUInt16();
237 Byte idLen = ReadByte(); 246 unsigned idLen = ReadByte();
247 /* for Descriptor Root Directory Record:
248 idLen == 1 : by ISO Specification
249 idLen == 1 : for some Joliet archives
250 idLen == 2 : for some Joliet archives for UCS-2 (UTF-16BE).
251 but (len == 34) is fixed for Descriptor Root Directory Record
252 so we ignore idLen == 2 value in Joliet Descriptor.
253 */
254 if (isJolietDescriptor && idLen == 2) // v26.03 : we support Joliet cases
255 idLen = 0;
238 r.FileId.Alloc(idLen); 256 r.FileId.Alloc(idLen);
239 ReadBytes((Byte *)r.FileId, idLen); 257 ReadBytes((Byte *)r.FileId, idLen);
240 unsigned padSize = 1 - (idLen & 1); 258 idLen += 33;
241 259 const unsigned padSize = idLen & 1;
242 // SkipZeros(padSize); 260 // SkipZeros(padSize);
243 Skip(padSize); // it's bug in some cd's. Must be zeros 261 Skip(padSize); // it's bug in some cd's. Must be zeros
244 262 idLen += padSize;
245 unsigned curPos = 33 + idLen + padSize; 263 if (len < idLen)
246 if (curPos > len)
247 throw CHeaderErrorException(); 264 throw CHeaderErrorException();
248 unsigned rem = len - curPos; 265 len -= idLen;
249 r.SystemUse.Alloc(rem); 266 r.SystemUse.Alloc(len);
250 ReadBytes((Byte *)r.SystemUse, rem); 267 ReadBytes((Byte *)r.SystemUse, len);
251}
252
253void CInArchive::ReadDirRecord(CDirRecord &r)
254{
255 Byte len = ReadByte();
256 // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor.
257 // But maybe we must use real "len" for other records.
258 len = 34;
259 ReadDirRecord2(r, len);
260} 268}
261 269
262void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d) 270void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
@@ -275,7 +283,16 @@ void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
275 d.LOptionalPathTableLocation = ReadUInt32Le(); 283 d.LOptionalPathTableLocation = ReadUInt32Le();
276 d.MPathTableLocation = ReadUInt32Be(); 284 d.MPathTableLocation = ReadUInt32Be();
277 d.MOptionalPathTableLocation = ReadUInt32Be(); 285 d.MOptionalPathTableLocation = ReadUInt32Be();
278 ReadDirRecord(d.RootDirRecord); 286 {
287 unsigned len;
288 /* len = */ ReadByte();
289 // len == 34 is expected by ISO specification
290 // len == 36 is possible for some Joliet archives
291 // len == 48 is possible for Rock Ridge?
292 len = 34; // we ignore (len) value from header because
293 // next field (VolumeSetId) always starts after 34 bytes
294 ReadDirRecord(d.RootDirRecord, len, d.IsJoliet());
295 }
279 ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId)); 296 ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId));
280 ReadBytes(d.PublisherId, sizeof(d.PublisherId)); 297 ReadBytes(d.PublisherId, sizeof(d.PublisherId));
281 ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId)); 298 ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId));
@@ -330,16 +347,16 @@ void CInArchive::SeekToBlock(UInt32 blockIndex)
330 m_BufferPos = 0; 347 m_BufferPos = 0;
331} 348}
332 349
333static const int kNumLevelsMax = 256; 350static const unsigned kNumLevelsMax = 256;
334 351
335void CInArchive::ReadDir(CDir &d, int level) 352HRESULT CInArchive::ReadDir(CDir &d, unsigned level)
336{ 353{
337 if (!d.IsDir()) 354 if (!d.IsDir())
338 return; 355 return S_OK;
339 if (level > kNumLevelsMax) 356 if (level > kNumLevelsMax)
340 { 357 {
341 TooDeepDirs = true; 358 TooDeepDirs = true;
342 return; 359 return S_OK;
343 } 360 }
344 361
345 { 362 {
@@ -347,7 +364,7 @@ void CInArchive::ReadDir(CDir &d, int level)
347 if (UniqStartLocations[i] == d.ExtentLocation) 364 if (UniqStartLocations[i] == d.ExtentLocation)
348 { 365 {
349 SelfLinkedDirs = true; 366 SelfLinkedDirs = true;
350 return; 367 return S_OK;
351 } 368 }
352 UniqStartLocations.Add(d.ExtentLocation); 369 UniqStartLocations.Add(d.ExtentLocation);
353 } 370 }
@@ -358,26 +375,47 @@ void CInArchive::ReadDir(CDir &d, int level)
358 bool firstItem = true; 375 bool firstItem = true;
359 for (;;) 376 for (;;)
360 { 377 {
361 UInt64 offset = _position - startPos; 378 const UInt64 offset = _position - startPos;
362 if (offset >= d.Size) 379 if (offset >= d.Size)
363 break; 380 break;
364 Byte len = ReadByte(); 381 const unsigned len = ReadByte();
365 if (len == 0) 382 if (len == 0)
366 continue; 383 continue;
367 CDir subItem; 384 CDir subItem;
368 ReadDirRecord2(subItem, len); 385 ReadDirRecord(subItem, len);
369 if (firstItem && level == 0) 386 if (firstItem && level == 0)
370 IsSusp = subItem.CheckSusp(SuspSkipSize); 387 IsSusp = subItem.CheckSusp(SuspSkipSize);
371 388
372 if (!subItem.IsSystemItem()) 389 if (!subItem.IsSystemItem())
390 {
391 if (_numFiles >= (1u << 30))
392 {
393 TooBigMetadata = true; // Too many files
394 return S_FALSE;
395 }
373 d._subItems.Add(subItem); 396 d._subItems.Add(subItem);
397 _numFiles++;
398 }
374 399
400 if (_openCallback && _processedBytes - _processedBytes_prev >= (1 << 24))
401 {
402 _processedBytes_prev = _processedBytes;
403 RINOK(_openCallback->SetTotal(&_numFiles, &_processedBytes))
404 }
405 if (_processedBytes > _fileSize + (1u << 24))
406 {
407 TooBigMetadata = true;
408 return S_FALSE;
409 }
375 firstItem = false; 410 firstItem = false;
376 } 411 }
377 FOR_VECTOR (i, d._subItems) 412 FOR_VECTOR (i, d._subItems)
378 ReadDir(d._subItems[i], level + 1); 413 {
414 RINOK(ReadDir(d._subItems[i], level + 1))
415 }
379 416
380 UniqStartLocations.DeleteBack(); 417 UniqStartLocations.DeleteBack();
418 return S_OK;
381} 419}
382 420
383void CInArchive::CreateRefs(CDir &d) 421void CInArchive::CreateRefs(CDir &d)
@@ -614,7 +652,7 @@ HRESULT CInArchive::Open2()
614 IsArc = true; 652 IsArc = true;
615 653
616 (CDirRecord &)_rootDir = vd.RootDirRecord; 654 (CDirRecord &)_rootDir = vd.RootDirRecord;
617 ReadDir(_rootDir, 0); 655 RINOK(ReadDir(_rootDir, 0))
618 CreateRefs(_rootDir); 656 CreateRefs(_rootDir);
619 ReadBootInfo(); 657 ReadBootInfo();
620 658
@@ -671,10 +709,12 @@ HRESULT CInArchive::Open2()
671 return S_OK; 709 return S_OK;
672} 710}
673 711
674HRESULT CInArchive::Open(IInStream *inStream) 712HRESULT CInArchive::Open(IInStream *inStream, IArchiveOpenCallback *openCallback)
675{ 713{
676 Clear(); 714 Clear();
677 _stream = inStream; 715 _stream = inStream;
716 _openCallback = openCallback;
717 _numFiles = _processedBytes = _processedBytes_prev = 0;
678 try { return Open2(); } 718 try { return Open2(); }
679 catch(const CSystemException &e) { return e.ErrorCode; } 719 catch(const CSystemException &e) { return e.ErrorCode; }
680 catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } 720 catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
@@ -689,6 +729,7 @@ void CInArchive::Clear()
689 HeadersError = false; 729 HeadersError = false;
690 IncorrectBigEndian = false; 730 IncorrectBigEndian = false;
691 TooDeepDirs = false; 731 TooDeepDirs = false;
732 TooBigMetadata = false;
692 SelfLinkedDirs = false; 733 SelfLinkedDirs = false;
693 734
694 UniqStartLocations.Clear(); 735 UniqStartLocations.Clear();
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
index e7d1fee..6a031ba 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.h
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -237,14 +237,12 @@ struct CRef
237 UInt64 TotalSize; 237 UInt64 TotalSize;
238}; 238};
239 239
240const UInt32 kBlockSize = 1 << 11; 240const unsigned kBlockSize = 1 << 11;
241 241
242class CInArchive 242class CInArchive
243{ 243{
244 IInStream *_stream;
245 UInt64 _position; 244 UInt64 _position;
246 245 unsigned m_BufferPos;
247 UInt32 m_BufferPos;
248 246
249 void Skip(size_t size); 247 void Skip(size_t size);
250 void SkipZeros(size_t size); 248 void SkipZeros(size_t size);
@@ -255,23 +253,22 @@ class CInArchive
255 UInt32 ReadUInt32Be(); 253 UInt32 ReadUInt32Be();
256 UInt32 ReadUInt32(); 254 UInt32 ReadUInt32();
257 UInt64 ReadUInt64(); 255 UInt64 ReadUInt64();
258 UInt32 ReadDigits(int numDigits); 256 unsigned ReadDigits(unsigned numDigits);
259 void ReadDateTime(CDateTime &d); 257 void ReadDateTime(CDateTime &d);
260 void ReadRecordingDateTime(CRecordingDateTime &t); 258 void ReadRecordingDateTime(CRecordingDateTime &t);
261 void ReadDirRecord2(CDirRecord &r, Byte len); 259 void ReadDirRecord(CDirRecord &r, unsigned len, bool isJolietDescriptor = false);
262 void ReadDirRecord(CDirRecord &r);
263 260
264 void ReadBootRecordDescriptor(CBootRecordDescriptor &d); 261 void ReadBootRecordDescriptor(CBootRecordDescriptor &d);
265 void ReadVolumeDescriptor(CVolumeDescriptor &d); 262 void ReadVolumeDescriptor(CVolumeDescriptor &d);
266 263
267 void SeekToBlock(UInt32 blockIndex); 264 void SeekToBlock(UInt32 blockIndex);
268 void ReadDir(CDir &d, int level); 265 HRESULT ReadDir(CDir &d, unsigned level);
269 void CreateRefs(CDir &d); 266 void CreateRefs(CDir &d);
270 267
271 void ReadBootInfo(); 268 void ReadBootInfo();
272 HRESULT Open2(); 269 HRESULT Open2();
273public: 270public:
274 HRESULT Open(IInStream *inStream); 271 HRESULT Open(IInStream *inStream, IArchiveOpenCallback *openCallback);
275 void Clear(); 272 void Clear();
276 273
277 UInt64 _fileSize; 274 UInt64 _fileSize;
@@ -291,10 +288,12 @@ public:
291 bool HeadersError; 288 bool HeadersError;
292 bool IncorrectBigEndian; 289 bool IncorrectBigEndian;
293 bool TooDeepDirs; 290 bool TooDeepDirs;
291 bool TooBigMetadata;
294 bool SelfLinkedDirs; 292 bool SelfLinkedDirs;
295 bool IsSusp; 293 bool IsSusp;
296 unsigned SuspSkipSize; 294 unsigned SuspSkipSize;
297 295
296private:
298 int _expand_BootEntries_index; 297 int _expand_BootEntries_index;
299 298
300 CRecordVector<UInt32> UniqStartLocations; 299 CRecordVector<UInt32> UniqStartLocations;
@@ -307,12 +306,19 @@ public:
307 PhySize = end; 306 PhySize = end;
308 } 307 }
309 308
309public:
310 bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } 310 bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
311 311
312 UInt64 GetBootItemSize(unsigned index) const; 312 UInt64 GetBootItemSize(unsigned index) const;
313 313
314private: 314private:
315 CDir _rootDir; 315 CDir _rootDir;
316 IInStream *_stream;
317 IArchiveOpenCallback *_openCallback;
318 UInt64 _numFiles;
319 UInt64 _processedBytes;
320 UInt64 _processedBytes_prev;
321
316 Byte m_Buffer[kBlockSize]; 322 Byte m_Buffer[kBlockSize];
317 CBootRecordDescriptor _bootDesc; 323 CBootRecordDescriptor _bootDesc;
318}; 324};
diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h
index 65829d0..ef3832a 100644
--- a/CPP/7zip/Archive/Iso/IsoItem.h
+++ b/CPP/7zip/Archive/Iso/IsoItem.h
@@ -81,8 +81,7 @@ struct CDirRecord
81 bool AreMultiPartEqualWith(const CDirRecord &a) const 81 bool AreMultiPartEqualWith(const CDirRecord &a) const
82 { 82 {
83 return FileId == a.FileId 83 return FileId == a.FileId
84 && (FileFlags & (~NFileFlags::kNonFinalExtent)) == 84 && ((FileFlags ^ a.FileFlags) & ~NFileFlags::kNonFinalExtent) == 0;
85 (a.FileFlags & (~NFileFlags::kNonFinalExtent));
86 } 85 }
87 86
88 bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; } 87 bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; }
@@ -90,10 +89,7 @@ struct CDirRecord
90 89
91 bool IsSystemItem() const 90 bool IsSystemItem() const
92 { 91 {
93 if (FileId.Size() != 1) 92 return FileId.Size() == 1 && *(const Byte *)FileId < 2;
94 return false;
95 Byte b = *(const Byte *)FileId;
96 return (b == 0 || b == 1);
97 } 93 }
98 94
99 95
diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp
index 7cbabf4..a0c5021 100644
--- a/CPP/7zip/Archive/LzmaHandler.cpp
+++ b/CPP/7zip/Archive/LzmaHandler.cpp
@@ -185,7 +185,7 @@ Z7_CLASS_IMP_CHandler_IInArchive_1(
185 UInt64 _unpackSize; 185 UInt64 _unpackSize;
186 UInt64 _numStreams; 186 UInt64 _numStreams;
187 187
188 void GetMethod(NCOM::CPropVariant &prop); 188 void GetMethod(NCOM::CPropVariant &prop) const;
189 189
190 unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); } 190 unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); }
191public: 191public:
@@ -249,7 +249,7 @@ static char *AddProp32(char *s, const char *name, UInt32 v)
249 return ::ConvertUInt32ToString(v, s); 249 return ::ConvertUInt32ToString(v, s);
250} 250}
251 251
252void CHandler::GetMethod(NCOM::CPropVariant &prop) 252void CHandler::GetMethod(NCOM::CPropVariant &prop) const
253{ 253{
254 if (!_stream) 254 if (!_stream)
255 return; 255 return;
@@ -270,7 +270,7 @@ void CHandler::GetMethod(NCOM::CPropVariant &prop)
270 UInt32 lp = d % 5; 270 UInt32 lp = d % 5;
271 if (lc != 3) s = AddProp32(s, "lc", lc); 271 if (lc != 3) s = AddProp32(s, "lc", lc);
272 if (lp != 0) s = AddProp32(s, "lp", lp); 272 if (lp != 0) s = AddProp32(s, "lp", lp);
273 if (pb != 2) s = AddProp32(s, "pb", pb); 273 if (pb != 2) /* s = */ AddProp32(s, "pb", pb);
274 } 274 }
275 prop = sz; 275 prop = sz;
276} 276}
@@ -568,9 +568,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
568 opResult = NExtract::NOperationResult::kDataAfterEnd; 568 opResult = NExtract::NOperationResult::kDataAfterEnd;
569 else if (hres == S_FALSE) 569 else if (hres == S_FALSE)
570 opResult = NExtract::NOperationResult::kDataError; 570 opResult = NExtract::NOperationResult::kDataError;
571 else if (hres == S_OK) 571 else if (hres != S_OK)
572 opResult = NExtract::NOperationResult::kOK;
573 else
574 return hres; 572 return hres;
575 573
576 // outStream.Release(); 574 // outStream.Release();
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
index 7ce2e8e..d17dca7 100644
--- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
@@ -148,7 +148,17 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
148 prop = v; 148 prop = v;
149 break; 149 break;
150 } 150 }
151 151 case kpidWarningFlags:
152 {
153 UInt32 flags = 0;
154 if (_archive.CREATEDIR_processing_WasStopped
155 || _archive.FILENAME_processing_WasStopped)
156 flags |= kpv_ErrorFlags_HeadersError;
157 if (flags != 0)
158 prop = flags;
159 break;
160 }
161
152 case kpidName: 162 case kpidName:
153 { 163 {
154 AString s; 164 AString s;
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp
index 577062e..b6ff749 100644
--- a/CPP/7zip/Archive/Nsis/NsisIn.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -17,6 +17,8 @@
17namespace NArchive { 17namespace NArchive {
18namespace NNsis { 18namespace NNsis {
19 19
20struct CInArchiveException {};
21
20static const size_t kInputBufSize = 1 << 20; 22static const size_t kInputBufSize = 1 << 20;
21 23
22const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; 24const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE;
@@ -591,7 +593,7 @@ void CInArchive::GetVar2(AString &res, UInt32 index)
591 { 593 {
592 if (index >= 10) 594 if (index >= 10)
593 { 595 {
594 res += 'R'; 596 res.Add_Char('R');
595 index -= 10; 597 index -= 10;
596 } 598 }
597 UIntToString(res, index); 599 UIntToString(res, index);
@@ -607,16 +609,16 @@ void CInArchive::GetVar2(AString &res, UInt32 index)
607 } 609 }
608 else 610 else
609 { 611 {
610 res += '_'; 612 res.Add_Char('_');
611 UIntToString(res, index - numInternalVars); 613 UIntToString(res, index - numInternalVars);
612 res += '_'; 614 res.Add_Char('_');
613 } 615 }
614 } 616 }
615} 617}
616 618
617void CInArchive::GetVar(AString &res, UInt32 index) 619void CInArchive::GetVar(AString &res, UInt32 index)
618{ 620{
619 res += '$'; 621 res.Add_Char('$');
620 GetVar2(res, index); 622 GetVar2(res, index);
621} 623}
622 624
@@ -737,7 +739,7 @@ void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2)
737 739
738 if (id < 0) 740 if (id < 0)
739 { 741 {
740 s += '('; 742 s.Add_Char('(');
741 if (IsUnicode) 743 if (IsUnicode)
742 { 744 {
743 for (unsigned i = 0; i < 256; i++) 745 for (unsigned i = 0; i < 256; i++)
@@ -751,12 +753,12 @@ void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2)
751 } 753 }
752 else 754 else
753 s += (const char *)p; 755 s += (const char *)p;
754 s += ')'; 756 s.Add_Char(')');
755 } 757 }
756 return; 758 return;
757 } 759 }
758 760
759 s += '$'; 761 s.Add_Char('$');
760 if (index1 < Z7_ARRAY_SIZE(kShellStrings)) 762 if (index1 < Z7_ARRAY_SIZE(kShellStrings))
761 { 763 {
762 const char *sz = kShellStrings[index1]; 764 const char *sz = kShellStrings[index1];
@@ -776,11 +778,11 @@ void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2)
776 } 778 }
777 } 779 }
778 s += "_ERROR_UNSUPPORTED_SHELL_"; 780 s += "_ERROR_UNSUPPORTED_SHELL_";
779 s += '['; 781 s.Add_Char('[');
780 UIntToString(s, index1); 782 UIntToString(s, index1);
781 s += ','; 783 s.Add_Char(',');
782 UIntToString(s, index2); 784 UIntToString(s, index2);
783 s += ']'; 785 s.Add_Char(']');
784} 786}
785 787
786#ifdef NSIS_SCRIPT 788#ifdef NSIS_SCRIPT
@@ -800,9 +802,16 @@ void CInArchive::Add_LangStr(AString &res, UInt32 id)
800 #endif 802 #endif
801 res += "$(LSTR_"; 803 res += "$(LSTR_";
802 UIntToString(res, id); 804 UIntToString(res, id);
803 res += ')'; 805 res.Add_Char(')');
804} 806}
805 807
808static const unsigned k_StringLen_Limit = 1 << 16;
809
810#define CHECK_STRING_LEN(s) \
811 { if (s.Len() >= k_StringLen_Limit) \
812 { /* s = "[LONG_PATH]"; return; */ throw CInArchiveException(); } }
813
814
806void CInArchive::GetNsisString_Raw(const Byte *s) 815void CInArchive::GetNsisString_Raw(const Byte *s)
807{ 816{
808 Raw_AString.Empty(); 817 Raw_AString.Empty();
@@ -811,6 +820,7 @@ void CInArchive::GetNsisString_Raw(const Byte *s)
811 { 820 {
812 for (;;) 821 for (;;)
813 { 822 {
823 CHECK_STRING_LEN(Raw_AString)
814 Byte c = *s++; 824 Byte c = *s++;
815 if (c == 0) 825 if (c == 0)
816 return; 826 return;
@@ -846,6 +856,7 @@ void CInArchive::GetNsisString_Raw(const Byte *s)
846 // NSIS-3 ANSI 856 // NSIS-3 ANSI
847 for (;;) 857 for (;;)
848 { 858 {
859 CHECK_STRING_LEN(Raw_AString)
849 Byte c = *s++; 860 Byte c = *s++;
850 if (c <= NS_3_CODE_SKIP) 861 if (c <= NS_3_CODE_SKIP)
851 { 862 {
@@ -973,6 +984,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p)
973 { 984 {
974 for (;;) 985 for (;;)
975 { 986 {
987 CHECK_STRING_LEN(Raw_UString)
976 unsigned c = Get16(p); 988 unsigned c = Get16(p);
977 p += 2; 989 p += 2;
978 if (c == 0) 990 if (c == 0)
@@ -1017,6 +1029,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p)
1017 // NSIS-3 Unicode 1029 // NSIS-3 Unicode
1018 for (;;) 1030 for (;;)
1019 { 1031 {
1032 CHECK_STRING_LEN(Raw_UString)
1020 unsigned c = Get16(p); 1033 unsigned c = Get16(p);
1021 p += 2; 1034 p += 2;
1022 if (c > NS_3_CODE_SKIP) 1035 if (c > NS_3_CODE_SKIP)
@@ -2124,7 +2137,7 @@ bool CInArchive::PrintSectionBegin(const CSection &sect, unsigned index)
2124{ 2137{
2125 AString name; 2138 AString name;
2126 if (sect.Flags & SF_BOLD) 2139 if (sect.Flags & SF_BOLD)
2127 name += '!'; 2140 name.Add_Char('!');
2128 AString s2; 2141 AString s2;
2129 ReadString2(s2, sect.Name); 2142 ReadString2(s2, sect.Name);
2130 if (!IsInstaller) 2143 if (!IsInstaller)
@@ -2330,9 +2343,9 @@ void CInArchive::MessageBox_MB_Part(UInt32 param)
2330static const Byte k_InitPluginDir_Commands[] = 2343static const Byte k_InitPluginDir_Commands[] =
2331 { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 }; 2344 { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 };
2332 2345
2333bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) 2346bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) const
2334{ 2347{
2335 for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) 2348 for (size_t kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize)
2336 if (GetCmd(Get32(rawCmds)) != sequence[kkk]) 2349 if (GetCmd(Get32(rawCmds)) != sequence[kkk])
2337 return false; 2350 return false;
2338 return true; 2351 return true;
@@ -2410,7 +2423,7 @@ unsigned CInArchive::GetNumSupportedCommands() const
2410 2423
2411#endif 2424#endif
2412 2425
2413UInt32 CInArchive::GetCmd(UInt32 a) 2426UInt32 CInArchive::GetCmd(UInt32 a) const
2414{ 2427{
2415 if (!IsPark()) 2428 if (!IsPark())
2416 { 2429 {
@@ -2875,21 +2888,58 @@ static bool IsAbsolutePath(const char *s)
2875 return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s); 2888 return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s);
2876} 2889}
2877 2890
2878void CInArchive::SetItemName(CItem &item, UInt32 strPos) 2891
2892static const unsigned k_PathLen_Small_Limit = 60 + 260 * 4; // we reserve some space for multibyte encoding and for prefix
2893static const unsigned k_PathLen_Break_Limit = 1 << 12; // must be >= k_PathLen_Small_Limit
2894
2895#define k_LONG_PATH_DIR "[LONG_PATH]"
2896#define k_UNKNOWN_PATH_DIR "[UNKNOWN_PATH]"
2897#define k_LONG_PATH_FILE "[LONG_PATH_FILE]"
2898#define k_UNKNOWN_PATH_FILE "[UNKNOWN_PATH_FILE]"
2899
2900void CInArchive::SetItemName(CItem &item, const UInt32 strPos)
2879{ 2901{
2880 ReadString2_Raw(strPos); 2902 item.Prefix = -1;
2881 const bool isAbs = IsAbsolutePathVar(strPos); 2903 if (FILENAME_processing_WasStopped)
2882 if (IsUnicode)
2883 { 2904 {
2884 item.NameU = Raw_UString; 2905 if (IsUnicode)
2885 if (!isAbs && !IsAbsolutePath(Raw_UString)) 2906 item.NameU = k_UNKNOWN_PATH_FILE;
2886 item.Prefix = (int)UPrefixes.Size() - 1; 2907 else
2908 item.NameA = k_UNKNOWN_PATH_FILE;
2887 } 2909 }
2888 else 2910 else
2889 { 2911 {
2890 item.NameA = Raw_AString; 2912 ReadString2_Raw(strPos);
2891 if (!isAbs && !IsAbsolutePath(Raw_AString)) 2913 const bool isAbs = IsAbsolutePathVar(strPos);
2892 item.Prefix = (int)APrefixes.Size() - 1; 2914 if (IsUnicode)
2915 {
2916 if (Raw_UString.Len() >= k_PathLen_Small_Limit)
2917 item.NameU = k_LONG_PATH_FILE;
2918 else
2919 {
2920 item.NameU = Raw_UString;
2921 if (!isAbs && !IsAbsolutePath(Raw_UString))
2922 item.Prefix = (int)UPrefixes.Size() - 1;
2923 }
2924 if (Raw_UString.Len() >= k_PathLen_Break_Limit)
2925 FILENAME_processing_WasStopped = true;
2926 }
2927 else
2928 {
2929 if (Raw_AString.Len() >= k_PathLen_Small_Limit)
2930 item.NameA = k_LONG_PATH_FILE;
2931 else
2932 {
2933 item.NameA = Raw_AString;
2934 if (!isAbs && !IsAbsolutePath(Raw_AString))
2935 item.Prefix = (int)APrefixes.Size() - 1;
2936 }
2937 if (Raw_AString.Len() >= k_PathLen_Break_Limit)
2938 FILENAME_processing_WasStopped = true;
2939 }
2940 _memUsage_Files += item.NameA.Len() + item.NameU.Len() * 2 + 128;
2941 if (_memUsage_Files >= (1 << 29))
2942 FILENAME_processing_WasStopped = true;
2893 } 2943 }
2894} 2944}
2895 2945
@@ -3387,14 +3437,14 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
3387 { 3437 {
3388 case EW_CREATEDIR: 3438 case EW_CREATEDIR:
3389 { 3439 {
3390 bool isSetOutPath = (params[1] != 0); 3440 const bool isSetOutPath = (params[1] != 0);
3391 3441
3392 if (isSetOutPath) 3442 if (isSetOutPath && !CREATEDIR_processing_WasStopped)
3393 { 3443 {
3394 UInt32 par0 = params[0]; 3444 UInt32 par0 = params[0];
3395 3445
3396 UInt32 resOffset; 3446 UInt32 resOffset;
3397 Int32 idx = GetVarIndex(par0, resOffset); 3447 const Int32 idx = GetVarIndex(par0, resOffset);
3398 if (idx == (Int32)spec_outdir_VarIndex || 3448 if (idx == (Int32)spec_outdir_VarIndex ||
3399 idx == kVar_OUTDIR) 3449 idx == kVar_OUTDIR)
3400 par0 += resOffset; 3450 par0 += resOffset;
@@ -3407,7 +3457,11 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
3407 Raw_UString.Insert(0, spec_outdir_U); 3457 Raw_UString.Insert(0, spec_outdir_U);
3408 else if (idx == kVar_OUTDIR) 3458 else if (idx == kVar_OUTDIR)
3409 Raw_UString.Insert(0, UPrefixes.Back()); 3459 Raw_UString.Insert(0, UPrefixes.Back());
3410 UPrefixes.Add(Raw_UString); 3460 if (Raw_UString.Len() >= k_PathLen_Break_Limit)
3461 CREATEDIR_processing_WasStopped = true;
3462 if (Raw_UString.Len() >= k_PathLen_Small_Limit)
3463 Raw_UString = k_LONG_PATH_DIR;
3464 _memUsage_Dirs += Raw_UString.Len() * 2;
3411 } 3465 }
3412 else 3466 else
3413 { 3467 {
@@ -3415,11 +3469,30 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
3415 Raw_AString.Insert(0, spec_outdir_A); 3469 Raw_AString.Insert(0, spec_outdir_A);
3416 else if (idx == kVar_OUTDIR) 3470 else if (idx == kVar_OUTDIR)
3417 Raw_AString.Insert(0, APrefixes.Back()); 3471 Raw_AString.Insert(0, APrefixes.Back());
3418 APrefixes.Add(Raw_AString); 3472 if (Raw_AString.Len() >= k_PathLen_Break_Limit)
3473 CREATEDIR_processing_WasStopped = true;
3474 if (Raw_AString.Len() >= k_PathLen_Small_Limit)
3475 Raw_AString = k_LONG_PATH_DIR;
3476 _memUsage_Dirs += Raw_AString.Len();
3477 }
3478 _memUsage_Dirs += 64;
3479 if (_memUsage_Dirs >= (1 << 25))
3480 {
3481 CREATEDIR_processing_WasStopped = true;
3482 if (IsUnicode)
3483 Raw_UString = k_UNKNOWN_PATH_DIR;
3484 else
3485 Raw_AString = k_UNKNOWN_PATH_DIR;
3419 } 3486 }
3487 if (IsUnicode)
3488 UPrefixes.Add(Raw_UString);
3489 else
3490 APrefixes.Add(Raw_AString);
3420 } 3491 }
3421 3492
3422 #ifdef NSIS_SCRIPT 3493 #ifdef NSIS_SCRIPT
3494 if (!s.IsError())
3495 {
3423 s += isSetOutPath ? "SetOutPath" : "CreateDirectory"; 3496 s += isSetOutPath ? "SetOutPath" : "CreateDirectory";
3424 AddParam(params[0]); 3497 AddParam(params[0]);
3425 if (params[2] != 0) // 2.51+ & 3.0b3+ 3498 if (params[2] != 0) // 2.51+ & 3.0b3+
@@ -3427,6 +3500,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
3427 SmallSpaceComment(); 3500 SmallSpaceComment();
3428 s += "CreateRestrictedDirectory"; 3501 s += "CreateRestrictedDirectory";
3429 } 3502 }
3503 }
3430 #endif 3504 #endif
3431 3505
3432 break; 3506 break;
@@ -5242,7 +5316,7 @@ HRESULT CInArchive::Parse()
5242 } 5316 }
5243 } 5317 }
5244 5318
5245 if (bhEntries.Num > (1 << 25)) 5319 if (bhEntries.Num > (1 << 24))
5246 return S_FALSE; 5320 return S_FALSE;
5247 if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) 5321 if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset)
5248 return S_FALSE; 5322 return S_FALSE;
@@ -5495,7 +5569,12 @@ HRESULT CInArchive::Parse()
5495 return E_NOTIMPL; // maybe it's old NSIS archive() 5569 return E_NOTIMPL; // maybe it's old NSIS archive()
5496 5570
5497 if (langtable_size < 10) 5571 if (langtable_size < 10)
5498 return S_FALSE; 5572 {
5573 // return S_FALSE;
5574 }
5575 else
5576 {
5577
5499 if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size) 5578 if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size)
5500 return S_FALSE; 5579 return S_FALSE;
5501 5580
@@ -5610,6 +5689,7 @@ HRESULT CInArchive::Parse()
5610 AddLF(); 5689 AddLF();
5611 } 5690 }
5612 ClearLangComment(); 5691 ClearLangComment();
5692 }
5613 } 5693 }
5614 5694
5615 { 5695 {
@@ -6077,6 +6157,7 @@ HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPositio
6077 DataStreamOffset -= pos; 6157 DataStreamOffset -= pos;
6078 res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize); 6158 res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize);
6079 } 6159 }
6160 catch(CInArchiveException &) { res = S_FALSE; }
6080 catch(...) 6161 catch(...)
6081 { 6162 {
6082 _stream.Release(); 6163 _stream.Release();
@@ -6112,6 +6193,10 @@ void CInArchive::Clear2()
6112 LogCmdIsEnabled = false; 6193 LogCmdIsEnabled = false;
6113 BadCmd = -1; 6194 BadCmd = -1;
6114 Is64Bit = false; 6195 Is64Bit = false;
6196 CREATEDIR_processing_WasStopped = false;
6197 FILENAME_processing_WasStopped = false;
6198 _memUsage_Dirs = 0;
6199 _memUsage_Files = 0;
6115 6200
6116 #ifdef NSIS_SCRIPT 6201 #ifdef NSIS_SCRIPT
6117 Name.Empty(); 6202 Name.Empty();
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h
index 1f8c967..772f13f 100644
--- a/CPP/7zip/Archive/Nsis/NsisIn.h
+++ b/CPP/7zip/Archive/Nsis/NsisIn.h
@@ -165,8 +165,11 @@ public:
165 #endif 165 #endif
166 CByteBuffer _data; 166 CByteBuffer _data;
167 CObjectVector<CItem> Items; 167 CObjectVector<CItem> Items;
168 bool IsArc;
168 bool IsUnicode; 169 bool IsUnicode;
169 bool Is64Bit; 170 bool Is64Bit;
171 bool CREATEDIR_processing_WasStopped;
172 bool FILENAME_processing_WasStopped;
170private: 173private:
171 UInt32 _stringsPos; // relative to _data 174 UInt32 _stringsPos; // relative to _data
172 UInt32 NumStringChars; 175 UInt32 NumStringChars;
@@ -217,13 +220,14 @@ private:
217 #endif 220 #endif
218 221
219 222
223 UInt32 _memUsage_Dirs;
224 UInt32 _memUsage_Files;
225
220public: 226public:
221 CMyComPtr<IInStream> _stream; // it's limited stream that contains only NSIS archive 227 CMyComPtr<IInStream> _stream; // it's limited stream that contains only NSIS archive
222 UInt64 StartOffset; // offset in original stream. 228 UInt64 StartOffset; // offset in original stream.
223 UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream 229 UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream
224 230
225 bool IsArc;
226
227 CDecoder Decoder; 231 CDecoder Decoder;
228 CByteBuffer ExeStub; 232 CByteBuffer ExeStub;
229 CFirstHeader FirstHeader; 233 CFirstHeader FirstHeader;
@@ -322,7 +326,7 @@ private:
322 void PrintNumComment(const char *name, UInt32 value); 326 void PrintNumComment(const char *name, UInt32 value);
323 void Add_QuStr(const AString &s); 327 void Add_QuStr(const AString &s);
324 void SpaceQuStr(const AString &s); 328 void SpaceQuStr(const AString &s);
325 bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands); 329 bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) const;
326 330
327 #endif 331 #endif
328 332
@@ -330,7 +334,7 @@ private:
330 unsigned GetNumSupportedCommands() const; 334 unsigned GetNumSupportedCommands() const;
331 #endif 335 #endif
332 336
333 UInt32 GetCmd(UInt32 a); 337 UInt32 GetCmd(UInt32 a) const;
334 void FindBadCmd(const CBlockHeader &bh, const Byte *); 338 void FindBadCmd(const CBlockHeader &bh, const Byte *);
335 void DetectNsisType(const CBlockHeader &bh, const Byte *); 339 void DetectNsisType(const CBlockHeader &bh, const Byte *);
336 340
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index 006f0ad..baf6a4d 100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -813,7 +813,8 @@ Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
813 { 813 {
814 memset((Byte *)data, 0, size); 814 memset((Byte *)data, 0, size);
815 _virtPos += size; 815 _virtPos += size;
816 *processedSize = size; 816 if (processedSize)
817 *processedSize = size;
817 return S_OK; 818 return S_OK;
818 } 819 }
819 820
@@ -836,7 +837,8 @@ Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
836 if (cur > size) 837 if (cur > size)
837 cur = size; 838 cur = size;
838 memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur); 839 memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur);
839 *processedSize = (UInt32)cur; 840 if (processedSize)
841 *processedSize = (UInt32)cur;
840 _virtPos += cur; 842 _virtPos += cur;
841 return S_OK; 843 return S_OK;
842 } 844 }
@@ -1311,7 +1313,7 @@ bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 r
1311 // PRF(printf("\nusn = %d", usn)); 1313 // PRF(printf("\nusn = %d", usn));
1312 for (UInt32 i = 1; i < numUsaItems; i++) 1314 for (UInt32 i = 1; i < numUsaItems; i++)
1313 { 1315 {
1314 void *pp = p + (i << sectorSizeLog) - 2; 1316 void *pp = p + ((size_t)i << sectorSizeLog) - 2;
1315 if (Get16(pp) != usn) 1317 if (Get16(pp) != usn)
1316 return false; 1318 return false;
1317 SetUi16(pp, Get16(p + usaOffset + i * 2)) 1319 SetUi16(pp, Get16(p + usaOffset + i * 2))
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
index f5f66b0..7d78234 100644
--- a/CPP/7zip/Archive/PeHandler.cpp
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -1562,8 +1562,8 @@ struct CMy_VS_FIXEDFILEINFO
1562 UInt32 OS; 1562 UInt32 OS;
1563 UInt32 Type; 1563 UInt32 Type;
1564 UInt32 Subtype; 1564 UInt32 Subtype;
1565 UInt32 DateMS; 1565 // UInt32 DateMS;
1566 UInt32 DateLS; 1566 // UInt32 DateLS;
1567 1567
1568 bool Parse(const Byte *p); 1568 bool Parse(const Byte *p);
1569 void PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys); 1569 void PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys);
@@ -1583,8 +1583,8 @@ bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p)
1583 G32(0x20, OS); 1583 G32(0x20, OS);
1584 G32(0x24, Type); 1584 G32(0x24, Type);
1585 G32(0x28, Subtype); 1585 G32(0x28, Subtype);
1586 G32(0x2C, DateMS); 1586 // G32(0x2C, DateMS);
1587 G32(0x40, DateLS); 1587 // G32(0x30, DateLS);
1588 return true; 1588 return true;
1589} 1589}
1590 1590
diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp
index 5f9e1c3..b3b1cdb 100644
--- a/CPP/7zip/Archive/PpmdHandler.cpp
+++ b/CPP/7zip/Archive/PpmdHandler.cpp
@@ -27,7 +27,7 @@ using namespace NWindows;
27namespace NArchive { 27namespace NArchive {
28namespace NPpmd { 28namespace NPpmd {
29 29
30static const UInt32 kBufSize = (1 << 20); 30static const size_t kBufSize = 1 << 20;
31 31
32struct CBuf 32struct CBuf
33{ 33{
@@ -220,58 +220,74 @@ Z7_COM7F_IMF(CHandler::Close())
220 220
221struct CPpmdCpp 221struct CPpmdCpp
222{ 222{
223 unsigned Ver; 223 CPpmd7 *_ppmd7;
224 CPpmd7 _ppmd7; 224 CPpmd8 *_ppmd8;
225 CPpmd8 _ppmd8;
226 225
227 CPpmdCpp(unsigned version) 226 CPpmdCpp(unsigned version):
227 _ppmd7(NULL),
228 _ppmd8(NULL)
228 { 229 {
229 Ver = version; 230 if (version == 7)
230 Ppmd7_Construct(&_ppmd7); 231 {
231 Ppmd8_Construct(&_ppmd8); 232 _ppmd7 = new CPpmd7();
233 Ppmd7_Construct(_ppmd7);
234 }
235 else
236 {
237 _ppmd8 = new CPpmd8();
238 Ppmd8_Construct(_ppmd8);
239 }
232 } 240 }
233 241
234 ~CPpmdCpp() 242 ~CPpmdCpp()
235 { 243 {
236 Ppmd7_Free(&_ppmd7, &g_BigAlloc); 244 if (_ppmd7)
237 Ppmd8_Free(&_ppmd8, &g_BigAlloc); 245 {
246 Ppmd7_Free(_ppmd7, &g_BigAlloc);
247 delete _ppmd7;
248 }
249 if (_ppmd8)
250 {
251 Ppmd8_Free(_ppmd8, &g_BigAlloc);
252 delete _ppmd8;
253 }
238 } 254 }
239 255
240 bool Alloc(UInt32 memInMB) 256 BoolInt Alloc(UInt32 memInMB)
241 { 257 {
242 memInMB <<= 20; 258 memInMB <<= 20;
243 if (Ver == 7) 259 if (_ppmd7)
244 return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0; 260 return Ppmd7_Alloc(_ppmd7, memInMB, &g_BigAlloc);
245 return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0; 261 return Ppmd8_Alloc(_ppmd8, memInMB, &g_BigAlloc);
246 } 262 }
247 263
248 void Init(unsigned order, unsigned restor) 264 void Init(unsigned order, unsigned restor)
249 { 265 {
250 if (Ver == 7) 266 if (_ppmd7)
251 Ppmd7_Init(&_ppmd7, order); 267 Ppmd7_Init(_ppmd7, order);
252 else 268 else
253 Ppmd8_Init(&_ppmd8, order, restor); 269 Ppmd8_Init(_ppmd8, order, restor);
254 } 270 }
255 271
256 bool InitRc(CByteInBufWrap *inStream) 272 bool InitRc(CByteInBufWrap *inStream)
257 { 273 {
258 if (Ver == 7) 274 if (_ppmd7)
259 { 275 {
260 _ppmd7.rc.dec.Stream = &inStream->vt; 276 _ppmd7->rc.dec.Stream = &inStream->vt;
261 return (Ppmd7a_RangeDec_Init(&_ppmd7.rc.dec) != 0); 277 return (Ppmd7a_RangeDec_Init(&_ppmd7->rc.dec) != 0);
262 } 278 }
263 else 279 else
264 { 280 {
265 _ppmd8.Stream.In = &inStream->vt; 281 _ppmd8->Stream.In = &inStream->vt;
266 return Ppmd8_Init_RangeDec(&_ppmd8) != 0; 282 return Ppmd8_Init_RangeDec(_ppmd8) != 0;
267 } 283 }
268 } 284 }
269 285
270 bool IsFinishedOK() 286 bool IsFinishedOK()
271 { 287 {
272 if (Ver == 7) 288 if (_ppmd7)
273 return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7.rc.dec); 289 return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7->rc.dec);
274 return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8); 290 return Ppmd8_RangeDec_IsFinishedOK(_ppmd8);
275 } 291 }
276}; 292};
277 293
@@ -311,14 +327,14 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
311 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps; 327 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
312 lps->Init(extractCallback, true); 328 lps->Init(extractCallback, true);
313 329
314 CPpmdCpp ppmd(_item.Ver);
315 if (!ppmd.Alloc(_item.MemInMB))
316 return E_OUTOFMEMORY;
317
318 opRes = NExtract::NOperationResult::kUnsupportedMethod; 330 opRes = NExtract::NOperationResult::kUnsupportedMethod;
319 331
320 if (_item.IsSupported()) 332 if (_item.IsSupported())
321 { 333 {
334 CPpmdCpp ppmd(_item.Ver);
335 if (!ppmd.Alloc(_item.MemInMB))
336 return E_OUTOFMEMORY;
337
322 opRes = NExtract::NOperationResult::kDataError; 338 opRes = NExtract::NOperationResult::kDataError;
323 339
324 ppmd.Init(_item.Order, _item.Restor); 340 ppmd.Init(_item.Order, _item.Restor);
@@ -336,11 +352,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
336 int sym = 0; 352 int sym = 0;
337 353
338 Byte *buf = outBuf.Buf; 354 Byte *buf = outBuf.Buf;
339 if (ppmd.Ver == 7) 355 if (ppmd._ppmd7)
340 { 356 {
341 for (i = 0; i < kBufSize; i++) 357 for (i = 0; i < kBufSize; i++)
342 { 358 {
343 sym = Ppmd7a_DecodeSymbol(&ppmd._ppmd7); 359 sym = Ppmd7a_DecodeSymbol(ppmd._ppmd7);
344 if (inBuf.Extra || sym < 0) 360 if (inBuf.Extra || sym < 0)
345 break; 361 break;
346 buf[i] = (Byte)sym; 362 buf[i] = (Byte)sym;
@@ -350,7 +366,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
350 { 366 {
351 for (i = 0; i < kBufSize; i++) 367 for (i = 0; i < kBufSize; i++)
352 { 368 {
353 sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8); 369 sym = Ppmd8_DecodeSymbol(ppmd._ppmd8);
354 if (inBuf.Extra || sym < 0) 370 if (inBuf.Extra || sym < 0)
355 break; 371 break;
356 buf[i] = (Byte)sym; 372 buf[i] = (Byte)sym;
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
index c15ff52..1e01134 100644
--- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -1673,7 +1673,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1673 case kpidExtension: 1673 case kpidExtension:
1674 if (_arcs.Size() == 1) 1674 if (_arcs.Size() == 1)
1675 { 1675 {
1676 if (arcInfo->IsVolume()) 1676 if (arcInfo && arcInfo->IsVolume())
1677 { 1677 {
1678 AString s ("part"); 1678 AString s ("part");
1679 UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1; 1679 UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1;
@@ -1809,14 +1809,14 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
1809 size -= num; 1809 size -= num;
1810 } 1810 }
1811 1811
1812 if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0) 1812 if (((UInt32)flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0)
1813 return; 1813 return;
1814 1814
1815 unsigned numStamps = 0; 1815 unsigned numStamps = 0;
1816 unsigned curStamp = 0; 1816 unsigned curStamp = 0;
1817 1817
1818 for (unsigned i = 0; i < 3; i++) 1818 for (unsigned i = 0; i < 3; i++)
1819 if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) 1819 if (((UInt32)flags & (NTimeRecord::NFlags::kMTime << i)) != 0)
1820 { 1820 {
1821 if (i == stampIndex) 1821 if (i == stampIndex)
1822 curStamp = numStamps; 1822 curStamp = numStamps;
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index 6c53847..4f181f4 100644
--- a/CPP/7zip/Archive/Rar/RarHandler.cpp
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -150,8 +150,7 @@ class CInArchive
150 CByteBuffer _comment; 150 CByteBuffer _comment;
151 CByteBuffer m_FileHeaderData; 151 CByteBuffer m_FileHeaderData;
152 NHeader::NBlock::CBlock m_BlockHeader; 152 NHeader::NBlock::CBlock m_BlockHeader;
153 NCrypto::NRar3::CDecoder *m_RarAESSpec; 153 CMyComPtr2<ICompressFilter, NCrypto::NRar3::CDecoder> m_RarAES;
154 CMyComPtr<ICompressFilter> m_RarAES;
155 CAlignedBuffer m_DecryptedDataAligned; 154 CAlignedBuffer m_DecryptedDataAligned;
156 UInt32 m_DecryptedDataSize; 155 UInt32 m_DecryptedDataSize;
157 bool m_CryptoMode; 156 bool m_CryptoMode;
@@ -532,12 +531,8 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
532 error = k_ErrorType_DecryptionError; 531 error = k_ErrorType_DecryptionError;
533 return S_OK; // return S_FALSE; 532 return S_OK; // return S_FALSE;
534 } 533 }
535 if (!m_RarAES) 534 m_RarAES.Create_if_Empty();
536 { 535 // m_RarAES->SetRar350Mode(ArcInfo.IsEncryptOld());
537 m_RarAESSpec = new NCrypto::NRar3::CDecoder;
538 m_RarAES = m_RarAESSpec;
539 }
540 // m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld());
541 536
542 { 537 {
543 // Salt 538 // Salt
@@ -546,7 +541,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
546 if (!ReadBytesAndTestSize(salt, kSaltSize)) 541 if (!ReadBytesAndTestSize(salt, kSaltSize))
547 return S_FALSE; 542 return S_FALSE;
548 m_Position += kSaltSize; 543 m_Position += kSaltSize;
549 RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) 544 RINOK(m_RarAES->SetDecoderProperties2(salt, kSaltSize))
550 } 545 }
551 546
552 { 547 {
@@ -567,7 +562,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass
567 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); 562 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
568 } 563 }
569 564
570 m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2); 565 m_RarAES->SetPassword((const Byte *)buffer, len * 2);
571 } 566 }
572 567
573 const UInt32 kDecryptedBufferSize = (1 << 12); 568 const UInt32 kDecryptedBufferSize = (1 << 12);
@@ -1477,22 +1472,17 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1477 1472
1478 CObjectVector<CMethodItem> methodItems; 1473 CObjectVector<CMethodItem> methodItems;
1479 1474
1480 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; 1475 CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1481 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
1482 1476
1483 CFilterCoder *filterStreamSpec = new CFilterCoder(false); 1477 CFilterCoder *filterStreamSpec = new CFilterCoder(false);
1484 CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec; 1478 CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
1485 1479
1486 NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL; 1480 CMyComPtr2<ICompressFilter, NCrypto::NRar2::CDecoder> rar20CryptoDecoder;
1487 CMyComPtr<ICompressFilter> rar20CryptoDecoder; 1481 CMyComPtr2<ICompressFilter, NCrypto::NRar3::CDecoder> rar3CryptoDecoder;
1488 NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL;
1489 CMyComPtr<ICompressFilter> rar3CryptoDecoder;
1490 1482
1491 CVolsInStream *volsInStreamSpec = NULL; 1483 CMyComPtr2<ISequentialInStream, CVolsInStream> volsInStream;
1492 CMyComPtr<ISequentialInStream> volsInStream;
1493 1484
1494 CLocalProgress *lps = new CLocalProgress; 1485 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1495 CMyComPtr<ICompressProgressInfo> progress = lps;
1496 lps->Init(extractCallback, false); 1486 lps->Init(extractCallback, false);
1497 1487
1498 bool solidStart = true; 1488 bool solidStart = true;
@@ -1572,13 +1562,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1572 outStreamSpec->Init(); 1562 outStreamSpec->Init();
1573 realOutStream.Release(); 1563 realOutStream.Release();
1574 1564
1575 if (!volsInStream) 1565 volsInStream.Create_if_Empty();
1576 { 1566 volsInStream->Init(&_arcs, &_items, refItem);
1577 volsInStreamSpec = new CVolsInStream;
1578 volsInStream = volsInStreamSpec;
1579 }
1580
1581 volsInStreamSpec->Init(&_arcs, &_items, refItem);
1582 1567
1583 UInt64 packSize = currentPackSize; 1568 UInt64 packSize = currentPackSize;
1584 1569
@@ -1593,27 +1578,19 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1593 1578
1594 if (item.UnPackVersion >= 29) 1579 if (item.UnPackVersion >= 29)
1595 { 1580 {
1596 if (!rar3CryptoDecoder) 1581 rar3CryptoDecoder.Create_if_Empty();
1597 { 1582 // rar3CryptoDecoder->SetRar350Mode(item.UnPackVersion < 36);
1598 rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder;
1599 rar3CryptoDecoder = rar3CryptoDecoderSpec;
1600 }
1601 // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
1602 /* 1583 /*
1603 CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties; 1584 CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
1604 RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, 1585 RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
1605 &cryptoProperties)); 1586 &cryptoProperties));
1606 */ 1587 */
1607 RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)) 1588 RINOK(rar3CryptoDecoder->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0))
1608 filterStreamSpec->Filter = rar3CryptoDecoder; 1589 filterStreamSpec->Filter = rar3CryptoDecoder;
1609 } 1590 }
1610 else if (item.UnPackVersion >= 20) 1591 else if (item.UnPackVersion >= 20)
1611 { 1592 {
1612 if (!rar20CryptoDecoder) 1593 rar20CryptoDecoder.Create_if_Empty();
1613 {
1614 rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder;
1615 rar20CryptoDecoder = rar20CryptoDecoderSpec;
1616 }
1617 filterStreamSpec->Filter = rar20CryptoDecoder; 1594 filterStreamSpec->Filter = rar20CryptoDecoder;
1618 } 1595 }
1619 else 1596 else
@@ -1654,7 +1631,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1654 ((Byte *)buffer)[k * 2] = (Byte)c; 1631 ((Byte *)buffer)[k * 2] = (Byte)c;
1655 ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); 1632 ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
1656 } 1633 }
1657 rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2); 1634 rar3CryptoDecoder->SetPassword((const Byte *)buffer, len * 2);
1658 } 1635 }
1659 else 1636 else
1660 { 1637 {
@@ -1667,7 +1644,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1667 unicode.DeleteFrom(kPasswordLen_MAX); 1644 unicode.DeleteFrom(kPasswordLen_MAX);
1668 UnicodeStringToMultiByte2(oemPassword, unicode, CP_OEMCP); 1645 UnicodeStringToMultiByte2(oemPassword, unicode, CP_OEMCP);
1669 } 1646 }
1670 rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()); 1647 rar20CryptoDecoder->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len());
1671 } 1648 }
1672 } 1649 }
1673 /* 1650 /*
@@ -1757,7 +1734,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1757 continue; 1734 continue;
1758 } 1735 }
1759 1736
1760 HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, progress); 1737 HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, lps);
1761 1738
1762 if (item.IsEncrypted()) 1739 if (item.IsEncrypted())
1763 filterStreamSpec->ReleaseInStream(); 1740 filterStreamSpec->ReleaseInStream();
@@ -1765,7 +1742,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1765 if (outSize == (UInt64)(Int64)-1) 1742 if (outSize == (UInt64)(Int64)-1)
1766 currentUnPackSize = outStreamSpec->GetSize(); 1743 currentUnPackSize = outStreamSpec->GetSize();
1767 1744
1768 int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ? 1745 int opRes = (volsInStream->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ?
1769 NExtract::NOperationResult::kOK: 1746 NExtract::NOperationResult::kOK:
1770 NExtract::NOperationResult::kCRCError; 1747 NExtract::NOperationResult::kCRCError;
1771 outStream.Release(); 1748 outStream.Release();
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp
index 83cb1cf..e841879 100644
--- a/CPP/7zip/Archive/SquashfsHandler.cpp
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -1634,11 +1634,13 @@ HRESULT CHandler::Open2(IInStream *inStream)
1634 RINOK(Seek2(offset)) 1634 RINOK(Seek2(offset))
1635 RINOK(ReadMetadataBlock2()) 1635 RINOK(ReadMetadataBlock2())
1636 const UInt32 unpackSize = (UInt32)_dynOutStream->GetSize(); 1636 const UInt32 unpackSize = (UInt32)_dynOutStream->GetSize();
1637 if (unpackSize != kMetadataBlockSize) 1637 UInt32 remSize = (_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1);
1638 if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) 1638 if (remSize == 0 || i != numBlocks - 1)
1639 return S_FALSE; 1639 remSize = kMetadataBlockSize;
1640 if (unpackSize != remSize)
1641 return S_FALSE;
1640 const Byte *buf = _dynOutStream->GetBuffer(); 1642 const Byte *buf = _dynOutStream->GetBuffer();
1641 for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) 1643 for (UInt32 j = 0; j < unpackSize;)
1642 { 1644 {
1643 CFrag frag; 1645 CFrag frag;
1644 if (bigFrag) 1646 if (bigFrag)
@@ -1723,8 +1725,9 @@ HRESULT CHandler::Open2(IInStream *inStream)
1723 // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); 1725 // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
1724 RINOK(ReadMetadataBlock2()) 1726 RINOK(ReadMetadataBlock2())
1725 const size_t unpackSize = _dynOutStream->GetSize(); 1727 const size_t unpackSize = _dynOutStream->GetSize();
1726 const UInt32 remSize = (i == numBlocks - 1) ? 1728 UInt32 remSize = size & (kMetadataBlockSize - 1);
1727 (size & (kMetadataBlockSize - 1)) : kMetadataBlockSize; 1729 if (remSize == 0 || i != numBlocks - 1)
1730 remSize = kMetadataBlockSize;
1728 if (unpackSize != remSize) 1731 if (unpackSize != remSize)
1729 return S_FALSE; 1732 return S_FALSE;
1730 memcpy(_uids + kMetadataBlockSize * i, _dynOutStream->GetBuffer(), remSize); 1733 memcpy(_uids + kMetadataBlockSize * i, _dynOutStream->GetBuffer(), remSize);
@@ -2171,8 +2174,8 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
2171 if (compressed) 2174 if (compressed)
2172 { 2175 {
2173 _outStream->Init((Byte *)_cachedBlock, _h.BlockSize); 2176 _outStream->Init((Byte *)_cachedBlock, _h.BlockSize);
2174 bool outBufWasWritten; 2177 bool outBufWasWritten = false;
2175 UInt32 outBufWasWrittenSize; 2178 UInt32 outBufWasWrittenSize = 0;
2176 HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize); 2179 HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize);
2177 RINOK(res) 2180 RINOK(res)
2178 if (outBufWasWritten) 2181 if (outBufWasWritten)
diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp
index b143d9a..9586f7d 100644
--- a/CPP/7zip/Archive/SwfHandler.cpp
+++ b/CPP/7zip/Archive/SwfHandler.cpp
@@ -412,6 +412,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
412 if (_item.IsZlib()) 412 if (_item.IsZlib())
413 { 413 {
414 _packSizeDefined = true; 414 _packSizeDefined = true;
415 if (!_decoderZlibSpec)
416 return E_FAIL;
415 _packSize = _decoderZlibSpec->GetInputProcessedSize(); 417 _packSize = _decoderZlibSpec->GetInputProcessedSize();
416 opRes = NExtract::NOperationResult::kOK; 418 opRes = NExtract::NOperationResult::kOK;
417 } 419 }
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index e5332b5..c8ea56e 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -859,8 +859,10 @@ HRESULT CInArchive::Open2()
859 } 859 }
860 } 860 }
861 } 861 }
862 862 {
863 PhySize = (UInt32)(256 + 1) << SecLogSize; 863 const UInt32 temp = (UInt32)(256 + 1) << SecLogSize;
864 PhySize = temp;
865 }
864 IsArc = true; 866 IsArc = true;
865 867
866 // UDF 2.2.3 AnchorVolumeDescriptorPointer 868 // UDF 2.2.3 AnchorVolumeDescriptorPointer
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
index 2fef079..8101c4c 100644
--- a/CPP/7zip/Archive/VhdHandler.cpp
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -157,10 +157,11 @@ struct CDynHeader
157 CParentLocatorEntry ParentLocators[8]; 157 CParentLocatorEntry ParentLocators[8];
158 158
159 bool Parse(const Byte *p); 159 bool Parse(const Byte *p);
160 UInt32 NumBitMapSectors() const 160 UInt32 NumBitMapBytes() const
161 { 161 {
162 UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log)); 162 const UInt32 numSectorsInBlock = (UInt32)1 << (BlockSizeLog - kSectorSize_Log);
163 return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8); 163 const UInt32 NumBitMapSectors = (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8);
164 return NumBitMapSectors << kSectorSize_Log;
164 } 165 }
165 void Clear() 166 void Clear()
166 { 167 {
@@ -325,7 +326,7 @@ HRESULT CHandler::InitAndSeek()
325 } 326 }
326 _virtPos = _posInArc = 0; 327 _virtPos = _posInArc = 0;
327 BitMapTag = kUnusedBlock; 328 BitMapTag = kUnusedBlock;
328 BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); 329 BitMap.Alloc(Dyn.NumBitMapBytes());
329 return Seek2(0); 330 return Seek2(0);
330} 331}
331 332
@@ -463,7 +464,7 @@ HRESULT CHandler::Open3()
463 464
464 Bat.ClearAndReserve(Dyn.NumBlocks); 465 Bat.ClearAndReserve(Dyn.NumBlocks);
465 466
466 UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log; 467 const UInt32 bitmapSize = Dyn.NumBitMapBytes();
467 468
468 while ((UInt32)Bat.Size() < Dyn.NumBlocks) 469 while ((UInt32)Bat.Size() < Dyn.NumBlocks)
469 { 470 {
diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp
index ca450e5..64e6273 100644
--- a/CPP/7zip/Archive/VhdxHandler.cpp
+++ b/CPP/7zip/Archive/VhdxHandler.cpp
@@ -1170,6 +1170,7 @@ HRESULT CHandler::Open3()
1170 1170
1171 HeadersSize = (UInt32)1 << 20; 1171 HeadersSize = (UInt32)1 << 20;
1172 CHeader headers[2]; 1172 CHeader headers[2];
1173 Z7_memset_0_ARRAY(headers);
1173 { 1174 {
1174 Byte header[kHeader2Size]; 1175 Byte header[kHeader2Size];
1175 for (unsigned i = 0; i < 2; i++) 1176 for (unsigned i = 0; i < 2; i++)
@@ -1224,6 +1225,7 @@ HRESULT CHandler::Open3()
1224 } 1225 }
1225 } 1226 }
1226 CRegion regions[2]; 1227 CRegion regions[2];
1228 Z7_memset_0_ARRAY(regions);
1227 int correctRegionIndex = -1; 1229 int correctRegionIndex = -1;
1228 1230
1229 { 1231 {
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
index cc24697..d08e060 100644
--- a/CPP/7zip/Archive/Wim/WimHandler.cpp
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -164,15 +164,12 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
164 164
165 case kpidUnpackVer: 165 case kpidUnpackVer:
166 { 166 {
167 UInt32 ver1 = _version >> 16;
168 UInt32 ver2 = (_version >> 8) & 0xFF;
169 UInt32 ver3 = (_version) & 0xFF;
170
171 AString res; 167 AString res;
172 res.Add_UInt32(ver1); 168 res.Add_UInt32(_version >> 16);
173 res.Add_Dot(); 169 res.Add_Dot();
174 res.Add_UInt32(ver2); 170 res.Add_UInt32((_version >> 8) & 0xFF);
175 if (ver3 != 0) 171 const UInt32 ver3 = _version & 0xFF;
172 if (ver3)
176 { 173 {
177 res.Add_Dot(); 174 res.Add_Dot();
178 res.Add_UInt32(ver3); 175 res.Add_UInt32(ver3);
@@ -182,27 +179,33 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
182 } 179 }
183 180
184 case kpidIsVolume: 181 case kpidIsVolume:
185 if (_xmls.Size() > 0) 182 if (!_xmls.IsEmpty())
186 { 183 {
187 UInt16 volIndex = _xmls[0].VolIndex; 184 const unsigned volIndex = _xmls[0].VolIndex;
188 if (volIndex < _volumes.Size()) 185 if (volIndex < _volumes.Size())
189 prop = (_volumes[volIndex].Header.NumParts > 1); 186 prop = (_volumes[volIndex].Header.NumParts > 1);
190 } 187 }
191 break; 188 break;
192 case kpidVolume: 189 case kpidVolume:
193 if (_xmls.Size() > 0) 190 if (!_xmls.IsEmpty())
194 { 191 {
195 UInt16 volIndex = _xmls[0].VolIndex; 192 const unsigned volIndex = _xmls[0].VolIndex;
196 if (volIndex < _volumes.Size()) 193 if (volIndex < _volumes.Size())
197 prop = (UInt32)_volumes[volIndex].Header.PartNumber; 194 prop = (UInt32)_volumes[volIndex].Header.PartNumber;
198 } 195 }
199 break; 196 break;
200 case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; 197 case kpidNumVolumes:
198 {
199 const unsigned n = _volumes.Size();
200 if (n)
201 prop = (UInt32)(n - 1);
202 break;
203 }
201 204
202 case kpidClusterSize: 205 case kpidClusterSize:
203 if (_xmls.Size() > 0) 206 if (!_xmls.IsEmpty())
204 { 207 {
205 UInt16 volIndex = _xmls[0].VolIndex; 208 const unsigned volIndex = _xmls[0].VolIndex;
206 if (volIndex < _volumes.Size()) 209 if (volIndex < _volumes.Size())
207 { 210 {
208 const CHeader &h = _volumes[volIndex].Header; 211 const CHeader &h = _volumes[volIndex].Header;
@@ -318,7 +321,8 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
318 { 321 {
319 UInt32 flags = 0; 322 UInt32 flags = 0;
320 if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; 323 if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc;
321 if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError; 324 if (_db.HeadersError || _volError || _error_in_PartNumber)
325 flags |= kpv_ErrorFlags_HeadersError;
322 if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod; 326 if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod;
323 prop = flags; 327 prop = flags;
324 break; 328 break;
@@ -364,19 +368,14 @@ static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &pro
364 if (method >= 0) 368 if (method >= 0)
365 { 369 {
366 char temp[32]; 370 char temp[32];
367 371 char *dest = ((unsigned)method < Z7_ARRAY_SIZE(k_Methods)) ?
368 if ((unsigned)method < Z7_ARRAY_SIZE(k_Methods)) 372 MyStpCpy(temp, k_Methods[(unsigned)method]) :
369 MyStringCopy(temp, k_Methods[(unsigned)method]); 373 ConvertUInt32ToString((UInt32)(unsigned)method, temp);
370 else
371 ConvertUInt32ToString((UInt32)(unsigned)method, temp);
372
373 if (chunksSizeBits >= 0) 374 if (chunksSizeBits >= 0)
374 { 375 {
375 size_t pos = strlen(temp); 376 *dest++ = ':';
376 temp[pos++] = ':'; 377 ConvertUInt32ToString((unsigned)chunksSizeBits, dest);
377 ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos);
378 } 378 }
379
380 prop = temp; 379 prop = temp;
381 } 380 }
382} 381}
@@ -389,14 +388,15 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
389 388
390 if (index < _db.SortedItems.Size()) 389 if (index < _db.SortedItems.Size())
391 { 390 {
392 unsigned realIndex = _db.SortedItems[index]; 391 const unsigned realIndex = _db.SortedItems[index];
393 const CItem &item = _db.Items[realIndex]; 392 const CItem &item = _db.Items[realIndex];
394 const CStreamInfo *si = NULL; 393 const CStreamInfo *si = NULL;
395 const CVolume *vol = NULL; 394 const CVolume *vol = NULL;
396 if (item.StreamIndex >= 0) 395 if (item.StreamIndex >= 0)
397 { 396 {
398 si = &_db.DataStreams[item.StreamIndex]; 397 si = &_db.DataStreams[item.StreamIndex];
399 vol = &_volumes[si->PartNumber]; 398 if (si->PartNumber < _volumes.Size())
399 vol = &_volumes[si->PartNumber];
400 } 400 }
401 401
402 const CItem *mainItem = &item; 402 const CItem *mainItem = &item;
@@ -501,7 +501,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
501 case kpidIsAltStream: prop = item.IsAltStream; break; 501 case kpidIsAltStream: prop = item.IsAltStream; break;
502 case kpidNumAltStreams: 502 case kpidNumAltStreams:
503 { 503 {
504 if (!item.IsAltStream && mainItem->HasMetadata()) 504 if (!item.IsAltStream && metadata /* mainItem->HasMetadata() */)
505 { 505 {
506 UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; 506 UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
507 UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6); 507 UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6);
@@ -525,12 +525,12 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
525 prop = (UInt32)Get32(metadata + 8); 525 prop = (UInt32)Get32(metadata + 8);
526 } 526 }
527 break; 527 break;
528 case kpidCTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; 528 case kpidCTime: if (metadata /* mainItem->HasMetadata() */ ) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break;
529 case kpidATime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; 529 case kpidATime: if (metadata /* mainItem->HasMetadata() */ ) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break;
530 case kpidMTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; 530 case kpidMTime: if (metadata /* mainItem->HasMetadata() */ ) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break;
531 531
532 case kpidINode: 532 case kpidINode:
533 if (mainItem->HasMetadata() && !_isOldVersion) 533 if (metadata /* mainItem->HasMetadata() */ && !_isOldVersion)
534 { 534 {
535 UInt32 attrib = (UInt32)Get32(metadata + 8); 535 UInt32 attrib = (UInt32)Get32(metadata + 8);
536 if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) 536 if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
@@ -552,26 +552,26 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
552 case kpidMethod: 552 case kpidMethod:
553 if (si) 553 if (si)
554 { 554 {
555 int method = -1;
556 int chunkSizeBits = -1;
555 const CResource &r = si->Resource; 557 const CResource &r = si->Resource;
556 if (r.IsSolid()) 558 if (r.IsSolid())
557 { 559 {
558 if (r.SolidIndex >= 0) 560 if (r.SolidIndex >= 0)
559 { 561 {
560 CSolid &ss = _db.Solids[r.SolidIndex]; 562 const CSolid &ss = _db.Solids[r.SolidIndex];
561 MethodToProp(ss.Method, (int)ss.ChunkSizeBits, prop); 563 method = ss.Method;
564 chunkSizeBits = (int)ss.ChunkSizeBits;
562 } 565 }
563 } 566 }
564 else 567 else if (!r.IsCompressed())
568 method = 0;
569 else if (vol)
565 { 570 {
566 int method = 0; 571 method = (int)vol->Header.GetMethod();
567 int chunkSizeBits = -1; 572 chunkSizeBits = (int)vol->Header.ChunkSizeBits;
568 if (r.IsCompressed())
569 {
570 method = (int)vol->Header.GetMethod();
571 chunkSizeBits = (int)vol->Header.ChunkSizeBits;
572 }
573 MethodToProp(method, chunkSizeBits, prop);
574 } 573 }
574 MethodToProp(method, chunkSizeBits, prop);
575 } 575 }
576 break; 576 break;
577 577
@@ -891,8 +891,14 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
891 } 891 }
892 892
893 CHeader header; 893 CHeader header;
894 HRESULT res = NWim::ReadHeader(curStream, header, _phySize); 894
895 895 _db.PhySize = 0;
896 HRESULT res;
897 {
898 res = NWim::ReadHeader(curStream, header, _db.PhySize);
899 if (i == 1)
900 _phySize = _db.PhySize;
901 }
896 if (res != S_OK) 902 if (res != S_OK)
897 { 903 {
898 if (i != 1 && res == S_FALSE) 904 if (i != 1 && res == S_FALSE)
@@ -901,12 +907,20 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
901 } 907 }
902 908
903 _isArc = true; 909 _isArc = true;
904 _bootIndex = header.BootIndex; 910 if (i == 1)
905 _version = header.Version; 911 {
906 _isOldVersion = header.IsOldVersion(); 912 _bootIndex = header.BootIndex;
913 _version = header.Version;
914 _isOldVersion = header.IsOldVersion();
915 }
916
907 if (_firstVolumeIndex >= 0) 917 if (_firstVolumeIndex >= 0)
908 if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header)) 918 if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header))
909 break; 919 break;
920
921 if (i != 1 && _isOldVersion != header.IsOldVersion())
922 _volError = true;
923
910 if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream) 924 if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
911 break; 925 break;
912 CWimXml xml; 926 CWimXml xml;
@@ -924,17 +938,24 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
924 return S_FALSE; 938 return S_FALSE;
925 } 939 }
926 940
927 UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size(); 941 UInt64 totalFiles = xml.GetTotalFilesAndDirs();
942 if (totalFiles >= ((UInt32)1 << 30))
943 totalFiles = 0;
928 totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items 944 totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items
929 if (totalFiles >= ((UInt32)1 << 30)) 945 if (totalFiles >= ((UInt32)1 << 30))
930 totalFiles = 0; 946 totalFiles = 0;
931 res = _db.Open(curStream, header, (unsigned)totalFiles, callback); 947 res = _db.Open(curStream, header, (unsigned)totalFiles, callback);
948 if (i == 1)
949 _phySize = _db.PhySize;
932 } 950 }
933 951
934 if (res != S_OK) 952 if (res != S_OK)
935 { 953 {
936 if (i != 1 && res == S_FALSE) 954 if (i != 1 && res == S_FALSE)
955 {
956 _volError = true;
937 continue; 957 continue;
958 }
938 return res; 959 return res;
939 } 960 }
940 961
@@ -985,6 +1006,8 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal
985 1006
986 RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber)) 1007 RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber))
987 RINOK(_db.ExtractReparseStreams(_volumes, callback)) 1008 RINOK(_db.ExtractReparseStreams(_volumes, callback))
1009 if (!_db.Check_PartNumber_in_Items(_volumes.Size()))
1010 _error_in_PartNumber = true;
988 1011
989 /* 1012 /*
990 wchar_t sz[16]; 1013 wchar_t sz[16];
@@ -1012,7 +1035,7 @@ Z7_COM7F_IMF(CHandler::Close())
1012 _xmlInComments = false; 1035 _xmlInComments = false;
1013 _numXmlItems = 0; 1036 _numXmlItems = 0;
1014 _numIgnoreItems = 0; 1037 _numIgnoreItems = 0;
1015 _xmlError = false; 1038 ClearErrors();
1016 _isArc = false; 1039 _isArc = false;
1017 _unsupported = false; 1040 _unsupported = false;
1018 return S_OK; 1041 return S_OK;
@@ -1127,7 +1150,9 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1127 RINOK(extractCallback->PrepareOperation(askMode)) 1150 RINOK(extractCallback->PrepareOperation(askMode))
1128 Int32 opRes = NExtract::NOperationResult::kOK; 1151 Int32 opRes = NExtract::NOperationResult::kOK;
1129 1152
1130 if (streamIndex != prevSuccessStreamIndex || realOutStream) 1153 if (si.PartNumber >= _volumes.Size())
1154 opRes = NExtract::NOperationResult::kUnavailable;
1155 else if (streamIndex != prevSuccessStreamIndex || realOutStream)
1131 { 1156 {
1132 Byte digest[kHashSize]; 1157 Byte digest[kHashSize];
1133 const CVolume &vol = _volumes[si.PartNumber]; 1158 const CVolume &vol = _volumes[si.PartNumber];
@@ -1172,7 +1197,7 @@ CHandler::CHandler()
1172{ 1197{
1173 _keepMode_ShowImageNumber = false; 1198 _keepMode_ShowImageNumber = false;
1174 InitDefaults(); 1199 InitDefaults();
1175 _xmlError = false; 1200 ClearErrors();
1176} 1201}
1177 1202
1178Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) 1203Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h
index 126d233..b477d8e 100644
--- a/CPP/7zip/Archive/Wim/WimHandler.h
+++ b/CPP/7zip/Archive/Wim/WimHandler.h
@@ -35,6 +35,8 @@ Z7_CLASS_IMP_CHandler_IInArchive_5(
35 bool _isOldVersion; 35 bool _isOldVersion;
36 bool _xmlInComments; 36 bool _xmlInComments;
37 37
38 bool _error_in_PartNumber;
39 bool _volError;
38 bool _xmlError; 40 bool _xmlError;
39 bool _isArc; 41 bool _isArc;
40 bool _unsupported; 42 bool _unsupported;
@@ -81,7 +83,18 @@ Z7_CLASS_IMP_CHandler_IInArchive_5(
81 return true; 83 return true;
82 } 84 }
83 85
84 bool ThereIsError() const { return _xmlError || _db.ThereIsError(); } 86 void ClearErrors()
87 {
88 _error_in_PartNumber = false;
89 _volError = false;
90 _xmlError = false;
91 }
92
93 bool ThereIsError() const
94 {
95 return _error_in_PartNumber || _volError || _xmlError
96 || _db.ThereIsError();
97 }
85 HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType); 98 HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType);
86 99
87 HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); 100 HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value);
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
index 33fbe82..b2470e1 100644
--- a/CPP/7zip/Archive/Wim/WimIn.cpp
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -1094,6 +1094,7 @@ HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItems
1094 1094
1095 if (h.PartNumber != 1 || si.PartNumber != h.PartNumber) 1095 if (h.PartNumber != 1 || si.PartNumber != h.PartNumber)
1096 continue; 1096 continue;
1097 si.Resource.UpdatePhySize(PhySize);
1097 1098
1098 const unsigned userImage = Images.Size() + GetStartImageIndex(); 1099 const unsigned userImage = Images.Size() + GetStartImageIndex();
1099 CImage &image = Images.AddNew(); 1100 CImage &image = Images.AddNew();
@@ -1623,6 +1624,22 @@ static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size)
1623} 1624}
1624 1625
1625 1626
1627bool CDatabase::Check_PartNumber_in_Items(unsigned numVolumes) const
1628{
1629 // maybe it's better to check all Items[] or all DataStreams[] items instead
1630 FOR_VECTOR(indexInSorted, SortedItems)
1631 {
1632 const unsigned itemIndex = SortedItems[indexInSorted];
1633 const CItem &item = Items[itemIndex];
1634 if (item.StreamIndex < 0)
1635 continue;
1636 const CStreamInfo &si = DataStreams[item.StreamIndex];
1637 if (si.PartNumber >= numVolumes)
1638 return false;
1639 }
1640 return true;
1641}
1642
1626HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback) 1643HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback)
1627{ 1644{
1628 ItemToReparse.Clear(); 1645 ItemToReparse.Clear();
@@ -1639,7 +1656,7 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes,
1639 FOR_VECTOR(indexInSorted, SortedItems) 1656 FOR_VECTOR(indexInSorted, SortedItems)
1640 { 1657 {
1641 // we use sorted items for faster access 1658 // we use sorted items for faster access
1642 unsigned itemIndex = SortedItems[indexInSorted]; 1659 const unsigned itemIndex = SortedItems[indexInSorted];
1643 const CItem &item = Items[itemIndex]; 1660 const CItem &item = Items[itemIndex];
1644 1661
1645 if (!item.HasMetadata() || item.IsAltStream) 1662 if (!item.HasMetadata() || item.IsAltStream)
@@ -1692,10 +1709,8 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes,
1692 } 1709 }
1693 else 1710 else
1694 { 1711 {
1695 /*
1696 if (si.PartNumber >= volumes.Size()) 1712 if (si.PartNumber >= volumes.Size())
1697 continue; 1713 continue;
1698 */
1699 const CVolume &vol = volumes[si.PartNumber]; 1714 const CVolume &vol = volumes[si.PartNumber];
1700 /* 1715 /*
1701 if (!vol.Stream) 1716 if (!vol.Stream)
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h
index ae7cd6b..53a088b 100644
--- a/CPP/7zip/Archive/Wim/WimIn.h
+++ b/CPP/7zip/Archive/Wim/WimIn.h
@@ -163,12 +163,16 @@ struct CResource
163 163
164 UInt64 GetEndLimit() const { return Offset + PackSize; } 164 UInt64 GetEndLimit() const { return Offset + PackSize; }
165 void Parse(const Byte *p); 165 void Parse(const Byte *p);
166 void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) 166 void UpdatePhySize(UInt64 &phySize) const
167 { 167 {
168 Parse(p);
169 UInt64 v = GetEndLimit(); 168 UInt64 v = GetEndLimit();
170 if (phySize < v) 169 if (phySize < v)
171 phySize = v; 170 phySize = v;
171 }
172 void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize)
173 {
174 Parse(p);
175 UpdatePhySize(phySize);
172 } 176 }
173 177
174 void WriteTo(Byte *p) const; 178 void WriteTo(Byte *p) const;
@@ -391,7 +395,13 @@ struct CImageInfo
391 395
392 int ItemIndexInXml; 396 int ItemIndexInXml;
393 397
394 UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; } 398 UInt64 GetTotalFilesAndDirs() const
399 {
400 UInt64 v = DirCount + FileCount;
401 if (v < DirCount)
402 v = 0;
403 return v;
404 }
395 405
396 CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false), 406 CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false),
397 IndexDefined(false), ItemIndexInXml(-1) {} 407 IndexDefined(false), ItemIndexInXml(-1) {}
@@ -405,16 +415,21 @@ struct CWimXml
405 CXml Xml; 415 CXml Xml;
406 416
407 UInt16 VolIndex; 417 UInt16 VolIndex;
418 bool IsEncrypted;
408 CObjectVector<CImageInfo> Images; 419 CObjectVector<CImageInfo> Images;
409 420
410 UString FileName; 421 UString FileName;
411 bool IsEncrypted;
412 422
413 UInt64 GetTotalFilesAndDirs() const 423 UInt64 GetTotalFilesAndDirs() const
414 { 424 {
415 UInt64 sum = 0; 425 UInt64 sum = 0;
416 FOR_VECTOR (i, Images) 426 FOR_VECTOR (i, Images)
417 sum += Images[i].GetTotalFilesAndDirs(); 427 {
428 const UInt64 v = Images[i].GetTotalFilesAndDirs();
429 sum += v;
430 if (sum < v)
431 return 0;
432 }
418 return sum; 433 return sum;
419 } 434 }
420 435
@@ -474,6 +489,7 @@ public:
474 int ExludedItem; // -1 : if there are no exclude items 489 int ExludedItem; // -1 : if there are no exclude items
475 CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives 490 CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives
476 491
492 UInt64 PhySize;
477 bool ThereIsError() const { return RefCountError || HeadersError; } 493 bool ThereIsError() const { return RefCountError || HeadersError; }
478 494
479 unsigned GetNumUserItemsInImage(unsigned imageIndex) const 495 unsigned GetNumUserItemsInImage(unsigned imageIndex) const
@@ -530,6 +546,7 @@ public:
530 546
531 void Clear() 547 void Clear()
532 { 548 {
549 PhySize = 0;
533 DataStreams.Clear(); 550 DataStreams.Clear();
534 MetaStreams.Clear(); 551 MetaStreams.Clear();
535 Solids.Clear(); 552 Solids.Clear();
@@ -572,6 +589,7 @@ public:
572 */ 589 */
573 HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber); 590 HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber);
574 591
592 bool Check_PartNumber_in_Items(unsigned numVolumes) const;
575 HRESULT ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback); 593 HRESULT ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback);
576}; 594};
577 595
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
index 43d68c7..ba61710 100644
--- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -410,7 +410,7 @@ HRESULT CAddCommon::Compress(
410 } 410 }
411 } 411 }
412 } 412 }
413 if (method == NCompressionMethod::kLZMA) 413 if (method == NCompressionMethod::kLZMA && _lzmaEncoder)
414 _isLzmaEos = _lzmaEncoder->Encoder->IsWriteEndMark(); 414 _isLzmaEos = _lzmaEncoder->Encoder->IsWriteEndMark();
415 } 415 }
416 416
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
index 9d77e87..3bcbe22 100644
--- a/CPP/7zip/Archive/Zip/ZipIn.cpp
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -2393,10 +2393,7 @@ HRESULT CInArchive::ReadVols()
2393 { 2393 {
2394 // get volumes required for cd. 2394 // get volumes required for cd.
2395 RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols)) 2395 RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols))
2396 if (numMissingVols != 0) 2396 // if (numMissingVols) cdOK = false;
2397 {
2398 // cdOK = false;
2399 }
2400 } 2397 }
2401 } 2398 }
2402 else if (res != S_FALSE) 2399 else if (res != S_FALSE)
diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
index e43e8b1..28ac2ea 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
@@ -534,11 +534,9 @@ static int main2(int numArgs, const char *args[])
534 dict = (UInt32)1 << kDictSizeLog; 534 dict = (UInt32)1 << kDictSizeLog;
535 if (fileSizeDefined) 535 if (fileSizeDefined)
536 { 536 {
537 unsigned i; 537 for (dict = 1 << 16; dict < ((UInt32)1 << kDictSizeLog); dict <<= 1)
538 for (i = 16; i < kDictSizeLog; i++) 538 if (dict >= fileSize)
539 if ((UInt32)((UInt32)1 << i) >= fileSize)
540 break; 539 break;
541 dict = (UInt32)1 << i;
542 } 540 }
543 } 541 }
544 542
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp
index b7e4fbe..37c1f49 100644
--- a/CPP/7zip/Common/FileStreams.cpp
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -882,7 +882,7 @@ Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *pro
882 882
883 UInt32 realProcessedSize; 883 UInt32 realProcessedSize;
884 BOOL res = TRUE; 884 BOOL res = TRUE;
885 if (size > 0) 885 if (size)
886 { 886 {
887 // Seems that Windows doesn't like big amounts writing to stdout. 887 // Seems that Windows doesn't like big amounts writing to stdout.
888 // So we limit portions by 32KB. 888 // So we limit portions by 32KB.
@@ -892,8 +892,8 @@ Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *pro
892 res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), 892 res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
893 data, sizeTemp, (DWORD *)&realProcessedSize, NULL); 893 data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
894 _size += realProcessedSize; 894 _size += realProcessedSize;
895 size -= realProcessedSize; 895 // size -= realProcessedSize;
896 data = (const void *)((const Byte *)data + realProcessedSize); 896 // data = (const void *)((const Byte *)data + realProcessedSize);
897 if (processedSize) 897 if (processedSize)
898 *processedSize += realProcessedSize; 898 *processedSize += realProcessedSize;
899 } 899 }
diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp
index 664cd0c..e2b536d 100644
--- a/CPP/7zip/Common/LimitedStreams.cpp
+++ b/CPP/7zip/Common/LimitedStreams.cpp
@@ -105,18 +105,20 @@ Z7_COM7F_IMF(CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSi
105 const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); 105 const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
106 const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); 106 const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
107 const UInt32 phyBlock = Vector[virtBlock]; 107 const UInt32 phyBlock = Vector[virtBlock];
108 108 const UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
109 UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
110 if (newPos != _physPos) 109 if (newPos != _physPos)
111 { 110 {
112 _physPos = newPos; 111 _physPos = newPos;
113 RINOK(SeekToPhys()) 112 RINOK(SeekToPhys())
114 } 113 }
115
116 _curRem = blockSize - offsetInBlock; 114 _curRem = blockSize - offsetInBlock;
117 115 for (unsigned i = 1; i < 64
118 for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) 116 && _curRem < size
119 _curRem += (UInt32)1 << BlockSizeLog; 117 && _curRem < ((UInt32)1 << 31) - blockSize
118 && virtBlock + i < Vector.Size()
119 && phyBlock + i == Vector[virtBlock + i]
120 ; i++)
121 _curRem += blockSize;
120 } 122 }
121 123
122 if (size > _curRem) 124 if (size > _curRem)
diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h
index 69fcdcd..328efb3 100644
--- a/CPP/7zip/Common/LimitedStreams.h
+++ b/CPP/7zip/Common/LimitedStreams.h
@@ -14,18 +14,18 @@ Z7_CLASS_IMP_COM_1(
14 CLimitedSequentialInStream 14 CLimitedSequentialInStream
15 , ISequentialInStream 15 , ISequentialInStream
16) 16)
17 bool _wasFinished;
17 CMyComPtr<ISequentialInStream> _stream; 18 CMyComPtr<ISequentialInStream> _stream;
18 UInt64 _size; 19 UInt64 _size;
19 UInt64 _pos; 20 UInt64 _pos;
20 bool _wasFinished;
21public: 21public:
22 void SetStream(ISequentialInStream *stream) { _stream = stream; } 22 void SetStream(ISequentialInStream *stream) { _stream = stream; }
23 void ReleaseStream() { _stream.Release(); } 23 void ReleaseStream() { _stream.Release(); }
24 void Init(UInt64 streamSize) 24 void Init(UInt64 streamSize)
25 { 25 {
26 _wasFinished = false;
26 _size = streamSize; 27 _size = streamSize;
27 _pos = 0; 28 _pos = 0;
28 _wasFinished = false;
29 } 29 }
30 UInt64 GetSize() const { return _pos; } 30 UInt64 GetSize() const { return _pos; }
31 UInt64 GetRem() const { return _size - _pos; } 31 UInt64 GetRem() const { return _size - _pos; }
@@ -79,9 +79,9 @@ public:
79 _curRem = 0; 79 _curRem = 0;
80 _virtPos = 0; 80 _virtPos = 0;
81 _physPos = StartOffset; 81 _physPos = StartOffset;
82 if (Vector.Size() > 0) 82 if (Vector.Size())
83 { 83 {
84 _physPos = StartOffset + (Vector[0] << BlockSizeLog); 84 _physPos = StartOffset + ((UInt64)Vector[0] << BlockSizeLog);
85 return SeekToPhys(); 85 return SeekToPhys();
86 } 86 }
87 return S_OK; 87 return S_OK;
@@ -105,9 +105,9 @@ struct CSeekExtent
105Z7_CLASS_IMP_IInStream( 105Z7_CLASS_IMP_IInStream(
106 CExtentsStream 106 CExtentsStream
107) 107)
108 unsigned _prevExtentIndex;
108 UInt64 _virtPos; 109 UInt64 _virtPos;
109 UInt64 _phyPos; 110 UInt64 _phyPos;
110 unsigned _prevExtentIndex;
111public: 111public:
112 CMyComPtr<IInStream> Stream; 112 CMyComPtr<IInStream> Stream;
113 CRecordVector<CSeekExtent> Extents; 113 CRecordVector<CSeekExtent> Extents;
@@ -115,9 +115,9 @@ public:
115 void ReleaseStream() { Stream.Release(); } 115 void ReleaseStream() { Stream.Release(); }
116 void Init() 116 void Init()
117 { 117 {
118 _prevExtentIndex = 0;
118 _virtPos = 0; 119 _virtPos = 0;
119 _phyPos = (UInt64)0 - 1; // we need Seek() for Stream 120 _phyPos = (UInt64)0 - 1; // we need Seek() for Stream
120 _prevExtentIndex = 0;
121 } 121 }
122}; 122};
123 123
@@ -127,10 +127,10 @@ Z7_CLASS_IMP_COM_1(
127 CLimitedSequentialOutStream 127 CLimitedSequentialOutStream
128 , ISequentialOutStream 128 , ISequentialOutStream
129) 129)
130 CMyComPtr<ISequentialOutStream> _stream;
131 UInt64 _size;
132 bool _overflow; 130 bool _overflow;
133 bool _overflowIsAllowed; 131 bool _overflowIsAllowed;
132 CMyComPtr<ISequentialOutStream> _stream;
133 UInt64 _size;
134public: 134public:
135 void SetStream(ISequentialOutStream *stream) { _stream = stream; } 135 void SetStream(ISequentialOutStream *stream) { _stream = stream; }
136 void ReleaseStream() { _stream.Release(); } 136 void ReleaseStream() { _stream.Release(); }
diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp
index af0b312..bc93dd5 100644
--- a/CPP/7zip/Compress/BZip2Encoder.cpp
+++ b/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -436,7 +436,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
436 WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false) 436 WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false)
437 } 437 }
438 Byte mtfBuf[256]; 438 Byte mtfBuf[256];
439 // memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning 439 Z7_memset_0_ARRAY(mtfBuf); // to suppress MSVC warning in -analyze mode
440 unsigned numInUse; 440 unsigned numInUse;
441 { 441 {
442 Byte inUse[256]; 442 Byte inUse[256];
diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h
index 318190d..b05f389 100644
--- a/CPP/7zip/Compress/HuffmanDecoder.h
+++ b/CPP/7zip/Compress/HuffmanDecoder.h
@@ -481,25 +481,26 @@ public:
481 if (len == 0) 481 if (len == 0)
482 continue; 482 continue;
483 const unsigned offset = counts[len]++; 483 const unsigned offset = counts[len]++;
484 { 484 const unsigned temp = (offset - _poses[len]) << (kNumBitsMax - len);
485 Byte *dest = _lens + _limits[(size_t)len - 1] 485 Byte *dest = _lens + _limits[(size_t)len - 1] + temp;
486 + ((offset - _poses[len]) << (kNumBitsMax - len)); 486 unsigned num = 1u << (kNumBitsMax - len);
487 const unsigned num = (unsigned)1 << (kNumBitsMax - len); 487 const unsigned val = (i << 3) + len;
488 const unsigned val = (i << 3) + len; 488 do
489 for (unsigned k = 0; k < num; k++) 489 *dest++ = (Byte)val;
490 dest[k] = (Byte)val; 490 while (--num);
491 }
492 } 491 }
493 492
494 if (!full) 493 if (!full)
495 { 494 {
496 const unsigned limit = _limits[kNumBitsMax]; 495 const unsigned limit = _limits[kNumBitsMax];
497 const unsigned num = ((unsigned)1 << kNumBitsMax) - limit; 496 unsigned num = (1u << kNumBitsMax) - limit;
498 Byte *dest = _lens + limit; 497 if (num)
499 for (unsigned k = 0; k < num; k++) 498 {
500 dest[k] = (Byte) 499 Byte *dest = _lens + limit;
501 // (0x1f << 3); 500 do
502 ((0x1f << 3) + 0x7); 501 *dest++ = (0x1f << 3) + 7;
502 while (--num);
503 }
503 } 504 }
504 505
505 return true; 506 return true;
diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp
index bca2eee..8b7a79f 100644
--- a/CPP/7zip/Compress/LzmaEncoder.cpp
+++ b/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -43,7 +43,7 @@ CEncoder::~CEncoder()
43 43
44static inline wchar_t GetLowCharFast(wchar_t c) 44static inline wchar_t GetLowCharFast(wchar_t c)
45{ 45{
46 return c |= 0x20; 46 return (wchar_t)(c | 0x20);
47} 47}
48 48
49static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) 49static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp
index c17d46d..7e4fb2f 100644
--- a/CPP/7zip/Compress/Rar3Decoder.cpp
+++ b/CPP/7zip/Compress/Rar3Decoder.cpp
@@ -454,7 +454,7 @@ HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
454 } 454 }
455 } 455 }
456 if (InputEofError_Fast()) 456 if (InputEofError_Fast())
457 return false; 457 return S_FALSE;
458 const int c = DecodePpmSymbol(); 458 const int c = DecodePpmSymbol();
459 if (c < 0) 459 if (c < 0)
460 { 460 {
diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp
index 34ea4ff..ef9607b 100644
--- a/CPP/7zip/Crypto/Rar5Aes.cpp
+++ b/CPP/7zip/Crypto/Rar5Aes.cpp
@@ -209,6 +209,7 @@ bool CDecoder::CalcKey_and_CheckPassword()
209 { 209 {
210 MY_ALIGN_FOR_SHA256 210 MY_ALIGN_FOR_SHA256
211 UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS]; 211 UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS];
212 Z7_memset_0_ARRAY(pswCheck);
212 { 213 {
213 // Pbkdf HMAC-SHA-256 214 // Pbkdf HMAC-SHA-256
214 MY_ALIGN_FOR_SHA256 215 MY_ALIGN_FOR_SHA256
diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp
index 46b740a..b7815c6 100644
--- a/CPP/7zip/UI/Agent/Agent.cpp
+++ b/CPP/7zip/UI/Agent/Agent.cpp
@@ -11,11 +11,14 @@
11#include "../../../Windows/FileDir.h" 11#include "../../../Windows/FileDir.h"
12#include "../../../Windows/FileName.h" 12#include "../../../Windows/FileName.h"
13#include "../../../Windows/PropVariantConv.h" 13#include "../../../Windows/PropVariantConv.h"
14#include "../../../Windows/System.h"
14 15
15#ifndef Z7_ST 16#ifndef Z7_ST
16#include "../../../Windows/Synchronization.h" 17#include "../../../Windows/Synchronization.h"
17#endif 18#endif
18 19
20#include "../../Archive/Common/ItemNameUtils.h"
21
19#include "../Common/ArchiveExtractCallback.h" 22#include "../Common/ArchiveExtractCallback.h"
20#include "../FileManager/RegistryUtils.h" 23#include "../FileManager/RegistryUtils.h"
21 24
@@ -109,28 +112,48 @@ Z7_COM7F_IMF(CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder))
109 return S_OK; 112 return S_OK;
110} 113}
111 114
112void CAgentFolder::LoadFolder(unsigned proxyDirIndex) 115void CAgentFolder::LoadFolder(unsigned dirIndex)
113{ 116{
114 CProxyItem item; 117 CProxyItem item;
115 item.DirIndex = proxyDirIndex;
116 118
117 if (_proxy2) 119 if (_proxy2)
118 { 120 {
119 const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex]; 121 CUIntVector vec;
120 FOR_VECTOR (i, dir.Items) 122 unsigned i = 0;
123 for (;;)
121 { 124 {
125 const CProxyDir2 &dir = _proxy2->Dirs[dirIndex];
126 if (i == dir.Items.Size())
127 {
128 const unsigned num = vec.Size();
129 if (num < 2)
130 return;
131 dirIndex = vec[num - 2];
132 i = vec[num - 1];
133 vec.DeleteFrom(num - 2);
134 continue;
135 }
136
137 item.DirIndex = dirIndex;
122 item.Index = i; 138 item.Index = i;
123 _items.Add(item); 139 _items.Add(item);
124 const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; 140 const unsigned index = dir.Items[i];
125 if (file.DirIndex != -1) 141 i++;
126 LoadFolder((unsigned)file.DirIndex); 142 const CProxyFile2 &file = _proxy2->Files[index];
127 if (_loadAltStreams && file.AltDirIndex != -1) 143 if (_loadAltStreams && file.AltDirIndex != -1)
128 LoadFolder((unsigned)file.AltDirIndex); 144 LoadFolder((unsigned)file.AltDirIndex);
145 if (file.DirIndex != -1)
146 {
147 vec.Add(dirIndex);
148 vec.Add(i);
149 dirIndex = (unsigned)file.DirIndex;
150 i = 0;
151 }
129 } 152 }
130 return;
131 } 153 }
132 154
133 const CProxyDir &dir = _proxy->Dirs[proxyDirIndex]; 155 item.DirIndex = dirIndex;
156 const CProxyDir &dir = _proxy->Dirs[dirIndex];
134 unsigned i; 157 unsigned i;
135 for (i = 0; i < dir.SubDirs.Size(); i++) 158 for (i = 0; i < dir.SubDirs.Size(); i++)
136 { 159 {
@@ -139,7 +162,7 @@ void CAgentFolder::LoadFolder(unsigned proxyDirIndex)
139 LoadFolder(dir.SubDirs[i]); 162 LoadFolder(dir.SubDirs[i]);
140 } 163 }
141 164
142 unsigned start = dir.SubDirs.Size(); 165 const unsigned start = dir.SubDirs.Size();
143 for (i = 0; i < dir.SubFiles.Size(); i++) 166 for (i = 0; i < dir.SubFiles.Size(); i++)
144 { 167 {
145 item.Index = start + i; 168 item.Index = start + i;
@@ -201,79 +224,39 @@ UString CAgentFolder::GetName(UInt32 index) const
201 return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name; 224 return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name;
202} 225}
203 226
204void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const 227
228/* called for (_flatMode == true) from:
229 CAgentFolder::GetProperty(kpidPrefix)
230 CAgentFolder::CompareItems(kpidPrefix)
231*/
232void CAgentFolder::GetPrefix(const UInt32 index, UString &prefix) const
205{ 233{
234 prefix.Empty();
206 if (!_flatMode) 235 if (!_flatMode)
207 {
208 prefix.Empty();
209 return; 236 return;
210 } 237 const unsigned itemDirIndex = _items[index].DirIndex;
211 238 if (itemDirIndex == _proxyDirIndex)
212 const CProxyItem &item = _items[index]; 239 return;
213 unsigned proxyIndex = item.DirIndex;
214
215 if (_proxy2) 240 if (_proxy2)
216 { 241 {
217 // that code is unused. 7-Zip gets prefix via GetItemPrefix() . 242 const unsigned kLenLimit = 1u << 12;
218 243 _proxy2->GetDirPath_as_Prefix_from_Base(itemDirIndex, prefix, _proxyDirIndex, kLenLimit);
219 unsigned len = 0;
220 while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
221 {
222 const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
223 len += file.NameLen + 1;
224 proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
225 }
226
227 wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
228 proxyIndex = item.DirIndex;
229 while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
230 {
231 const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
232 p--;
233 *p = WCHAR_PATH_SEPARATOR;
234 p -= file.NameLen;
235 wmemcpy(p, file.Name, file.NameLen);
236 proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
237 }
238 } 244 }
239 else 245 else
240 { 246 _proxy->GetDirPath_as_Prefix_from_Base(itemDirIndex, prefix, _proxyDirIndex);
241 unsigned len = 0;
242 while (proxyIndex != _proxyDirIndex)
243 {
244 const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
245 len += dir->NameLen + 1;
246 proxyIndex = (unsigned)dir->ParentDir;
247 }
248
249 wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
250 proxyIndex = item.DirIndex;
251 while (proxyIndex != _proxyDirIndex)
252 {
253 const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
254 p--;
255 *p = WCHAR_PATH_SEPARATOR;
256 p -= dir->NameLen;
257 wmemcpy(p, dir->Name, dir->NameLen);
258 proxyIndex = (unsigned)dir->ParentDir;
259 }
260 }
261} 247}
262 248
263UString CAgentFolder::GetFullPrefix(UInt32 index) const 249UString CAgentFolder::GetFullPrefix(const UInt32 index) const
264{ 250{
265 unsigned foldIndex = _proxyDirIndex; 251 unsigned foldIndex = _proxyDirIndex;
266
267 if (_flatMode) 252 if (_flatMode)
268 foldIndex = _items[index].DirIndex; 253 foldIndex = _items[index].DirIndex;
269
270 if (_proxy2) 254 if (_proxy2)
271 return _proxy2->Dirs[foldIndex].PathPrefix; 255 return _proxy2->GetDirPath_as_Prefix(foldIndex);
272 else 256 return _proxy->GetDirPath_as_Prefix(foldIndex);
273 return _proxy->GetDirPath_as_Prefix(foldIndex);
274} 257}
275 258
276Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(UInt32 index)) 259Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(const UInt32 index))
277{ 260{
278 unsigned arcIndex; 261 unsigned arcIndex;
279 if (_proxy2) 262 if (_proxy2)
@@ -471,29 +454,48 @@ Z7_COM7F_IMF(CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsig
471 } 454 }
472} 455}
473 456
457
458/* called for (_flatMode == true) from:
459 CPanel::RefreshListCtrl() : to check selected items and focused item.
460 CPanel::SetItemText() : to show prefix column
461*/
474Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) 462Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len))
475{ 463{
476 *name = NULL; 464 *name = NULL;
477 *len = 0; 465 *len = 0;
466#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
478 if (!_flatMode) 467 if (!_flatMode)
479 return S_OK; 468 return S_OK;
480 469
481 if (_proxy2) 470 if (_proxy2)
482 { 471 {
483 const CProxyItem &item = _items[index]; 472 const CProxyItem &item = _items[index];
484 const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix; 473 const CProxyDir2 &dir = _proxy2->Dirs[item.DirIndex];
485 unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len(); 474 const CProxyDir2 &baseDir = _proxy2->Dirs[_proxyDirIndex];
486 if (baseLen <= s.Len()) 475 const UString &s = dir.PathPrefix;
476 if (dir.IsLongPath)
487 { 477 {
488 *name = (const wchar_t *)s + baseLen; 478 // in case of IsLongPath we can return reduced prefix or return nothing.
489 *len = s.Len() - baseLen; 479 // so caller will call it with full prefix.
480#if 1 // 1 - for fast processing of long strings, 0 - for full processing
481 *name = (const wchar_t *)s;
482 *len = s.Len();
483#endif
490 } 484 }
491 else 485 else
492 { 486 {
493 return E_FAIL; 487 if (baseDir.IsLongPath)
494 // throw 111l; 488 return E_FAIL; // throw 1;
489 const unsigned baseLen = baseDir.PathPrefix.Len();
490 if (s.Len() < baseLen)
491 return E_FAIL; // throw 1;
492 *name = (const wchar_t *)s + baseLen;
493 *len = s.Len() - baseLen;
495 } 494 }
496 } 495 }
496#else
497 UNUSED_VAR(index)
498#endif
497 return S_OK; 499 return S_OK;
498} 500}
499 501
@@ -552,6 +554,15 @@ int CAgentFolder::CompareItems3(UInt32 index1, UInt32 index2, PROPID propID)
552 return prop1.Compare(prop2); 554 return prop1.Compare(prop2);
553} 555}
554 556
557int CAgentFolder::ComparePrefixes(const UInt32 index1, const UInt32 index2)
558{
559 // we use CAgentFolder::_temp1 instead of local vaiables for faster execution.
560 // it's not allowed to call ComparePrefixes() from different threads simultaneously.
561 // UString _temp1, _temp2;
562 GetPrefix(index1, _temp1);
563 GetPrefix(index2, _temp2);
564 return CompareFileNames_ForFolderList(_temp1, _temp2);
565}
555 566
556int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw) 567int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)
557{ 568{
@@ -591,9 +602,13 @@ int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int
591 { 602 {
592 if (!_flatMode) 603 if (!_flatMode)
593 return 0; 604 return 0;
605#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
594 return CompareFileNames_ForFolderList( 606 return CompareFileNames_ForFolderList(
595 _proxy2->Dirs[_items[index1].DirIndex].PathPrefix, 607 _proxy2->Dirs[_items[index1].DirIndex].PathPrefix,
596 _proxy2->Dirs[_items[index2].DirIndex].PathPrefix); 608 _proxy2->Dirs[_items[index2].DirIndex].PathPrefix);
609#else
610 return ComparePrefixes(index1, index2);
611#endif
597 } 612 }
598 613
599 if (propID == kpidExtension) 614 if (propID == kpidExtension)
@@ -714,10 +729,7 @@ Z7_COM7F_IMF2(Int32, CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PR
714 { 729 {
715 if (!_flatMode) 730 if (!_flatMode)
716 return 0; 731 return 0;
717 UString prefix1, prefix2; 732 return ComparePrefixes(index1, index2);
718 GetPrefix(index1, prefix1);
719 GetPrefix(index2, prefix2);
720 return CompareFileNames_ForFolderList(prefix1, prefix2);
721 } 733 }
722 734
723 UInt32 arcIndex1; 735 UInt32 arcIndex1;
@@ -1004,10 +1016,10 @@ Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder *
1004 return BindToAltStreams((UInt32)(Int32)-1, resultFolder); 1016 return BindToAltStreams((UInt32)(Int32)-1, resultFolder);
1005 1017
1006 { 1018 {
1007 const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; 1019 const CUIntVector &subFiles = _proxy2->Dirs[_proxyDirIndex].Items;
1008 FOR_VECTOR (i, dir.Items) 1020 FOR_VECTOR (i, subFiles)
1009 { 1021 {
1010 const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; 1022 const CProxyFile2 &file = _proxy2->Files[subFiles[i]];
1011 if (file.AltDirIndex != -1) 1023 if (file.AltDirIndex != -1)
1012 if (CompareFileNames(file.Name, name) == 0) 1024 if (CompareFileNames(file.Name, name) == 0)
1013 return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder); 1025 return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder);
@@ -1234,7 +1246,8 @@ Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
1234 1246
1235 if (propID == kpidReadOnly) 1247 if (propID == kpidReadOnly)
1236 { 1248 {
1237 if (_agentSpec->Is_Attrib_ReadOnly()) 1249 if ((_agentSpec->_proxy && _agentSpec->_proxy->Are_Changed_LongPaths)
1250 || _agentSpec->Is_Attrib_ReadOnly())
1238 prop = true; 1251 prop = true;
1239 else 1252 else
1240 prop = _agentSpec->IsThere_ReadOnlyArc(); 1253 prop = _agentSpec->IsThere_ReadOnlyArc();
@@ -1253,8 +1266,8 @@ Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
1253 } 1266 }
1254 else if (propID == kpidPath) 1267 else if (propID == kpidPath)
1255 { 1268 {
1256 bool isAltStreamFolder = false; 1269 // Here we allow the return of reduced path:
1257 prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder); 1270 prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, true); // canReducePath
1258 } 1271 }
1259 else switch (propID) 1272 else switch (propID)
1260 { 1273 {
@@ -1406,17 +1419,20 @@ int CAgentFolder::GetRealIndex(unsigned index) const
1406 } 1419 }
1407} 1420}
1408 1421
1409void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const 1422void CAgentFolder::GetRealIndices(
1423 const UInt32 *indices, const UInt32 numItems,
1424 const bool includeAltStreams, const bool includeFolderSubItemsInFlatMode,
1425 CUIntVector &realIndices) const
1410{ 1426{
1411 if (!_flatMode) 1427 if (!_flatMode)
1412 { 1428 {
1413 if (_proxy2) 1429 if (_proxy2)
1414 _proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices); 1430 _proxy2->GetRealIndices_Unsorted(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices);
1415 else 1431 else
1416 _proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices); 1432 _proxy->GetRealIndices_Unsorted(_proxyDirIndex, indices, numItems, realIndices);
1417 return;
1418 } 1433 }
1419 1434 else
1435 {
1420 realIndices.Clear(); 1436 realIndices.Clear();
1421 1437
1422 for (UInt32 i = 0; i < numItems; i++) 1438 for (UInt32 i = 0; i < numItems; i++)
@@ -1425,13 +1441,14 @@ void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool i
1425 if (_proxy2) 1441 if (_proxy2)
1426 { 1442 {
1427 const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex]; 1443 const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
1428 _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices); 1444 _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index],
1445 includeAltStreams, includeFolderSubItemsInFlatMode, realIndices);
1429 continue; 1446 continue;
1430 } 1447 }
1431 UInt32 arcIndex; 1448 UInt32 arcIndex;
1432 { 1449 {
1433 const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; 1450 const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
1434 unsigned realIndex = item.Index; 1451 const unsigned realIndex = item.Index;
1435 if (realIndex < dir->SubDirs.Size()) 1452 if (realIndex < dir->SubDirs.Size())
1436 { 1453 {
1437 if (includeFolderSubItemsInFlatMode) 1454 if (includeFolderSubItemsInFlatMode)
@@ -1449,6 +1466,7 @@ void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool i
1449 } 1466 }
1450 realIndices.Add(arcIndex); 1467 realIndices.Add(arcIndex);
1451 } 1468 }
1469 }
1452 1470
1453 HeapSort(realIndices.NonConstData(), realIndices.Size()); 1471 HeapSort(realIndices.NonConstData(), realIndices.Size());
1454} 1472}
@@ -1472,11 +1490,13 @@ Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices,
1472 CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec; 1490 CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
1473 UStringVector pathParts; 1491 UStringVector pathParts;
1474 bool isAltStreamFolder = false; 1492 bool isAltStreamFolder = false;
1493 bool isChangedPath = false;
1475 if (_proxy2) 1494 if (_proxy2)
1476 _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); 1495 _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
1477 else 1496 else
1478 _proxy->GetDirPathParts(_proxyDirIndex, pathParts); 1497 _proxy->GetDirPathParts_isChanged(_proxyDirIndex, pathParts, isChangedPath);
1479 1498 if (isChangedPath)
1499 return E_NOTIMPL;
1480 /* 1500 /*
1481 if (_flatMode) 1501 if (_flatMode)
1482 pathMode = NExtract::NPathMode::kNoPathnames; 1502 pathMode = NExtract::NPathMode::kNoPathnames;
@@ -1538,7 +1558,8 @@ Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices,
1538 extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix; 1558 extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix;
1539 1559
1540 CUIntVector realIndices; 1560 CUIntVector realIndices;
1541 GetRealIndices(indices, numItems, IntToBool(includeAltStreams), 1561 GetRealIndices(indices, numItems,
1562 (_loadAltStreams && _flatMode) ? false : IntToBool(includeAltStreams), // v26.03
1542 false, // includeFolderSubItemsInFlatMode 1563 false, // includeFolderSubItemsInFlatMode
1543 realIndices); // 1564 realIndices); //
1544 1565
@@ -1574,7 +1595,8 @@ CAgent::CAgent():
1574 _proxy2(NULL), 1595 _proxy2(NULL),
1575 _updatePathPrefix_is_AltFolder(false), 1596 _updatePathPrefix_is_AltFolder(false),
1576 _isDeviceFile(false), 1597 _isDeviceFile(false),
1577 _isHashHandler(false) 1598 _isHashHandler(false),
1599 _progress_for_Open(NULL)
1578{ 1600{
1579} 1601}
1580 1602
@@ -1588,6 +1610,8 @@ CAgent::~CAgent()
1588 1610
1589bool CAgent::CanUpdate() const 1611bool CAgent::CanUpdate() const
1590{ 1612{
1613 if (_proxy && _proxy->Are_Changed_LongPaths)
1614 return false;
1591 // FAR plugin uses empty agent to create new archive !!! 1615 // FAR plugin uses empty agent to create new archive !!!
1592 if (_archiveLink.Arcs.Size() == 0) 1616 if (_archiveLink.Arcs.Size() == 0)
1593 return true; 1617 return true;
@@ -1746,6 +1770,16 @@ HRESULT CAgent::ReadItems()
1746 else 1770 else
1747 _proxy = new CProxyArc(); 1771 _proxy = new CProxyArc();
1748 1772
1773 size_t ramSize;
1774 if (NWindows::NSystem::GetRamSize(ramSize))
1775 {
1776 ramSize = ramSize / 4 * 3;
1777 if (_proxy2)
1778 _proxy2->MemUsage_Limit = ramSize;
1779 else
1780 _proxy->MemUsage_Limit = ramSize;
1781 }
1782
1749 { 1783 {
1750 ThereIsPathProp = false; 1784 ThereIsPathProp = false;
1751 // ThereIsAltStreamProp = false; 1785 // ThereIsAltStreamProp = false;
@@ -1767,8 +1801,8 @@ HRESULT CAgent::ReadItems()
1767 } 1801 }
1768 1802
1769 if (_proxy2) 1803 if (_proxy2)
1770 return _proxy2->Load(GetArc(), NULL); 1804 return _proxy2->Load(GetArc(), _progress_for_Open);
1771 return _proxy->Load(GetArc(), NULL); 1805 return _proxy->Load(GetArc(), _progress_ArchiveOpenCallback_for_Open);
1772} 1806}
1773 1807
1774Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder)) 1808Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder))
diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h
index a63e459..e19ccd8 100644
--- a/CPP/7zip/UI/Agent/Agent.h
+++ b/CPP/7zip/UI/Agent/Agent.h
@@ -107,11 +107,13 @@ public:
107 107
108 int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID); 108 int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID);
109 int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); 109 int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw);
110 int ComparePrefixes(UInt32 index1, UInt32 index2);
110 111
111 CAgentFolder(): 112 CAgentFolder():
112 _isAltStreamFolder(false), 113 _isAltStreamFolder(false),
113 _flatMode(false), 114 _flatMode(false),
114 _loadAltStreams(false), // _loadAltStreams alt streams works in flat mode, but we don't use it now 115 _loadAltStreams(false), // _loadAltStreams alt streams works in flat mode, but we don't use it now
116 // _loadAltStreams(true), // for debug
115 _proxyDirIndex(0), 117 _proxyDirIndex(0),
116 _zoneMode(NExtract::NZoneIdMode::kNone) 118 _zoneMode(NExtract::NZoneIdMode::kNone)
117 /* , _replaceAltStreamCharsMode(0) */ 119 /* , _replaceAltStreamCharsMode(0) */
@@ -161,6 +163,8 @@ public:
161 CMyComPtr<IInFolderArchive> _agent; 163 CMyComPtr<IInFolderArchive> _agent;
162 CAgent *_agentSpec; 164 CAgent *_agentSpec;
163 CRecordVector<CProxyItem> _items; 165 CRecordVector<CProxyItem> _items;
166
167 UString _temp1, _temp2;
164}; 168};
165 169
166 170
@@ -241,6 +245,9 @@ public:
241 CObjectVector<NWindows::NCOM::CPropVariant> m_PropValues; 245 CObjectVector<NWindows::NCOM::CPropVariant> m_PropValues;
242 #endif 246 #endif
243 247
248 IArchiveOpenCallback *_progress_ArchiveOpenCallback_for_Open; // it's for parsing after archive openning
249 IProgress *_progress_for_Open; // it's for parsing after archive openning
250
244 CAgent(); 251 CAgent();
245 ~CAgent(); 252 ~CAgent();
246 253
diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp
index 265b943..3b2a8b7 100644
--- a/CPP/7zip/UI/Agent/AgentOut.cpp
+++ b/CPP/7zip/UI/Agent/AgentOut.cpp
@@ -42,7 +42,10 @@ Z7_COM7F_IMF(CAgent::SetFolder(IFolderFolder *folder))
42 } 42 }
43 43
44 if (_proxy2) 44 if (_proxy2)
45 _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder); 45 {
46 _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
47 _updatePathPrefix_is_AltFolder = _proxy2->IsAltDir(_agentFolder->_proxyDirIndex);
48 }
46 else 49 else
47 _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); 50 _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
48 return S_OK; 51 return S_OK;
@@ -58,86 +61,140 @@ Z7_COM7F_IMF(CAgent::SetFiles(const wchar_t *folderPrefix,
58 return S_OK; 61 return S_OK;
59} 62}
60 63
61static HRESULT EnumerateArchiveItems(CAgent *agent, 64
62 const CProxyDir &item, 65static HRESULT EnumerateArchiveItems(const CAgent *agent,
63 const UString &prefix,
64 CObjectVector<CArcItem> &arcItems) 66 CObjectVector<CArcItem> &arcItems)
65{ 67{
66 unsigned i; 68 CUIntVector vec;
67 69 CArcItem ai;
68 for (i = 0; i < item.SubFiles.Size(); i++) 70 ai.Censored = true; // test it
69 { 71 unsigned prefixLen = 0;
70 unsigned arcIndex = item.SubFiles[i]; 72 unsigned dirIndex = k_Proxy_RootDirIndex; // 0
71 const CProxyFile &fileItem = agent->_proxy->Files[arcIndex]; 73 unsigned i = 0;
72 CArcItem ai; 74 for (;;)
73 RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
74 RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
75 ai.IsDir = false;
76 ai.Name = prefix + fileItem.Name;
77 ai.Censored = true; // test it
78 ai.IndexInServer = arcIndex;
79 arcItems.Add(ai);
80 }
81
82 for (i = 0; i < item.SubDirs.Size(); i++)
83 { 75 {
84 const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]]; 76 const CProxyDir &dir = agent->_proxy->Dirs[dirIndex];
85 UString fullName = prefix + dirItem.Name; 77
86 if (dirItem.IsLeaf()) 78 if (i == dir.SubDirs.Size()) // we fill SubFiles after SubDirs
79 {
80 ai.IsDir = false;
81 FOR_VECTOR (k, dir.SubFiles)
82 {
83 const unsigned arcIndex = dir.SubFiles[k];
84 ai.IndexInServer = arcIndex;
85 RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
86 RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
87 RINOK(Archive_IsItem_AltStream(agent->GetArc().Archive, arcIndex, ai.IsAltStream))
88 ai.Name.DeleteFrom(prefixLen);
89 const CProxyFile &file = agent->_proxy->Files[arcIndex];
90 ai.Name += file.Name;
91 arcItems.Add(ai);
92 }
93
94 const unsigned num = vec.Size();
95 if (num < 3)
96 return S_OK;
97 prefixLen = vec[num - 3];
98 dirIndex = vec[num - 2];
99 i = vec[num - 1];
100 vec.DeleteFrom(num - 3);
101 continue;
102 }
103
104 const unsigned subDirIndex = dir.SubDirs[i];
105 i++;
106 const CProxyDir &subDir = agent->_proxy->Dirs[subDirIndex];
107 ai.Name.DeleteFrom(prefixLen);
108 ai.Name += subDir.Name;
109 if (subDir.IsLeaf())
87 { 110 {
88 CArcItem ai; 111 ai.IndexInServer = (unsigned)subDir.ArcIndex;
89 RINOK(agent->GetArc().GetItem_MTime((unsigned)dirItem.ArcIndex, ai.MTime)) 112 RINOK(agent->GetArc().GetItem_MTime((unsigned)subDir.ArcIndex, ai.MTime))
90 ai.IsDir = true; 113 ai.IsDir = true;
114 ai.IsAltStream = false;
91 ai.Size_Defined = false; 115 ai.Size_Defined = false;
92 ai.Name = fullName; 116 ai.Size = 0;
93 ai.Censored = true; // test it
94 ai.IndexInServer = (unsigned)dirItem.ArcIndex;
95 arcItems.Add(ai); 117 arcItems.Add(ai);
96 } 118 }
97 RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems)) 119
120 vec.Add(prefixLen);
121 vec.Add(dirIndex);
122 vec.Add(i);
123 ai.Name.Add_PathSepar();
124 prefixLen = ai.Name.Len();
125 if (prefixLen >= (1 << 15) /* || vec.Size() >= (3 << 14) */ ) // NTFS limit
126 return E_NOTIMPL;
127 dirIndex = subDirIndex;
128 i = 0;
98 } 129 }
99
100 return S_OK;
101} 130}
102 131
132
103static HRESULT EnumerateArchiveItems2(const CAgent *agent, 133static HRESULT EnumerateArchiveItems2(const CAgent *agent,
104 unsigned dirIndex, 134 unsigned dirIndex,
105 const UString &prefix, 135 const UString &prefix,
106 CObjectVector<CArcItem> &arcItems) 136 CObjectVector<CArcItem> &arcItems)
107{ 137{
108 const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex]; 138 CUIntVector vec;
109 FOR_VECTOR (i, dir.Items) 139 CArcItem ai;
140 ai.Censored = true; // test it
141 ai.Name = prefix;
142 unsigned prefixLen = ai.Name.Len();
143 unsigned i = 0;
144 for (;;)
110 { 145 {
111 unsigned arcIndex = dir.Items[i]; 146 const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex];
147 if (i == dir.Items.Size())
148 {
149 const unsigned num = vec.Size();
150 if (num < 3)
151 return S_OK;
152 prefixLen = vec[num - 3];
153 dirIndex = vec[num - 2];
154 i = vec[num - 1];
155 vec.DeleteFrom(num - 3);
156 continue;
157 }
158
159 const unsigned arcIndex = dir.Items[i];
160 i++;
161 ai.Name.DeleteFrom(prefixLen);
112 const CProxyFile2 &file = agent->_proxy2->Files[arcIndex]; 162 const CProxyFile2 &file = agent->_proxy2->Files[arcIndex];
113 CArcItem ai; 163 ai.Name += file.Name;
164 // v23.03: we normalize slashes:
165 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(
166 ai.Name.Ptr_non_const() + (ai.Name.Len() - file.NameLen), file.NameLen);
114 ai.IndexInServer = arcIndex; 167 ai.IndexInServer = arcIndex;
115 ai.Name = prefix + file.Name;
116 ai.Censored = true; // test it
117 RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) 168 RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
118 ai.IsDir = file.IsDir(); 169 ai.Size = 0;
119 ai.Size_Defined = false; 170 ai.Size_Defined = false;
120 ai.IsAltStream = file.IsAltStream; 171 ai.IsAltStream = file.IsAltStream;
121 if (!ai.IsDir) 172 ai.IsDir = file.IsDir();
122 { 173 if (!file.IsDir())
123 RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) 174 RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
124 ai.IsDir = false;
125 }
126 arcItems.Add(ai);
127 175
176 arcItems.Add(ai);
177
128 if (file.AltDirIndex != -1) 178 if (file.AltDirIndex != -1)
179 RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex,
180 ai.Name + L':', arcItems))
181
182 if (file.IsDir())
129 { 183 {
130 RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, ai.Name + L':', arcItems)) 184 vec.Add(prefixLen);
131 } 185 vec.Add(dirIndex);
132 186 vec.Add(i);
133 if (ai.IsDir) 187 ai.Name.Add_PathSepar();
134 { 188 prefixLen = ai.Name.Len();
135 RINOK(EnumerateArchiveItems2(agent, (unsigned)file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems)) 189 if (prefixLen >= (1 << 15) /* || vec.Size() >= (3 << 14) */ ) // NTFS limit
190 return E_NOTIMPL;
191 dirIndex = (unsigned)file.DirIndex;
192 i = 0;
136 } 193 }
137 } 194 }
138 return S_OK;
139} 195}
140 196
197
141struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback 198struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback
142{ 199{
143 const CObjectVector<CArcItem> *_arcItems; 200 const CObjectVector<CArcItem> *_arcItems;
@@ -299,7 +356,7 @@ Z7_COM7F_IMF(CAgent::DoOperation(
299 } 356 }
300 else 357 else
301 { 358 {
302 RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems)) 359 RINOK(EnumerateArchiveItems(this, arcItems))
303 } 360 }
304 } 361 }
305 362
@@ -510,9 +567,8 @@ HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream,
510 567
511 di.Attrib = FILE_ATTRIBUTE_DIRECTORY; 568 di.Attrib = FILE_ATTRIBUTE_DIRECTORY;
512 di.Size = 0; 569 di.Size = 0;
513 bool isAltStreamFolder = false;
514 if (_proxy2) 570 if (_proxy2)
515 di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder); 571 di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex /* , isAltStreamFolder */);
516 else 572 else
517 di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); 573 di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
518 di.Name += folderName; 574 di.Name += folderName;
diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp
index c8edd19..71b01da 100644
--- a/CPP/7zip/UI/Agent/AgentProxy.cpp
+++ b/CPP/7zip/UI/Agent/AgentProxy.cpp
@@ -9,7 +9,6 @@
9#include <ctype.h> 9#include <ctype.h>
10#endif 10#endif
11 11
12#include "../../../../C/Sort.h"
13#include "../../../../C/CpuArch.h" 12#include "../../../../C/CpuArch.h"
14 13
15#include "../../../Common/UTFConvert.h" 14#include "../../../Common/UTFConvert.h"
@@ -24,10 +23,12 @@
24 23
25using namespace NWindows; 24using namespace NWindows;
26 25
27int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const 26#define CHECK_MEM_USAGE { if (MemUsage > MemUsage_Limit) return E_OUTOFMEMORY; }
27
28int CProxyArc::FindSubDir(const unsigned *items, unsigned right,
29 const wchar_t *name, unsigned &insertPos) const
28{ 30{
29 const CRecordVector<unsigned> &subDirs = Dirs[dirIndex].SubDirs; 31 unsigned left = 0;
30 unsigned left = 0, right = subDirs.Size();
31 for (;;) 32 for (;;)
32 { 33 {
33 if (left == right) 34 if (left == right)
@@ -36,10 +37,13 @@ int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &inse
36 return -1; 37 return -1;
37 } 38 }
38 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); 39 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
39 const unsigned dirIndex2 = subDirs[mid]; 40 const unsigned dirIndex2 = items[mid];
40 const int comp = CompareFileNames(name, Dirs[dirIndex2].Name); 41 const int comp = CompareFileNames(name, Dirs[dirIndex2].Name);
41 if (comp == 0) 42 if (comp == 0)
43 {
44 insertPos = mid; // not used, but we set it to suppress compiler warnings
42 return (int)dirIndex2; 45 return (int)dirIndex2;
46 }
43 if (comp < 0) 47 if (comp < 0)
44 right = mid; 48 right = mid;
45 else 49 else
@@ -50,88 +54,151 @@ int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &inse
50int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const 54int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const
51{ 55{
52 unsigned insertPos; 56 unsigned insertPos;
53 return FindSubDir(dirIndex, name, insertPos); 57 const CUIntVector &dirs = Dirs[dirIndex].SubDirs;
58 return FindSubDir(dirs.ConstData(), dirs.Size(), name, insertPos);
54} 59}
55 60
56static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len) 61static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len)
57{ 62{
58 wchar_t *p = new wchar_t[len + 1]; 63 ++len;
59 MyStringCopy(p, s); 64 wchar_t *p = new wchar_t[len];
60 return p; 65 return wmemcpy(p, s, len);
66 // MyStringCopy(p, s); return p;
61} 67}
62 68
63static const wchar_t *AllocStringAndCopy(const UString &s) 69static const wchar_t *AllocStringAndCopy(const UString &s)
64{ 70{
65 return AllocStringAndCopy(s, s.Len()); 71 return AllocStringAndCopy(s, s.Len());
66} 72}
67 73
68unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) 74
75void CProxyArc::MergeSubDirs(CProxyDir &baseDir)
69{ 76{
77 CUIntVector &dirs2 = baseDir.SubDirs2;
78 unsigned i = dirs2.Size();
79 if (i == 0)
80 return;
81 CUIntVector &dirs = baseDir.SubDirs;
82 unsigned right = dirs.Size();
83 unsigned total = right + i;
84 dirs.ChangeSize_KeepData_plus_AdditionalReserve(total);
85 unsigned * const items = dirs.NonConstData();
86 do
87 {
88 const unsigned index = dirs2[--i];
89 unsigned insertPos;
90 if (FindSubDir(items, right, Dirs[index].Name, insertPos) != -1)
91 throw 1;
92 const unsigned numItems = right - insertPos;
93 right = insertPos;
94 total -= numItems;
95 memmove(items + total, items + insertPos, numItems * sizeof(*items));
96 items[--total] = index;
97 }
98 while (i);
99 dirs2.Clear();
100}
101
102
103unsigned CProxyArc::AddDir(const unsigned dirIndex, const int arcIndex, const UString &name)
104{
105 CProxyDir &baseDir = Dirs[dirIndex];
106 CUIntVector &dirs = baseDir.SubDirs;
107 CUIntVector &dirs2 = baseDir.SubDirs2;
108 {
109 const unsigned numSmallDirs = dirs2.Size();
110 if (numSmallDirs * numSmallDirs > dirs.Size())
111 MergeSubDirs(baseDir);
112 }
70 unsigned insertPos; 113 unsigned insertPos;
71 int subDirIndex = FindSubDir(dirIndex, name, insertPos); 114 int subDirIndex = FindSubDir(dirs.ConstData(), dirs.Size(), name, insertPos);
72 if (subDirIndex != -1) 115 if (subDirIndex == -1)
73 { 116 {
74 if (arcIndex != -1) 117 unsigned insertPos2;
118 subDirIndex = FindSubDir(dirs2.ConstData(), dirs2.Size(), name, insertPos2);
119 if (subDirIndex == -1)
75 { 120 {
76 CProxyDir &item = Dirs[(unsigned)subDirIndex]; 121 CUIntVector *subDirsWork = &dirs;
77 if (item.ArcIndex == -1) 122 if (dirs.Size() - insertPos >= (1 << 12))
78 item.ArcIndex = arcIndex; 123 {
124 subDirsWork = &dirs2;
125 insertPos = insertPos2;
126 }
127 subDirIndex = (int)Dirs.Size();
128 subDirsWork->Insert(insertPos, (unsigned)subDirIndex);
129 CProxyDir &item = Dirs.AddNew();
130 item.NameLen = name.Len();
131 MemUsage += (size_t)item.NameLen * sizeof(*item.Name)
132 + sizeof(CProxyDir) + sizeof(void *) * 3 + 24;
133 item.Name = AllocStringAndCopy(name);
134 item.ArcIndex = arcIndex;
135 item.ParentDir = (int)dirIndex;
136 return (unsigned)subDirIndex;
79 } 137 }
80 return (unsigned)subDirIndex;
81 } 138 }
82 subDirIndex = (int)Dirs.Size();
83 Dirs[dirIndex].SubDirs.Insert(insertPos, (unsigned)subDirIndex);
84 CProxyDir &item = Dirs.AddNew();
85
86 item.NameLen = name.Len();
87 item.Name = AllocStringAndCopy(name);
88 139
89 item.ArcIndex = arcIndex; 140 CProxyDir &item = Dirs[(unsigned)subDirIndex];
90 item.ParentDir = (int)dirIndex; 141 if (item.ArcIndex == -1)
142 item.ArcIndex = arcIndex;
91 return (unsigned)subDirIndex; 143 return (unsigned)subDirIndex;
92} 144}
93 145
94void CProxyDir::Clear()
95{
96 SubDirs.Clear();
97 SubFiles.Clear();
98}
99 146
100void CProxyArc::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const 147void CProxyArc::GetDirPathParts_isChanged(unsigned dirIndex,
148 UStringVector &pathParts, bool &isChangedPath) const
101{ 149{
150 isChangedPath = false;
102 pathParts.Clear(); 151 pathParts.Clear();
103 // while (dirIndex != -1) 152 while (dirIndex != k_Proxy_RootDirIndex)
104 for (;;)
105 { 153 {
106 const CProxyDir &dir = Dirs[dirIndex]; 154 const CProxyDir &dir = Dirs[dirIndex];
155 if (dir.Is_Changed_LongPath)
156 isChangedPath = true;
107 dirIndex = (unsigned)dir.ParentDir; 157 dirIndex = (unsigned)dir.ParentDir;
108 if (dir.ParentDir == -1)
109 break;
110 pathParts.Insert(0, dir.Name); 158 pathParts.Insert(0, dir.Name);
111 // 22.00: we normalize name 159 // 22.00: we normalize name
112 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]); 160 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]);
113 } 161 }
114} 162}
115 163
116UString CProxyArc::GetDirPath_as_Prefix(unsigned dirIndex) const 164
165void CProxyArc::GetDirPath_as_Prefix_from_Base(const unsigned dirIndex,
166 UString &prefix, const unsigned baseDirIndex) const
117{ 167{
118 UString s; 168 prefix.Empty();
119 // while (dirIndex != -1) 169 if (dirIndex == baseDirIndex)
120 for (;;) 170 return;
171 unsigned len = 0;
172 unsigned i = dirIndex;
173 do
121 { 174 {
122 const CProxyDir &dir = Dirs[dirIndex]; 175 const CProxyDir &dir = Dirs[i];
123 dirIndex = (unsigned)dir.ParentDir; 176 len += dir.NameLen + 1;
124 if (dir.ParentDir == -1) 177 i = (unsigned)dir.ParentDir;
125 break; 178 }
126 s.InsertAtFront(WCHAR_PATH_SEPARATOR); 179 while (i != baseDirIndex);
127 s.Insert(0, dir.Name); 180
128 // 22.00: we normalize name 181 wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
129 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name)); 182 i = dirIndex;
183 do
184 {
185 const CProxyDir &dir = Dirs[i];
186 *--p = WCHAR_PATH_SEPARATOR;
187 p -= dir.NameLen;
188 wmemcpy(p, dir.Name, dir.NameLen);
189 i = (unsigned)dir.ParentDir;
130 } 190 }
191 while (i != baseDirIndex);
192}
193
194UString CProxyArc::GetDirPath_as_Prefix(const unsigned dirIndex) const
195{
196 UString s;
197 GetDirPath_as_Prefix_from_Base(dirIndex, s, k_Proxy_RootDirIndex);
131 return s; 198 return s;
132} 199}
133 200
134void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const 201void CProxyArc::AddRealIndices(const unsigned dirIndex, CUIntVector &realIndices) const
135{ 202{
136 const CProxyDir &dir = Dirs[dirIndex]; 203 const CProxyDir &dir = Dirs[dirIndex];
137 if (dir.IsLeaf()) 204 if (dir.IsLeaf())
@@ -143,7 +210,7 @@ void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) cons
143 realIndices.Add(dir.SubFiles[i]); 210 realIndices.Add(dir.SubFiles[i]);
144} 211}
145 212
146int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const 213int CProxyArc::GetRealIndex(const unsigned dirIndex, const unsigned index) const
147{ 214{
148 const CProxyDir &dir = Dirs[dirIndex]; 215 const CProxyDir &dir = Dirs[dirIndex];
149 const unsigned numDirItems = dir.SubDirs.Size(); 216 const unsigned numDirItems = dir.SubDirs.Size();
@@ -157,7 +224,8 @@ int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const
157 return (int)dir.SubFiles[index - numDirItems]; 224 return (int)dir.SubFiles[index - numDirItems];
158} 225}
159 226
160void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const 227void CProxyArc::GetRealIndices_Unsorted(unsigned dirIndex,
228 const UInt32 *indices, const UInt32 numItems, CUIntVector &realIndices) const
161{ 229{
162 const CProxyDir &dir = Dirs[dirIndex]; 230 const CProxyDir &dir = Dirs[dirIndex];
163 realIndices.Clear(); 231 realIndices.Clear();
@@ -170,11 +238,9 @@ void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32
170 else 238 else
171 realIndices.Add(dir.SubFiles[index - numDirItems]); 239 realIndices.Add(dir.SubFiles[index - numDirItems]);
172 } 240 }
173 HeapSort(realIndices.NonConstData(), realIndices.Size()); 241 // HeapSort(realIndices.NonConstData(), realIndices.Size());
174} 242}
175 243
176///////////////////////////////////////////////
177// CProxyArc
178 244
179static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size) 245static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size)
180{ 246{
@@ -185,51 +251,68 @@ static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &si
185 return ConvertPropVariantToUInt64(prop, size); 251 return ConvertPropVariantToUInt64(prop, size);
186} 252}
187 253
188void CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive) 254void CProxyArc::CalculateSizes(IInArchive *archive)
189{ 255{
190 CProxyDir &dir = Dirs[dirIndex]; 256 CUIntVector vec;
191 dir.Size = dir.PackSize = 0; 257 unsigned dirIndex = 0, i = 0;
192 dir.NumSubDirs = dir.SubDirs.Size(); 258 for (;;)
193 dir.NumSubFiles = dir.SubFiles.Size();
194 dir.CrcIsDefined = true;
195 dir.Crc = 0;
196
197 unsigned i;
198
199 for (i = 0; i < dir.SubFiles.Size(); i++)
200 { 259 {
201 const UInt32 index = (UInt32)dir.SubFiles[i]; 260 CProxyDir &dir = Dirs[dirIndex];
202 UInt64 size, packSize; 261 if (i == 0)
203 const bool sizeDefined = GetSize(archive, index, kpidSize, size);
204 dir.Size += size;
205 GetSize(archive, index, kpidPackSize, packSize);
206 dir.PackSize += packSize;
207 { 262 {
208 NCOM::CPropVariant prop; 263 dir.Size = dir.PackSize = 0;
209 if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) 264 dir.NumSubDirs = dir.SubDirs.Size();
265 dir.NumSubFiles = dir.SubFiles.Size();
266 dir.CrcIsDefined = true;
267 dir.Crc = 0;
268
269 FOR_VECTOR (k, dir.SubFiles)
210 { 270 {
211 if (prop.vt == VT_UI4) 271 const UInt32 index = (UInt32)dir.SubFiles[k];
212 dir.Crc += prop.ulVal; 272 UInt64 size, packSize;
213 else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) 273 const bool sizeDefined = GetSize(archive, index, kpidSize, size);
214 dir.CrcIsDefined = false; 274 dir.Size += size;
275 GetSize(archive, index, kpidPackSize, packSize);
276 dir.PackSize += packSize;
277 {
278 NCOM::CPropVariant prop;
279 if (archive->GetProperty(index, kpidCRC, &prop) == S_OK)
280 {
281 if (prop.vt == VT_UI4)
282 dir.Crc += prop.ulVal;
283 else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined)
284 dir.CrcIsDefined = false;
285 }
286 else
287 dir.CrcIsDefined = false;
288 }
215 } 289 }
216 else
217 dir.CrcIsDefined = false;
218 } 290 }
219 } 291
220 292 if (i == dir.SubDirs.Size())
221 for (i = 0; i < dir.SubDirs.Size(); i++) 293 {
222 { 294 const unsigned num = vec.Size();
223 unsigned subDirIndex = dir.SubDirs[i]; 295 if (num < 2)
224 CalculateSizes(subDirIndex, archive); 296 return;
225 CProxyDir &f = Dirs[subDirIndex]; 297 dirIndex = vec[num - 2];
226 dir.Size += f.Size; 298 i = vec[num - 1];
227 dir.PackSize += f.PackSize; 299 vec.DeleteFrom(num - 2);
228 dir.NumSubFiles += f.NumSubFiles; 300
229 dir.NumSubDirs += f.NumSubDirs; 301 CProxyDir &dir2 = Dirs[dirIndex];
230 dir.Crc += f.Crc; 302 dir2.Size += dir.Size;
231 if (!f.CrcIsDefined) 303 dir2.PackSize += dir.PackSize;
232 dir.CrcIsDefined = false; 304 dir2.NumSubFiles += dir.NumSubFiles;
305 dir2.NumSubDirs += dir.NumSubDirs;
306 dir2.Crc += dir.Crc;
307 if (!dir.CrcIsDefined)
308 dir2.CrcIsDefined = false;
309 continue;
310 }
311
312 vec.Add(dirIndex);
313 vec.Add(i + 1);
314 dirIndex = dir.SubDirs[i];
315 i = 0;
233 } 316 }
234} 317}
235 318
@@ -246,42 +329,54 @@ void CProxyArc::FreeFiles()
246 Files = NULL; 329 Files = NULL;
247} 330}
248 331
332
333static void SetPath_as_LONG_PATH(UString &s,
334 const unsigned fileIndex, const bool isDir)
335{
336 s = isDir ? "[LONG_PATH_DIR_" : "[LONG_PATH_FILE_";
337 s.Add_UInt32((UInt32)fileIndex);
338 s.Add_Char(']');
339}
340
341
249static const UInt32 k_NumFiles_Max = 0x7fffffff - 15; 342static const UInt32 k_NumFiles_Max = 0x7fffffff - 15;
250 343
251HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) 344HRESULT CProxyArc::Load(const CArc &arc, IArchiveOpenCallback *progress)
252{ 345{
253 // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { 346 // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) {
254
255 FreeFiles(); 347 FreeFiles();
256 Dirs.Clear(); 348 Dirs.Clear();
349 Are_Changed_LongPaths = false;
257 350
258 Dirs.AddNew(); 351 Dirs.AddNew();
259 IInArchive *archive = arc.Archive; 352 IInArchive *archive = arc.Archive;
260
261 UInt32 numItems; 353 UInt32 numItems;
262 RINOK(archive->GetNumberOfItems(&numItems)) 354 RINOK(archive->GetNumberOfItems(&numItems))
263 if (numItems > k_NumFiles_Max) 355 if (numItems > k_NumFiles_Max)
264 return E_OUTOFMEMORY; 356 return E_OUTOFMEMORY;
265
266 if (progress) 357 if (progress)
267 RINOK(progress->SetTotal(numItems)) 358 {
359 const UInt64 numItems64 = numItems;
360 RINOK(progress->SetTotal(&numItems64, NULL))
361 }
268 362
363 MemUsage = (UInt64)numItems * sizeof(*Files);
364 CHECK_MEM_USAGE
269 Z7_ARRAY_NEW(Files, CProxyFile, numItems) 365 Z7_ARRAY_NEW(Files, CProxyFile, numItems)
270 memset(Files, 0, (size_t)numItems * sizeof(*Files)); 366 memset(Files, 0, (size_t)numItems * sizeof(*Files));
271 NumFiles = numItems; 367 NumFiles = numItems;
272 368
273 UString path; 369 UString path, name;
274 UString name;
275 NCOM::CPropVariant prop; 370 NCOM::CPropVariant prop;
276 371
277 for (UInt32 i = 0; i < numItems; i++) 372 for (UInt32 i = 0; i < numItems; i++)
278 { 373 {
374 CHECK_MEM_USAGE
279 if (progress && (i & 0xFFFF) == 0) 375 if (progress && (i & 0xFFFF) == 0)
280 { 376 {
281 const UInt64 currentItemIndex = i; 377 const UInt64 currentItemIndex = i;
282 RINOK(progress->SetCompleted(&currentItemIndex)) 378 RINOK(progress->SetCompleted(&currentItemIndex, NULL))
283 } 379 }
284
285 const wchar_t *s = NULL; 380 const wchar_t *s = NULL;
286 unsigned len = 0; 381 unsigned len = 0;
287 bool isPtrName = false; 382 bool isPtrName = false;
@@ -313,6 +408,7 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
313 if (!s) 408 if (!s)
314 #endif 409 #endif
315 { 410 {
411 len = 0;
316 prop.Clear(); 412 prop.Clear();
317 RINOK(arc.Archive->GetProperty(i, kpidPath, &prop)) 413 RINOK(arc.Archive->GetProperty(i, kpidPath, &prop))
318 if (prop.vt == VT_BSTR) 414 if (prop.vt == VT_BSTR)
@@ -328,7 +424,6 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
328 len = path.Len(); 424 len = path.Len();
329 s = path; 425 s = path;
330 } 426 }
331
332 /* 427 /*
333 RINOK(arc.GetItemPath(i, path)); 428 RINOK(arc.GetItemPath(i, path));
334 len = path.Len(); 429 len = path.Len();
@@ -337,7 +432,6 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
337 } 432 }
338 433
339 unsigned curItem = 0; 434 unsigned curItem = 0;
340
341 /* 435 /*
342 if (arc.Ask_Deleted) 436 if (arc.Ask_Deleted)
343 { 437 {
@@ -347,12 +441,22 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
347 curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); 441 curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]");
348 } 442 }
349 */ 443 */
350
351 unsigned namePos = 0; 444 unsigned namePos = 0;
352
353 unsigned numLevels = 0; 445 unsigned numLevels = 0;
446 bool is_Changed_LongPath = false;
447 bool isDir;
448 RINOK(Archive_IsItem_Dir(archive, i, isDir))
354 449
355 for (unsigned j = 0; j < len; j++) 450 if (len >= (1 << 15))
451 {
452 Are_Changed_LongPaths = true;
453 is_Changed_LongPath = true;
454 SetPath_as_LONG_PATH(path, i, isDir);
455 s = path;
456 len = path.Len();
457 isPtrName = false;
458 }
459 else for (unsigned j = 0; j < len; j++)
356 { 460 {
357 const wchar_t c = s[j]; 461 const wchar_t c = s[j];
358 if (c == L'/' 462 if (c == L'/'
@@ -365,12 +469,18 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
365 if (numLevels <= kLevelLimit) 469 if (numLevels <= kLevelLimit)
366 { 470 {
367 if (numLevels == kLevelLimit) 471 if (numLevels == kLevelLimit)
472 {
368 name = "[LONG_PATH]"; 473 name = "[LONG_PATH]";
474 Are_Changed_LongPaths = true;
475 is_Changed_LongPath = true;
476 }
369 else 477 else
370 name.SetFrom(s + namePos, j - namePos); 478 name.SetFrom(s + namePos, j - namePos);
371 // 22.00: we can normalize dir here 479 // 22.00: we can normalize dir here
372 // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); 480 // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
373 curItem = AddDir(curItem, -1, name); 481 curItem = AddDir(curItem, -1, name);
482 if (is_Changed_LongPath)
483 Dirs[curItem].Is_Changed_LongPath = true;
374 } 484 }
375 namePos = j + 1; 485 namePos = j + 1;
376 numLevels++; 486 numLevels++;
@@ -378,24 +488,16 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
378 } 488 }
379 489
380 /* 490 /*
381 that code must be implemeted to hide alt streams in list. 491 that code must be implemented to hide alt streams in list.
382 if (arc.Ask_AltStreams) 492 if (arc.Ask_AltStreams)
383 { 493 {
384 bool isAltStream; 494 bool isAltStream;
385 RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); 495 RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
386 if (isAltStream) 496 if (isAltStream){}
387 {
388
389 }
390 } 497 }
391 */ 498 */
392
393 bool isDir;
394 RINOK(Archive_IsItem_Dir(archive, i, isDir))
395
396 CProxyFile &f = Files[i]; 499 CProxyFile &f = Files[i];
397 f.Construct(); // optional because memset() in code above 500 f.Construct(); // optional because memset() in code above
398
399 f.NameLen = len - namePos; 501 f.NameLen = len - namePos;
400 s += namePos; 502 s += namePos;
401 503
@@ -403,6 +505,7 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
403 f.Name = s; 505 f.Name = s;
404 else 506 else
405 { 507 {
508 MemUsage += 16 + (size_t)f.NameLen * sizeof(*f.Name);
406 f.Name = AllocStringAndCopy(s, f.NameLen); 509 f.Name = AllocStringAndCopy(s, f.NameLen);
407 f.NeedDeleteName = true; 510 f.NeedDeleteName = true;
408 } 511 }
@@ -412,16 +515,30 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
412 name = s; 515 name = s;
413 // 22.00: we can normalize dir here 516 // 22.00: we can normalize dir here
414 // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); 517 // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
415 AddDir(curItem, (int)i, name); 518 curItem = AddDir(curItem, (int)i, name);
519 if (is_Changed_LongPath)
520 Dirs[curItem].Is_Changed_LongPath = true;
416 } 521 }
417 else 522 else
523 {
524 MemUsage += Dirs[curItem].SubFiles.IsEmpty() ? 16u : 4u + 1;
418 Dirs[curItem].SubFiles.Add(i); 525 Dirs[curItem].SubFiles.Add(i);
526 }
419 } 527 }
420
421 CalculateSizes(0, archive);
422 528
529 FOR_VECTOR (k, Dirs)
530 {
531 MergeSubDirs(Dirs[k]);
532 Dirs[k].SubDirs2.ClearAndFree(); // these arryas are small
533 }
534
535 CalculateSizes(archive);
536 if (progress)
537 {
538 const UInt64 numItems64 = numItems;
539 RINOK(progress->SetCompleted(&numItems64, NULL))
540 }
423 // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); 541 // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s);
424
425 return S_OK; 542 return S_OK;
426} 543}
427 544
@@ -429,12 +546,38 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
429 546
430// ---------- for Tree-mode archive ---------- 547// ---------- for Tree-mode archive ----------
431 548
432void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const 549
550void SetDirPrefix_as_LONG_PATH(UString &s, unsigned fileIndex,
551 const bool asAltDirPrefix, const bool isDir)
552{
553 SetPath_as_LONG_PATH(s, fileIndex, isDir);
554 s.Add_Char(asAltDirPrefix ? ':' : CHAR_PATH_SEPARATOR);
555}
556
557
558bool CProxyArc2::IsAltDir(const unsigned dirIndex) const
559{
560 if (dirIndex == k_Proxy2_RootDirIndex)
561 return false;
562 if (dirIndex == k_Proxy2_AltRootDirIndex)
563 return true;
564 const CProxyDir2 &dir = Dirs[dirIndex];
565 if ((unsigned)dir.ArcIndex >= NumFiles) throw 1; // optional
566 return (int)dirIndex == Files[(unsigned)dir.ArcIndex].AltDirIndex;
567}
568
569
570/* called from:
571 Agent.cpp:
572 CAgentFolder::Extract()
573 ArchiveFolderOut.cpp:
574 CAgentFolder::GetPathParts()
575 CAgentFolder::CommonUpdateOperation()
576*/
577void CProxyArc2::GetDirPathParts(const unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const
433{ 578{
434 pathParts.Clear(); 579 pathParts.Clear();
435
436 isAltStreamDir = false; 580 isAltStreamDir = false;
437
438 if (dirIndex == k_Proxy2_RootDirIndex) 581 if (dirIndex == k_Proxy2_RootDirIndex)
439 return; 582 return;
440 if (dirIndex == k_Proxy2_AltRootDirIndex) 583 if (dirIndex == k_Proxy2_AltRootDirIndex)
@@ -442,94 +585,220 @@ void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bo
442 isAltStreamDir = true; 585 isAltStreamDir = true;
443 return; 586 return;
444 } 587 }
445 588 int fileIndex = Dirs[dirIndex].ArcIndex;
446 while (dirIndex >= k_Proxy2_NumRootDirs) 589 do
447 { 590 {
448 const CProxyDir2 &dir = Dirs[dirIndex]; 591 if ((unsigned)fileIndex >= NumFiles) throw 1; // optional
449 const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; 592 const CProxyFile2 &file = Files[(unsigned)fileIndex];
450 if (pathParts.IsEmpty() && (int)dirIndex == file.AltDirIndex) 593 // if (pathParts.Size() == 0) // optional
594 if ((int)dirIndex == file.AltDirIndex)
451 isAltStreamDir = true; 595 isAltStreamDir = true;
596 // that code is not optimized for big number of loop iterations.
452 pathParts.Insert(0, file.Name); 597 pathParts.Insert(0, file.Name);
453 const int par = file.Parent; 598 fileIndex = file.Parent;
454 if (par == -1)
455 break;
456 dirIndex = (unsigned)Files[(unsigned)par].DirIndex;
457 // if ((int)dirIndex == -1) break;
458 } 599 }
600 while (fileIndex != -1);
459} 601}
460 602
461bool CProxyArc2::IsAltDir(unsigned dirIndex) const 603
604// if Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX is defined,
605// { this code is unused mostly. 7-Zip gets prefix via GetItemPrefix(). }
606void CProxyArc2::GetDirPath_as_Prefix_from_Base(const unsigned dirIndex,
607 UString &prefix, const unsigned baseDirIndex, const unsigned lenLimit) const
462{ 608{
463 if (dirIndex == k_Proxy2_RootDirIndex) 609 prefix.Empty();
464 return false; 610 if (dirIndex == baseDirIndex)
611 return;
465 if (dirIndex == k_Proxy2_AltRootDirIndex) 612 if (dirIndex == k_Proxy2_AltRootDirIndex)
466 return true; 613 {
467 const CProxyDir2 &dir = Dirs[dirIndex]; 614 // (baseDirIndex == k_Proxy2_RootDirIndex) is expected
468 const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; 615 prefix.Add_Colon();
469 return ((int)dirIndex == file.AltDirIndex); 616 return;
470} 617 }
471 618
472UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const
473{
474 isAltStreamDir = false;
475 const CProxyDir2 &dir = Dirs[dirIndex]; 619 const CProxyDir2 &dir = Dirs[dirIndex];
476 if (dirIndex == k_Proxy2_AltRootDirIndex) 620 int arcIndex = dir.ArcIndex;
477 isAltStreamDir = true; 621 if (arcIndex != -1)
478 else if (dirIndex >= k_Proxy2_NumRootDirs)
479 { 622 {
480 const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; 623 const CProxyDir2 &baseDir = Dirs[baseDirIndex];
481 isAltStreamDir = ((int)dirIndex == file.AltDirIndex); 624 unsigned len = dir.PrefixLen - baseDir.PrefixLen;
625 if (len >= lenLimit)
626 {
627 const CProxyFile2 &file = Files[(unsigned)arcIndex];
628 SetDirPrefix_as_LONG_PATH(prefix, (unsigned)arcIndex,
629 (int)dirIndex == file.AltDirIndex, // asAltDir,
630 file.IsDir());
631 return;
632 }
633 const int baseArcIndex = baseDir.ArcIndex;
634 wchar_t * const p = prefix.GetBuf_SetEnd(len);
635 do
636 {
637 const CProxyFile2 &file = Files[(unsigned)arcIndex];
638 wchar_t c = CHAR_PATH_SEPARATOR;
639 if ((int)dirIndex == file.AltDirIndex)
640 c = ':';
641 if (len <= file.NameLen)
642 break;
643 p[--len] = c;
644 len -= file.NameLen;
645 wmemcpy(p + len, file.Name, file.NameLen);
646 // slash normalization can be omitted, if we want max speed of sorting operation:
647 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(p + len, file.NameLen);
648 arcIndex = file.Parent;
649 if (arcIndex == baseArcIndex)
650 {
651 if (len)
652 break;
653 return;
654 }
655 }
656 while (arcIndex != -1);
482 } 657 }
483 return dir.PathPrefix; 658 throw 1;
484} 659}
485 660
486void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const 661
662/* called from:
663 Agent.cpp:
664 CAgentFolder::GetFullPrefix()
665 CAgent::RenameItem() in AgentOut.cpp
666 CAgentFolder::GetFolderProperty(kpidPath)
667 GetFolderPath() in PanelFolderChange.cpp
668 LoadFullPath()
669 AgentOut.cpp:
670 CAgent::SetFolder()
671 CAgentFolder::CommonUpdateOperation() in ArchiveFolderOut.cpp
672 CAgent::CreateFolder()
673*/
674UString CProxyArc2::GetDirPath_as_Prefix(const unsigned dirIndex, const bool canReducePath) const
675{
676 UString s;
677 const unsigned lenLimit = canReducePath ? (1u << 14) : (1u << 28);
678 GetDirPath_as_Prefix_from_Base(dirIndex, s, k_Proxy2_RootDirIndex, lenLimit);
679 return s;
680}
681
682
683void CProxyArc2::AddRealIndices_of_ArcItem(const unsigned arcIndex,
684 const bool includeAltStreams, const bool includeDirSubItems,
685 CUIntVector &realIndices) const
487{ 686{
488 realIndices.Add(arcIndex); 687 realIndices.Add(arcIndex);
489 const CProxyFile2 &file = Files[arcIndex]; 688 const CProxyFile2 &file = Files[arcIndex];
490 if (file.DirIndex != -1) 689 if (includeDirSubItems && file.DirIndex != -1)
491 AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices); 690 AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices);
492 if (includeAltStreams && file.AltDirIndex != -1) 691 if (includeAltStreams && file.AltDirIndex != -1)
493 AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices); 692 AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices);
494} 693}
495 694
496void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const 695
696void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex,
697 const bool includeAltStreams,
698 CUIntVector &realIndices) const
497{ 699{
498 const CRecordVector<unsigned> &subFiles = Dirs[dirIndex].Items; 700 CUIntVector vec;
499 FOR_VECTOR (i, subFiles) 701 unsigned i = 0;
702 for (;;)
500 { 703 {
501 AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices); 704 const CProxyDir2 &dir = Dirs[dirIndex];
705 if (i == dir.Items.Size())
706 {
707 const unsigned num = vec.Size();
708 if (num < 2)
709 return;
710 dirIndex = vec[num - 2];
711 i = vec[num - 1];
712 vec.DeleteFrom(num - 2);
713 continue;
714 }
715
716 const unsigned arcIndex = dir.Items[i];
717 i++;
718 realIndices.Add(arcIndex);
719 const CProxyFile2 &file = Files[arcIndex];
720 if (includeAltStreams && file.AltDirIndex != -1)
721 AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices);
722 if (file.DirIndex != -1)
723 {
724 vec.Add(dirIndex);
725 vec.Add(i);
726 dirIndex = (unsigned)file.DirIndex;
727 i = 0;
728 }
502 } 729 }
503} 730}
504 731
505unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const
506{
507 return Dirs[dirIndex].Items[index];
508}
509 732
510void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const 733void CProxyArc2::GetRealIndices_Unsorted(const unsigned dirIndex,
734 const UInt32 *indices, const UInt32 numItems,
735 const bool includeAltStreams,
736 CUIntVector &realIndices) const
511{ 737{
512 const CProxyDir2 &dir = Dirs[dirIndex]; 738 const CUIntVector &items = Dirs[dirIndex].Items;
513 realIndices.Clear(); 739 realIndices.Clear();
514 for (UInt32 i = 0; i < numItems; i++) 740 for (UInt32 i = 0; i < numItems; i++)
515 { 741 AddRealIndices_of_ArcItem(items[indices[i]],
516 AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices); 742 includeAltStreams,
517 } 743 true, // includeDirSubItems
518 HeapSort(realIndices.NonConstData(), realIndices.Size()); 744 realIndices);
745 // HeapSort(realIndices.NonConstData(), realIndices.Size());
519} 746}
520 747
521void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive) 748
522{ 749CProxyDir2::CProxyDir2():
523 CProxyDir2 &dir = Dirs[dirIndex]; 750 ArcIndex(-1),
524 dir.Size = dir.PackSize = 0; 751 PrefixLen(0),
525 dir.NumSubDirs = 0; // dir.SubDirs.Size(); 752 Size(0),
526 dir.NumSubFiles = 0; // dir.Files.Size(); 753 PackSize(0),
527 dir.CrcIsDefined = true; 754#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
528 dir.Crc = 0; 755 IsLongPath(false),
756#endif
757 CrcIsDefined(true),
758 Crc(0),
759 NumSubDirs(0),
760 NumSubFiles(0)
761{}
529 762
530 FOR_VECTOR (i, dir.Items) 763
764HRESULT CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive
765 , IProgress *progress, const UInt64 *completed, unsigned &progressCounter)
766{
767 CUIntVector vec;
768#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
769 UString prefix, name;
770#endif
771 unsigned i = 0;
772 for (;;)
531 { 773 {
532 UInt32 index = dir.Items[i]; 774 CProxyDir2 &dir = Dirs[dirIndex];
775 // if (i == 0) {} // we can init some (dir) variables here instead of constructor
776
777 if (i == dir.Items.Size())
778 {
779 const unsigned num = vec.Size();
780 if (num < 2)
781 return S_OK;
782 dirIndex = vec[num - 2];
783 i = vec[num - 1];
784 vec.DeleteFrom(num - 2);
785
786 CProxyDir2 &dir2 = Dirs[dirIndex];
787 dir2.Size += dir.Size;
788 dir2.PackSize += dir.PackSize;
789 dir2.NumSubFiles += dir.NumSubFiles;
790 dir2.NumSubDirs += dir.NumSubDirs;
791 dir2.Crc += dir.Crc;
792 if (!dir.CrcIsDefined)
793 dir2.CrcIsDefined = false;
794 continue;
795 }
796
797 if (progress && (++progressCounter & 0xfffff) == 0)
798 RINOK(progress->SetCompleted(completed))
799
800 const UInt32 index = dir.Items[i];
801 i++;
533 UInt64 size, packSize; 802 UInt64 size, packSize;
534 const bool sizeDefined = GetSize(archive, index, kpidSize, size); 803 const bool sizeDefined = GetSize(archive, index, kpidSize, size);
535 dir.Size += size; 804 dir.Size += size;
@@ -549,56 +818,77 @@ void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive)
549 } 818 }
550 819
551 const CProxyFile2 &subFile = Files[index]; 820 const CProxyFile2 &subFile = Files[index];
552 if (subFile.DirIndex == -1) 821
553 { 822 if (subFile.NameLen >= (1u << 30) - dir.PrefixLen)
554 dir.NumSubFiles++; 823 return E_NOTIMPL;
555 } 824 const unsigned prefixLen = dir.PrefixLen + subFile.NameLen + 1;
556 else 825
826#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
827 bool isLongPath = dir.IsLongPath;
828 if (subFile.AltDirIndex != -1 || subFile.DirIndex != -1)
557 { 829 {
558 // 22.00: we normalize name 830 // 22.00: we normalize name
559 UString s = subFile.Name; 831 name = subFile.Name;
560 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s); 832 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
561 dir.NumSubDirs++; 833 if (!isLongPath)
562 CProxyDir2 &f = Dirs[subFile.DirIndex]; 834 {
563 f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR; 835 prefix = dir.PathPrefix;
564 CalculateSizes((unsigned)subFile.DirIndex, archive); 836 prefix += name;
565 dir.Size += f.Size; 837 if (prefix.Len() >= (1u << 11)) // CProxyDir2::PathPrefix limit
566 dir.PackSize += f.PackSize; 838 isLongPath = true;
567 dir.NumSubFiles += f.NumSubFiles; 839 }
568 dir.NumSubDirs += f.NumSubDirs;
569 dir.Crc += f.Crc;
570 if (!f.CrcIsDefined)
571 dir.CrcIsDefined = false;
572 } 840 }
841#endif
573 842
574 if (subFile.AltDirIndex == -1) 843 if (subFile.AltDirIndex != -1)
575 { 844 {
576 // dir.NumSubFiles++; 845 CProxyDir2 &f = Dirs[subFile.AltDirIndex];
846 f.PrefixLen = prefixLen;
847#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
848 f.IsLongPath = isLongPath;
849 if (isLongPath)
850 SetDirPrefix_as_LONG_PATH(prefix, index,
851 true, // asAltDirPrefix
852 subFile.IsDir());
853 else
854 prefix.Add_Colon();
855 f.PathPrefix = prefix;
856 UpdateMemUsage_with_StringLen(f.PathPrefix.Len());
857 CHECK_MEM_USAGE
858 prefix.DeleteBack(); // we delete Colon character
859#endif
860 RINOK(CalculateSizes((unsigned)subFile.AltDirIndex, archive, progress, completed, progressCounter))
577 } 861 }
862
863 if (subFile.DirIndex == -1)
864 dir.NumSubFiles++;
578 else 865 else
579 { 866 {
580 // dir.NumSubDirs++; 867 CProxyDir2 &f = Dirs[subFile.DirIndex];
581 CProxyDir2 &f = Dirs[subFile.AltDirIndex]; 868 f.PrefixLen = prefixLen;
582 f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; 869 dir.NumSubDirs++;
583 CalculateSizes((unsigned)subFile.AltDirIndex, archive); 870#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
871 f.IsLongPath = isLongPath;
872 if (isLongPath)
873 SetDirPrefix_as_LONG_PATH(prefix, index,
874 false, // asAltDirPrefix
875 true); // isDir
876 else
877 prefix.Add_PathSepar();
878 f.PathPrefix = prefix;
879 UpdateMemUsage_with_StringLen(f.PathPrefix.Len());
880 CHECK_MEM_USAGE
881#endif
882 if (vec.Size() >= (1u << 28)) // tree levels limit
883 return E_NOTIMPL;
884 vec.Add(dirIndex);
885 vec.Add(i);
886 dirIndex = (unsigned)subFile.DirIndex;
887 i = 0;
584 } 888 }
585 } 889 }
586} 890}
587 891
588
589bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const
590{
591 const CRecordVector<unsigned> &subFiles = Dirs[dirIndex].Items;
592 FOR_VECTOR (i, subFiles)
593 {
594 const CProxyFile2 &file = Files[subFiles[i]];
595 if (file.IsDir())
596 if (CompareFileNames(name, file.Name) == 0)
597 return true;
598 }
599 return false;
600}
601
602 892
603void CProxyArc2::FreeFiles() 893void CProxyArc2::FreeFiles()
604{ 894{
@@ -612,54 +902,55 @@ void CProxyArc2::FreeFiles()
612 Files = NULL; 902 Files = NULL;
613} 903}
614 904
905
906void CProxyArc2::AddDir(int arcIndex)
907{
908 Dirs.AddNew().ArcIndex = arcIndex;
909 MemUsage += sizeof(Dirs[0]) + sizeof(void *) + 11;
910}
911
615HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) 912HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
616{ 913{
617 if (!arc.GetRawProps) 914 if (!arc.GetRawProps)
618 return E_FAIL; 915 return E_FAIL;
619
620 // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { 916 // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) {
621 917
622 Dirs.Clear(); 918 Dirs.Clear();
623 FreeFiles(); 919 FreeFiles();
624 920
625 IInArchive *archive = arc.Archive; 921 IInArchive *archive = arc.Archive;
626
627 UInt32 numItems; 922 UInt32 numItems;
628 RINOK(archive->GetNumberOfItems(&numItems)) 923 RINOK(archive->GetNumberOfItems(&numItems))
629 if (numItems > k_NumFiles_Max) 924 if (numItems > k_NumFiles_Max)
630 return E_OUTOFMEMORY; 925 return E_OUTOFMEMORY;
631 if (progress) 926 if (progress)
632 RINOK(progress->SetTotal(numItems)) 927 RINOK(progress->SetTotal(numItems))
633 UString fileName; 928 Dirs.AddNew(); // Dirs[0] - root dir
634 929 Dirs.AddNew() // Dirs[1] - for alt streams of root dir
635 930#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
636 { 931 .PathPrefix.Add_Colon() // = ':';
637 // Dirs[0] - root dir 932#endif
638 /* CProxyDir2 &dir = */ Dirs.AddNew(); 933 ;
639 }
640
641 {
642 // Dirs[1] - for alt streams of root dir
643 CProxyDir2 &dir = Dirs.AddNew();
644 dir.PathPrefix = ':';
645 }
646 934
935 MemUsage = (UInt64)numItems * sizeof(*Files);
936 CHECK_MEM_USAGE
647 Z7_ARRAY_NEW(Files, CProxyFile2, numItems) 937 Z7_ARRAY_NEW(Files, CProxyFile2, numItems)
648 memset(Files, 0, (size_t)numItems * sizeof(*Files)); 938 memset(Files, 0, (size_t)numItems * sizeof(*Files));
649 NumFiles = numItems; 939 NumFiles = numItems;
650 940
941 UString fileName;
651 UString tempUString; 942 UString tempUString;
652 AString tempAString; 943 AString tempAString;
653 944
654 UInt32 i; 945 UInt32 i;
655 for (i = 0; i < numItems; i++) 946 for (i = 0; i < numItems; i++)
656 { 947 {
948 CHECK_MEM_USAGE
657 if (progress && (i & 0xFFFFF) == 0) 949 if (progress && (i & 0xFFFFF) == 0)
658 { 950 {
659 const UInt64 currentItemIndex = i; 951 const UInt64 currentItemIndex = i;
660 RINOK(progress->SetCompleted(&currentItemIndex)) 952 RINOK(progress->SetCompleted(&currentItemIndex))
661 } 953 }
662
663 CProxyFile2 &file = Files[i]; 954 CProxyFile2 &file = Files[i];
664 file.Construct(); 955 file.Construct();
665 956
@@ -668,7 +959,7 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
668 UInt32 propType; 959 UInt32 propType;
669 RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType)) 960 RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType))
670 961
671 #ifdef MY_CPU_LE 962#ifdef MY_CPU_LE_
672 if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) 963 if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
673 { 964 {
674 file.Name = (const wchar_t *)p; 965 file.Name = (const wchar_t *)p;
@@ -677,58 +968,59 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
677 file.NameLen = size / (unsigned)sizeof(wchar_t) - 1; 968 file.NameLen = size / (unsigned)sizeof(wchar_t) - 1;
678 } 969 }
679 else 970 else
680 #endif 971#endif
681 if (p && propType == NPropDataType::kUtf8z)
682 {
683 tempAString = (const char *)p;
684 ConvertUTF8ToUnicode(tempAString, tempUString);
685 file.NameLen = tempUString.Len();
686 file.Name = AllocStringAndCopy(tempUString);
687 file.NeedDeleteName = true;
688 }
689 else
690 { 972 {
691 NCOM::CPropVariant prop;
692 RINOK(arc.Archive->GetProperty(i, kpidName, &prop))
693 const wchar_t *s; 973 const wchar_t *s;
694 if (prop.vt == VT_BSTR) 974 unsigned len;
695 s = prop.bstrVal; 975 if (p && propType == NPropDataType::kUtf8z)
696 else if (prop.vt == VT_EMPTY) 976 {
697 s = L"[Content]"; 977 tempAString = (const char *)p;
978 ConvertUTF8ToUnicode(tempAString, tempUString);
979 s = tempUString.Ptr();
980 len = tempUString.Len();
981 }
698 else 982 else
699 return E_FAIL; 983 {
700 file.NameLen = MyStringLen(s); 984 NCOM::CPropVariant prop;
701 file.Name = AllocStringAndCopy(s, file.NameLen); 985 RINOK(arc.Archive->GetProperty(i, kpidName, &prop))
986 if (prop.vt == VT_BSTR)
987 s = prop.bstrVal;
988 else if (prop.vt == VT_EMPTY)
989 s = L"[Content]";
990 else
991 return E_FAIL;
992 len = MyStringLen(s);
993 }
994 file.NameLen = len;
995 file.Name = AllocStringAndCopy(s, len);
996 UpdateMemUsage_with_StringLen(len);
702 file.NeedDeleteName = true; 997 file.NeedDeleteName = true;
703 } 998 }
704 999
705 UInt32 parent = (UInt32)(Int32)-1; 1000 UInt32 parent = (UInt32)(Int32)-1;
706 UInt32 parentType = 0; 1001 UInt32 parentType = 0;
707 RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType)) 1002 RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType))
1003 if (parent >= numItems && parent != (UInt32)(Int32)-1)
1004 return E_FAIL;
708 file.Parent = (Int32)parent; 1005 file.Parent = (Int32)parent;
709 1006 /*
710 if (arc.Ask_Deleted) 1007 if (arc.Ask_Deleted)
711 { 1008 {
712 bool isDeleted = false; 1009 bool isDeleted = false;
713 RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)) 1010 RINOK(Archive_IsItem_Deleted(archive, i, isDeleted))
714 if (isDeleted) 1011 if (isDeleted) {}
715 {
716 // continue;
717 // curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]");
718 }
719 } 1012 }
720 1013 */
721 bool isDir; 1014 bool isDir;
722 RINOK(Archive_IsItem_Dir(archive, i, isDir)) 1015 RINOK(Archive_IsItem_Dir(archive, i, isDir))
723
724 if (isDir) 1016 if (isDir)
725 { 1017 {
726 file.DirIndex = (int)Dirs.Size(); 1018 file.DirIndex = (int)Dirs.Size();
727 CProxyDir2 &dir = Dirs.AddNew(); 1019 AddDir((int)i); // arcIndex
728 dir.ArcIndex = (int)i;
729 } 1020 }
730 if (arc.Ask_AltStream) 1021 if (arc.Ask_AltStream)
731 RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream)) 1022 RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream))
1023 // if (file.IsAltStream) file.Parent = -1; // for debug
732 } 1024 }
733 1025
734 for (i = 0; i < numItems; i++) 1026 for (i = 0; i < numItems; i++)
@@ -746,8 +1038,7 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
746 if (folderIndex2 == -1) 1038 if (folderIndex2 == -1)
747 { 1039 {
748 folderIndex2 = (int)Dirs.Size(); 1040 folderIndex2 = (int)Dirs.Size();
749 CProxyDir2 &dir = Dirs.AddNew(); 1041 AddDir(file.Parent); // arcIndex
750 dir.ArcIndex = file.Parent;
751 } 1042 }
752 dirIndex = folderIndex2; 1043 dirIndex = folderIndex2;
753 } 1044 }
@@ -764,27 +1055,38 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
764 } 1055 }
765 } 1056 }
766 1057
1058 MemUsage += Dirs[dirIndex].Items.IsEmpty() ? 16u : 4u + 1;
1059 CHECK_MEM_USAGE
767 Dirs[dirIndex].Items.Add(i); 1060 Dirs[dirIndex].Items.Add(i);
768 } 1061 }
769 1062
1063 unsigned progressCounter = 0;
770 for (i = 0; i < k_Proxy2_NumRootDirs; i++) 1064 for (i = 0; i < k_Proxy2_NumRootDirs; i++)
771 CalculateSizes(i, archive); 1065 {
1066 const UInt64 numItems64 = numItems;
1067 RINOK(CalculateSizes(i, archive, progress, &numItems64, progressCounter))
1068 }
1069 // OutputDebugStringA("finished");
772 1070
773 // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); 1071 // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s);
774
775 return S_OK; 1072 return S_OK;
776} 1073}
777 1074
778int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const 1075int CProxyArc2::FindItem(const unsigned dirIndex, const wchar_t *name, bool foldersOnly) const
779{ 1076{
780 const CProxyDir2 &dir = Dirs[dirIndex]; 1077 int index = -1;
781 FOR_VECTOR (i, dir.Items) 1078 const CUIntVector &subFiles = Dirs[dirIndex].Items;
1079 FOR_VECTOR (i, subFiles)
782 { 1080 {
783 const CProxyFile2 &file = Files[dir.Items[i]]; 1081 const CProxyFile2 &file = Files[subFiles[i]];
784 if (foldersOnly && file.DirIndex == -1) 1082 if (foldersOnly && file.DirIndex == -1)
785 continue; 1083 continue;
786 if (CompareFileNames(file.Name, name) == 0) 1084 if (CompareFileNames(file.Name, name) != 0)
1085 continue;
1086 if (MyStringCompare(file.Name, name) == 0)
787 return (int)i; 1087 return (int)i;
1088 if (index == -1)
1089 index = (int)i;
788 } 1090 }
789 return -1; 1091 return index;
790} 1092}
diff --git a/CPP/7zip/UI/Agent/AgentProxy.h b/CPP/7zip/UI/Agent/AgentProxy.h
index c6736a8..e486cb6 100644
--- a/CPP/7zip/UI/Agent/AgentProxy.h
+++ b/CPP/7zip/UI/Agent/AgentProxy.h
@@ -27,9 +27,10 @@ struct CProxyDir
27 unsigned NameLen; 27 unsigned NameLen;
28 28
29 int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder 29 int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder
30 int ParentDir; // index in proxy->Dirs[] ; -1 for root folder; ; 30 int ParentDir; // index in proxy->Dirs[] ; -1 for root folder
31 CRecordVector<unsigned> SubDirs; 31 CUIntVector SubDirs;
32 CRecordVector<unsigned> SubFiles; 32 CUIntVector SubDirs2;
33 CUIntVector SubFiles;
33 34
34 UInt64 Size; 35 UInt64 Size;
35 UInt64 PackSize; 36 UInt64 PackSize;
@@ -37,47 +38,56 @@ struct CProxyDir
37 UInt32 NumSubDirs; 38 UInt32 NumSubDirs;
38 UInt32 NumSubFiles; 39 UInt32 NumSubFiles;
39 bool CrcIsDefined; 40 bool CrcIsDefined;
41 bool Is_Changed_LongPath;
40 42
41 CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {} 43 CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1), Is_Changed_LongPath(false) {}
42 ~CProxyDir() { delete [](wchar_t *)(void *)Name; } 44 ~CProxyDir() { delete [](wchar_t *)(void *)Name; }
43 45
44 void Clear();
45 bool IsLeaf() const { return ArcIndex != -1; } 46 bool IsLeaf() const { return ArcIndex != -1; }
46}; 47};
47 48
48class CProxyArc 49class CProxyArc
49{ 50{
50 int FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const; 51 int FindSubDir(const unsigned *items, unsigned right,
52 const wchar_t *name, unsigned &insertPos) const;
51 53
52 void CalculateSizes(unsigned dirIndex, IInArchive *archive); 54 void CalculateSizes(IInArchive *archive);
55 void MergeSubDirs(CProxyDir &baseDir);
53 unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name); 56 unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name);
54 void FreeFiles(); 57 void FreeFiles();
55public: 58public:
56 CObjectVector<CProxyDir> Dirs; // Dirs[0] - root 59 CObjectVector<CProxyDir> Dirs; // Dirs[0] - root
57 CProxyFile *Files; // all items from archive in same order 60 CProxyFile *Files; // all items from archive in same order
58 unsigned NumFiles; 61 unsigned NumFiles;
62 bool Are_Changed_LongPaths;
63 UInt64 MemUsage;
64 UInt64 MemUsage_Limit;
59 65
60 CProxyArc(): Files(NULL), NumFiles(0) {} 66 CProxyArc(): Files(NULL), NumFiles(0), Are_Changed_LongPaths(false), MemUsage_Limit((UInt64)(Int64)-1) {}
61 ~CProxyArc() { FreeFiles(); } 67 ~CProxyArc() { FreeFiles(); }
62 68
63 // returns index in Dirs[], or -1, 69 // returns index in Dirs[], or -1,
64 int FindSubDir(unsigned dirIndex, const wchar_t *name) const; 70 int FindSubDir(unsigned dirIndex, const wchar_t *name) const;
65 71
66 void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const; 72 void GetDirPathParts_isChanged(unsigned dirIndex,
73 UStringVector &pathPartsm, bool &isChangedPath) const;
67 // returns full path of Dirs[dirIndex], including back slash 74 // returns full path of Dirs[dirIndex], including back slash
68 UString GetDirPath_as_Prefix(unsigned dirIndex) const; 75 UString GetDirPath_as_Prefix(unsigned dirIndex) const;
76 void GetDirPath_as_Prefix_from_Base(unsigned dirIndex, UString &prefix, unsigned baseDirIndex) const;
69 77
70 // AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf) 78 // AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf)
71 void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const; 79 void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const;
72 int GetRealIndex(unsigned dirIndex, unsigned index) const; 80 int GetRealIndex(unsigned dirIndex, unsigned index) const;
73 void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const; 81 void GetRealIndices_Unsorted(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const;
74 82
75 HRESULT Load(const CArc &arc, IProgress *progress); 83 HRESULT Load(const CArc &arc, IArchiveOpenCallback *progress);
76}; 84};
77 85
78 86
79// ---------- for Tree-mode archive ---------- 87// ---------- for Tree-mode archive ----------
80 88
89// #define Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
90
81struct CProxyFile2 91struct CProxyFile2
82{ 92{
83 int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs) 93 int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs)
@@ -86,7 +96,7 @@ struct CProxyFile2
86 const wchar_t *Name; 96 const wchar_t *Name;
87 unsigned NameLen; 97 unsigned NameLen;
88 bool NeedDeleteName; 98 bool NeedDeleteName;
89 bool Ignore; 99 bool Ignore; // = false always
90 bool IsAltStream; 100 bool IsAltStream;
91 101
92 int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; } 102 int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; }
@@ -108,17 +118,23 @@ struct CProxyFile2
108 118
109struct CProxyDir2 119struct CProxyDir2
110{ 120{
111 int ArcIndex; // = -1 for root folders, index in proxy->Files[] 121 int ArcIndex; // = -1 for root folders, index in CProxyArc2::Files[]
112 CRecordVector<unsigned> Items; 122 unsigned PrefixLen;
123 CUIntVector Items; // indexes in archive and in CProxyArc2::Files[]
124#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
113 UString PathPrefix; 125 UString PathPrefix;
126#endif
114 UInt64 Size; 127 UInt64 Size;
115 UInt64 PackSize; 128 UInt64 PackSize;
129#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX
130 bool IsLongPath;
131#endif
116 bool CrcIsDefined; 132 bool CrcIsDefined;
117 UInt32 Crc; 133 UInt32 Crc;
118 UInt32 NumSubDirs; 134 UInt32 NumSubDirs;
119 UInt32 NumSubFiles; 135 UInt32 NumSubFiles;
120 136
121 CProxyDir2(): ArcIndex(-1) {} 137 CProxyDir2();
122}; 138};
123 139
124const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex; 140const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex;
@@ -127,48 +143,54 @@ const unsigned k_Proxy2_NumRootDirs = 2;
127 143
128class CProxyArc2 144class CProxyArc2
129{ 145{
130 void CalculateSizes(unsigned dirIndex, IInArchive *archive); 146 HRESULT CalculateSizes(unsigned dirIndex, IInArchive *archive
147 , IProgress *progress, const UInt64 *completed, unsigned &progressCounter);
131 // AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex 148 // AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex
132 void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const; 149 void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const;
133 void FreeFiles(); 150 void FreeFiles();
151 void UpdateMemUsage_with_StringLen(unsigned len)
152 {
153 MemUsage += (size_t)len * sizeof(Files->Name[0]) + 16;
154 }
134public: 155public:
135 CObjectVector<CProxyDir2> Dirs; // Dirs[0] - root folder 156 CObjectVector<CProxyDir2> Dirs; // Dirs[0] - root folder
136 // Dirs[1] - for alt streams of root dir 157 // Dirs[1] - for alt streams of root dir
137 CProxyFile2 *Files; // all items from archive in same order 158 CProxyFile2 *Files; // all items from archive in same order
138 unsigned NumFiles; 159 unsigned NumFiles;
160 UInt64 MemUsage;
161 UInt64 MemUsage_Limit;
139 162
140 CProxyArc2(): Files(NULL), NumFiles(0) {} 163 CProxyArc2(): Files(NULL), NumFiles(0), MemUsage_Limit((UInt64)(Int64)-1) {}
141 ~CProxyArc2() { FreeFiles(); } 164 ~CProxyArc2() { FreeFiles(); }
142 165
143 bool IsThere_SubDir(unsigned dirIndex, const UString &name) const;
144
145 void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const; 166 void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const;
146 UString GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const; 167 void GetDirPath_as_Prefix_from_Base(unsigned dirIndex, UString &prefix, unsigned baseDirIndex, unsigned lenLimit) const;
168 UString GetDirPath_as_Prefix(unsigned dirIndex, bool canReducePath = false) const;
147 bool IsAltDir(unsigned dirIndex) const; 169 bool IsAltDir(unsigned dirIndex) const;
148 170
149 // AddRealIndices_of_ArcItem DOES ADD item and subItems 171 // AddRealIndices_of_ArcItem DOES ADD item and subItems
150 void AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const; 172 void AddRealIndices_of_ArcItem(unsigned arcIndex,
151 unsigned GetRealIndex(unsigned dirIndex, unsigned index) const; 173 bool includeAltStreams, bool includeDirSubItems,
152 void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const; 174 CUIntVector &realIndices) const;
175 unsigned GetRealIndex(const unsigned dirIndex, const unsigned index) const
176 {
177 return Dirs[dirIndex].Items[index];
178 }
179 void GetRealIndices_Unsorted(unsigned dirIndex, const UInt32 *indices, UInt32 numItems,
180 bool includeAltStreams, CUIntVector &realIndices) const;
153 181
154 HRESULT Load(const CArc &arc, IProgress *progress); 182 HRESULT Load(const CArc &arc, IProgress *progress);
155 183
156 int GetParentDirOfFile(UInt32 arcIndex) const 184 int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const;
185 bool IsThere_SubDir(unsigned dirIndex, const wchar_t *name) const
157 { 186 {
158 const CProxyFile2 &file = Files[arcIndex]; 187 return FindItem(dirIndex, name, true) != -1; // foldersOnly
159
160 if (file.Parent == -1)
161 return file.IsAltStream ?
162 k_Proxy2_AltRootDirIndex :
163 k_Proxy2_RootDirIndex;
164
165 const CProxyFile2 &parentFile = Files[file.Parent];
166 return file.IsAltStream ?
167 parentFile.AltDirIndex :
168 parentFile.DirIndex;
169 } 188 }
170 189
171 int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const; 190 void AddDir(int arcIndex);
172}; 191};
173 192
193void SetDirPrefix_as_LONG_PATH(UString &s, unsigned fileIndex,
194 bool asAltDirPrefix, bool isDir);
195
174#endif 196#endif
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
index 3fa027d..6430503 100644
--- a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
@@ -114,7 +114,19 @@ Z7_COM7F_IMF(CArchiveFolderManager::OpenFolderFile(IInStream *inStream,
114 return res; 114 return res;
115 } 115 }
116 116
117 RINOK(archive->BindToRootFolder(resultFolder)) 117 agent->_progress_for_Open = progress;
118 agent->_progress_ArchiveOpenCallback_for_Open = openArchiveCallback;
119 {
120 HRESULT hres = E_OUTOFMEMORY;
121 // IInFolderArchive::BindToRootFolder() doesn't raise exceptions.
122 // so try/catch is optional
123 try {
124 hres = archive->BindToRootFolder(resultFolder);
125 } catch (...) {}
126 agent->_progress_for_Open = NULL;
127 agent->_progress_ArchiveOpenCallback_for_Open = NULL;
128 RINOK(hres)
129 }
118 return res; 130 return res;
119} 131}
120 132
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
index 1da6601..44e9d91 100644
--- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
@@ -21,10 +21,11 @@ using namespace NDir;
21 21
22void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder) 22void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder)
23{ 23{
24 bool isChangedPath = false;
24 if (_proxy2) 25 if (_proxy2)
25 _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); 26 _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
26 else 27 else
27 _proxy->GetDirPathParts(_proxyDirIndex, pathParts); 28 _proxy->GetDirPathParts_isChanged(_proxyDirIndex, pathParts, isChangedPath);
28} 29}
29 30
30static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path) 31static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path)
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index 7f6da0c..a86dd20 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -161,7 +161,9 @@ static const char * const k_ZoneId_StreamName_With_Colon_Prefix = ":Zone.Identif
161 161
162bool Is_ZoneId_StreamName(const wchar_t *s) 162bool Is_ZoneId_StreamName(const wchar_t *s)
163{ 163{
164 return StringsAreEqualNoCase_Ascii(s, k_ZoneId_StreamName_With_Colon_Prefix + 1); 164 UString s2 = s;
165 Correct_AltStream_Name(s2);
166 return StringsAreEqualNoCase_Ascii(s2, k_ZoneId_StreamName_With_Colon_Prefix + 1);
165} 167}
166 168
167void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf) 169void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf)
@@ -358,20 +360,19 @@ void CArchiveExtractCallback::Init(
358 _folderArchiveExtractCallback2.Release(); 360 _folderArchiveExtractCallback2.Release();
359 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); 361 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
360 362
361 #ifndef Z7_SFX 363#ifndef Z7_SFX
362 364 _baseParentFolder = (UInt32)(Int32)-1;
365 _use_baseParentFolder_mode = false;
363 ExtractToStreamCallback.Release(); 366 ExtractToStreamCallback.Release();
364 _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); 367 _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback);
365 if (ExtractToStreamCallback) 368 if (ExtractToStreamCallback)
366 { 369 {
367 Int32 useStreams = 0; 370 Int32 useStreams = 0;
368 if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) 371 if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK
369 useStreams = 0; 372 || useStreams == 0)
370 if (useStreams == 0)
371 ExtractToStreamCallback.Release(); 373 ExtractToStreamCallback.Release();
372 } 374 }
373 375#endif
374 #endif
375 376
376 LocalProgressSpec->Init(extractCallback2, true); 377 LocalProgressSpec->Init(extractCallback2, true);
377 LocalProgressSpec->SendProgress = false; 378 LocalProgressSpec->SendProgress = false;
@@ -379,11 +380,6 @@ void CArchiveExtractCallback::Init(
379 _removePathParts = removePathParts; 380 _removePathParts = removePathParts;
380 _removePartsForAltStreams = removePartsForAltStreams; 381 _removePartsForAltStreams = removePartsForAltStreams;
381 382
382 #ifndef Z7_SFX
383 _baseParentFolder = (UInt32)(Int32)-1;
384 _use_baseParentFolder_mode = false;
385 #endif
386
387 _arc = arc; 383 _arc = arc;
388 _dirPathPrefix = directoryPath; 384 _dirPathPrefix = directoryPath;
389 _dirPathPrefix_Full = directoryPath; 385 _dirPathPrefix_Full = directoryPath;
@@ -464,21 +460,16 @@ void CArchiveExtractCallback::CreateComplexDirectory(
464 const UStringVector &dirPathParts, bool isFinal, FString &fullPath) 460 const UStringVector &dirPathParts, bool isFinal, FString &fullPath)
465{ 461{
466 // we use (_item.IsDir) in this function 462 // we use (_item.IsDir) in this function
467
468 bool isAbsPath = false; 463 bool isAbsPath = false;
469
470 if (!dirPathParts.IsEmpty()) 464 if (!dirPathParts.IsEmpty())
471 { 465 {
472 const UString &s = dirPathParts[0]; 466 const UString &s = dirPathParts[0];
473 if (s.IsEmpty()) 467 if (s.IsEmpty())
474 isAbsPath = true; 468 isAbsPath = true;
475 #if defined(_WIN32) && !defined(UNDER_CE) 469#if defined(_WIN32) && !defined(UNDER_CE)
476 else 470 else if (NName::IsDrivePath2(s))
477 { 471 isAbsPath = true;
478 if (NName::IsDrivePath2(s)) 472#endif
479 isAbsPath = true;
480 }
481 #endif
482 } 473 }
483 474
484 if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) 475 if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath)
@@ -495,37 +486,73 @@ void CArchiveExtractCallback::CreateComplexDirectory(
495 486
496 const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir); 487 const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir);
497 488
498 if (fullPath.IsEmpty()) 489 if (fullPath.IsEmpty()
490#if defined(_WIN32) && !defined(UNDER_CE)
491 || (_pathMode == NExtract::NPathMode::kAbsPaths
492 && i == 0 && s.Len() == 2 && NName::IsDrivePath2(s))
493#endif
494 )
499 { 495 {
500 if (isFinalDir) 496 if (isFinalDir)
501 _itemFailure = true; 497 _itemFailure = true; // we don't want to set attributes for root (or root drive) path
502 continue; 498 continue;
503 } 499 }
504 500
505 #if defined(_WIN32) && !defined(UNDER_CE) 501 // bool need_SetAttrib = isFinalDir;
506 if (_pathMode == NExtract::NPathMode::kAbsPaths) 502 if (!isFinalDir || !NFile::NFind::DoesDirExist(fullPath))
507 if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s)) 503 {
504 HRESULT hres = S_OK;
505#ifdef _WIN32
506 if (!CreateDir(fullPath))
507 hres = GetLastError_noZero_HRESULT();
508#else
509 mode_t mode = g_umask.mask;
510 if (isFinalDir && _fi.Attrib_Defined)
508 { 511 {
509 if (isFinalDir) 512 const UInt32 attrib = _fi.Attrib;
513 if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
510 { 514 {
511 // we don't want to call SetAttrib() for root drive path 515 mode = attrib >> 16;
512 _itemFailure = true; 516 if (S_ISDIR(mode))
517 mode |= (S_IRUSR | S_IWUSR | S_IXUSR); // user/7z must be able to create files in this directory
518 else
519 {
520 // we do not want to use attributes, if it's not directory type.
521 // SendMessageError("is not directory type in metadata", fullPath);
522 mode = g_umask.mask;
523 }
524 mode &= g_umask.mask;
513 } 525 }
514 continue;
515 } 526 }
516 #endif 527 // printf("\n mkdir mode = %o\n", (unsigned)mode);
528 if (mkdir(fullPath, mode) == 0)
529 {
530 if (isFinalDir)
531 _dirAttrib_wasSet = true;
532 // printf("\n mkdir OK\n");
533 // need_SetAttrib = false;
534 }
535 else
536 hres = GetLastError_noZero_HRESULT();
537#endif
517 538
518 HRESULT hres = S_OK; 539 if (isFinalDir && !NFile::NFind::DoesDirExist(fullPath))
519 if (!CreateDir(fullPath))
520 hres = GetLastError_noZero_HRESULT();
521 if (isFinalDir)
522 {
523 if (!NFile::NFind::DoesDirExist(fullPath))
524 { 540 {
525 _itemFailure = true; 541 _itemFailure = true;
526 SendMessageError_with_Error(hres, "Cannot create folder", fullPath); 542 SendMessageError_with_Error(hres, "Cannot create folder", fullPath);
543 // need_SetAttrib = false;
527 } 544 }
528 } 545 }
546 /*
547 // this code doesn't process item excluded by "Eliminate duplication of root folder"
548 // so we will set attributes later
549 if (need_SetAttrib)
550 {
551 // printf("\n SetAttrib \n");
552 SetAttrib(fullPath);
553 _dirAttrib_wasSet = true;
554 }
555 */
529 } 556 }
530} 557}
531 558
@@ -926,7 +953,38 @@ HRESULT CArchiveExtractCallback::ReadLink()
926#endif // SUPPORT_LINKS 953#endif // SUPPORT_LINKS
927 954
928 955
929#ifndef _WIN32 956#ifdef _WIN32
957
958#define SET_OWNER
959#define SET_NEED_SET_OWNER
960
961#else
962
963#define SET_OWNER { SetOwner(); }
964#define SET_NEED_SET_OWNER { _needSetOwner = true; }
965
966void CArchiveExtractCallback::SetOwner()
967{
968 if (!_needSetOwner)
969 return;
970 _needSetOwner = false;
971 // we want to call chown() only for file itself.
972 // we don't want to follow link.
973 // if (_isSymLinkCreated) return;
974 const FString &path = _diskFilePath;
975 if (_itemFailure
976 || path.IsEmpty()
977 || _stdOutMode
978 || !_extractMode)
979 return;
980 if (_fi.Owner.Id_Defined &&
981 _fi.Group.Id_Defined)
982 {
983 // printf("\n SetOwner() %s\n", path.Ptr());
984 if (my_chown(path, _fi.Owner.Id, _fi.Group.Id) != 0)
985 SendMessageError_with_LastError("Cannot set owner", path);
986 }
987}
930 988
931static HRESULT GetOwner(IInArchive *archive, 989static HRESULT GetOwner(IInArchive *archive,
932 UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res) 990 UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res)
@@ -1009,7 +1067,7 @@ HRESULT CArchiveExtractCallback::Read_fi_Props()
1009 #ifndef _WIN32 1067 #ifndef _WIN32
1010 if (_ntOptions.ExtractOwner) 1068 if (_ntOptions.ExtractOwner)
1011 { 1069 {
1012 // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath); 1070 // SendMessageError("_ntOptions.ExtractOwner", _diskFilePath);
1013 GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner); 1071 GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner);
1014 GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group); 1072 GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group);
1015 } 1073 }
@@ -1043,7 +1101,11 @@ void CArchiveExtractCallback::CorrectPathParts()
1043 { 1101 {
1044 pathParts.AddNew(); 1102 pathParts.AddNew();
1045 if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt) 1103 if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)
1104 {
1105 const UString s2 = Get_Correct_FsFile_Name(s);
1106 s = s2;
1046 needColon = false; 1107 needColon = false;
1108 }
1047 } 1109 }
1048 #ifdef _WIN32 1110 #ifdef _WIN32
1049 else if (_pathMode == NExtract::NPathMode::kAbsPaths && 1111 else if (_pathMode == NExtract::NPathMode::kAbsPaths &&
@@ -1371,8 +1433,15 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1371 if (_link.LinkPath.IsEmpty()) 1433 if (_link.LinkPath.IsEmpty())
1372 #endif 1434 #endif
1373 { 1435 {
1436 /* here we can set directory attributes for usual any items and for
1437 root directory excluded from processing by "Eliminate duplication of root folder" feature. */
1374 if (!isAnti) 1438 if (!isAnti)
1375 SetAttrib(); 1439 {
1440 if (!_dirAttrib_wasSet)
1441 SetAttrib(_diskFilePath);
1442 SET_NEED_SET_OWNER
1443 SET_OWNER
1444 }
1376 return S_OK; 1445 return S_OK;
1377 } 1446 }
1378 } 1447 }
@@ -1443,7 +1512,9 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1443 return S_OK; 1512 return S_OK;
1444 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); 1513 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
1445 // _needSetAttrib = true; // do we need to set attribute ? 1514 // _needSetAttrib = true; // do we need to set attribute ?
1446 SetAttrib(); 1515 SetAttrib(_diskFilePath);
1516 SET_NEED_SET_OWNER
1517 SET_OWNER
1447 /* if we set (needExit = false) here, _hashStreamSpec will be used, 1518 /* if we set (needExit = false) here, _hashStreamSpec will be used,
1448 and hash will be calulated for all hard links files (it's slower). 1519 and hash will be calulated for all hard links files (it's slower).
1449 But "Test" operation also calculates hashes. 1520 But "Test" operation also calculates hashes.
@@ -1462,7 +1533,46 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1462 1533
1463 _outFileStreamSpec = new COutFileStream; 1534 _outFileStreamSpec = new COutFileStream;
1464 CMyComPtr<IOutStream> outFileStream_Loc(_outFileStreamSpec); 1535 CMyComPtr<IOutStream> outFileStream_Loc(_outFileStreamSpec);
1536
1537 bool needSetAttrib = true;
1538#ifndef _WIN32
1539 if (_fi.Attrib_Defined)
1540 {
1541 /*
1542 system open() function uses system umask.
1543 our (g_umask.mask) is more restricted mask.
1544 So we use (mode) parameter in open(,, mode), because our mask for (mode)
1545 is more restricted than system umask.
1546 If we want to set unrestricted (mode) bits for file, then we must
1547 call additional fchmod() function later.
1548 */
1549 mode_t mode = NWindows::NFile::NIO::k_OutFile_mode_default; // 0666
1550 const UInt32 attrib = _fi.Attrib;
1551 if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
1552 {
1553 mode = (attrib >> 16);
1554 // mode &= 07777; // for debug
1555 if (!S_ISREG(mode))
1556 {
1557 // printf("\n !S_ISREG(mode) = %o\n", (unsigned)mode);
1558 needSetAttrib = false;
1559 }
1560 }
1561 else if (attrib & FILE_ATTRIBUTE_READONLY)
1562 mode &= (mode_t)~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions
1563 if (needSetAttrib)
1564 {
1565 // printf("\n File.mode_for_Create = %o\n", (unsigned)mode);
1566 mode &= g_umask.mask;
1567 // mode = 0777; // for debug
1568 // mode |= S_ISUID | S_ISGID | S_ISVTX; // for debug
1569 _outFileStreamSpec->File.mode_for_Create = mode;
1570 }
1571 needSetAttrib = false;
1572 }
1573#endif
1465 1574
1575 // printf("\n GetExtractStream Create_ALWAYS_or_Open_ALWAYS : %s\n", fullProcessedPath.Ptr());
1466 if (!_outFileStreamSpec->Create_ALWAYS_or_Open_ALWAYS(fullProcessedPath, !_isSplit)) 1576 if (!_outFileStreamSpec->Create_ALWAYS_or_Open_ALWAYS(fullProcessedPath, !_isSplit))
1467 { 1577 {
1468 // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) 1578 // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
@@ -1472,7 +1582,8 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1472 } 1582 }
1473 } 1583 }
1474 1584
1475 _needSetAttrib = true; 1585 SET_NEED_SET_OWNER
1586 _needSetAttrib = needSetAttrib;
1476 1587
1477 bool is_SymLink_in_Data = false; 1588 bool is_SymLink_in_Data = false;
1478 1589
@@ -1608,7 +1719,11 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1608 _extractMode = false; 1719 _extractMode = false;
1609 _is_SymLink_in_Data_Linux = false; 1720 _is_SymLink_in_Data_Linux = false;
1610 _needSetAttrib = false; 1721 _needSetAttrib = false;
1611 _isSymLinkCreated = false; 1722 _dirAttrib_wasSet = false;
1723#ifndef _WIN32
1724 _needSetOwner = false;
1725#endif
1726 // _isSymLinkCreated = false;
1612 _itemFailure = false; 1727 _itemFailure = false;
1613 _some_pathParts_wereRemoved = false; 1728 _some_pathParts_wereRemoved = false;
1614 // _op_WasReported = false; 1729 // _op_WasReported = false;
@@ -1979,13 +2094,48 @@ HRESULT CArchiveExtractCallback::CloseFile()
1979 CFiTimesCAM t; 2094 CFiTimesCAM t;
1980 GetFiTimesCAM(_fi, t, *_arc); 2095 GetFiTimesCAM(_fi, t, *_arc);
1981 2096
1982 // #ifdef _WIN32 2097 const bool needSetAttrib = (_needSetAttrib && _fi.Attrib_Defined);
1983 if (t.IsSomeTimeDefined()) 2098 if (t.IsSomeTimeDefined() || needSetAttrib)
1984 _outFileStreamSpec->SetTime( 2099 {
2100 bool needSetTime = true;
2101 if (needSetAttrib)
2102 {
2103 /*
2104 in Linux: { this code branch is not used,
2105 because (mode) was set in open() function in COutFile open function.
2106 If we call Set_Time_and_WinAttrib(), then later COutFile::Close() will call fchmod().
2107 So we need Set_Time_and_WinAttrib() in linux only if we need insecure nonrestricted (mode) bits with fchmod().
2108 }
2109
2110 win10: if (attrib & FILE_ATTRIBUTE_DIRECTORY)
2111 {
2112 NtSetInformationFile() returns (STATUS_INVALID_PARAMETER)
2113 SetFileAttributes() just ignores FILE_ATTRIBUTE_DIRECTORY()
2114 }
2115 */
2116 // _fi.Attrib |= 0xfffffff; // FOR DEBUG
2117 if (_outFileStreamSpec->File.Set_Time_and_WinAttrib(
2118 t.CTime_Defined ? &t.CTime : NULL,
2119 t.ATime_Defined ? &t.ATime : NULL,
2120 t.MTime_Defined ? &t.MTime : NULL,
2121 (DWORD)_fi.Attrib & ~(DWORD)FILE_ATTRIBUTE_DIRECTORY))
2122 {
2123 needSetTime = false;
2124 _needSetAttrib = false;
2125 }
2126 else
2127 {
2128 // it's unexpected case.
2129 // we will set timestamp/attributes with another code later
2130 // SendMessageError_with_LastError("Cannot set timestamp and file attribute", _diskFilePath);
2131 }
2132 }
2133 if (needSetTime)
2134 _outFileStreamSpec->SetTime(
1985 t.CTime_Defined ? &t.CTime : NULL, 2135 t.CTime_Defined ? &t.CTime : NULL,
1986 t.ATime_Defined ? &t.ATime : NULL, 2136 t.ATime_Defined ? &t.ATime : NULL,
1987 t.MTime_Defined ? &t.MTime : NULL); 2137 t.MTime_Defined ? &t.MTime : NULL);
1988 // #endif 2138 }
1989 2139
1990 RINOK(_outFileStreamSpec->Close()) 2140 RINOK(_outFileStreamSpec->Close())
1991 _outFileStream.Release(); 2141 _outFileStream.Release();
@@ -2096,7 +2246,7 @@ HRESULT CArchiveExtractCallback::SetLink(
2096 return SendMessageError("Cannot create temporary link file", fullProcessedPath_from); 2246 return SendMessageError("Cannot create temporary link file", fullProcessedPath_from);
2097#if 0 // 1 for debug 2247#if 0 // 1 for debug
2098 // here we can write link path to temporary link file placeholder, 2248 // here we can write link path to temporary link file placeholder,
2099 // but empty placeholder is better, because we don't want to get any non-eampty data instead of link file. 2249 // but empty placeholder is better, because we don't want to get any non-empty data instead of link file.
2100 AString s; 2250 AString s;
2101 ConvertUnicodeToUTF8(link.LinkPath, s); 2251 ConvertUnicodeToUTF8(link.LinkPath, s);
2102 outFile.WriteFull(s, s.Len()); 2252 outFile.WriteFull(s, s.Len());
@@ -2543,13 +2693,13 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2543 link.Parse_from_LinuxData(_outMemBuf, reparseSize) : 2693 link.Parse_from_LinuxData(_outMemBuf, reparseSize) :
2544 link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize); 2694 link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize);
2545 if (!needSetReparse) 2695 if (!needSetReparse)
2546 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); 2696 res = SendMessageError("Incorrect reparse stream", us2fs(_item.Path));
2547 // (link.LinkPath) uses system path separator. 2697 // (link.LinkPath) uses system path separator.
2548 // windows: (link.LinkPath) doesn't contain linux separator (slash). 2698 // windows: (link.LinkPath) doesn't contain linux separator (slash).
2549 } 2699 }
2550 else 2700 else
2551 { 2701 {
2552 res = SendMessageError_with_LastError("Unknown reparse stream", us2fs(_item.Path)); 2702 res = SendMessageError("Unknown reparse stream", us2fs(_item.Path));
2553 } 2703 }
2554 if (!needSetReparse && _outFileStream) 2704 if (!needSetReparse && _outFileStream)
2555 { 2705 {
@@ -2587,8 +2737,14 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2587 // link.isJunction = true; // for debug 2737 // link.isJunction = true; // for debug
2588 link.Normalize_to_RelativeSafe(_removePathParts); 2738 link.Normalize_to_RelativeSafe(_removePathParts);
2589 RINOK(SetLink(_diskFilePath, link, linkWasSet)) 2739 RINOK(SetLink(_diskFilePath, link, linkWasSet))
2740/* DOCs:
2741 posix: permissions are ignored for access via link.
2742 Linux: the permissions of an ordinary symbolic link are not
2743 used in any operations; the permissions are always 0777 (read,
2744 write, and execute for all user categories), and can't be changed.
2745 So we don't set attributes for placeholder.
2746*/
2590/* 2747/*
2591 // we don't set attributes for placeholder.
2592 if (linkWasSet) 2748 if (linkWasSet)
2593 _isSymLinkCreated = true; // link.IsSymLink(); 2749 _isSymLinkCreated = true; // link.IsSymLink();
2594 else 2750 else
@@ -2605,15 +2761,6 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2605static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi, 2761static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi,
2606 const CArchiveExtractCallback &callback) 2762 const CArchiveExtractCallback &callback)
2607{ 2763{
2608#ifndef _WIN32
2609 if (fi.Owner.Id_Defined &&
2610 fi.Group.Id_Defined)
2611 {
2612 if (my_chown(path, fi.Owner.Id, fi.Group.Id) != 0)
2613 callback.SendMessageError_with_LastError("Cannot set owner", path);
2614 }
2615#endif
2616
2617 if (fi.Attrib_Defined) 2764 if (fi.Attrib_Defined)
2618 { 2765 {
2619 // const AString s = GetAnsiString(_diskFilePath); 2766 // const AString s = GetAnsiString(_diskFilePath);
@@ -2626,21 +2773,21 @@ static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi,
2626 } 2773 }
2627} 2774}
2628 2775
2629void CArchiveExtractCallback::SetAttrib() const 2776void CArchiveExtractCallback::SetAttrib(const FString &path) const
2630{ 2777{
2631#ifndef _WIN32 2778#ifndef _WIN32
2632 // Linux now doesn't support permissions for symlinks 2779 // Linux now doesn't support permissions for symlinks
2633 if (_isSymLinkCreated) 2780 // if (_isSymLinkCreated) return;
2634 return;
2635#endif 2781#endif
2782 // printf("\n SetAttrib %s, \n", path.Ptr());
2636 2783
2637 if (_itemFailure 2784 if (_itemFailure
2638 || _diskFilePath.IsEmpty() 2785 || path.IsEmpty()
2639 || _stdOutMode 2786 || _stdOutMode
2640 || !_extractMode) 2787 || !_extractMode)
2641 return; 2788 return;
2642 2789
2643 SetAttrib_Base(_diskFilePath, _fi, *this); 2790 SetAttrib_Base(path, _fi, *this);
2644} 2791}
2645 2792
2646 2793
@@ -2688,9 +2835,6 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
2688 GetUnpackSize(); 2835 GetUnpackSize();
2689 return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize); 2836 return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize);
2690 } 2837 }
2691 #endif
2692
2693 #ifndef Z7_SFX
2694 2838
2695 if (_hashStreamWasUsed) 2839 if (_hashStreamWasUsed)
2696 { 2840 {
@@ -2738,11 +2882,11 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
2738 NumFiles++; 2882 NumFiles++;
2739 2883
2740 if (_needSetAttrib) 2884 if (_needSetAttrib)
2741 SetAttrib(); 2885 SetAttrib(_diskFilePath);
2742 2886
2743 RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted))) 2887 SET_OWNER
2744 2888
2745 return S_OK; 2889 return _extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted));
2746 2890
2747 COM_TRY_END 2891 COM_TRY_END
2748} 2892}
@@ -2987,15 +3131,30 @@ HRESULT CArchiveExtractCallback::SetPostLinks() const
2987 RINOK(SetLink2(*this, link, linkWasSet)) 3131 RINOK(SetLink2(*this, link, linkWasSet))
2988 if (linkWasSet) 3132 if (linkWasSet)
2989 { 3133 {
2990#ifdef _WIN32 3134 // we set timestamps before SetAttrib(),
2991 // Linux now doesn't support permissions for symlinks 3135 // because windows doesn't set timestamps, if file has read-only attribute
2992 SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this);
2993#endif
2994
2995 CFiTimesCAM pt; 3136 CFiTimesCAM pt;
2996 GetFiTimesCAM(link.item_FileInfo, pt, *_arc); 3137 GetFiTimesCAM(link.item_FileInfo, pt, *_arc);
2997 if (pt.IsSomeTimeDefined()) 3138 if (pt.IsSomeTimeDefined())
2998 pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from); 3139 if (!pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from))
3140 {
3141 // SendMessageError_with_LastError("cannot set timestamp", link.fullProcessedPath_from);
3142 }
3143
3144#ifdef _WIN32
3145 SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this);
3146#else
3147 // Linux now doesn't support permissions for symlinks.
3148 // We set only owner
3149 {
3150 const CProcessedFileInfo &fi = link.item_FileInfo;
3151 if (fi.Owner.Id_Defined && fi.Group.Id_Defined)
3152 {
3153 if (my_chown_Link(link.fullProcessedPath_from, fi.Owner.Id, fi.Group.Id) != 0)
3154 SendMessageError_with_LastError("Cannot set owner", link.fullProcessedPath_from);
3155 }
3156 }
3157#endif
2999 3158
3000#ifdef Z7_USE_SECURITY_CODE 3159#ifdef Z7_USE_SECURITY_CODE
3001 // we set security information after timestamps setting 3160 // we set security information after timestamps setting
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
index 3c62763..e1822c7 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -260,14 +260,6 @@ struct COwnerInfo
260 COwnerInfo Group; 260 COwnerInfo Group;
261#endif 261#endif
262 262
263 void Clear()
264 {
265#ifndef _WIN32
266 Attrib_Defined = false;
267 Owner.Clear();
268#endif
269 }
270
271 bool IsReparse() const 263 bool IsReparse() const
272 { 264 {
273 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); 265 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
@@ -386,7 +378,8 @@ private:
386 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX. 378 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX.
387 // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file. 379 // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file.
388 bool _needSetAttrib; 380 bool _needSetAttrib;
389 bool _isSymLinkCreated; 381 bool _dirAttrib_wasSet;
382 // bool _isSymLinkCreated;
390 bool _itemFailure; 383 bool _itemFailure;
391 bool _some_pathParts_wereRemoved; 384 bool _some_pathParts_wereRemoved;
392 385
@@ -395,6 +388,9 @@ private:
395#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) 388#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
396 bool _saclEnabled; 389 bool _saclEnabled;
397#endif 390#endif
391#ifndef _WIN32
392 bool _needSetOwner;
393#endif
398 394
399 NExtract::NPathMode::EEnum _pathMode; 395 NExtract::NPathMode::EEnum _pathMode;
400 NExtract::NOverwriteMode::EEnum _overwriteMode; 396 NExtract::NOverwriteMode::EEnum _overwriteMode;
@@ -470,8 +466,11 @@ private:
470 466
471 FString Hash_GetFullFilePath(); 467 FString Hash_GetFullFilePath();
472 468
473 void SetAttrib() const; 469 void SetAttrib(const FString &path) const;
474 470#ifndef _WIN32
471 void SetOwner();
472#endif
473
475public: 474public:
476 HRESULT SendMessageError(const char *message, const FString &path) const; 475 HRESULT SendMessageError(const char *message, const FString &path) const;
477 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const; 476 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const;
diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
index 8a72936..bf11d12 100644
--- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -394,5 +394,10 @@ Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */))
394 394
395Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */)) 395Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */))
396{ 396{
397 return S_OK; 397 // this call can be used for additional structure parsing after archive openning.
398 // so we ignore completed
399 // we just want to process open break
400 if (!Callback)
401 return S_OK;
402 return Callback->Open_CheckBreak();
398} 403}
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp
index 30fc1e6..6e083ea 100644
--- a/CPP/7zip/UI/Common/Bench.cpp
+++ b/CPP/7zip/UI/Common/Bench.cpp
@@ -2866,6 +2866,8 @@ static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, un
2866static void PrintChars(IBenchPrintCallback &f, char c, unsigned size) 2866static void PrintChars(IBenchPrintCallback &f, char c, unsigned size)
2867{ 2867{
2868 char s[256]; 2868 char s[256];
2869 if (size >= sizeof(s))
2870 size = sizeof(s) - 1;
2869 memset(s, (Byte)c, size); 2871 memset(s, (Byte)c, size);
2870 s[size] = 0; 2872 s[size] = 0;
2871 f.Print(s); 2873 f.Print(s);
@@ -4070,7 +4072,8 @@ HRESULT Bench(
4070 )); 4072 ));
4071 if (start >= freq * 16) 4073 if (start >= freq * 16)
4072 { 4074 {
4073 printCallback->Print(" (Cmplx)"); 4075 if (printCallback)
4076 printCallback->Print(" (Cmplx)");
4074 if (!freqCallback) // we don't want complexity change for old gui lzma benchmark 4077 if (!freqCallback) // we don't want complexity change for old gui lzma benchmark
4075 { 4078 {
4076 needSetComplexity = true; 4079 needSetComplexity = true;
@@ -4658,6 +4661,8 @@ HRESULT Bench(
4658 } 4661 }
4659 } 4662 }
4660 4663
4664 if (!printCallback)
4665 return E_NOTIMPL;
4661 IBenchPrintCallback &f = *printCallback; 4666 IBenchPrintCallback &f = *printCallback;
4662 4667
4663 if (threadsPassIndex > 0) 4668 if (threadsPassIndex > 0)
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
index e234670..7ca6680 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -99,10 +99,13 @@ void Correct_AltStream_Name(UString &s)
99 const unsigned kPostfixSize = 6; 99 const unsigned kPostfixSize = 6;
100 if (s.Len() >= kPostfixSize 100 if (s.Len() >= kPostfixSize
101 && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA")) 101 && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
102 {
102 len -= kPostfixSize; 103 len -= kPostfixSize;
104 s.DeleteFrom(len);
105 }
103 for (unsigned i = 0; i < len; i++) 106 for (unsigned i = 0; i < len; i++)
104 { 107 {
105 wchar_t c = s[i]; 108 const wchar_t c = s[i];
106 if (c == ':' || c == '\\' || c == '/' 109 if (c == ':' || c == '\\' || c == '/'
107 || c == 0x202E // RLO 110 || c == 0x202E // RLO
108 ) 111 )
diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp
index c26d4c0..f9e4fae 100644
--- a/CPP/7zip/UI/Common/OpenArchive.cpp
+++ b/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -524,32 +524,55 @@ static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &res
524 524
525#ifndef Z7_SFX 525#ifndef Z7_SFX
526 526
527HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const 527HRESULT CArc::GetItem_PathToParent(UInt32 index, const UInt32 parent, UStringVector &parts) const
528{ 528{
529 if (!GetRawProps) 529 if (!GetRawProps)
530 return E_FAIL; 530 return E_FAIL;
531 if (index == parent) 531 if (index == parent)
532 return S_OK; 532 return S_OK;
533 UInt32 curIndex = index;
534 533
534 CRecordVector<UInt32> vec;
535 UString s; 535 UString s;
536 536 bool isAltStream = false;
537 bool prevWasAltStream = false; 537
538
539 for (;;) 538 for (;;)
540 { 539 {
541 #ifdef MY_CPU_LE 540 vec.Add(index);
541 UInt32 curParent = (UInt32)(Int32)-1;
542 UInt32 parentType = 0;
543 RINOK(GetRawProps->GetParent(index, &curParent, &parentType))
544
545 if (parentType == NParentType::kAltStream)
546 {
547 // that case is not expected because
548 // we don't call GetItem_PathToParent() function for alt stream items
549 if (vec.Size() != 1)
550 return E_FAIL;
551 isAltStream = true;
552 }
553 if (parent == curParent)
554 break;
555 if (curParent == (UInt32)(Int32)-1)
556 return E_FAIL;
557 index = curParent;
558 }
559
560 unsigned k = vec.Size();
561 do
562 {
563 index = vec[--k];
564#ifdef MY_CPU_LE
542 const void *p; 565 const void *p;
543 UInt32 size; 566 UInt32 size;
544 UInt32 propType; 567 UInt32 propType;
545 RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)) 568 RINOK(GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType))
546 if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) 569 if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
547 s = (const wchar_t *)p; 570 s = (const wchar_t *)p;
548 else 571 else
549 #endif 572#endif
550 { 573 {
551 NCOM::CPropVariant prop; 574 NCOM::CPropVariant prop;
552 RINOK(Archive->GetProperty(curIndex, kpidName, &prop)) 575 RINOK(Archive->GetProperty(index, kpidName, &prop))
553 if (prop.vt == VT_BSTR && prop.bstrVal) 576 if (prop.vt == VT_BSTR && prop.bstrVal)
554 s.SetFromBstr(prop.bstrVal); 577 s.SetFromBstr(prop.bstrVal);
555 else if (prop.vt == VT_EMPTY) 578 else if (prop.vt == VT_EMPTY)
@@ -557,51 +580,17 @@ HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &p
557 else 580 else
558 return E_FAIL; 581 return E_FAIL;
559 } 582 }
560 583 if (isAltStream && k == 0 && !parts.IsEmpty())
561 UInt32 curParent = (UInt32)(Int32)-1;
562 UInt32 parentType = 0;
563 RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType))
564
565 // 18.06: fixed : we don't want to split name to parts
566 /*
567 if (parentType != NParentType::kAltStream)
568 {
569 for (;;)
570 {
571 int pos = s.ReverseFind_PathSepar();
572 if (pos < 0)
573 {
574 break;
575 }
576 parts.Insert(0, s.Ptr(pos + 1));
577 s.DeleteFrom(pos);
578 }
579 }
580 */
581
582 parts.Insert(0, s);
583
584 if (prevWasAltStream)
585 { 584 {
586 { 585 UString &s2 = parts.Back();
587 UString &s2 = parts[parts.Size() - 2]; 586 s2.Add_Colon();
588 s2.Add_Colon(); 587 s2 += s;
589 s2 += parts.Back();
590 }
591 parts.DeleteBack();
592 } 588 }
593 589 else
594 if (parent == curParent) 590 parts.Add(s);
595 return S_OK;
596
597 prevWasAltStream = false;
598 if (parentType == NParentType::kAltStream)
599 prevWasAltStream = true;
600
601 if (curParent == (UInt32)(Int32)-1)
602 return E_FAIL;
603 curIndex = curParent;
604 } 591 }
592 while (k);
593 return S_OK;
605} 594}
606 595
607#endif 596#endif
@@ -888,7 +877,7 @@ HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
888 { 877 {
889 /* Good handler must support GetRawProps::GetParent for alt streams. 878 /* Good handler must support GetRawProps::GetParent for alt streams.
890 So the following code currently is not used */ 879 So the following code currently is not used */
891 int colon = FindAltStreamColon_in_Path(item.Path); 880 const int colon = FindAltStreamColon_in_Path(item.Path);
892 if (colon >= 0) 881 if (colon >= 0)
893 { 882 {
894 item.MainPath.DeleteFrom((unsigned)colon); 883 item.MainPath.DeleteFrom((unsigned)colon);
@@ -3397,8 +3386,7 @@ HRESULT CArchiveLink::Open(COpenOptions &op)
3397HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) 3386HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI)
3398{ 3387{
3399 VolumesSize = 0; 3388 VolumesSize = 0;
3400 COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; 3389 CMyComPtr2_Create<IArchiveOpenCallback, COpenCallbackImp> openCallbackSpec;
3401 CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;
3402 openCallbackSpec->Callback = callbackUI; 3390 openCallbackSpec->Callback = callbackUI;
3403 3391
3404 FString prefix, name; 3392 FString prefix, name;
@@ -3413,8 +3401,8 @@ HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI)
3413 openCallbackSpec->SetSubArchiveName(op.filePath); 3401 openCallbackSpec->SetSubArchiveName(op.filePath);
3414 } 3402 }
3415 3403
3416 op.callback = callback; 3404 op.callback = openCallbackSpec;
3417 op.callbackSpec = openCallbackSpec; 3405 op.callbackSpec = openCallbackSpec.ClsPtr();
3418 3406
3419 HRESULT res = Open(op); 3407 HRESULT res = Open(op);
3420 3408
diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp
index d73680b..85f3fa8 100644
--- a/CPP/7zip/UI/Common/PropIDUtils.cpp
+++ b/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -55,27 +55,28 @@ FILE_ATTRIBUTE_
55 55
56 56
57static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; 57static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
58#define MY_ATTR_CHAR(a, n, c) (((a) & (1 << (n))) ? c : '-') 58#define MY_POSIX_MODE_CHAR(a, mask, c) (((a) & (mask)) ? (c) : '-')
59 59
60static void ConvertPosixAttribToString(char *s, UInt32 a) throw() 60static void ConvertPosixAttribToString(char *s, UInt32 a) throw()
61{ 61{
62 s[0] = kPosixTypes[(a >> 12) & 0xF]; 62 *s++ = kPosixTypes[(a >> 12) & 0xF];
63 for (int i = 6; i >= 0; i -= 3) 63 for (unsigned mask = 1 << 8; mask;)
64 { 64 {
65 s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); 65 s[0] = MY_POSIX_MODE_CHAR(a, mask, 'r'); mask >>= 1;
66 s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); 66 s[1] = MY_POSIX_MODE_CHAR(a, mask, 'w'); mask >>= 1;
67 s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); 67 s[2] = MY_POSIX_MODE_CHAR(a, mask, 'x'); mask >>= 1;
68 s += 3;
68 } 69 }
69 if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID 70 if (a & 0x800) s[-7] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID
70 if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID 71 if (a & 0x400) s[-4] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID
71 if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX 72 if (a & 0x200) s[-1] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX
72 s[10] = 0; 73 *s = 0;
73 74
74 a &= ~(UInt32)0xFFFF; 75 a &= ~(UInt32)0xFFFF;
75 if (a != 0) 76 if (a)
76 { 77 {
77 s[10] = ' '; 78 *s++ = ' ';
78 ConvertUInt32ToHex8Digits(a, s + 11); 79 ConvertUInt32ToHex8Digits(a, s);
79 } 80 }
80} 81}
81 82
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
index e2f1866..bea31ce 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -840,13 +840,18 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 in
840 { 840 {
841 if (index != (UInt32)(Int32)-1) 841 if (index != (UInt32)(Int32)-1)
842 { 842 {
843 // v26.03: we have no way to convert index_in_server to index_in_ArcItems
844 // so the code was commented:
845 /*
843 if (ArcItems) 846 if (ArcItems)
844 { 847 {
845 const CArcItem &ai = (*ArcItems)[index]; 848 const CArcItem &ai = (*ArcItems)[index];
846 s = ai.Name; 849 s = ai.Name;
847 isDir = ai.IsDir; 850 isDir = ai.IsDir;
848 } 851 }
849 else if (Arc) 852 else
853 */
854 if (Arc)
850 { 855 {
851 RINOK(Arc->GetItem_Path(index, s2)) 856 RINOK(Arc->GetItem_Path(index, s2))
852 s = s2; 857 s = s2;
@@ -899,9 +904,13 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt3
899 { 904 {
900 if (index != (UInt32)(Int32)-1) 905 if (index != (UInt32)(Int32)-1)
901 { 906 {
907 // v26.03: we have no way to convert index_in_server to index_in_ArcItems
908 /*
902 if (ArcItems) 909 if (ArcItems)
903 s = (*ArcItems)[index].Name; 910 s = (*ArcItems)[index].Name;
904 else if (Arc) 911 else
912 */
913 if (Arc)
905 { 914 {
906 RINOK(Arc->GetItem_Path(index, s2)) 915 RINOK(Arc->GetItem_Path(index, s2))
907 s = s2; 916 s = s2;
diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
index 685ac70..3ba811c 100644
--- a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
+++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
@@ -2,27 +2,6 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#ifdef __MINGW32_VERSION
6// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
7// for old mingw
8#include <ddk/ntddk.h>
9#else
10#ifndef Z7_OLD_WIN_SDK
11 #if !defined(_M_IA64)
12 #include <winternl.h>
13 #endif
14#else
15typedef LONG NTSTATUS;
16typedef struct _IO_STATUS_BLOCK {
17 union {
18 NTSTATUS Status;
19 PVOID Pointer;
20 };
21 ULONG_PTR Information;
22} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
23#endif
24#endif
25
26#include "../../../Common/ComTry.h" 5#include "../../../Common/ComTry.h"
27#include "../../../Common/StringConvert.h" 6#include "../../../Common/StringConvert.h"
28#include "../../../Common/Wildcard.h" 7#include "../../../Common/Wildcard.h"
@@ -511,13 +490,6 @@ static HRESULT UpdateFile(NFsFolder::CCopyStateIO &state, CFSTR inPath, CFSTR ou
511 490
512EXTERN_C_BEGIN 491EXTERN_C_BEGIN
513 492
514typedef enum
515{
516 Z7_WIN_FileRenameInformation = 10
517}
518Z7_WIN_FILE_INFORMATION_CLASS;
519
520
521typedef struct 493typedef struct
522{ 494{
523 // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1) 495 // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1)
@@ -534,34 +506,6 @@ typedef struct
534 WCHAR FileName[1]; 506 WCHAR FileName[1];
535} Z7_WIN_FILE_RENAME_INFORMATION; 507} Z7_WIN_FILE_RENAME_INFORMATION;
536 508
537#if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
538#define Z7_WIN_NTSTATUS NTSTATUS
539#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK
540#else
541typedef LONG Z7_WIN_NTSTATUS;
542typedef struct
543{
544 union
545 {
546 Z7_WIN_NTSTATUS Status;
547 PVOID Pointer;
548 } DUMMYUNIONNAME;
549 ULONG_PTR Information;
550} Z7_WIN_IO_STATUS_BLOCK;
551#endif
552
553typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)(
554 HANDLE FileHandle,
555 Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock,
556 PVOID FileInformation,
557 ULONG Length,
558 Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass);
559
560// NTAPI
561typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status);
562
563#define MY_STATUS_SUCCESS 0
564
565EXTERN_C_END 509EXTERN_C_END
566 510
567// static Func_NtSetInformationFile f_NtSetInformationFile; 511// static Func_NtSetInformationFile f_NtSetInformationFile;
@@ -572,16 +516,6 @@ Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IPr
572{ 516{
573 const CAltStream &ss = Streams[index]; 517 const CAltStream &ss = Streams[index];
574 const FString srcPath = _pathPrefix + us2fs(ss.Name); 518 const FString srcPath = _pathPrefix + us2fs(ss.Name);
575
576 const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
577 // if (!g_NtSetInformationFile_WasRequested) {
578 // g_NtSetInformationFile_WasRequested = true;
579 const
580 Func_NtSetInformationFile
581 f_NtSetInformationFile = Z7_GET_PROC_ADDRESS(
582 Func_NtSetInformationFile, ntdll,
583 "NtSetInformationFile");
584 if (f_NtSetInformationFile)
585 { 519 {
586 NIO::CInFile inFile; 520 NIO::CInFile inFile;
587 if (inFile.Open_for_FileRenameInformation(srcPath)) 521 if (inFile.Open_for_FileRenameInformation(srcPath))
@@ -599,24 +533,9 @@ Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IPr
599 fri->RootDirectory = NULL; 533 fri->RootDirectory = NULL;
600 fri->FileNameLength = len; 534 fri->FileNameLength = len;
601 memcpy(fri->FileName, destPath.Ptr(), len); 535 memcpy(fri->FileName, destPath.Ptr(), len);
602 Z7_WIN_IO_STATUS_BLOCK iosb; 536 const DWORD res = inFile.Call_NtSetInformationFile_return_WinError(
603 const Z7_WIN_NTSTATUS status = f_NtSetInformationFile (inFile.GetHandle(), 537 fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation);
604 &iosb, fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation); 538 return HRESULT_FROM_WIN32(res);
605 if (status != MY_STATUS_SUCCESS)
606 {
607 const
608 Func_RtlNtStatusToDosError
609 f_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS(
610 Func_RtlNtStatusToDosError, ntdll,
611 "RtlNtStatusToDosError");
612 if (f_RtlNtStatusToDosError)
613 {
614 const ULONG res = f_RtlNtStatusToDosError(status);
615 if (res != ERROR_MR_MID_NOT_FOUND)
616 return HRESULT_FROM_WIN32(res);
617 }
618 }
619 return status;
620 } 539 }
621 } 540 }
622 541
diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
index fc2fd6c..9351993 100644
--- a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
+++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
@@ -32,6 +32,8 @@ static void DeepCopyFormatEtc(FORMATETC *dest, const FORMATETC *src)
32 if (src->ptd) 32 if (src->ptd)
33 { 33 {
34 dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); 34 dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
35 if (!dest->ptd)
36 throw 2026; // CNewException()
35 *(dest->ptd) = *(src->ptd); 37 *(dest->ptd) = *(src->ptd);
36 } 38 }
37} 39}
diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp
index 51dfaa9..00c9353 100644
--- a/CPP/7zip/UI/FileManager/FSFolder.cpp
+++ b/CPP/7zip/UI/FileManager/FSFolder.cpp
@@ -45,6 +45,26 @@ typedef struct _IO_STATUS_BLOCK {
45 45
46#include "SysIconUtils.h" 46#include "SysIconUtils.h"
47 47
48EXTERN_C_BEGIN
49
50#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
51#define Z7_WIN_NTSTATUS NTSTATUS
52#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK
53#else
54typedef LONG Z7_WIN_NTSTATUS;
55typedef struct
56{
57 union
58 {
59 Z7_WIN_NTSTATUS Status;
60 PVOID Pointer;
61 } DUMMYUNIONNAME;
62 ULONG_PTR Information;
63} Z7_WIN_IO_STATUS_BLOCK;
64#endif
65
66EXTERN_C_END
67
48#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501 68#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
49#ifdef _APISETFILE_ 69#ifdef _APISETFILE_
50// Windows SDK 8.1 defines in fileapi.h the function GetCompressedFileSizeW only if _WIN32_WINNT >= 0x0501 70// Windows SDK 8.1 defines in fileapi.h the function GetCompressedFileSizeW only if _WIN32_WINNT >= 0x0501
@@ -445,46 +465,6 @@ bool CFSFolder::ReadFileInfo(CDirItem &di)
445 465
446 466
447EXTERN_C_BEGIN 467EXTERN_C_BEGIN
448
449typedef struct
450{
451 LARGE_INTEGER CreationTime;
452 LARGE_INTEGER LastAccessTime;
453 LARGE_INTEGER LastWriteTime;
454 LARGE_INTEGER ChangeTime;
455 ULONG FileAttributes;
456 UInt32 Reserved; // it's expected for alignment
457}
458Z7_WIN_FILE_BASIC_INFORMATION;
459
460
461typedef enum
462{
463 Z7_WIN_FileDirectoryInformation = 1,
464 Z7_WIN_FileFullDirectoryInformation,
465 Z7_WIN_FileBothDirectoryInformation,
466 Z7_WIN_FileBasicInformation
467}
468Z7_WIN_FILE_INFORMATION_CLASS;
469
470
471#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
472#define Z7_WIN_NTSTATUS NTSTATUS
473#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK
474#else
475typedef LONG Z7_WIN_NTSTATUS;
476typedef struct
477{
478 union
479 {
480 Z7_WIN_NTSTATUS Status;
481 PVOID Pointer;
482 } DUMMYUNIONNAME;
483 ULONG_PTR Information;
484} Z7_WIN_IO_STATUS_BLOCK;
485#endif
486
487
488typedef Z7_WIN_NTSTATUS (WINAPI * Func_NtQueryInformationFile)( 468typedef Z7_WIN_NTSTATUS (WINAPI * Func_NtQueryInformationFile)(
489 HANDLE handle, Z7_WIN_IO_STATUS_BLOCK *io, 469 HANDLE handle, Z7_WIN_IO_STATUS_BLOCK *io,
490 void *ptr, LONG len, Z7_WIN_FILE_INFORMATION_CLASS cls); 470 void *ptr, LONG len, Z7_WIN_FILE_INFORMATION_CLASS cls);
diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
index 9d78368..8a902ef 100644
--- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
@@ -871,27 +871,50 @@ bool CPanel::IsVirus_Message(const UString &name)
871 const wchar_t cRLO = (wchar_t)0x202E; 871 const wchar_t cRLO = (wchar_t)0x202E;
872 bool isVirus = false; 872 bool isVirus = false;
873 bool isSpaceError = false; 873 bool isSpaceError = false;
874 name2 = name; 874 {
875 875 unsigned numSpaces = 0;
876 for (unsigned i = 0; i < name.Len(); i++)
877 {
878 const wchar_t c = name[i];
879 switch (c)
880 {
881 case ' ':
882 case '\t':
883 case 0x00A0: // Non-Breaking Space
884 case 0x2002: // En Space
885 case 0x2003: // Em Space
886 case 0x2004: // Three-Per-Em Space
887 case 0x2005: // Four-Per-Em Space
888 case 0x2006: // Six-Per-Em Space
889 case 0x2007: // Figure Space
890 case 0x2008: // Punctuation Space
891 case 0x2009: // Thin Space
892 case 0x200A: // Hair Space
893 case 0x200B: // Zero Width Space
894 case 0x202F: // Narrow Non-Breaking Space
895 case 0x205F: // Medium Mathematical Space
896 case 0x3000: // Ideographic Space
897 numSpaces++;
898 break;
899 default:
900 numSpaces = 0;
901 break;
902 }
903 if (numSpaces <= 1)
904 name2 += c;
905 if (numSpaces >= 5)
906 {
907 isVirus = true;
908 isSpaceError = true;
909 }
910 }
911 }
876 if (name2.Find(cRLO) >= 0) 912 if (name2.Find(cRLO) >= 0)
877 { 913 {
878 const UString badString(cRLO); 914 const UString badString(cRLO);
879 name2.Replace(badString, L"[RLO]"); 915 name2.Replace(badString, L"[RLO]");
880 isVirus = true; 916 isVirus = true;
881 } 917 }
882 {
883 const wchar_t * const kVirusSpaces = L" ";
884 // const unsigned kNumSpaces = strlen(kVirusSpaces);
885 for (;;)
886 {
887 int pos = name2.Find(kVirusSpaces);
888 if (pos < 0)
889 break;
890 isVirus = true;
891 isSpaceError = true;
892 name2.Replace(kVirusSpaces, L" ");
893 }
894 }
895 918
896 #ifdef _WIN32 919 #ifdef _WIN32
897 { 920 {
diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp
index 868ad22..1bc8174 100644
--- a/CPP/7zip/UI/FileManager/PanelItems.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItems.cpp
@@ -648,9 +648,28 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
648 648
649 // OutputDebugStringA("S1\n"); 649 // OutputDebugStringA("S1\n");
650 650
651 UString correctedName; 651 UString correctedName, itemName, relPath, focusedNamePure, selectedName;
652 UString itemName; 652 bool needCheckSlash = false;
653 UString relPath; 653 if (state.FocusedName_Defined)
654 {
655 focusedNamePure = state.FocusedName;
656 const int pos = focusedNamePure.ReverseFind_PathSepar();
657 if (pos >= 0)
658 {
659 focusedNamePure.DeleteFrontal((unsigned)pos + 1);
660 needCheckSlash = true;
661 }
662 }
663 if (state.SelectedNames.Size() == 1)
664 {
665 selectedName = state.SelectedNames[0];
666 const int pos = selectedName.ReverseFind_PathSepar();
667 if (pos >= 0)
668 {
669 selectedName.DeleteFrontal((unsigned)pos + 1);
670 needCheckSlash = true;
671 }
672 }
654 673
655 for (UInt32 i = 0; i < numItems; i++) 674 for (UInt32 i = 0; i < numItems; i++)
656 { 675 {
@@ -667,8 +686,11 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
667 } 686 }
668 687
669 bool selected = false; 688 bool selected = false;
670 689
671 if (state.FocusedName_Defined || !state.SelectedNames.IsEmpty()) 690 if (state.SelectedNames.Size() > 1
691 || (state.SelectedNames.Size() == 1 && selectedName == name)
692 || (state.FocusedName_Defined && focusedNamePure == name)
693 || (needCheckSlash && NWindows::NFile::NName::FindSepar(name) >= 0))
672 { 694 {
673 relPath.Empty(); 695 relPath.Empty();
674 // relPath += GetItemPrefix(i); 696 // relPath += GetItemPrefix(i);
@@ -875,10 +897,10 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
875 SetFocusedSelectedItem(cursorIndex, state.SelectFocused); 897 SetFocusedSelectedItem(cursorIndex, state.SelectFocused);
876 898
877 Print_OnNotify("after SetFocusedSelectedItem"); 899 Print_OnNotify("after SetFocusedSelectedItem");
878 900 // OutputDebugStringA("Sort before");
879 SetSortRawStatus(); 901 SetSortRawStatus();
880 _listView.SortItems(CompareItems, (LPARAM)this); 902 _listView.SortItems(CompareItems, (LPARAM)this);
881 903 // OutputDebugStringA("=== Sort after");
882 Print_OnNotify("after Sort"); 904 Print_OnNotify("after Sort");
883 905
884 if (cursorIndex < 0 && _listView.GetItemCount() > 0) 906 if (cursorIndex < 0 && _listView.GetItemCount() > 0)
@@ -1089,19 +1111,19 @@ void CPanel::OpenSelectedItems(bool tryInternal)
1089 indices.Insert(0, realIndex); 1111 indices.Insert(0, realIndex);
1090 } 1112 }
1091 1113
1092 bool dirIsStarted = false; 1114 // bool dirIsStarted = false;
1093 FOR_VECTOR (i, indices) 1115 FOR_VECTOR (i, indices)
1094 { 1116 {
1095 UInt32 index = indices[i]; 1117 UInt32 index = indices[i];
1096 // CFileInfo &aFile = m_Files[index]; 1118 // CFileInfo &aFile = m_Files[index];
1097 if (IsItem_Folder(index)) 1119 if (IsItem_Folder(index))
1098 { 1120 {
1099 if (!dirIsStarted) 1121 // if (!dirIsStarted)
1100 { 1122 {
1101 if (tryInternal) 1123 if (tryInternal)
1102 { 1124 {
1103 OpenFolder(index); 1125 OpenFolder(index);
1104 dirIsStarted = true; 1126 // dirIsStarted = true;
1105 break; 1127 break;
1106 } 1128 }
1107 else 1129 else
@@ -1162,14 +1184,15 @@ void CPanel::GetItemName(unsigned itemIndex, UString &s) const
1162 1184
1163UString CPanel::GetItemPrefix(unsigned itemIndex) const 1185UString CPanel::GetItemPrefix(unsigned itemIndex) const
1164{ 1186{
1165 if (itemIndex == kParentIndex)
1166 return UString();
1167 NCOM::CPropVariant prop;
1168 if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK)
1169 throw 2723400;
1170 UString prefix; 1187 UString prefix;
1171 if (prop.vt == VT_BSTR) 1188 if (itemIndex != kParentIndex)
1172 prefix.SetFromBstr(prop.bstrVal); 1189 {
1190 NCOM::CPropVariant prop;
1191 if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK)
1192 throw 2723400;
1193 if (prop.vt == VT_BSTR)
1194 prefix.SetFromBstr(prop.bstrVal);
1195 }
1173 return prefix; 1196 return prefix;
1174} 1197}
1175 1198
diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp
index e655843..231a68f 100644
--- a/CPP/7zip/UI/FileManager/PanelMenu.cpp
+++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp
@@ -493,9 +493,11 @@ HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder,
493HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder, 493HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder,
494 HWND hwnd, const UString &path, LPITEMIDLIST *ppidl) 494 HWND hwnd, const UString &path, LPITEMIDLIST *ppidl)
495{ 495{
496 ULONG eaten = 0; 496 // ULONG eaten = 0;
497 return shellFolder->ParseDisplayName(hwnd, NULL, 497 return shellFolder->ParseDisplayName(hwnd, NULL,
498 path.Ptr_non_const(), &eaten, ppidl, NULL); 498 path.Ptr_non_const(),
499 NULL, // &eaten
500 ppidl, NULL);
499} 501}
500 502
501 503
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
index 72fe5e7..d342181 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
@@ -25,7 +25,7 @@ CExtToIconMap g_Ext_to_Icon_Map;
25int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl) 25int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl)
26{ 26{
27 LPITEMIDLIST pidl = NULL; 27 LPITEMIDLIST pidl = NULL;
28 SHGetSpecialFolderLocation(NULL, csidl, &pidl); 28 if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK)
29 if (pidl) 29 if (pidl)
30 { 30 {
31 SHFILEINFO shFileInfo; 31 SHFILEINFO shFileInfo;
@@ -333,6 +333,7 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin
333HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons) 333HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons)
334{ 334{
335 SHFILEINFO shFileInfo; 335 SHFILEINFO shFileInfo;
336 Z7_memset_0_VAR(shFileInfo); // optional
336 // shFileInfo.hIcon = NULL; // optional 337 // shFileInfo.hIcon = NULL; // optional
337 const DWORD_PTR res = SHGetFileInfo(TEXT(""), 338 const DWORD_PTR res = SHGetFileInfo(TEXT(""),
338 /* FILE_ATTRIBUTE_ARCHIVE | */ 339 /* FILE_ATTRIBUTE_ARCHIVE | */
diff --git a/CPP/Build.mak b/CPP/Build.mak
index d9fcfb5..355063b 100644
--- a/CPP/Build.mak
+++ b/CPP/Build.mak
@@ -63,23 +63,24 @@ COMPL_ASM = $(MY_ML) $** $O/$(*B).obj
63COMPL_ASM = $(MY_ML) -c -Fo$O/ $** 63COMPL_ASM = $(MY_ML) -c -Fo$O/ $**
64!ENDIF 64!ENDIF
65 65
66CFLAGS_c_switch = -c -Fo$O/
67
66!IFDEF OLD_COMPILER 68!IFDEF OLD_COMPILER
67CFLAGS_WARN_LEVEL = -W4 69CFLAGS_WARN_LEVEL = -W4
68!ELSE 70!ELSE
71!IF "$(CC)" != "clang-cl"
72CFLAGS_WARN_LEVEL = -Wall -analyze
73!ELSE
74CFLAGS_WARN_LEVEL = -Wall --analyze -Xclang -analyzer-output=text
75# CFLAGS_c_switch =
76!ENDIF
69CFLAGS_WARN_LEVEL = -Wall 77CFLAGS_WARN_LEVEL = -Wall
70!ENDIF 78!ENDIF
71 79
72CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF 80CFLAGS = $(CFLAGS) -nologo $(CFLAGS_c_switch) $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF
73 81
74!IF "$(CC)" == "clang-cl" 82!IF "$(CC)" == "clang-cl"
75 83CFLAGS = $(CFLAGS) -Werror -Wall -Wextra -Weverything -Wfatal-errors
76CFLAGS = $(CFLAGS) \
77 -Werror \
78 -Wall \
79 -Wextra \
80 -Weverything \
81 -Wfatal-errors \
82
83!ENDIF 84!ENDIF
84 85
85# !IFDEF MY_DYNAMIC_LINK 86# !IFDEF MY_DYNAMIC_LINK
diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h
index 7dc21ba..b45530a 100644
--- a/CPP/Common/MyCom.h
+++ b/CPP/Common/MyCom.h
@@ -688,6 +688,6 @@ EXTERN_C_END
688 Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) \ 688 Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) \
689 689
690 690
691#define k_My_HRESULT_WritingWasCut 0x20000010 691#define k_My_HRESULT_WritingWasCut ((HRESULT)0x20000010)
692 692
693#endif 693#endif
diff --git a/CPP/Common/MyVector.h b/CPP/Common/MyVector.h
index a772785..c806767 100644
--- a/CPP/Common/MyVector.h
+++ b/CPP/Common/MyVector.h
@@ -92,6 +92,21 @@ public:
92 _size = newSize; 92 _size = newSize;
93 } 93 }
94 94
95 void ChangeSize_KeepData_plus_AdditionalReserve(const unsigned newSize)
96 {
97 if (newSize > _capacity)
98 {
99 if (newSize > k_VectorSizeMax)
100 throw 2021;
101 const unsigned rem = k_VectorSizeMax - newSize;
102 unsigned add = newSize >> 2;
103 if (add > rem)
104 add = rem;
105 ReAllocForNewCapacity(newSize + add);
106 }
107 _size = newSize;
108 }
109
95 void ClearAndReserve(unsigned newCapacity) 110 void ClearAndReserve(unsigned newCapacity)
96 { 111 {
97 Clear(); 112 Clear();
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
index ad0d8c9..bf77c15 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -34,7 +34,9 @@ using namespace NName;
34 34
35#ifndef _WIN32 35#ifndef _WIN32
36 36
37static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) 37extern
38bool FiTime_To_timespec(const CFiTime *ft, timespec &ts);
39bool FiTime_To_timespec(const CFiTime *ft, timespec &ts)
38{ 40{
39 if (ft) 41 if (ft)
40 { 42 {
@@ -51,7 +53,7 @@ static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts)
51 ts.tv_sec = 0; 53 ts.tv_sec = 0;
52 ts.tv_nsec = 54 ts.tv_nsec =
53 #ifdef UTIME_OMIT 55 #ifdef UTIME_OMIT
54 UTIME_OMIT; // -2 keep old timesptamp 56 UTIME_OMIT; // -2 keep old timestamp
55 #else 57 #else
56 // UTIME_NOW; -1 // set to the current time 58 // UTIME_NOW; -1 // set to the current time
57 0; 59 0;
@@ -170,6 +172,10 @@ bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, con
170 172
171bool SetFileAttrib(CFSTR path, DWORD attrib) 173bool SetFileAttrib(CFSTR path, DWORD attrib)
172{ 174{
175 /* win10:
176 if (attrib == 0), it sets (FILE_ATTRIBUTE_NORMAL) attribute
177 (FILE_ATTRIBUTE_DIRECTORY and some another attributes are ignored for files).
178 */
173 #ifndef _UNICODE 179 #ifndef _UNICODE
174 if (!g_IsNT) 180 if (!g_IsNT)
175 { 181 {
@@ -1078,7 +1084,7 @@ static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile, ICopyFileProgress *progres
1078 } 1084 }
1079 // There is file IO error or process was interrupted by user. 1085 // There is file IO error or process was interrupted by user.
1080 // We close output file and delete it. 1086 // We close output file and delete it.
1081 // DeleteFileAlways doesn't change errno (if successed), but we restore errno. 1087 // DeleteFileAlways doesn't change errno (if succeed), but we restore errno.
1082 const int errno_save = errno; 1088 const int errno_save = errno;
1083 DeleteFileAlways(newFile); 1089 DeleteFileAlways(newFile);
1084 errno = errno_save; 1090 errno = errno_save;
@@ -1240,26 +1246,34 @@ bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, con
1240} 1246}
1241 1247
1242 1248
1243struct C_umask 1249C_umask::C_umask()
1244{ 1250{
1245 mode_t mask; 1251/*
1246 1252 For security purposes, we restrict the file (mode) attributes
1247 C_umask() 1253 using the process's file mode creation mask (umask).
1248 { 1254 System's umask is used by open(), mkdir(), and other system calls
1249 /* by security reasons we restrict attributes according 1255 that create files to modify the permissions placed on newly
1250 with process's file mode creation mask (umask) */ 1256 created files or directories.
1251 const mode_t um = umask(0); // octal :0022 is expected 1257 We use (g_umask.mask) for any function that changes the file's access
1252 mask = 0777 & (~um); // octal: 0755 is expected 1258 mode but is not affected by the system's umask.
1253 umask(um); // restore the umask 1259 We use additional mask restiction 0777 for security purposes.
1254 // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); 1260 So we don't create the following mode bits for files and directories:
1255 1261 S_ISUID 04000 set-user-ID bit
1256 // mask = 0777; // debug we can disable the restriction: 1262 S_ISGID 02000 set-group-ID bit
1257 } 1263 S_ISVTX 01000 sticky bit
1258}; 1264 system's open(), mkdir() also can have similar 0777 restiction for some cases.
1265*/
1266 const mode_t um = umask(0); // um = 0022 (octal) is expected
1267 mask = ~um
1268 & 0777; // 0777 is our additional mode restruction : is secure
1269 // & 07777; // for debug : 07777 to support all mode bits : is not secure
1270 // mask = 07777; // for debug : to restore all mode bits
1271 umask(um); // restore original umask that was changed by umask(0) in code above
1272}
1259 1273
1260static C_umask g_umask; 1274C_umask g_umask;
1261 1275
1262// #define PRF(x) x; 1276// #define PRF(x) x
1263#define PRF(x) 1277#define PRF(x)
1264 1278
1265#define TRACE_SetFileAttrib(msg) \ 1279#define TRACE_SetFileAttrib(msg) \
@@ -1273,12 +1287,17 @@ int my_chown(CFSTR path, uid_t owner, gid_t group)
1273 return chown(path, owner, group); 1287 return chown(path, owner, group);
1274} 1288}
1275 1289
1290int my_chown_Link(CFSTR path, uid_t owner, gid_t group)
1291{
1292 return lchown(path, owner, group);
1293 // return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW);
1294}
1295
1276bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) 1296bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
1277{ 1297{
1278 TRACE_SetFileAttrib("") 1298 TRACE_SetFileAttrib("")
1279 1299 mode_t mode;
1280 struct stat st; 1300 struct stat st;
1281
1282 bool use_lstat = true; 1301 bool use_lstat = true;
1283 if (use_lstat) 1302 if (use_lstat)
1284 { 1303 {
@@ -1297,20 +1316,26 @@ bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
1297 return false; 1316 return false;
1298 } 1317 }
1299 } 1318 }
1300 1319 mode = st.st_mode;
1320
1301 if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) 1321 if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
1302 { 1322 {
1303 TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION") 1323 TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION")
1304 st.st_mode = attrib >> 16; 1324 mode = attrib >> 16;
1305 if (S_ISDIR(st.st_mode)) 1325 if (S_ISDIR(mode))
1306 { 1326 {
1327 if (!S_ISDIR(st.st_mode))
1328 return true;
1307 // user/7z must be able to create files in this directory 1329 // user/7z must be able to create files in this directory
1308 st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); 1330 mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
1331 }
1332 else
1333 {
1334 if (!S_ISREG(mode) || !S_ISREG(st.st_mode))
1335 return true;
1309 } 1336 }
1310 else if (!S_ISREG(st.st_mode))
1311 return true;
1312 } 1337 }
1313 else if (S_ISLNK(st.st_mode)) 1338 else if (S_ISLNK(mode))
1314 { 1339 {
1315 /* for most systems: permissions for symlinks are fixed to rwxrwxrwx. 1340 /* for most systems: permissions for symlinks are fixed to rwxrwxrwx.
1316 so we don't need chmod() for symlinks. */ 1341 so we don't need chmod() for symlinks. */
@@ -1322,27 +1347,28 @@ bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
1322 { 1347 {
1323 TRACE_SetFileAttrib("Only Windows Attributes") 1348 TRACE_SetFileAttrib("Only Windows Attributes")
1324 // Only Windows Attributes 1349 // Only Windows Attributes
1325 if (S_ISDIR(st.st_mode) 1350 if (S_ISDIR(mode)
1326 || (attrib & FILE_ATTRIBUTE_READONLY) == 0) 1351 || (attrib & FILE_ATTRIBUTE_READONLY) == 0)
1327 return true; 1352 return true;
1328 st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions 1353 mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions
1329 } 1354 }
1330 1355
1331 int res; 1356 int res;
1357 mode &= g_umask.mask;
1332 /* 1358 /*
1333 if (S_ISLNK(st.st_mode)) 1359 if (S_ISLNK(mode))
1334 { 1360 {
1335 printf("\nfchmodat()\n"); 1361 printf("\nfchmodat()\n");
1336 TRACE_chmod(path, (st.st_mode) & g_umask.mask) 1362 TRACE_chmod(path, (mode))
1337 // AT_SYMLINK_NOFOLLOW is not implemted still in Linux. 1363 // AT_SYMLINK_NOFOLLOW is not implemented still in Linux.
1338 res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask, 1364 res = fchmodat(AT_FDCWD, path, (mode),
1339 S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0); 1365 S_ISLNK(mode) ? AT_SYMLINK_NOFOLLOW : 0);
1340 } 1366 }
1341 else 1367 else
1342 */ 1368 */
1343 { 1369 {
1344 TRACE_chmod(path, (st.st_mode) & g_umask.mask) 1370 TRACE_chmod(path, mode)
1345 res = chmod(path, (st.st_mode) & g_umask.mask); 1371 res = chmod(path, mode);
1346 } 1372 }
1347 // TRACE_SetFileAttrib("End") 1373 // TRACE_SetFileAttrib("End")
1348 return (res == 0); 1374 return (res == 0);
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 9ba98fc..e8d9d31 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -46,6 +46,7 @@ bool SetFileAttrib(CFSTR path, DWORD attrib);
46#else 46#else
47 47
48int my_chown(CFSTR path, uid_t owner, gid_t group); 48int my_chown(CFSTR path, uid_t owner, gid_t group);
49int my_chown_Link(CFSTR path, uid_t owner, gid_t group);
49 50
50#endif 51#endif
51 52
diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp
index dc4de14..8be06fc 100644
--- a/CPP/Windows/FileIO.cpp
+++ b/CPP/Windows/FileIO.cpp
@@ -6,6 +6,29 @@
6#include "../../C/Alloc.h" 6#include "../../C/Alloc.h"
7#endif 7#endif
8 8
9#ifdef _WIN32
10#ifdef __MINGW32_VERSION
11// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
12// for old mingw
13#include <ddk/ntddk.h>
14#else
15#ifndef Z7_OLD_WIN_SDK
16 #if !defined(_M_IA64)
17 #include <winternl.h>
18 #endif
19#else
20typedef LONG NTSTATUS;
21typedef struct _IO_STATUS_BLOCK {
22 union {
23 NTSTATUS Status;
24 PVOID Pointer;
25 };
26 ULONG_PTR Information;
27} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
28#endif
29#endif
30#endif // _WIN32
31
9// #include <stdio.h> 32// #include <stdio.h>
10 33
11/* 34/*
@@ -33,6 +56,48 @@ HRESULT GetLastError_noZero_HRESULT()
33extern bool g_IsNT; 56extern bool g_IsNT;
34#endif 57#endif
35 58
59#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
60#define Z7_WIN_NTSTATUS NTSTATUS
61#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK
62#else
63typedef LONG Z7_WIN_NTSTATUS;
64typedef struct
65{
66 union
67 {
68 Z7_WIN_NTSTATUS Status;
69 PVOID Pointer;
70 } DUMMYUNIONNAME;
71 ULONG_PTR Information;
72} Z7_WIN_IO_STATUS_BLOCK;
73#endif
74
75typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)(
76 HANDLE FileHandle,
77 Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock,
78 PVOID FileInformation,
79 ULONG Length,
80 Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass);
81// NTAPI
82typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status);
83
84Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
85static Func_NtSetInformationFile g_NtSetInformationFile;
86static Func_RtlNtStatusToDosError g_RtlNtStatusToDosError;
87static struct C_Init_NtSetInformationFile
88{
89 C_Init_NtSetInformationFile()
90 {
91 const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
92 g_NtSetInformationFile = Z7_GET_PROC_ADDRESS(
93 Func_NtSetInformationFile, ntdll,
94 "NtSetInformationFile");
95 g_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS(
96 Func_RtlNtStatusToDosError, ntdll,
97 "RtlNtStatusToDosError");
98 }
99} g_C_Init_NtSetInformationFile;
100
36using namespace NWindows; 101using namespace NWindows;
37using namespace NFile; 102using namespace NFile;
38using namespace NName; 103using namespace NName;
@@ -353,7 +418,7 @@ void CInFile::CalcDeviceSize(CFSTR s)
353 WinXP 64-bit: 418 WinXP 64-bit:
354 419
355 HDD \\.\PhysicalDrive0 (MBR): 420 HDD \\.\PhysicalDrive0 (MBR):
356 GetPartitionInfo == GeometryEx : corrrect size? (includes tail) 421 GetPartitionInfo == GeometryEx : correct size? (includes tail)
357 Geometry : smaller than GeometryEx (no tail, maybe correct too?) 422 Geometry : smaller than GeometryEx (no tail, maybe correct too?)
358 MyGetDiskFreeSpace : FAIL 423 MyGetDiskFreeSpace : FAIL
359 Size correction is slow and block size (kClusterSize) must be small? 424 Size correction is slow and block size (kClusterSize) must be small?
@@ -365,8 +430,8 @@ void CInFile::CalcDeviceSize(CFSTR s)
365 430
366 CD-ROM drive (ISO): 431 CD-ROM drive (ISO):
367 MyGetDiskFreeSpace : correct size. Same size can be calculated after correction 432 MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
368 Geometry == CdRomGeometry : smaller than corrrect size 433 Geometry == CdRomGeometry : smaller than correct size
369 GetPartitionInfo == GeometryEx : larger than corrrect size 434 GetPartitionInfo == GeometryEx : larger than correct size
370 435
371 Floppy \\.\a: (FAT): 436 Floppy \\.\a: (FAT):
372 Geometry : correct size. 437 Geometry : correct size.
@@ -539,6 +604,70 @@ bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition)
539bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) 604bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes)
540 { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); } 605 { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); }
541 606
607DWORD CFileBase::Call_NtSetInformationFile_return_WinError(
608 void *data, ULONG len, Z7_WIN_FILE_INFORMATION_CLASS fileInformationClass) const
609{
610 if (!g_NtSetInformationFile)
611 return ERROR_PROC_NOT_FOUND;
612 Z7_WIN_IO_STATUS_BLOCK ioStatus;
613 Z7_memset_0_VAR(ioStatus); // optional
614 const Z7_WIN_NTSTATUS status = g_NtSetInformationFile(_handle,
615 &ioStatus, data, len, fileInformationClass);
616 if (status == 0) // MY_STATUS_SUCCESS
617 return 0;
618 if (g_RtlNtStatusToDosError)
619 {
620 const ULONG res = g_RtlNtStatusToDosError(status);
621 if (res != ERROR_MR_MID_NOT_FOUND)
622 return res;
623 }
624 return 1;
625}
626
627
628#define SET_TIME_FIELD_IF_DEFINED(dest, src) \
629{ if (src) { \
630 dest.LowPart = (src)->dwLowDateTime; \
631 dest.HighPart = (LONG)(src)->dwHighDateTime; \
632 } \
633}
634
635bool COutFile::Set_Time_and_WinAttrib(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime, DWORD attrib) throw()
636{
637#ifdef _WIN32
638 // similar to GetAttrib_PosixHighDetect(attrib)
639 if (attrib & 0xF0000000)
640 attrib &= 0x3FFF;
641#endif
642
643 Z7_WIN_FILE_BASIC_INFORMATION fbi;
644 Z7_memset_0_VAR(fbi);
645 SET_TIME_FIELD_IF_DEFINED (fbi.CreationTime, cTime)
646 SET_TIME_FIELD_IF_DEFINED (fbi.LastAccessTime, aTime)
647 SET_TIME_FIELD_IF_DEFINED (fbi.LastWriteTime, mTime)
648 // fbi.ChangeTime.QuadPart = 0;
649 /*
650 if (attrib == 0)
651 { win10: NtSetInformationFile() doesn't change file attribute
652 if (attrib & FILE_ATTRIBUTE_DIRECTORY)
653 { win10: NtSetInformationFile() returns (STATUS_INVALID_PARAMETER) }
654 we provide similar attribute processing as
655 SetFileAttributes():
656 - we ignore (FILE_ATTRIBUTE_DIRECTORY)
657 - we write (FILE_ATTRIBUTE_NORMAL) instead of (0)
658 */
659 attrib &= ~(DWORD)FILE_ATTRIBUTE_DIRECTORY;
660 if (attrib == 0)
661 attrib = FILE_ATTRIBUTE_NORMAL;
662 fbi.FileAttributes = attrib;
663 const DWORD wres = Call_NtSetInformationFile_return_WinError(
664 &fbi, sizeof(fbi), Z7_WIN_FileBasicInformation);
665 if (wres == 0)
666 return true;
667 SetLastError(wres);
668 return false;
669}
670
542bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() 671bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
543 { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } 672 { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
544 673
@@ -628,10 +757,16 @@ bool COutFile::SetLength_KeepPosition(UInt64 length) throw()
628#include <fcntl.h> 757#include <fcntl.h>
629#include <unistd.h> 758#include <unistd.h>
630 759
760extern
761bool FiTime_To_timespec(const CFiTime *ft, timespec &ts);
762
631namespace NWindows { 763namespace NWindows {
632namespace NFile { 764namespace NFile {
633 765
634namespace NDir { 766namespace NDir {
767
768extern C_umask g_umask;
769
635bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); 770bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
636} 771}
637 772
@@ -644,6 +779,34 @@ bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode)
644 #endif 779 #endif
645 780
646 Close(); 781 Close();
782 /*
783 The mode argument specifies the file mode bits to be
784 applied when a new file is created. If neither O_CREAT nor
785 O_TMPFILE is specified in flags, then mode is ignored (and
786 can thus be specified as 0, or simply omitted).
787
788 The effective mode is modified by the process's umask in
789 the usual way: in the absence of a default ACL, the mode of
790 the created file is (mode & ~umask).
791
792 Note that mode applies only to future accesses of the newly
793 created file; the open() call that creates a read-only file
794 may well return a read/write file descriptor.
795
796 POSIX: if other bits (~0777) are set in mode : the effect is unspecified
797 Linux:
798 S_ISUID 04000 set-user-ID bit
799 S_ISGID 02000 set-group-ID bit
800 S_ISVTX 01000 sticky bit
801
802 S_ISVTX can be set, but it's useless for file in modern linux.
803 by security reasons:
804 open() ignores S_ISUID
805 open() ignores S_ISGID, if S_IXGRP is set.
806 */
807 // mode |= S_ISUID | S_ISGID | S_ISVTX; // for debug
808 // printf("\n open() mode=%o\n", (unsigned)(mode));
809
647 _handle = ::open(name, flags, mode); 810 _handle = ::open(name, flags, mode);
648 return _handle != -1; 811 return _handle != -1;
649 812
@@ -740,7 +903,7 @@ bool CFileBase::SeekToBegin() const throw()
740 903
741bool CInFile::Open(const char *name) 904bool CInFile::Open(const char *name)
742{ 905{
743 return CFileBase::OpenBinary(name, O_RDONLY); 906 return CFileBase::OpenBinary(name, O_RDONLY, k_OutFile_mode_default);
744} 907}
745 908
746bool CInFile::OpenShared(const char *name, bool) 909bool CInFile::OpenShared(const char *name, bool)
@@ -903,11 +1066,64 @@ bool COutFile::SetLength(UInt64 length) throw()
903 return (iret == 0); 1066 return (iret == 0);
904} 1067}
905 1068
1069// #define PRF(x) x
1070#define PRF(x)
1071
906bool COutFile::Close() 1072bool COutFile::Close()
907{ 1073{
908 const bool res = CFileBase::Close(); 1074 bool res = true;
909 if (!res) 1075 if (_handle == -1)
910 return res; 1076 return true;
1077 {
1078 // bool res2 = true;
1079 if (mode_for_Close_defined)
1080 {
1081 PRF(printf("\n COutFile::Close() mode=%o\n", (unsigned)(mode_for_Close));)
1082 // fchmod() function ignores the file creation mask set by umask()
1083 // so we can restore any of (07777) mode bits
1084 // mode_for_Close |= (0xffff << 12); // for debug
1085 if (fchmod(_handle, mode_for_Close) == 0)
1086 {
1087 mode_for_Close_defined = false;
1088 PRF(printf("\n COutFile::Close() fchmod() == 0\n");)
1089 }
1090 // else res2 = false;
1091 }
1092 {
1093 if (MTime_defined || ATime_defined)
1094 {
1095 struct timespec times[2];
1096 FiTime_To_timespec(ATime_defined ? &ATime : NULL, times[0]);
1097 FiTime_To_timespec(MTime_defined ? &MTime : NULL, times[1]);
1098 // futimens : POSIX.1-2008
1099 if (futimens(_handle, times) == 0)
1100 {
1101 PRF(printf("\n futimens() OK \n");)
1102 ATime_defined = false;
1103 MTime_defined = false;
1104 }
1105 else
1106 {
1107 PRF(printf("\n futimens() ERROR: %d=%s\n", errno, strerror(errno));)
1108 }
1109 }
1110 }
1111 res = CFileBase::Close();
1112 if (!res)
1113 return res;
1114 // res = res2;
1115 }
1116 if (mode_for_Close_defined)
1117 {
1118 // chmod() ignores the file creation mask set by umask()
1119 // so we can restore any of (07777) mode bits
1120 // const int res_chmod =
1121 chmod(Path, mode_for_Close);
1122 mode_for_Close_defined = false;
1123 // if (res_chmod != 0 && res == true) res = false;
1124 // PRF(printf("\n COutFile::Close() chmod res=%d\n", (int)res_chmod);)
1125 }
1126
911 if (CTime_defined || ATime_defined || MTime_defined) 1127 if (CTime_defined || ATime_defined || MTime_defined)
912 { 1128 {
913 /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, 1129 /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
@@ -942,6 +1158,24 @@ bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime
942 */ 1158 */
943} 1159}
944 1160
1161bool COutFile::Set_Time_and_WinAttrib(
1162 const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw()
1163{
1164 PRF(printf("\n Set_Time_and_WinAttrib() mode=%o\n", (unsigned)(attrib >> 16));)
1165 SetTime(cTime, aTime, mTime);
1166 // we will use fchmod() or chmod() later in Close() fucntion.
1167 // fchmod() or chmod() are not limited by system umask.
1168 // but for security reasons we use the system mask (g_umask.mask) derived from umask().
1169 mode_t mode = k_OutFile_mode_default; // 0666
1170 if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
1171 mode = (attrib >> 16);
1172 else if (attrib & FILE_ATTRIBUTE_READONLY)
1173 mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions
1174 mode_for_Close = mode & NDir::g_umask.mask;
1175 mode_for_Close_defined = true;
1176 return true;
1177}
1178
945bool COutFile::SetMTime(const CFiTime *mTime) throw() 1179bool COutFile::SetMTime(const CFiTime *mTime) throw()
946{ 1180{
947 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; 1181 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h
index a202df5..9c32137 100644
--- a/CPP/Windows/FileIO.h
+++ b/CPP/Windows/FileIO.h
@@ -19,6 +19,27 @@
19#include <winioctl.h> 19#include <winioctl.h>
20#endif 20#endif
21 21
22typedef enum
23{
24 Z7_WIN_FileDirectoryInformation = 1,
25 Z7_WIN_FileFullDirectoryInformation,
26 Z7_WIN_FileBothDirectoryInformation,
27 Z7_WIN_FileBasicInformation,
28 Z7_WIN_FileRenameInformation = 10
29} Z7_WIN_FILE_INFORMATION_CLASS;
30
31// FILE_BASIC_INFORMATION / FILE_BASIC_INFO
32typedef struct
33{
34 LARGE_INTEGER CreationTime;
35 LARGE_INTEGER LastAccessTime;
36 LARGE_INTEGER LastWriteTime;
37 LARGE_INTEGER ChangeTime;
38 ULONG FileAttributes;
39 ULONG Reserved; // it's expected dummy variable for alignment : optional
40}
41Z7_WIN_FILE_BASIC_INFORMATION;
42
22#else 43#else
23 44
24#include <sys/types.h> 45#include <sys/types.h>
@@ -205,6 +226,9 @@ public:
205 return false; 226 return false;
206 return file.GetFileInformation(info); 227 return file.GetFileInformation(info);
207 } 228 }
229
230 DWORD Call_NtSetInformationFile_return_WinError(void *data, ULONG len,
231 Z7_WIN_FILE_INFORMATION_CLASS fileInformationClass) const;
208}; 232};
209 233
210#ifndef UNDER_CE 234#ifndef UNDER_CE
@@ -323,6 +347,8 @@ public:
323 347
324 bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes); 348 bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes);
325 349
350 bool Set_Time_and_WinAttrib(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw();
351
326 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); 352 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
327 bool SetMTime(const CFiTime *mTime) throw(); 353 bool SetMTime(const CFiTime *mTime) throw();
328 bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); 354 bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();
@@ -338,6 +364,15 @@ public:
338 364
339#else // _WIN32 365#else // _WIN32
340 366
367namespace NDir {
368struct C_umask
369{
370 mode_t mask;
371 C_umask();
372};
373extern C_umask g_umask;
374}
375
341namespace NIO { 376namespace NIO {
342 377
343bool GetReparseData(CFSTR path, CByteBuffer &reparseData); 378bool GetReparseData(CFSTR path, CByteBuffer &reparseData);
@@ -347,6 +382,7 @@ bool GetReparseData(CFSTR path, CByteBuffer &reparseData);
347bool SetSymLink(CFSTR from, CFSTR to); 382bool SetSymLink(CFSTR from, CFSTR to);
348bool SetSymLink_UString(CFSTR from, const UString &to); 383bool SetSymLink_UString(CFSTR from, const UString &to);
349 384
385const mode_t k_OutFile_mode_default = 0666;
350 386
351class CFileBase 387class CFileBase
352{ 388{
@@ -359,7 +395,7 @@ protected:
359 UInt64 Size; // it can be larger than real available size 395 UInt64 Size; // it can be larger than real available size
360 */ 396 */
361 397
362 bool OpenBinary(const char *name, int flags, mode_t mode = 0666); 398 bool OpenBinary(const char *name, int flags, mode_t mode /* = k_OutFile_mode_default */);
363public: 399public:
364 bool PreserveATime; 400 bool PreserveATime;
365#if 0 401#if 0
@@ -411,9 +447,11 @@ class COutFile: public CFileBase
411 bool CTime_defined; 447 bool CTime_defined;
412 bool ATime_defined; 448 bool ATime_defined;
413 bool MTime_defined; 449 bool MTime_defined;
450 bool mode_for_Close_defined;
414 CFiTime CTime; 451 CFiTime CTime;
415 CFiTime ATime; 452 CFiTime ATime;
416 CFiTime MTime; 453 CFiTime MTime;
454 mode_t mode_for_Close;
417 455
418 AString Path; 456 AString Path;
419 ssize_t write_part(const void *data, size_t size) throw(); 457 ssize_t write_part(const void *data, size_t size) throw();
@@ -425,9 +463,11 @@ public:
425 CTime_defined(false), 463 CTime_defined(false),
426 ATime_defined(false), 464 ATime_defined(false),
427 MTime_defined(false), 465 MTime_defined(false),
428 mode_for_Create(0666) 466 mode_for_Close_defined(false),
467 mode_for_Create(k_OutFile_mode_default) // 0666
429 {} 468 {}
430 469
470 ~COutFile() { Close(); }
431 bool Close(); 471 bool Close();
432 472
433 bool Open_EXISTING(CFSTR fileName); 473 bool Open_EXISTING(CFSTR fileName);
@@ -454,6 +494,7 @@ public:
454 return SetLength(length); 494 return SetLength(length);
455 } 495 }
456 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); 496 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
497 bool Set_Time_and_WinAttrib(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw();
457 bool SetMTime(const CFiTime *mTime) throw(); 498 bool SetMTime(const CFiTime *mTime) throw();
458}; 499};
459 500
diff --git a/DOC/7zC.txt b/DOC/7zC.txt
index 939b720..8c76b94 100644
--- a/DOC/7zC.txt
+++ b/DOC/7zC.txt
@@ -165,8 +165,8 @@ Memory usage for archive Decompressing:
165 - Memory for LZMA decompressing structures 165 - Memory for LZMA decompressing structures
166 - Main pool: 166 - Main pool:
167 - Memory for decompressed solid block 167 - Memory for decompressed solid block
168 - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these 168 - Memory for temporary buffers, if BCJ2 filter is used. Usually these
169 temprorary buffers can be about 15% of solid block size. 169 temporary buffers can be about 15% of solid block size.
170 170
171 171
1727z Decoder doesn't allocate memory for compressed blocks. 1727z Decoder doesn't allocate memory for compressed blocks.
diff --git a/DOC/7zFormat.txt b/DOC/7zFormat.txt
index 74cdfa4..0347196 100644
--- a/DOC/7zFormat.txt
+++ b/DOC/7zFormat.txt
@@ -398,7 +398,7 @@ FilesInfo
398 if(External != 0) 398 if(External != 0)
399 UINT64 DataIndex 399 UINT64 DataIndex
400 [] 400 []
401 for(Definded Items) 401 for(Defined Items)
402 REAL_UINT64 Time 402 REAL_UINT64 Time
403 [] 403 []
404 404
@@ -425,7 +425,7 @@ FilesInfo
425 if(External != 0) 425 if(External != 0)
426 UINT64 DataIndex 426 UINT64 DataIndex
427 [] 427 []
428 for(Definded Attributes) 428 for(Defined Attributes)
429 UINT32 Attributes 429 UINT32 Attributes
430 [] 430 []
431 } 431 }
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs
index 44e71e1..2ddcfb7 100644
--- a/DOC/7zip.wxs
+++ b/DOC/7zip.wxs
@@ -1,7 +1,7 @@
1<?xml version="1.0"?> 1<?xml version="1.0"?>
2 2
3<?define VerMajor = "26" ?> 3<?define VerMajor = "26" ?>
4<?define VerMinor = "02" ?> 4<?define VerMinor = "03" ?>
5<?define VerBuild = "00" ?> 5<?define VerBuild = "00" ?>
6<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> 6<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
7<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> 7<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>
diff --git a/DOC/Methods.txt b/DOC/Methods.txt
index 3e5707c..cd5fa04 100644
--- a/DOC/Methods.txt
+++ b/DOC/Methods.txt
@@ -137,7 +137,7 @@ List of defined IDs
137 05 - LZ5 137 05 - LZ5
138 06 - LIZARD 138 06 - LIZARD
139 139
140 12 xx - reserverd (Denis Anisimov) 140 12 xx - reserved (Denis Anisimov)
141 141
142 01 - WavPack2 142 01 - WavPack2
143 FE - eSplitter 143 FE - eSplitter
diff --git a/DOC/readme.txt b/DOC/readme.txt
index fd01e3b..dd2171f 100644
--- a/DOC/readme.txt
+++ b/DOC/readme.txt
@@ -1,4 +1,4 @@
17-Zip 26.02 Sources 17-Zip 26.03 Sources
2------------------- 2-------------------
3 3
47-Zip is a file archiver for Windows. 47-Zip is a file archiver for Windows.
@@ -12,7 +12,7 @@ License Info
127-Zip is free software distributed under the GNU LGPL 127-Zip is free software distributed under the GNU LGPL
13(except for unRar code). Also some code 13(except for unRar code). Also some code
14is licensed under the "BSD 3-clause License". 14is licensed under the "BSD 3-clause License".
15Read "License.txt" for more infomation about license. 15Read "License.txt" for more information about license.
16 16
17Notes about unRAR license: 17Notes about unRAR license:
18 18
@@ -111,8 +111,8 @@ Compiling 7-Zip for Unix/Linux
111------------------------------ 111------------------------------
112 112
113There are several options to compile 7-Zip with different compilers: gcc and clang. 113There are several options to compile 7-Zip with different compilers: gcc and clang.
114Also 7-Zip code contains two versions for some parts of code: in C and in Assembeler. 114Also 7-Zip code contains two versions for some parts of code: in C and in Assembler.
115So if you compile the version with Assembeler code, you will get faster 7-Zip binary. 115So if you compile the version with Assembler code, you will get faster 7-Zip binary.
116 116
1177-Zip's assembler code uses the following syntax for different platforms: 1177-Zip's assembler code uses the following syntax for different platforms:
118 118
@@ -144,7 +144,7 @@ Then you can compile `makefile.gcc` with the command:
144 make -j -f makefile.gcc 144 make -j -f makefile.gcc
145 145
146Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile 146Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile
1477-Zip binaries with optimized code and optimzing options. 1477-Zip binaries with optimized code and optimizing options.
148 148
149To compile with GCC without assembler: 149To compile with GCC without assembler:
150 cd CPP/7zip/Bundles/Alone2 150 cd CPP/7zip/Bundles/Alone2
diff --git a/DOC/src-history.txt b/DOC/src-history.txt
index 7858175..717cf91 100644
--- a/DOC/src-history.txt
+++ b/DOC/src-history.txt
@@ -1,9 +1,17 @@
1HISTORY of the 7-Zip source code 1HISTORY of the 7-Zip source code
2-------------------------------- 2--------------------------------
3 3
426.03 2026-09-03
5-------------------------
6- Improved support for Joliet ISO images and Compound archives.
7- Some bugs and vulnerabilities were fixed.
8- CVE-2026-58052 : 7-Zip failed to preserve the Mark-of-the-Web when extracting a crafted archive.
9
10
426.02 2026-06-25 1126.02 2026-06-25
5------------------------- 12-------------------------
6- Some bugs and vulnerabilities were fixed. 13- Some bugs and vulnerabilities were fixed.
14- CVE-2026-14266 : XZ Decompression Heap-based Buffer Overflow Remote Code Execution.
7 15
8 16
926.01 2026-04-27 1726.01 2026-04-27
@@ -19,7 +27,15 @@ HISTORY of the 7-Zip source code
19 to form the final path to the output directory. 27 to form the final path to the output directory.
20 -spor : 7-Zip will replace asterisk (*) character in the path specified in the -o{dir_path} 28 -spor : 7-Zip will replace asterisk (*) character in the path specified in the -o{dir_path}
21 with the archive name. This is the default option. 29 with the archive name. This is the default option.
22- some bugs were fixed. 30- Some bugs and vulnerabilities were fixed.
31- CVE-2026-48092 : A heap memory disclosure via SquashFS fragment offset integer overflow on 32-bit builds.
32- CVE-2026-48095 : A heap buffer overflow in the NTFS archive handler.
33- CVE-2026-48101 : An uninitialized memory disclosure vulnerability in the UEFI archive handler.
34- CVE-2026-48102 : A heap out-of-bounds read in the UDF archive handler.
35- CVE-2026-48103 : A heap out-of-bounds read in the WIM archive handler.
36- CVE-2026-48104 : An uninitialized heap read in the SquashFS archive handler.
37- CVE-2026-48111 : An out-of-bounds read vulnerability UEFI archive handler.
38- CVE-2026-48112 : A heap out-of-bounds read in 7-Zip Ar archive handler.
23 39
24 40
2526.00 2026-02-12 4126.00 2026-02-12
@@ -145,7 +161,7 @@ HISTORY of the 7-Zip source code
145- 7-Zip now can unpack ZIP and SquashFS archives that use ZSTD compression method. 161- 7-Zip now can unpack ZIP and SquashFS archives that use ZSTD compression method.
146- 7-Zip now supports fast hash algorithm XXH64 that is used in ZSTD. 162- 7-Zip now supports fast hash algorithm XXH64 that is used in ZSTD.
147- Speed optimizations for archive unpacking: rar, zip, gz, wim, cab. 163- Speed optimizations for archive unpacking: rar, zip, gz, wim, cab.
148- Speed optimizations for hash caclulation: CRC-32, CRC-64, Blake2sp. 164- Speed optimizations for hash calculation: CRC-32, CRC-64, Blake2sp.
149- The bug was fixed: 7-Zip for Linux could fail for multivolume creation in some cases. 165- The bug was fixed: 7-Zip for Linux could fail for multivolume creation in some cases.
150- Some bugs were fixed. 166- Some bugs were fixed.
151 167
@@ -164,7 +180,7 @@ HISTORY of the 7-Zip source code
164 // virtual ~IUnknown() {} 180 // virtual ~IUnknown() {}
165 So 7-Zip's dynamically linked shared libraries (codecs) are not compatible 181 So 7-Zip's dynamically linked shared libraries (codecs) are not compatible
166 between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip). 182 between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip).
167- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers. 183- Some optimizations in filters code: BCJ, BCJ2, Swap* and others.
168- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp 184- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp
169 files in system's TEMP folder. 7-Zip uses temp file for additional compressed 185 files in system's TEMP folder. 7-Zip uses temp file for additional compressed
170 data stream, if size of such compressed stream is larger than predefined limit: 186 data stream, if size of such compressed stream is larger than predefined limit:
@@ -419,7 +435,7 @@ HISTORY of the 7-Zip source code
4199.09 2009-12-12 4359.09 2009-12-12
420------------------------- 436-------------------------
421- The bug was fixed: 437- The bug was fixed:
422 Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c 438 Utf16_To_Utf8 functions in UTFConvert.cpp and 7zMain.c
423 incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8. 439 incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
424 440
425 441
@@ -457,7 +473,7 @@ HISTORY of the 7-Zip source code
457------------------------- 473-------------------------
458- BUGS was fixed: 474- BUGS was fixed:
459 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases. 475 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases.
460 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties. 476 7zIn.cpp: 7-Zip incorrectly work with archive, containing archive properties.
461 477
4624.58 alpha 9 2008-04-29 4784.58 alpha 9 2008-04-29
463------------------------- 479-------------------------
@@ -513,7 +529,7 @@ HISTORY of the 7-Zip source code
513 - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF. 529 - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF.
514 - ZIP name updating: 530 - ZIP name updating:
515 If zip file contains extra field and you try to change properties of files, 531 If zip file contains extra field and you try to change properties of files,
516 7-zip tries to delete all extra fileds (except for WzAES). 532 7-zip tries to delete all extra fields (except for WzAES).
517 And that code could hang. 533 And that code could hang.
518 - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run. 534 - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run.
519 - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp 535 - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp
@@ -581,7 +597,7 @@ HISTORY of the 7-Zip source code
581 data++ 597 data++
582 fixed version: 598 fixed version:
583 data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1; 599 data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
584 It could lead to very small cpmpression ratio decreasing when block needs move. 600 It could lead to very small compression ratio decreasing when block needs move.
585 601
586 602
5874.30 beta 2005-11-18 6034.30 beta 2005-11-18
@@ -606,7 +622,7 @@ HISTORY of the 7-Zip source code
606 622
6074.25 beta 2005-07-31 6234.25 beta 2005-07-31
608------------------------- 624-------------------------
609- More 64-bit compatibilty 625- More 64-bit compatibility
610 626
611 627
6124.24 beta 2005-07-06 6284.24 beta 2005-07-06
@@ -628,7 +644,7 @@ HISTORY of the 7-Zip source code
6284.14 beta 2005-01-11 6444.14 beta 2005-01-11
629------------------------- 645-------------------------
630- STL using was reduced 646- STL using was reduced
631- 7za now supports Split(001) archves 647- 7za now supports Split(001) archives
632 648
633 649
6344.10 beta 2004-10-21 6504.10 beta 2004-10-21
@@ -746,7 +762,7 @@ HISTORY of the 7-Zip source code
746- SDK/Stream/WindowOut.h 762- SDK/Stream/WindowOut.h
747 now it uses only required memory (dictionary size). 763 now it uses only required memory (dictionary size).
748- Project/Archiver/Resource 764- Project/Archiver/Resource
749 contains common resurces 765 contains common resources
750 766
751 767
7522.30 Beta 19 2002-04-11 7682.30 Beta 19 2002-04-11
@@ -766,7 +782,7 @@ HISTORY of the 7-Zip source code
766 782
7672.30 Beta 17 2002-03-03 7832.30 Beta 17 2002-03-03
768------------------------- 784-------------------------
769- ARJ suppport. 785- ARJ support.
770 786
771 787
7722.30 Beta 16 2002-02-24 7882.30 Beta 16 2002-02-24
@@ -824,14 +840,14 @@ HISTORY of the 7-Zip source code
824 Compress/LZ/MatchFinder/Patricia.h: 840 Compress/LZ/MatchFinder/Patricia.h:
825 Compress/PPM/PPMd/SubAlloc.h: 841 Compress/PPM/PPMd/SubAlloc.h:
826 using VirtualAlloc for memory allocating 842 using VirtualAlloc for memory allocating
827- Exlorer/ContextMenu.cpp: 843- Explorer/ContextMenu.cpp:
828 Testing supporting. 844 Testing supporting.
829 CreateProcess instead WinExec 845 CreateProcess instead WinExec
830- Format/Common/IArchiveHandler.h: 846- Format/Common/IArchiveHandler.h:
831 Exlorer/ProxyHandler.cpp: 847 Explorer/ProxyHandler.cpp:
832 FAR/Plugin.cpp: 848 FAR/Plugin.cpp:
833 New properties names: Method, HostOS. 849 New properties names: Method, HostOS.
834- Exlorer/OverwriteDialog.cpp: 850- Explorer/OverwriteDialog.cpp:
835 FAR/OverwriteDialog.cpp: 851 FAR/OverwriteDialog.cpp:
836 Windows/PropVariantConversions.h 852 Windows/PropVariantConversions.h
837 Using National time format was eliminated. 853 Using National time format was eliminated.
@@ -840,16 +856,16 @@ HISTORY of the 7-Zip source code
840 856
8412.30 Beta 10 2002-01-11 8572.30 Beta 10 2002-01-11
842------------------------- 858-------------------------
843- Exlorer/ContextMenu.cpp: bug with context menu on 859- Explorer/ContextMenu.cpp: bug with context menu on
844 Windows NT4 in Unicode version was fixed. 860 Windows NT4 in Unicode version was fixed.
845- Format/7z/UpdateArchiveEngine.cpp: bug was fixed - 861- Format/7z/UpdateArchiveEngine.cpp: bug was fixed -
846 Updating in Beta 8 and 9 didn't work. 862 Updating in Beta 8 and 9 didn't work.
847- Exlorer/CCompressDialog.cpp: history growing bug was fixed. 863- Explorer/CCompressDialog.cpp: history growing bug was fixed.
848 864
849 865
8502.30 Beta 9 2002-01-08 8662.30 Beta 9 2002-01-08
851------------------------- 867-------------------------
852- SDK/Common/Vector.h: sopporting sorted object vectors . 868- SDK/Common/Vector.h: supporting sorted object vectors .
853- Lang features. 869- Lang features.
854- Two new match finders: pat3h and pat4h. 870- Two new match finders: pat3h and pat4h.
855- SDK/Archive/Zip/InEngine.cpp: bug was fixed. 871- SDK/Archive/Zip/InEngine.cpp: bug was fixed.