aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--C/7zVersion.h10
-rw-r--r--C/7zWindows.h10
-rw-r--r--C/7zip_gcc_c.mak2
-rw-r--r--C/CpuArch.c4
-rw-r--r--C/CpuArch.h19
-rw-r--r--C/HuffEnc.c9
-rw-r--r--C/HuffEnc.h2
-rw-r--r--C/Xxh64.c98
-rw-r--r--CPP/7zip/7zip_gcc.mak4
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.cpp2
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp1324
-rw-r--r--CPP/7zip/Archive/CpioHandler.cpp2
-rw-r--r--CPP/7zip/Archive/QcowHandler.cpp5
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp11
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp22
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.cpp35
-rw-r--r--CPP/7zip/Archive/Tar/TarIn.cpp147
-rw-r--r--CPP/7zip/Archive/Tar/TarItem.h1
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.cpp18
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.h7
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp90
-rw-r--r--CPP/7zip/Archive/Zip/ZipOut.cpp44
-rw-r--r--CPP/7zip/Bundles/SFXCon/SfxCon.cpp2
-rw-r--r--CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp50
-rw-r--r--CPP/7zip/Common/FileStreams.cpp2
-rw-r--r--CPP/7zip/Common/FileStreams.h4
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp2
-rw-r--r--CPP/7zip/UI/Common/ArchiveName.cpp4
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp9
-rw-r--r--CPP/7zip/UI/Console/List.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/BrowseDialog2.cpp94
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.cpp8
-rw-r--r--CPP/7zip/UI/FileManager/LangPage.cpp3
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage.cpp3
-rw-r--r--CPP/7zip/UI/FileManager/PanelItemOpen.cpp25
-rw-r--r--CPP/7zip/UI/FileManager/PanelMenu.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/PanelSort.cpp55
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.cpp55
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp129
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.rc4
-rw-r--r--CPP/7zip/UI/GUI/ExtractDialog.cpp3
-rw-r--r--CPP/Common/Common0.h5
-rw-r--r--CPP/Common/MyBuffer.h48
-rw-r--r--CPP/Windows/Control/ComboBox.cpp9
-rw-r--r--CPP/Windows/Control/ComboBox.h2
-rw-r--r--CPP/Windows/FileFind.cpp13
-rw-r--r--CPP/Windows/FileFind.h6
-rw-r--r--CPP/Windows/SecurityUtils.h4
-rw-r--r--CPP/Windows/System.cpp10
-rw-r--r--CPP/Windows/System.h23
-rw-r--r--CPP/Windows/SystemInfo.cpp4
-rw-r--r--CPP/Windows/TimeUtils.h8
-rw-r--r--DOC/7zip.wxs4
-rw-r--r--DOC/License.txt6
-rw-r--r--DOC/readme.txt50
-rw-r--r--DOC/src-history.txt182
56 files changed, 1740 insertions, 960 deletions
diff --git a/C/7zVersion.h b/C/7zVersion.h
index b6142e9..770370a 100644
--- a/C/7zVersion.h
+++ b/C/7zVersion.h
@@ -1,7 +1,7 @@
1#define MY_VER_MAJOR 25 1#define MY_VER_MAJOR 26
2#define MY_VER_MINOR 1 2#define MY_VER_MINOR 0
3#define MY_VER_BUILD 0 3#define MY_VER_BUILD 0
4#define MY_VERSION_NUMBERS "25.01" 4#define MY_VERSION_NUMBERS "26.00"
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,12 +10,12 @@
10 #define MY_VERSION_CPU MY_VERSION 10 #define MY_VERSION_CPU MY_VERSION
11#endif 11#endif
12 12
13#define MY_DATE "2025-08-03" 13#define MY_DATE "2026-02-12"
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"
17#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" 17#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
18#define MY_COPYRIGHT_CR "Copyright (c) 1999-2025 Igor Pavlov" 18#define MY_COPYRIGHT_CR "Copyright (c) 1999-2026 Igor Pavlov"
19 19
20#ifdef USE_COPYRIGHT_CR 20#ifdef USE_COPYRIGHT_CR
21 #define MY_COPYRIGHT MY_COPYRIGHT_CR 21 #define MY_COPYRIGHT MY_COPYRIGHT_CR
diff --git a/C/7zWindows.h b/C/7zWindows.h
index 42c6db8..381159e 100644
--- a/C/7zWindows.h
+++ b/C/7zWindows.h
@@ -1,11 +1,17 @@
1/* 7zWindows.h -- StdAfx 1/* 7zWindows.h -- Windows.h and related code
22023-04-02 : Igor Pavlov : Public domain */ 2Igor Pavlov : Public domain */
3 3
4#ifndef ZIP7_INC_7Z_WINDOWS_H 4#ifndef ZIP7_INC_7Z_WINDOWS_H
5#define ZIP7_INC_7Z_WINDOWS_H 5#define ZIP7_INC_7Z_WINDOWS_H
6 6
7#ifdef _WIN32 7#ifdef _WIN32
8 8
9#if defined(_MSC_VER) && _MSC_VER >= 1950 && !defined(__clang__) // VS2026
10// <Windows.h> and some another windows files need that option
11// VS2026: wtypesbase.h: warning C4865: 'tagCLSCTX': the underlying type will change from 'int' to 'unsigned int' when '/Zc:enumTypes' is specified on the command line
12#pragma warning(disable : 4865)
13#endif
14
9#if defined(__clang__) 15#if defined(__clang__)
10# pragma clang diagnostic push 16# pragma clang diagnostic push
11#endif 17#endif
diff --git a/C/7zip_gcc_c.mak b/C/7zip_gcc_c.mak
index 195d23d..006cfe0 100644
--- a/C/7zip_gcc_c.mak
+++ b/C/7zip_gcc_c.mak
@@ -106,7 +106,7 @@ DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
106endif 106endif
107 107
108 108
109LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32 -lShell32 109LIB2 = -lole32 -loleaut32 -luuid -ladvapi32 -luser32 -lshell32
110 110
111CFLAGS_EXTRA = -DUNICODE -D_UNICODE 111CFLAGS_EXTRA = -DUNICODE -D_UNICODE
112# -Wno-delete-non-virtual-dtor 112# -Wno-delete-non-virtual-dtor
diff --git a/C/CpuArch.c b/C/CpuArch.c
index 6e02551..342280d 100644
--- a/C/CpuArch.c
+++ b/C/CpuArch.c
@@ -859,7 +859,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
859 859
860#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216) 860#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216)
861 #define Z7_GETAUXV_AVAILABLE 861 #define Z7_GETAUXV_AVAILABLE
862#else 862#elif !defined(__QNXNTO__)
863// #pragma message("=== is not NEW GLIBC === ") 863// #pragma message("=== is not NEW GLIBC === ")
864 #if defined __has_include 864 #if defined __has_include
865 #if __has_include (<sys/auxv.h>) 865 #if __has_include (<sys/auxv.h>)
@@ -877,7 +877,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
877 877
878#ifdef USE_HWCAP 878#ifdef USE_HWCAP
879 879
880#if defined(__FreeBSD__) 880#if defined(__FreeBSD__) || defined(__OpenBSD__)
881static unsigned long MY_getauxval(int aux) 881static unsigned long MY_getauxval(int aux)
882{ 882{
883 unsigned long val; 883 unsigned long val;
diff --git a/C/CpuArch.h b/C/CpuArch.h
index 1690a5b..c682720 100644
--- a/C/CpuArch.h
+++ b/C/CpuArch.h
@@ -31,7 +31,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
31 #define MY_CPU_NAME "x32" 31 #define MY_CPU_NAME "x32"
32 #define MY_CPU_SIZEOF_POINTER 4 32 #define MY_CPU_SIZEOF_POINTER 4
33 #else 33 #else
34 #define MY_CPU_NAME "x64" 34 #if defined(__APX_EGPR__) || defined(__EGPR__)
35 #define MY_CPU_NAME "x64-apx"
36 #define MY_CPU_AMD64_APX
37 #else
38 #define MY_CPU_NAME "x64"
39 #endif
35 #define MY_CPU_SIZEOF_POINTER 8 40 #define MY_CPU_SIZEOF_POINTER 8
36 #endif 41 #endif
37 #define MY_CPU_64BIT 42 #define MY_CPU_64BIT
@@ -596,8 +601,20 @@ problem-4 : performace:
596#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); } 601#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
597#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); } 602#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
598 603
604// gcc and clang for powerpc can transform load byte access to load reverse word access.
605// sp we can use byte access instead of word access. Z7_BSWAP64 cab be slow
606#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_64BIT)
607#define GetUi64a(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p))
608#else
599#define GetUi64a(p) GetUi64(p) 609#define GetUi64a(p) GetUi64(p)
610#endif
611
612#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
613#define GetUi32a(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p))
614#else
600#define GetUi32a(p) GetUi32(p) 615#define GetUi32a(p) GetUi32(p)
616#endif
617
601#define GetUi16a(p) GetUi16(p) 618#define GetUi16a(p) GetUi16(p)
602#define SetUi32a(p, v) SetUi32(p, v) 619#define SetUi32a(p, v) SetUi32(p, v)
603#define SetUi16a(p, v) SetUi16(p, v) 620#define SetUi16a(p, v) SetUi16(p, v)
diff --git a/C/HuffEnc.c b/C/HuffEnc.c
index cbf8c22..297b41a 100644
--- a/C/HuffEnc.c
+++ b/C/HuffEnc.c
@@ -13,7 +13,7 @@ Igor Pavlov : Public domain */
13#define NUM_BITS 10 13#define NUM_BITS 10
14#define MASK ((1u << NUM_BITS) - 1) 14#define MASK ((1u << NUM_BITS) - 1)
15#define FREQ_MASK (~(UInt32)MASK) 15#define FREQ_MASK (~(UInt32)MASK)
16#define NUM_COUNTERS (48 * 2) 16#define NUM_COUNTERS (104 * 2) // (80 * 2) or (128 * 2) : ((prime_number + 1) * 2) for smaller code.
17 17
18#if 1 && (defined(MY_CPU_LE) || defined(MY_CPU_BE)) 18#if 1 && (defined(MY_CPU_LE) || defined(MY_CPU_BE))
19#if defined(MY_CPU_LE) 19#if defined(MY_CPU_LE)
@@ -95,9 +95,10 @@ void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, unsigned numSy
95 counters[1] = 0; 95 counters[1] = 0;
96 for (i = 2; i != NUM_COUNTERS; i += 2) 96 for (i = 2; i != NUM_COUNTERS; i += 2)
97 { 97 {
98 unsigned c; 98 const unsigned c0 = (counters )[i];
99 c = (counters )[i]; (counters )[i] = num; num += c; 99 const unsigned c1 = (counters + 1)[i];
100 c = (counters + 1)[i]; (counters + 1)[i] = num; num += c; 100 (counters )[i] = num; num += c0;
101 (counters + 1)[i] = num; num += c1;
101 } 102 }
102 counters[0] = num; // we want to write (freq==0) symbols to the end of (p) array 103 counters[0] = num; // we want to write (freq==0) symbols to the end of (p) array
103 { 104 {
diff --git a/C/HuffEnc.h b/C/HuffEnc.h
index 2217f55..45567d0 100644
--- a/C/HuffEnc.h
+++ b/C/HuffEnc.h
@@ -16,7 +16,7 @@ Conditions:
16 1 <= maxLen <= 16 = Z7_HUFFMAN_LEN_MAX 16 1 <= maxLen <= 16 = Z7_HUFFMAN_LEN_MAX
17 Num_Items(p) >= HUFFMAN_TEMP_SIZE(num) 17 Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
18*/ 18*/
19void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen); 19void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, unsigned num, unsigned maxLen);
20 20
21EXTERN_C_END 21EXTERN_C_END
22 22
diff --git a/C/Xxh64.c b/C/Xxh64.c
index dc02a02..660e0be 100644
--- a/C/Xxh64.c
+++ b/C/Xxh64.c
@@ -1,6 +1,6 @@
1/* Xxh64.c -- XXH64 hash calculation 1/* Xxh64.c -- XXH64 hash calculation
2original code: Copyright (c) Yann Collet. 2original code: Copyright (c) Yann Collet.
32023-08-18 : modified by Igor Pavlov. 3modified by Igor Pavlov.
4This source code is licensed under BSD 2-Clause License. 4This source code is licensed under BSD 2-Clause License.
5*/ 5*/
6 6
@@ -27,6 +27,14 @@ void Xxh64State_Init(CXxh64State *p)
27 27
28#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) && defined(_MSC_VER) 28#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) && defined(_MSC_VER)
29 #define Z7_XXH64_USE_ASM 29 #define Z7_XXH64_USE_ASM
30#elif !defined(MY_CPU_LE_UNALIGN_64) // && defined (MY_CPU_LE)
31 #define Z7_XXH64_USE_ALIGNED
32#endif
33
34#ifdef Z7_XXH64_USE_ALIGNED
35 #define Xxh64State_UpdateBlocks_Unaligned_Select Xxh64State_UpdateBlocks_Unaligned
36#else
37 #define Xxh64State_UpdateBlocks_Unaligned_Select Xxh64State_UpdateBlocks
30#endif 38#endif
31 39
32#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) \ 40#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) \
@@ -188,32 +196,76 @@ Xxh64State_UpdateBlocks(CXxh64State *p, const void *data, const void *end)
188 196
189#else 197#else
190 198
199#ifdef Z7_XXH64_USE_ALIGNED
200static
201#endif
191void 202void
192Z7_NO_INLINE 203Z7_NO_INLINE
193Z7_FASTCALL 204Z7_FASTCALL
194Xxh64State_UpdateBlocks(CXxh64State *p, const void *_data, const void *end) 205Xxh64State_UpdateBlocks_Unaligned_Select(CXxh64State *p, const void *_data, const void *end)
195{ 206{
196 const Byte *data = (const Byte *)_data; 207 const Byte *data = (const Byte *)_data;
197 UInt64 v[4]; 208 UInt64 v0, v1, v2, v3;
198 v[0] = p->v[0]; 209 v0 = p->v[0];
199 v[1] = p->v[1]; 210 v1 = p->v[1];
200 v[2] = p->v[2]; 211 v2 = p->v[2];
201 v[3] = p->v[3]; 212 v3 = p->v[3];
202 do 213 do
203 { 214 {
204 v[0] = Xxh64_Round(v[0], GetUi64(data)); data += 8; 215 v0 = Xxh64_Round(v0, GetUi64(data)); data += 8;
205 v[1] = Xxh64_Round(v[1], GetUi64(data)); data += 8; 216 v1 = Xxh64_Round(v1, GetUi64(data)); data += 8;
206 v[2] = Xxh64_Round(v[2], GetUi64(data)); data += 8; 217 v2 = Xxh64_Round(v2, GetUi64(data)); data += 8;
207 v[3] = Xxh64_Round(v[3], GetUi64(data)); data += 8; 218 v3 = Xxh64_Round(v3, GetUi64(data)); data += 8;
208 } 219 }
209 while (data != end); 220 while (data != end);
210 p->v[0] = v[0]; 221 p->v[0] = v0;
211 p->v[1] = v[1]; 222 p->v[1] = v1;
212 p->v[2] = v[2]; 223 p->v[2] = v2;
213 p->v[3] = v[3]; 224 p->v[3] = v3;
214} 225}
215 226
216#endif 227
228#ifdef Z7_XXH64_USE_ALIGNED
229
230static
231void
232Z7_NO_INLINE
233Z7_FASTCALL
234Xxh64State_UpdateBlocks_Aligned(CXxh64State *p, const void *_data, const void *end)
235{
236 const Byte *data = (const Byte *)_data;
237 UInt64 v0, v1, v2, v3;
238 v0 = p->v[0];
239 v1 = p->v[1];
240 v2 = p->v[2];
241 v3 = p->v[3];
242 do
243 {
244 v0 = Xxh64_Round(v0, GetUi64a(data)); data += 8;
245 v1 = Xxh64_Round(v1, GetUi64a(data)); data += 8;
246 v2 = Xxh64_Round(v2, GetUi64a(data)); data += 8;
247 v3 = Xxh64_Round(v3, GetUi64a(data)); data += 8;
248 }
249 while (data != end);
250 p->v[0] = v0;
251 p->v[1] = v1;
252 p->v[2] = v2;
253 p->v[3] = v3;
254}
255
256void
257Z7_NO_INLINE
258Z7_FASTCALL
259Xxh64State_UpdateBlocks(CXxh64State *p, const void *data, const void *end)
260{
261 if (((unsigned)(ptrdiff_t)data & 7) == 0)
262 Xxh64State_UpdateBlocks_Aligned(p, data, end);
263 else
264 Xxh64State_UpdateBlocks_Unaligned(p, data, end);
265}
266
267#endif // Z7_XXH64_USE_ALIGNED
268#endif // Z7_XXH64_USE_ASM
217 269
218UInt64 Xxh64State_Digest(const CXxh64State *p, const void *_data, UInt64 count) 270UInt64 Xxh64State_Digest(const CXxh64State *p, const void *_data, UInt64 count)
219{ 271{
@@ -306,12 +358,22 @@ void Xxh64_Update(CXxh64 *p, const void *_data, size_t size)
306 while (--rem); 358 while (--rem);
307 if (cnt != 32) 359 if (cnt != 32)
308 return; 360 return;
309 Xxh64State_UpdateBlocks(&p->state, p->buf64, &p->buf64[4]); 361#ifdef Z7_XXH64_USE_ALIGNED
362 Xxh64State_UpdateBlocks_Aligned
363#else
364 Xxh64State_UpdateBlocks_Unaligned_Select
365#endif
366 (&p->state, p->buf64, &p->buf64[4]);
310 } 367 }
311 368
312 if (size &= ~(size_t)31) 369 if (size &= ~(size_t)31)
313 { 370 {
314 Xxh64State_UpdateBlocks(&p->state, data, data + size); 371#ifdef Z7_XXH64_USE_ALIGNED
372 if (((unsigned)(ptrdiff_t)data & 7) == 0)
373 Xxh64State_UpdateBlocks_Aligned(&p->state, data, data + size);
374 else
375#endif
376 Xxh64State_UpdateBlocks_Unaligned_Select(&p->state, data, data + size);
315 data += size; 377 data += size;
316 } 378 }
317 379
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
index 12f1ef2..a78c0fa 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -142,8 +142,8 @@ MY_MKDIR=mkdir
142DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll 142DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
143endif 143endif
144 144
145LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 -lShell32 $(LIB_HTMLHELP) 145LIB2_GUI = -lole32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 $(LIB_HTMLHELP)
146LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) 146LIB2 = -loleaut32 -luuid -ladvapi32 -luser32 $(LIB2_GUI)
147 147
148# v24.00: -DUNICODE and -D_UNICODE are defined in precompilation header files 148# v24.00: -DUNICODE and -D_UNICODE are defined in precompilation header files
149# CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE 149# CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE
diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp
index c8c5d26..6ba04a2 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.cpp
+++ b/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -721,7 +721,7 @@ static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param
721 return (u1.IsDir && u1.IsAnti) ? -n : n; 721 return (u1.IsDir && u1.IsAnti) ? -n : n;
722} 722}
723 723
724static const char *g_Exts = 724static const char * const g_Exts =
725 " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo" 725 " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo"
726 " zip jar ear war msi" 726 " zip jar ear war msi"
727 " 3gp avi mov mpeg mpg mpe wmv" 727 " 3gp avi mov mpeg mpg mpe wmv"
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
index 144369e..40a5349 100644
--- a/CPP/7zip/Archive/ComHandler.cpp
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -2,41 +2,62 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#include "../../../C/Alloc.h"
6#include "../../../C/CpuArch.h" 5#include "../../../C/CpuArch.h"
7 6
8#include "../../Common/IntToString.h"
9#include "../../Common/ComTry.h" 7#include "../../Common/ComTry.h"
10#include "../../Common/MyCom.h"
11#include "../../Common/MyBuffer.h"
12#include "../../Common/MyString.h"
13 8
14#include "../../Windows/PropVariant.h" 9#include "../../Windows/PropVariant.h"
15 10
16#include "../Common/LimitedStreams.h" 11#include "../Common/LimitedStreams.h"
17#include "../Common/ProgressUtils.h" 12#include "../Common/ProgressUtils.h"
18#include "../Common/RegisterArc.h" 13#include "../Common/RegisterArc.h"
14#include "../Common/StreamObjects.h"
19#include "../Common/StreamUtils.h" 15#include "../Common/StreamUtils.h"
20 16
21#include "../Compress/CopyCoder.h" 17#include "../Compress/CopyCoder.h"
22 18
23#define Get16(p) GetUi16(p) 19#include "Common/ItemNameUtils.h"
24#define Get32(p) GetUi32(p) 20
21#define Get16(p) GetUi16a(p)
22#define Get32(p) GetUi32a(p)
23
24// we don't expect to get deleted files in real files
25// define Z7_COMPOUND_SHOW_DELETED for debug
26// #define Z7_COMPOUND_SHOW_DELETED
25 27
26namespace NArchive { 28namespace NArchive {
27namespace NCom { 29namespace NCom {
28 30
31static const unsigned k_Long_path_level_limit = 256;
32
29static const Byte kSignature[] = 33static const Byte kSignature[] =
30 { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; 34 { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
35
36// encoded "[!]MsiPatchSequence" name in "msp" file
37static const Byte k_Sequence_msp[] =
38 { 0x40, 0x48, 0x96, 0x45, 0x6c, 0x3e, 0xe4, 0x45,
39 0xe6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41,
40 0x37, 0x41, 0, 0 };
41
42// encoded "MergeModule.CABinet" name in "msm" file
43static const Byte k_Sequence_msm[] =
44 { 0x16, 0x42, 0xb5, 0x42, 0xa8, 0x3d, 0xf2, 0x41,
45 0xf8, 0x43, 0xa8, 0x47, 0x8c, 0x3a, 0x0b, 0x43,
46 0x31, 0x42, 0x37, 0x48, 0, 0 };
47
48// static const Byte k_CLSID_AAF_V3[] = { 0x41, 0x41, 0x46, 0x42, 0x0d, 0x00, 0x4f, 0x4d, 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0xff };
49// static const Byte k_CLSID_AAF_V4[] = { 0x01, 0x02, 0x01, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x06, 0x0e, 0x2b, 0x34, 0x03, 0x02, 0x01, 0x01 };
31 50
32enum EType 51enum EArcType
33{ 52{
34 k_Type_Common, 53 k_Type_Common,
35 k_Type_Msi, 54 k_Type_Msi,
36 k_Type_Msp, 55 k_Type_Msp,
56 k_Type_Msm,
37 k_Type_Doc, 57 k_Type_Doc,
38 k_Type_Ppt, 58 k_Type_Ppt,
39 k_Type_Xls 59 k_Type_Xls,
60 k_Type_Aaf
40}; 61};
41 62
42static const char * const kExtensions[] = 63static const char * const kExtensions[] =
@@ -44,35 +65,63 @@ static const char * const kExtensions[] =
44 "compound" 65 "compound"
45 , "msi" 66 , "msi"
46 , "msp" 67 , "msp"
68 , "msm"
47 , "doc" 69 , "doc"
48 , "ppt" 70 , "ppt"
49 , "xls" 71 , "xls"
72 , "aaf"
50}; 73};
51 74
52namespace NFatID 75namespace NFatID
53{ 76{
54 // static const UInt32 kFree = 0xFFFFFFFF; 77 static const UInt32 kFree = 0xffffffff;
55 static const UInt32 kEndOfChain = 0xFFFFFFFE; 78 static const UInt32 kEndOfChain = 0xfffffffe;
56 // static const UInt32 kFatSector = 0xFFFFFFFD; 79 static const UInt32 kFatSector = 0xfffffffd;
57 // static const UInt32 kMatSector = 0xFFFFFFFC; 80 static const UInt32 k_DIF_SECT = 0xfffffffc; // double-indirect file allocation table (DIFAT)
58 static const UInt32 kMaxValue = 0xFFFFFFFA; 81 static const UInt32 kMaxValue = 0xfffffffa;
59} 82}
60 83
61namespace NItemType 84namespace NItemType
62{ 85{
63 static const Byte kEmpty = 0; 86 static const unsigned kEmpty = 0;
64 static const Byte kStorage = 1; 87 static const unsigned kStorage = 1;
65 // static const Byte kStream = 2; 88 static const unsigned kStream = 2;
66 // static const Byte kLockBytes = 3; 89 // static const unsigned kLockBytes = 3;
67 // static const Byte kProperty = 4; 90 // static const unsigned kProperty = 4;
68 static const Byte kRootStorage = 5; 91 static const unsigned kRootStorage = 5;
92}
93
94static const unsigned k_MiniSectorSizeBits = 6;
95static const UInt32 k_LongStreamMinSize = 1 << 12;
96
97static const unsigned k_Msi_NumBits = 6;
98static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits;
99static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1;
100static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1);
101static const unsigned k_Msi_StartUnicodeChar = 0x3800;
102static const unsigned k_Msi_SpecUnicodeChar = k_Msi_StartUnicodeChar + k_Msi_UnicodeRange;
103// (k_Msi_SpecUnicodeChar == 0x4840) is used as special symbol that is used
104// as first character in some names in dir entries
105/*
106static bool IsMsiName(const Byte *p)
107{
108 unsigned c = Get16(p);
109 c -= k_Msi_StartUnicodeChar;
110 return c <= k_Msi_UnicodeRange;
111}
112*/
113
114Z7_FORCE_INLINE static bool IsLargeStream(UInt64 size)
115{
116 return size >= k_LongStreamMinSize;
69} 117}
70 118
71static const unsigned kNameSizeMax = 64; 119static const unsigned kNameSizeMax = 64;
120static const UInt32 k_Item_Level_Unused = (UInt32)0 - 1;
72 121
73struct CItem 122struct CItem
74{ 123{
75 Byte Name[kNameSizeMax]; 124 Byte Name[kNameSizeMax]; // must be aligned for 2-bytes
76 // UInt16 NameSize; 125 // UInt16 NameSize;
77 // UInt32 Flags; 126 // UInt32 Flags;
78 FILETIME CTime; 127 FILETIME CTime;
@@ -82,484 +131,792 @@ struct CItem
82 UInt32 RightDid; 131 UInt32 RightDid;
83 UInt32 SonDid; 132 UInt32 SonDid;
84 UInt32 Sid; 133 UInt32 Sid;
85 Byte Type; 134 unsigned Type; // Byte : we use unsigned instead of Byte for alignment
135
136 UInt32 Level;
86 137
87 bool IsEmpty() const { return Type == NItemType::kEmpty; } 138 bool IsEmptyType() const { return Type == NItemType::kEmpty; }
88 bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; } 139 bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
140 bool IsStorage() const { return Type == NItemType::kStorage; }
141
142 bool IsLevel_Unused() const { return Level == k_Item_Level_Unused; }
89 143
90 void Parse(const Byte *p, bool mode64bit); 144 // bool IsSpecMsiName() const { return Get16(Name) == k_Msi_SpecUnicodeChar; }
145 bool AreMsiChars() const
146 {
147 for (unsigned i = 0; i < kNameSizeMax; i += 2)
148 {
149 unsigned c = Get16(Name + i);
150 if (c == 0)
151 break;
152 c -= k_Msi_StartUnicodeChar;
153 if (c <= k_Msi_UnicodeRange)
154 return true;
155 }
156 return false;
157 }
158 bool Parse(const Byte *p, bool mode64bit);
91}; 159};
92 160
161
162static const UInt32 k_Ref_Parent_Root = 0xffffffff;
163
93struct CRef 164struct CRef
94{ 165{
95 int Parent; 166 UInt32 Parent; // index in Refs[]
96 UInt32 Did; 167 UInt32 Did; // index in Items[]
97}; 168};
98 169
170
99class CDatabase 171class CDatabase
100{ 172{
101 CObjArray<UInt32> MiniSids;
102
103 HRESULT AddNode(int parent, UInt32 did);
104
105public: 173public:
174 CRecordVector<CRef> Refs;
175 CObjectVector<CItem> Items;
106 CObjArray<UInt32> Fat; 176 CObjArray<UInt32> Fat;
107 CObjArray<UInt32> Mat; 177 CObjArray<UInt32> Mat;
108 CObjectVector<CItem> Items; 178 CObjArray<UInt32> MiniSids;
109 CRecordVector<CRef> Refs; 179
110private:
111 UInt32 NumSectorsInMiniStream;
112public:
113 UInt32 MatSize;
114 UInt32 FatSize; 180 UInt32 FatSize;
181 UInt32 MatSize;
182 UInt32 NumSectors_in_MiniStream;
115 183
116 UInt32 LongStreamMinSize; 184 // UInt32 LongStreamMinSize;
117 unsigned SectorSizeBits; 185 unsigned SectorSizeBits;
118 unsigned MiniSectorSizeBits;
119 186
120 Int32 MainSubfile; 187 Int32 MainSubfile;
121 EType Type; 188 EArcType Type;
189
190 bool IsArc;
191 bool HeadersError;
192 // bool IsMsi;
122 193
123 UInt64 PhySize; 194 UInt64 PhySize;
124 UInt64 PhySize_Aligned; 195 UInt64 PhySize_Unaligned;
196 // UInt64 FreeSize;
125 197
126 bool IsNotArcType() const 198 IArchiveOpenCallback *OpenCallback;
199 UInt32 Callback_Cur;
200
201private:
202 /*
203 HRESULT IncreaseOpenTotal(UInt32 numSects)
127 { 204 {
128 return 205 if (!OpenCallback)
129 Type != k_Type_Msi && 206 return S_OK;
130 Type != k_Type_Msp; 207 const UInt64 total = (UInt64)(Callback_Cur + numSects) << SectorSizeBits;
208 return OpenCallback->SetTotal(NULL, &total);
131 } 209 }
210 */
211 HRESULT AddNodes();
212 HRESULT ReadSector(IInStream *inStream, Byte *buf, UInt32 sid);
213 HRESULT ReadIDs(IInStream *inStream, Byte *buf, UInt32 sid, UInt32 *dest);
214 HRESULT Check_Item(unsigned index);
132 215
133 void UpdatePhySize(UInt64 val, UInt64 val_Aligned) 216public:
217 bool IsNotArcType() const
134 { 218 {
135 if (PhySize < val) 219 return
136 PhySize = val; 220 Type != k_Type_Msi &&
137 if (PhySize_Aligned < val_Aligned) 221 Type != k_Type_Msp &&
138 PhySize_Aligned = val_Aligned; 222 Type != k_Type_Msm;
139 } 223 }
140 HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid);
141 HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest);
142
143 HRESULT Update_PhySize_WithItem(unsigned index);
144 224
145 void Clear(); 225 void Clear();
146 bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
147 UString GetItemPath(UInt32 index) const; 226 UString GetItemPath(UInt32 index) const;
148 227
149 UInt64 GetItemPackSize(UInt64 size) const 228 UInt64 GetItemPackSize(UInt64 size) const
150 { 229 {
151 const UInt64 mask = ((UInt32)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; 230 const UInt64 mask = ((UInt32)1 << (IsLargeStream(size) ? SectorSizeBits : k_MiniSectorSizeBits)) - 1;
152 return (size + mask) & ~mask; 231 return (size + mask) & ~(UInt64)mask;
153 }
154
155 bool GetMiniCluster(UInt32 sid, UInt64 &res) const
156 {
157 const unsigned subBits = SectorSizeBits - MiniSectorSizeBits;
158 const UInt32 fid = sid >> subBits;
159 if (fid >= NumSectorsInMiniStream)
160 return false;
161 res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
162 return true;
163 } 232 }
164 233
165 HRESULT Open(IInStream *inStream); 234 HRESULT Open(IInStream *inStream);
166}; 235};
167 236
168 237
169HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid) 238HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, UInt32 sid)
170{ 239{
171 const UInt64 end = ((UInt64)sid + 2) << sectorSizeBits; 240 const unsigned sb = SectorSizeBits;
172 UpdatePhySize(end, end); 241 RINOK(InStream_SeekSet(inStream, ((UInt64)sid + 1) << sb))
173 RINOK(InStream_SeekSet(inStream, (((UInt64)sid + 1) << sectorSizeBits))) 242 RINOK(ReadStream_FALSE(inStream, buf, (size_t)1 << sb))
174 return ReadStream_FALSE(inStream, buf, (size_t)1 << sectorSizeBits); 243 if (OpenCallback)
244 {
245 if ((++Callback_Cur & 0xfff) == 0)
246 {
247 const UInt64 processed = (UInt64)Callback_Cur << sb;
248 const UInt64 numFiles = Items.Size();
249 RINOK(OpenCallback->SetCompleted(&numFiles, &processed))
250 }
251 }
252 return S_OK;
175} 253}
176 254
177HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) 255HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, UInt32 sid, UInt32 *dest)
178{ 256{
179 RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)) 257 RINOK(ReadSector(inStream, buf, sid))
180 const UInt32 sectorSize = (UInt32)1 << sectorSizeBits; 258 const size_t sectorSize = (size_t)1 << SectorSizeBits;
181 for (UInt32 t = 0; t < sectorSize; t += 4) 259 for (size_t t = 0; t < sectorSize; t += 4)
182 *dest++ = Get32(buf + t); 260 *dest++ = Get32(buf + t);
183 return S_OK; 261 return S_OK;
184} 262}
185 263
264
265Z7_FORCE_INLINE
186static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) 266static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
187{ 267{
188 ft->dwLowDateTime = Get32(p); 268 ft->dwLowDateTime = Get32(p);
189 ft->dwHighDateTime = Get32(p + 4); 269 ft->dwHighDateTime = Get32(p + 4);
190} 270}
191 271
192void CItem::Parse(const Byte *p, bool mode64bit) 272bool CItem::Parse(const Byte *p, bool mode64bit)
193{ 273{
194 memcpy(Name, p, kNameSizeMax); 274 memcpy(Name, p, kNameSizeMax);
195 // NameSize = Get16(p + 64); 275 unsigned i;
276 for (i = 0; i < kNameSizeMax; i += 2)
277 if (*(const UInt16 *)(const void *)(p + i) == 0)
278 break;
279#if 0 // 1 : for debug : for more strict field check
280 {
281 for (unsigned k = i; k < kNameSizeMax; k += 2)
282 if (*(const UInt16 *)(const void *)(p + k) != 0)
283 return false;
284 }
285#endif
196 Type = p[66]; 286 Type = p[66];
287 // DOC: names are limited to 32 UTF-16 code points, including the terminating null character.
288 if (!IsEmptyType())
289 if (i == kNameSizeMax || i + 2 != Get16(p + 64)) // NameLength
290 return false;
291 if (p[67] >= 2) // Color: 0 (red) or 1 (black)
292 return false;
197 LeftDid = Get32(p + 68); 293 LeftDid = Get32(p + 68);
198 RightDid = Get32(p + 72); 294 RightDid = Get32(p + 72);
199 SonDid = Get32(p + 76); 295 SonDid = Get32(p + 76);
200 // Flags = Get32(p + 96); 296 // if (Get32(p + 96) == 0) return false; // State / Flags
201 GetFileTimeFromMem(p + 100, &CTime); 297 GetFileTimeFromMem(p + 100, &CTime);
202 GetFileTimeFromMem(p + 108, &MTime); 298 GetFileTimeFromMem(p + 108, &MTime);
203 Sid = Get32(p + 116); 299 Sid = Get32(p + 116);
204 Size = Get32(p + 120); 300 Size = Get32(p + 120);
301 /* MS DOC: it is recommended that parsers ignore the most
302 significant 32 bits of this field in version 3 compound files */
205 if (mode64bit) 303 if (mode64bit)
206 Size |= ((UInt64)Get32(p + 124) << 32); 304 Size |= ((UInt64)Get32(p + 124) << 32);
305 return true;
207} 306}
208 307
308
209void CDatabase::Clear() 309void CDatabase::Clear()
210{ 310{
311 Type = k_Type_Common;
312 MainSubfile = -1;
313 IsArc = false;
314 HeadersError = false;
315 // IsMsi = false;
211 PhySize = 0; 316 PhySize = 0;
212 PhySize_Aligned = 0; 317 PhySize_Unaligned = 0;
213 318 // FreeSize = 0;
319 Callback_Cur = 0;
320 // OpenCallback = NULL;
321
322 FatSize = 0;
323 MatSize = 0;
324 NumSectors_in_MiniStream = 0;
325
214 Fat.Free(); 326 Fat.Free();
215 MiniSids.Free();
216 Mat.Free(); 327 Mat.Free();
328 MiniSids.Free();
217 Items.Clear(); 329 Items.Clear();
218 Refs.Clear(); 330 Refs.Clear();
219} 331}
220 332
221static const UInt32 kNoDid = 0xFFFFFFFF;
222 333
223HRESULT CDatabase::AddNode(int parent, UInt32 did) 334static const UInt32 kNoDid = 0xffffffff;
335
336HRESULT CDatabase::AddNodes()
224{ 337{
225 if (did == kNoDid) 338 UInt32 index = Items[0].SonDid; // Items[0] is root item
339 if (index == kNoDid) // no files case
226 return S_OK; 340 return S_OK;
227 if (did >= (UInt32)Items.Size()) 341 if (index == 0 || index >= Items.Size())
228 return S_FALSE;
229 const CItem &item = Items[did];
230 if (item.IsEmpty())
231 return S_FALSE;
232 CRef ref;
233 ref.Parent = parent;
234 ref.Did = did;
235 const unsigned index = Refs.Add(ref);
236 if (Refs.Size() > Items.Size())
237 return S_FALSE; 342 return S_FALSE;
238 RINOK(AddNode(parent, item.LeftDid)) 343
239 RINOK(AddNode(parent, item.RightDid)) 344 CObjArray<UInt32> itemParents(Items.Size());
240 if (item.IsDir()) 345 CByteArr states(Items.Size());
346 memset(itemParents, 0, (size_t)Items.Size() * sizeof(itemParents[0])); // optional
347 memset(states, 0, Items.Size());
348
349#if 1 // 0 : for debug
350 const UInt32 k_exitParent = 0;
351 const UInt32 k_startLevel = 1;
352 // we don't show "Root Entry" dir
353 states[0] = 3; // we mark root node as processed, also we block any cycle links to root node
354 // itemParents[0] = 0xffffffff; // optional / unused value
355#else
356 // we show item[0] "Root Entry" dir
357 const UInt32 k_exitParent = 0xffffffff;
358 const UInt32 k_startLevel = 0;
359 index = 0;
360#endif
361
362 UInt32 level = k_startLevel; // directory level
363 unsigned state = 0;
364 UInt32 parent = k_exitParent; // in Items[], itemParents[], states[]
365 UInt32 refParent = k_Ref_Parent_Root; // in Refs[]
366
367 for (;;)
241 { 368 {
242 RINOK(AddNode((int)index, item.SonDid)) 369 if (state >= 3)
243 } 370 {
244 return S_OK; 371 // we return to parent node
245} 372 if (state != 3)
373 return E_FAIL;
374 index = parent;
375 if (index == k_exitParent)
376 break;
377 if (index >= Items.Size())
378 return E_FAIL; // (index) was checked already
379 parent = itemParents[index];
380 state = states[index];
381 if (state == 0)
382 return E_FAIL;
383 if (state == 2)
384 {
385 // we return to parent Dir node
386 if (refParent >= Refs.Size())
387 return E_FAIL;
388 refParent = Refs[refParent].Parent;
389 level--;
390 }
391 continue;
392 }
246 393
247static UString CompoundNameToFileName(const UString &s) 394 if (index >= Items.Size())
248{ 395 return S_FALSE;
249 UString res; 396 CItem &item = Items[index];
250 for (unsigned i = 0; i < s.Len(); i++) 397 if (item.IsEmptyType())
398 return S_FALSE;
399 item.Level = level;
400 state++;
401 states[index] = (Byte)state; // we mark current (index) node as used node
402
403 UInt32 newIndex;
404 if (state != 2)
405 newIndex = (state < 2) ? item.LeftDid : item.RightDid;
406 else
407 {
408 CRef ref;
409 ref.Parent = refParent;
410 ref.Did = index;
411 const unsigned refIndex = Refs.Add(ref);
412 if (!item.IsDir())
413 continue;
414 newIndex = item.SonDid;
415 if (newIndex != kNoDid)
416 {
417 level++;
418 refParent = refIndex;
419 }
420 }
421
422 if (newIndex != kNoDid)
423 {
424 itemParents[index] = parent;
425 state = 0;
426 parent = index;
427 index = newIndex;
428 if (index >= Items.Size() || states[index])
429 return S_FALSE;
430 }
431 }
432
433 if (level != k_startLevel || refParent != k_Ref_Parent_Root)
434 return E_FAIL;
435#if 1 // 1 : optional
436 // we check that all non-empty items were processed correctly
437 FOR_VECTOR(i, Items)
251 { 438 {
252 const wchar_t c = s[i]; 439 const unsigned st = states[i];
253 if ((unsigned)(int)c < 0x20) 440 if (Items[i].IsEmptyType())
254 { 441 {
255 res.Add_Char('['); 442 if (st)
256 res.Add_UInt32((UInt32)(unsigned)(int)c); 443 return E_FAIL;
257 res.Add_Char(']');
258 } 444 }
445 else if (st == 3)
446 continue;
447 else if (st)
448 return E_FAIL;
259 else 449 else
260 res += c; 450 return S_FALSE; // there is unused directory item
261 } 451 }
262 return res; 452#endif
453 return S_OK;
263} 454}
264 455
456
265static const char k_Msi_Chars[] = 457static const char k_Msi_Chars[] =
266 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; 458 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
267 459static const char k_Msi_SpecChar_Replace = '!';
268// static const char * const k_Msi_ID = ""; // "{msi}";
269static const char k_Msi_SpecChar = '!';
270
271static const unsigned k_Msi_NumBits = 6;
272static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits;
273static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1;
274static const unsigned k_Msi_StartUnicodeChar = 0x3800;
275static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1);
276
277
278static bool IsMsiName(const Byte *p)
279{
280 UInt32 c = Get16(p);
281 return
282 c >= k_Msi_StartUnicodeChar &&
283 c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange;
284}
285 460
286static bool AreEqualNames(const Byte *rawName, const char *asciiName) 461static bool AreEqualNames(const Byte *rawName, const char *asciiName)
287{ 462{
288 for (unsigned i = 0; i < kNameSizeMax / 2; i++) 463 for (;;)
289 { 464 {
290 wchar_t c = Get16(rawName + i * 2); 465 const unsigned c = Get16(rawName);
291 wchar_t c2 = (Byte)asciiName[i]; 466 rawName += 2;
467 const unsigned c2 = (Byte)*asciiName;
468 asciiName++;
292 if (c != c2) 469 if (c != c2)
293 return false; 470 return false;
294 if (c == 0) 471 if (c2 == 0)
295 return true; 472 return true;
296 } 473 }
297 return false;
298} 474}
299 475
300static bool CompoundMsiNameToFileName(const UString &name, UString &res)
301{
302 res.Empty();
303 for (unsigned i = 0; i < name.Len(); i++)
304 {
305 wchar_t c = name[i];
306 if (c < (wchar_t)k_Msi_StartUnicodeChar || c > (wchar_t)(k_Msi_StartUnicodeChar + k_Msi_UnicodeRange))
307 return false;
308 /*
309 if (i == 0)
310 res += k_Msi_ID;
311 */
312 c -= (wchar_t)k_Msi_StartUnicodeChar;
313
314 const unsigned c0 = (unsigned)c & k_Msi_CharMask;
315 const unsigned c1 = (unsigned)c >> k_Msi_NumBits;
316 476
317 if (c1 <= k_Msi_NumChars) 477static void MsiName_To_FileName(const Byte *p, UString &res)
318 {
319 res.Add_Char(k_Msi_Chars[c0]);
320 if (c1 == k_Msi_NumChars)
321 break;
322 res.Add_Char(k_Msi_Chars[c1]);
323 }
324 else
325 res.Add_Char(k_Msi_SpecChar);
326 }
327 return true;
328}
329
330static UString ConvertName(const Byte *p, bool &isMsi)
331{ 478{
332 isMsi = false; 479 res.Empty();
333 UString s;
334
335 for (unsigned i = 0; i < kNameSizeMax; i += 2) 480 for (unsigned i = 0; i < kNameSizeMax; i += 2)
336 { 481 {
337 wchar_t c = Get16(p + i); 482 unsigned c = Get16(p + i);
338 if (c == 0) 483 if (c == 0)
339 break; 484 break;
340 s += c; 485 if (c <= k_Msi_SpecUnicodeChar)
341 } 486 {
342 487 if (c < k_Msi_StartUnicodeChar)
343 UString msiName; 488 {
344 if (CompoundMsiNameToFileName(s, msiName)) 489 if (c < 0x20)
345 { 490 {
346 isMsi = true; 491 res.Add_Char('[');
347 return msiName; 492 res.Add_UInt32((UInt32)c);
493 c = ']';
494 }
495 }
496 else
497 {
498#if 0 // 1 : for debug
499 if (i == 0) res += "{msi}";
500#endif
501 c -= k_Msi_StartUnicodeChar;
502 const unsigned c1 = (unsigned)c >> k_Msi_NumBits;
503 if (c1 <= k_Msi_NumChars)
504 {
505 res.Add_Char(k_Msi_Chars[(unsigned)c & k_Msi_CharMask]);
506 if (c1 == k_Msi_NumChars)
507 continue;
508 c = (Byte)k_Msi_Chars[c1];
509 }
510 else
511 c = k_Msi_SpecChar_Replace;
512 }
513 }
514 res += (wchar_t)c;
348 } 515 }
349 return CompoundNameToFileName(s);
350} 516}
351 517
352static UString ConvertName(const Byte *p)
353{
354 bool isMsi;
355 return ConvertName(p, isMsi);
356}
357 518
358UString CDatabase::GetItemPath(UInt32 index) const 519UString CDatabase::GetItemPath(UInt32 index) const
359{ 520{
360 UString s; 521 UString s;
361 while (index != kNoDid) 522 UString name;
523 unsigned level = 0;
524 while (index != k_Ref_Parent_Root)
362 { 525 {
363 const CRef &ref = Refs[index]; 526 const CRef &ref = Refs[index];
364 const CItem &item = Items[ref.Did]; 527 const CItem &item = Items[ref.Did];
365 if (!s.IsEmpty()) 528 if (!s.IsEmpty())
366 s.InsertAtFront(WCHAR_PATH_SEPARATOR); 529 s.InsertAtFront(WCHAR_PATH_SEPARATOR);
367 s.Insert(0, ConvertName(item.Name)); 530 // if (IsMsi)
368 index = (unsigned)ref.Parent; 531 MsiName_To_FileName(item.Name, name);
532 // else NonMsiName_To_FileName(item.Name, name);
533 NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
534 if (name.IsEmpty())
535 name = "[]";
536 s.Insert(0, name);
537 index = ref.Parent;
538#ifdef Z7_COMPOUND_SHOW_DELETED
539 if (item.IsLevel_Unused())
540 {
541 s.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR);
542 break;
543 }
544#endif
545 if (item.Level >= k_Long_path_level_limit && level)
546 {
547 s.Insert(0, L"[LONG_PATH]" WSTRING_PATH_SEPARATOR);
548 break;
549 }
550 level = 1; // level++;
369 } 551 }
370 return s; 552 return s;
371} 553}
372 554
373HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) 555
556HRESULT CDatabase::Check_Item(unsigned index)
374{ 557{
375 const CItem &item = Items[index]; 558 const CItem &item = Items[index];
376 const bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); 559 if (item.IsEmptyType() || item.IsStorage())
377 if (!isLargeStream)
378 return S_OK; 560 return S_OK;
379 const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits;
380 // streamSpec->Size = item.Size;
381
382 const UInt32 clusterSize = (UInt32)1 << bsLog;
383 const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
384 if (numClusters64 >= ((UInt32)1 << 31))
385 return S_FALSE;
386 UInt32 sid = item.Sid;
387 UInt64 size = item.Size; 561 UInt64 size = item.Size;
388 562 const bool isLargeStream = (index == 0 || IsLargeStream(size));
389 if (size != 0) 563 if (!isLargeStream)
390 { 564 {
391 for (;; size -= clusterSize) 565 const unsigned bsLog = k_MiniSectorSizeBits;
566 const UInt32 clusterSize = (UInt32)1 << bsLog;
567 const UInt64 numClusters = (size + clusterSize - 1) >> bsLog;
568 if (numClusters > MatSize)
569 return S_FALSE;
570 UInt32 sid = item.Sid;
571 if (size != 0)
392 { 572 {
393 // if (isLargeStream) 573 for (;; size -= clusterSize)
574 {
575 if (sid >= MatSize)
576 return S_FALSE;
577 const unsigned subBits = SectorSizeBits - k_MiniSectorSizeBits;
578 const UInt32 fid = sid >> subBits;
579 if (fid >= NumSectors_in_MiniStream)
580 return false;
581 sid = Mat[sid];
582 if (size <= clusterSize)
583 break;
584 }
585 }
586 if (sid != NFatID::kEndOfChain)
587 return S_FALSE;
588 }
589 else
590 {
591 const unsigned bsLog = SectorSizeBits;
592 const UInt32 clusterSize = (UInt32)1 << bsLog;
593 const UInt64 numClusters = (size + clusterSize - 1) >> bsLog;
594 if (numClusters > FatSize)
595 return S_FALSE;
596 UInt32 sid = item.Sid;
597 if (size != 0)
598 {
599 for (;; size -= clusterSize)
394 { 600 {
395 if (sid >= FatSize) 601 if (sid >= FatSize)
396 return S_FALSE; 602 return S_FALSE;
397 UInt64 end = ((UInt64)sid + 1) << bsLog; 603 const UInt32 sidPrev = sid;
398 const UInt64 end_Aligned = end + clusterSize;
399 if (size < clusterSize)
400 end += size;
401 else
402 end = end_Aligned;
403 UpdatePhySize(end, end_Aligned);
404 sid = Fat[sid]; 604 sid = Fat[sid];
605 if (size <= clusterSize)
606 {
607 const UInt64 phySize = (((UInt64)sidPrev + 1) << SectorSizeBits) + size;
608 if (PhySize_Unaligned < phySize)
609 PhySize_Unaligned = phySize;
610 break;
611 }
405 } 612 }
406 if (size <= clusterSize)
407 break;
408 } 613 }
614 if (sid != NFatID::kEndOfChain)
615 return S_FALSE;
409 } 616 }
410 if (sid != NFatID::kEndOfChain)
411 return S_FALSE;
412 return S_OK; 617 return S_OK;
413} 618}
414 619
415// There is name "[!]MsiPatchSequence" in msp files
416static const unsigned kMspSequence_Size = 18;
417static const Byte kMspSequence[kMspSequence_Size] =
418 { 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45,
419 0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41,
420 0x37, 0x41 };
421 620
422HRESULT CDatabase::Open(IInStream *inStream) 621HRESULT CDatabase::Open(IInStream *inStream)
423{ 622{
424 MainSubfile = -1; 623 const unsigned kHeaderSize = 512;
425 Type = k_Type_Common; 624 UInt32 p32[kHeaderSize / 4];
426 const UInt32 kHeaderSize = 512; 625 RINOK(ReadStream_FALSE(inStream, p32, kHeaderSize))
427 Byte p[kHeaderSize]; 626 const Byte *p = (const Byte *)(const void *)p32;
428 PhySize = kHeaderSize; 627 if (memcmp(p, kSignature, Z7_ARRAY_SIZE(kSignature)))
429 RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)) 628 return S_FALSE;
430 if (memcmp(p, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0) 629 /*
630 if (memcmp(p + 8, k_CLSID_AAF_V3, Z7_ARRAY_SIZE(k_CLSID_AAF_V3)) == 0 ||
631 memcmp(p + 8, k_CLSID_AAF_V4, Z7_ARRAY_SIZE(k_CLSID_AAF_V4)) == 0)
632 */
633 if (Get32(p32 + 4) == 0x342b0e06) // simplified AAF signature check
634 Type = k_Type_Aaf;
635 if (Get16(p + 0x18) != 0x3e) // minorVer
431 return S_FALSE; 636 return S_FALSE;
432 if (Get16(p + 0x1A) > 4) // majorVer 637 const unsigned ver = Get16(p + 0x1a); // majorVer
638 if (ver < 3 || ver > 4)
433 return S_FALSE; 639 return S_FALSE;
434 if (Get16(p + 0x1C) != 0xFFFE) // Little-endian 640 if (Get16(p + 0x1c) != 0xfffe) // Little-endian
641 return S_FALSE;
642 const unsigned sectorSizeBits = Get16(p + 0x1e);
643 if (sectorSizeBits != ver * 3) // (ver == 3 ? 9 : 12)
435 return S_FALSE; 644 return S_FALSE;
436 unsigned sectorSizeBits = Get16(p + 0x1E);
437 bool mode64bit = (sectorSizeBits >= 12);
438 unsigned miniSectorSizeBits = Get16(p + 0x20);
439 SectorSizeBits = sectorSizeBits; 645 SectorSizeBits = sectorSizeBits;
440 MiniSectorSizeBits = miniSectorSizeBits; 646 if (Get16(p + 0x20) != k_MiniSectorSizeBits)
647 return S_FALSE;
648
649 IsArc = true;
650 HeadersError = true;
441 651
442 if (sectorSizeBits > 24 || 652 const bool mode64bit = (sectorSizeBits >= 12); // (ver == 4)
443 sectorSizeBits < 7 || 653 if (Get16(p + 0x22) || p32[9]) // reserved
444 miniSectorSizeBits > 24 || 654 return S_FALSE;
445 miniSectorSizeBits < 2 || 655
446 miniSectorSizeBits > sectorSizeBits) 656 const UInt32 numDirSectors = Get32(p32 + 10);
657 // If (ver==3), the Number of Directory Sectors MUST be zero.
658 if (ver != 3 + (unsigned)(numDirSectors != 0))
659 return S_FALSE;
660 if (numDirSectors > ((1u << (32 - 2)) >> (sectorSizeBits - (7 + 2))))
661 return S_FALSE;
662
663 const UInt32 numSectorsForFAT = Get32(p32 + 11); // SAT
664
665 // MSDOC: A 512-byte sector compound file MUST be no greater than 2 GB in size for compatibility reasons.
666 // but actual restriction for windows compond creation code can be more strict:
667 // (numSectorsForFAT < (1 << 15)) : actual restriction in win10 for compound creation code
668 // (numSectorsForFAT <= (1 << 15)) : relaxed restriction to allow 2 GB files.
669 if (sectorSizeBits == 9 &&
670 numSectorsForFAT >= (1u << (31 - (9 + 9 - 2)))) // we use most strict check
447 return S_FALSE; 671 return S_FALSE;
448 UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT
449 LongStreamMinSize = Get32(p + 0x38);
450
451 UInt32 sectSize = (UInt32)1 << sectorSizeBits;
452 672
453 CByteBuffer sect(sectSize); 673 // const UInt32 TransactionSignatureNumber = Get32(p32 + 13);
674 if (Get32(p32 + 14) != k_LongStreamMinSize)
675 return S_FALSE;
454 676
455 unsigned ssb2 = sectorSizeBits - 2; 677 const unsigned ssb2 = sectorSizeBits - 2;
456 UInt32 numSidsInSec = (UInt32)1 << ssb2; 678 const UInt32 numSidsInSec = (UInt32)1 << ssb2;
457 UInt32 numFatItems = numSectorsForFAT << ssb2; 679 const UInt32 numFatItems = numSectorsForFAT << ssb2;
458 if ((numFatItems >> ssb2) != numSectorsForFAT) 680 if (numFatItems == 0 || (numFatItems >> ssb2) != numSectorsForFAT)
459 return S_FALSE; 681 return S_FALSE;
460 FatSize = numFatItems;
461 682
683 const size_t sectSize = (size_t)1 << sectorSizeBits;
684 CByteArr sect(sectSize);
685 CByteArr used(numFatItems);
686 // don't change these const values. These values use same order as (0xffffffff - NFatID::const)
687 // const Byte k_Used_Free = 0;
688 const Byte k_Used_ChainTo = 1;
689 const Byte k_Used_FAT = 2;
690 const Byte k_Used_DIFAT = 3;
691 memset(used, 0, numFatItems);
692 UInt32 *fat;
462 { 693 {
463 UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table 694 // ========== READ FAT ==========
464 const UInt32 kNumHeaderBatItems = 109; 695 const UInt32 numSectorsForBat = Get32(p32 + 18); // master sector allocation table
465 UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); 696 const unsigned ssb2_m1 = ssb2 - 1;
466 if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) 697 if (numSectorsForBat > ((1u << 30) >> ssb2_m1 >> ssb2_m1))
467 return S_FALSE; 698 return S_FALSE;
699 const unsigned kNumHeaderBatItems = 109;
700 UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); // real size can be smaller
468 CObjArray<UInt32> bat(numBatItems); 701 CObjArray<UInt32> bat(numBatItems);
469 UInt32 i; 702 size_t i;
470 for (i = 0; i < kNumHeaderBatItems; i++) 703 for (i = 0; i < kNumHeaderBatItems; i++)
471 bat[i] = Get32(p + 0x4c + i * 4); 704 bat[i] = Get32(p32 + 19 + i);
472 UInt32 sid = Get32(p + 0x44);
473 for (UInt32 s = 0; s < numSectorsForBat; s++)
474 { 705 {
475 RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)) 706 UInt32 sid = Get32(p32 + 17);
476 i += numSidsInSec - 1; 707 for (UInt32 s = 0; s < numSectorsForBat; s++)
477 sid = bat[i]; 708 {
709 if (sid >= numFatItems || used[sid])
710 return S_FALSE;
711 used[sid] = k_Used_DIFAT;
712 RINOK(ReadIDs(inStream, sect, sid, bat + i))
713 i += numSidsInSec - 1;
714 sid = bat[i];
715 }
716 if (sid != NFatID::kEndOfChain // NFatID::kEndOfChain is expected value for most files
717 && sid != NFatID::kFree) // NFatID::kFree is used in some AAF files
718 return S_FALSE;
478 } 719 }
479 numBatItems = i; 720 numBatItems = (UInt32)i; // corrected value
480 721 if (numSectorsForFAT > numBatItems)
722 return S_FALSE;
723 for (i = numSectorsForFAT; i < numBatItems; i++)
724 if (bat[i] != NFatID::kFree)
725 return S_FALSE;
726
727 // RINOK(IncreaseOpenTotal(numSectorsForFAT + numDirSectors))
728
481 Fat.Alloc(numFatItems); 729 Fat.Alloc(numFatItems);
482 UInt32 j = 0; 730 fat = Fat;
483 731 for (i = 0; i < numSectorsForFAT; i++)
484 for (i = 0; i < numFatItems; j++, i += numSidsInSec)
485 { 732 {
486 if (j >= numBatItems) 733 const UInt32 sectorIndex = bat[i];
734 if (sectorIndex >= numFatItems)
487 return S_FALSE; 735 return S_FALSE;
488 RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i)) 736 if (used[sectorIndex])
737 return S_FALSE;
738 used[sectorIndex] = k_Used_FAT;
739 UInt32 *fat2 = fat + ((size_t)i << ssb2);
740 RINOK(ReadIDs(inStream, sect, sectorIndex, fat2))
741 for (size_t k = 0; k < numSidsInSec; k++)
742 {
743 const UInt32 sid = fat2[k];
744 if (sid > NFatID::kMaxValue)
745 {
746 if (sid == NFatID::k_DIF_SECT
747 && used[((size_t)i << ssb2) + k] != k_Used_DIFAT)
748 return S_FALSE;
749 continue;
750 }
751 if (sid >= numFatItems || used[sid])
752 return S_FALSE; // strict error check
753 used[sid] = k_Used_ChainTo;
754 }
489 } 755 }
490 FatSize = numFatItems = i; 756 {
757 for (i = 0; i < numSectorsForFAT; i++)
758 if (fat[bat[i]] != NFatID::kFatSector)
759 return S_FALSE;
760 }
761 FatSize = numFatItems;
762 }
763
764 {
765 size_t i = numFatItems;
766 do
767 if (fat[i - 1] != NFatID::kFree)
768 break;
769 while (--i);
770 PhySize = ((UInt64)i + 1) << sectorSizeBits;
771 /*
772 if (i)
773 {
774 const UInt32 *lim = fat + i;
775 UInt32 num = 0;
776 do
777 if (*fat++ == NFatID::kFree)
778 num++;
779 while (fat != lim);
780 FreeSize = num << sectorSizeBits;
781 }
782 */
491 } 783 }
492 784
493 UInt32 numMatItems; 785 UInt32 numMatItems;
494 { 786 {
495 UInt32 numSectorsForMat = Get32(p + 0x40); 787 // ========== READ MAT ==========
788 const UInt32 numSectorsForMat = Get32(p32 + 16);
496 numMatItems = (UInt32)numSectorsForMat << ssb2; 789 numMatItems = (UInt32)numSectorsForMat << ssb2;
497 if ((numMatItems >> ssb2) != numSectorsForMat) 790 if ((numMatItems >> ssb2) != numSectorsForMat)
498 return S_FALSE; 791 return S_FALSE;
499 Mat.Alloc(numMatItems); 792 Mat.Alloc(numMatItems);
500 UInt32 i; 793 UInt32 sid = Get32(p32 + 15); // short-sector table SID
501 UInt32 sid = Get32(p + 0x3C); // short-sector table SID 794 if (numMatItems)
502 for (i = 0; i < numMatItems; i += numSidsInSec) 795 {
796 if (sid >= numFatItems || used[sid])
797 return S_FALSE;
798 used[sid] = k_Used_ChainTo;
799 }
800 for (UInt32 i = 0; i < numMatItems; i += numSidsInSec)
503 { 801 {
504 RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i))
505 if (sid >= numFatItems) 802 if (sid >= numFatItems)
506 return S_FALSE; 803 return S_FALSE;
507 sid = Fat[sid]; 804 RINOK(ReadIDs(inStream, sect, sid, Mat + i))
805 sid = fat[sid];
508 } 806 }
509 if (sid != NFatID::kEndOfChain) 807 if (sid != NFatID::kEndOfChain)
510 return S_FALSE; 808 return S_FALSE;
511 } 809 }
512 810
513 { 811 {
514 CByteBuffer used(numFatItems); 812 // ========== READ DIR ITEMS ==========
515 for (UInt32 i = 0; i < numFatItems; i++) 813 UInt32 sid = Get32(p32 + 12); // directory stream SID
516 used[i] = 0; 814 UInt32 numDirSectors_Processed = 0;
517 UInt32 sid = Get32(p + 0x30); // directory stream SID 815 if (sid >= numFatItems || used[sid])
518 for (;;) 816 return S_FALSE;
817 used[sid] = k_Used_ChainTo;
818 do
519 { 819 {
820 // we need to check sid here becase kEndOfChain sid < numFatItems is required
520 if (sid >= numFatItems) 821 if (sid >= numFatItems)
521 return S_FALSE; 822 return S_FALSE;
522 if (used[sid]) 823 if (numDirSectors && numDirSectors_Processed >= numDirSectors)
523 return S_FALSE; 824 return S_FALSE;
524 used[sid] = 1; 825 numDirSectors_Processed++;
525 RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)) 826 RINOK(ReadSector(inStream, sect, sid))
526 for (UInt32 i = 0; i < sectSize; i += 128) 827 for (size_t i = 0; i < sectSize; i += (1 << 7))
527 { 828 {
528 CItem item; 829 CItem item;
529 item.Parse(sect + i, mode64bit); 830 item.Level = k_Item_Level_Unused;
831 if (!item.Parse(sect + i, mode64bit))
832 return S_FALSE;
530 // we use (item.Size) check here. 833 // we use (item.Size) check here.
531 // so we don't need additional overflow checks for (item.Size +) in another code 834 // so we don't need additional overflow checks for (item.Size +) in another code
532 if (item.Size >= ((UInt64)1 << 63)) 835 if ((UInt32)(item.Size >> 32) >= sectSize) // it's because FAT size is limited by (1 << 32) items.
533 return S_FALSE; 836 return S_FALSE;
837
838 if (Items.IsEmpty())
839 {
840 if (item.Type != NItemType::kRootStorage
841 || item.LeftDid != kNoDid
842 || item.RightDid != kNoDid
843 || item.SonDid == 0)
844 return S_FALSE;
845 if (item.Sid != NFatID::kEndOfChain)
846 {
847 if (item.Sid >= numFatItems || used[item.Sid])
848 return S_FALSE;
849 used[item.Sid] = k_Used_ChainTo;
850 }
851 }
852 else if (item.IsStorage())
853 {
854 if (item.Size != 0) // by specification
855 return S_FALSE;
856 if (item.Sid != 0 // by specification
857 && item.Sid != NFatID::kFree) // NFatID::kFree is used in some AAF files
858 return S_FALSE;
859 }
860 // else if (item.Type == NItemType::kRootStorage) return S_FALSE;
861 else if (item.IsEmptyType())
862 {
863 // kNoDid is expected in *Did fileds, but rare case MSI contains zero in all fields
864 if ((item.Sid != 0 // expected value
865 && item.Sid != NFatID::kFree // NFatID::kFree is used in some AAF files
866 && item.Sid != NFatID::kEndOfChain) // used by some MSI file
867 || (item.LeftDid != kNoDid && item.LeftDid)
868 || (item.RightDid != kNoDid && item.RightDid)
869 || (item.SonDid != kNoDid && item.SonDid)
870 // || item.Size != 0 // the check is disabled because some MSI file contains non zero
871 // || Get16(item.Name) != 0 // the check is disabled because some MSI file contains some name
872 )
873 return S_FALSE;
874 }
875 else
876 {
877 if (item.Type != NItemType::kStream)
878 return S_FALSE;
879 // NItemType::kStream case
880 if (item.SonDid != kNoDid) // optional check
881 return S_FALSE;
882 if (item.Size == 0)
883 {
884 if (item.Sid != NFatID::kEndOfChain)
885 return S_FALSE;
886 }
887 else if (IsLargeStream(item.Size))
888 {
889 if (item.Sid >= numFatItems || used[item.Sid])
890 return S_FALSE;
891 used[item.Sid] = k_Used_ChainTo;
892 }
893 }
894
534 Items.Add(item); 895 Items.Add(item);
535 } 896 }
536 sid = Fat[sid]; 897 sid = fat[sid];
537 if (sid == NFatID::kEndOfChain)
538 break;
539 } 898 }
899 while (sid != NFatID::kEndOfChain);
540 } 900 }
541 901
542 const CItem &root = Items[0];
543
544 { 902 {
903 // root stream contains all data that stored with mini Sectors
904 const CItem &root = Items[0];
545 UInt32 numSectorsInMiniStream; 905 UInt32 numSectorsInMiniStream;
546 { 906 {
547 UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; 907 const UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
548 if (numSatSects64 > NFatID::kMaxValue) 908 if (numSatSects64 > NFatID::kMaxValue + 1)
549 return S_FALSE; 909 return S_FALSE;
550 numSectorsInMiniStream = (UInt32)numSatSects64; 910 numSectorsInMiniStream = (UInt32)numSatSects64;
551 } 911 }
552 NumSectorsInMiniStream = numSectorsInMiniStream;
553 MiniSids.Alloc(numSectorsInMiniStream);
554 { 912 {
555 UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; 913 const UInt64 matSize64 = (root.Size + (1 << k_MiniSectorSizeBits) - 1) >> k_MiniSectorSizeBits;
556 if (matSize64 > NFatID::kMaxValue) 914 if (matSize64 > numMatItems)
557 return S_FALSE; 915 return S_FALSE;
558 MatSize = (UInt32)matSize64; 916 MatSize = (UInt32)matSize64;
559 if (numMatItems < MatSize)
560 return S_FALSE;
561 } 917 }
562 918 MiniSids.Alloc(numSectorsInMiniStream);
919 UInt32 * const miniSids = MiniSids;
563 UInt32 sid = root.Sid; 920 UInt32 sid = root.Sid;
564 for (UInt32 i = 0; ; i++) 921 for (UInt32 i = 0; ; i++)
565 { 922 {
@@ -571,95 +928,186 @@ HRESULT CDatabase::Open(IInStream *inStream)
571 } 928 }
572 if (i >= numSectorsInMiniStream) 929 if (i >= numSectorsInMiniStream)
573 return S_FALSE; 930 return S_FALSE;
574 MiniSids[i] = sid;
575 if (sid >= numFatItems) 931 if (sid >= numFatItems)
576 return S_FALSE; 932 return S_FALSE;
577 sid = Fat[sid]; 933 miniSids[i] = sid;
934 sid = fat[sid];
578 } 935 }
936 NumSectors_in_MiniStream = numSectorsInMiniStream;
579 } 937 }
580 938
581 RINOK(AddNode(-1, root.SonDid)) 939
582
583 unsigned numCabs = 0;
584
585 FOR_VECTOR (i, Refs)
586 { 940 {
587 const CItem &item = Items[Refs[i].Did]; 941/*
588 if (item.IsDir() || numCabs > 1) 942 MS DOCs:
589 continue; 943 The range lock sector covers file offsets 0x7FFFFF00-0x7FFFFFFF.
590 bool isMsiName; 944 These offsets are reserved for byte-range locking to support
591 const UString msiName = ConvertName(item.Name, isMsiName); 945 concurrency, transactions, and other compound file features.
592 if (isMsiName && !msiName.IsEmpty()) 946 The range lock sector MUST be allocated in the FAT and marked with
593 { 947 ENDOFCHAIN (0xFFFFFFFE), when the compound file grows beyond 2 GB.
594 // bool isThereExt = (msiName.Find(L'.') >= 0); 948 If the compound file is greater than 2 GB and then shrinks to below 2 GB,
595 bool isMsiSpec = (msiName[0] == k_Msi_SpecChar); 949 the range lock sector SHOULD be marked as FREESECT (0xFFFFFFFF) in the FAT.
596 if ((msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab")) 950*/
597 || (!isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe")) 951 {
598 // || (!isMsiSpec && !isThereExt) 952 const UInt32 lockSector = (0x7fffffff >> sectorSizeBits) - 1;
599 ) 953 if (lockSector < numFatItems)
600 { 954 {
601 numCabs++; 955 if (used[lockSector])
602 MainSubfile = (int)i; 956 return S_FALSE;
957 const UInt32 f = fat[lockSector];
958 if (f == NFatID::kEndOfChain)
959 used[lockSector] = k_Used_ChainTo; // we use fake state to pass the check in loop below
960 else if (f != NFatID::kFree)
961 return S_FALSE;
603 } 962 }
604 } 963 }
964 for (size_t i = 0; i < numFatItems; i++)
965 {
966 UInt32 f = fat[i];
967 const UInt32 u = ~(UInt32)used[i]; // (0xffffffff - used[i])
968 if (f < NFatID::kMaxValue + 1)
969 f = NFatID::kEndOfChain;
970 if (f != u)
971 return S_FALSE;
972 }
605 } 973 }
606
607 if (numCabs > 1)
608 MainSubfile = -1;
609 974
610 { 975 {
611 FOR_VECTOR (t, Items) 976 // Don't move that code up, becase Check_Item uses Mat[] array.
977 FOR_VECTOR(t, Items)
612 { 978 {
613 Update_PhySize_WithItem(t); 979 RINOK(Check_Item(t))
614 } 980 }
615 } 981 }
982
983 RINOK(AddNodes())
984
985 {
986 // some msi (in rare cases) have unaligned size of archive,
987 // unaligned size of compond files is also possible if we create just one stream
988 // where there is no padding data after payload data in last cluster of archive
989 UInt64 fileSize;
990 RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
991 if ( fileSize < PhySize
992 && fileSize > PhySize - sectSize
993 && fileSize >= PhySize_Unaligned
994 && PhySize_Unaligned > PhySize - sectSize)
995 PhySize = PhySize_Unaligned;
996 }
997
998 bool isMsi = false;
616 { 999 {
617 if (PhySize != PhySize_Aligned) 1000 FOR_VECTOR (i, Refs)
618 { 1001 {
619 /* some msi (in rare cases) have unaligned size of archive, 1002 const CItem &item = Items[Refs[i].Did];
620 where there is no padding data after payload data in last cluster of archive */ 1003 if (item.IsDir())
621 UInt64 fileSize; 1004 continue;
622 RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) 1005 if (item.AreMsiChars())
623 if (PhySize != fileSize) 1006 // if (item.IsSpecMsiName())
624 PhySize = PhySize_Aligned; 1007 {
1008 isMsi = true;
1009 break;
1010 }
625 } 1011 }
626 } 1012 }
1013
1014 // IsMsi = isMsi;
1015 if (isMsi)
627 { 1016 {
628 FOR_VECTOR (t, Items) 1017 unsigned numCabs = 0;
1018 UString name;
1019 FOR_VECTOR (i, Refs)
629 { 1020 {
630 const CItem &item = Items[t]; 1021 const CItem &item = Items[Refs[i].Did];
631 1022 if (item.IsDir() /* || item.IsSpecMsiName() */)
632 if (IsMsiName(item.Name)) 1023 continue;
1024 MsiName_To_FileName(item.Name, name);
1025 if ( (name.Len() >= 4 && StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".cab"))
1026 || (name.Len() >= 3 && StringsAreEqualNoCase_Ascii(name.RightPtr(3), "exe"))
1027 )
633 { 1028 {
634 Type = k_Type_Msi; 1029 numCabs++;
635 if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0) 1030 if (numCabs > 1)
636 { 1031 {
637 Type = k_Type_Msp; 1032 MainSubfile = -1;
638 break; 1033 break;
639 } 1034 }
640 continue; 1035 MainSubfile = (int)i;
641 }
642 if (AreEqualNames(item.Name, "WordDocument"))
643 {
644 Type = k_Type_Doc;
645 break;
646 } 1036 }
647 if (AreEqualNames(item.Name, "PowerPoint Document")) 1037 }
1038 }
1039
1040 if (isMsi) // we provide msi priority over AAF
1041 Type = k_Type_Msi;
1042 if (Type != k_Type_Aaf)
1043 {
1044 FOR_VECTOR (i, Refs)
1045 {
1046 const CItem &item = Items[Refs[i].Did];
1047 if (item.IsDir())
1048 continue;
1049 const Byte *name = item.Name;
1050 // if (IsMsiName(name))
1051 if (isMsi)
648 { 1052 {
649 Type = k_Type_Ppt; 1053 if (memcmp(name, k_Sequence_msp, sizeof(k_Sequence_msp)) == 0)
650 break; 1054 {
1055 Type = k_Type_Msp;
1056 break;
1057 }
1058 if (memcmp(name, k_Sequence_msm, sizeof(k_Sequence_msm)) == 0)
1059 {
1060 Type = k_Type_Msm;
1061 break;
1062 }
651 } 1063 }
652 if (AreEqualNames(item.Name, "Workbook")) 1064 else
653 { 1065 {
654 Type = k_Type_Xls; 1066 if (AreEqualNames(name, "WordDocument"))
655 break; 1067 {
1068 Type = k_Type_Doc;
1069 break;
1070 }
1071 if (AreEqualNames(name, "PowerPoint Document"))
1072 {
1073 Type = k_Type_Ppt;
1074 break;
1075 }
1076 if (AreEqualNames(name, "Workbook"))
1077 {
1078 Type = k_Type_Xls;
1079 break;
1080 }
656 } 1081 }
657 } 1082 }
658 } 1083 }
659 1084
1085#ifdef Z7_COMPOUND_SHOW_DELETED
1086 {
1087 // we skip Items[0] that is root item
1088 for (unsigned t = 1; t < Items.Size(); t++)
1089 {
1090 const CItem &item = Items[t];
1091 if (
1092#if 1 // 0 for debug to show empty files
1093 item.IsEmptyType() ||
1094#endif
1095 !item.IsLevel_Unused())
1096 continue;
1097 CRef ref;
1098 ref.Parent = k_Ref_Parent_Root;
1099 ref.Did = t;
1100 Refs.Add(ref);
1101 }
1102 }
1103#endif
1104
1105 HeadersError = false;
660 return S_OK; 1106 return S_OK;
661} 1107}
662 1108
1109
1110
663Z7_CLASS_IMP_CHandler_IInArchive_1( 1111Z7_CLASS_IMP_CHandler_IInArchive_1(
664 IInArchiveGetStream 1112 IInArchiveGetStream
665) 1113)
@@ -674,13 +1122,15 @@ static const Byte kProps[] =
674 kpidPackSize, 1122 kpidPackSize,
675 kpidCTime, 1123 kpidCTime,
676 kpidMTime 1124 kpidMTime
1125 // , kpidCharacts // for debug
677}; 1126};
678 1127
679static const Byte kArcProps[] = 1128static const Byte kArcProps[] =
680{ 1129{
681 kpidExtension, 1130 kpidExtension,
682 kpidClusterSize, 1131 kpidClusterSize
683 kpidSectorSize 1132 // , kpidSectorSize
1133 // , kpidFreeSpace
684}; 1134};
685 1135
686IMP_IInArchive_Props 1136IMP_IInArchive_Props
@@ -695,9 +1145,20 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
695 case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break; 1145 case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break;
696 case kpidPhySize: prop = _db.PhySize; break; 1146 case kpidPhySize: prop = _db.PhySize; break;
697 case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break; 1147 case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
698 case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break; 1148 // case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
699 case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break; 1149 case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
1150 // case kpidFreeSpace: prop = _db.FreeSize; break;
700 case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break; 1151 case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break;
1152 case kpidErrorFlags:
1153 {
1154 UInt32 v = 0;
1155 if (!_db.IsArc)
1156 v |= kpv_ErrorFlags_IsNotArc;
1157 if (_db.HeadersError)
1158 v |= kpv_ErrorFlags_HeadersError;
1159 prop = v;
1160 break;
1161 }
701 } 1162 }
702 prop.Detach(value); 1163 prop.Detach(value);
703 return S_OK; 1164 return S_OK;
@@ -719,6 +1180,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
719 case kpidMTime: prop = item.MTime; break; 1180 case kpidMTime: prop = item.MTime; break;
720 case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; 1181 case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
721 case kpidSize: if (!item.IsDir()) prop = item.Size; break; 1182 case kpidSize: if (!item.IsDir()) prop = item.Size; break;
1183 // case kpidCharacts: prop = item.Level; break;
722 } 1184 }
723 prop.Detach(value); 1185 prop.Detach(value);
724 return S_OK; 1186 return S_OK;
@@ -727,17 +1189,17 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
727 1189
728Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, 1190Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
729 const UInt64 * /* maxCheckStartPosition */, 1191 const UInt64 * /* maxCheckStartPosition */,
730 IArchiveOpenCallback * /* openArchiveCallback */)) 1192 IArchiveOpenCallback *openArchiveCallback))
731{ 1193{
732 COM_TRY_BEGIN 1194 COM_TRY_BEGIN
733 Close(); 1195 Close();
734 try 1196 _db.OpenCallback = openArchiveCallback;
1197 // try
735 { 1198 {
736 if (_db.Open(inStream) != S_OK) 1199 RINOK(_db.Open(inStream))
737 return S_FALSE;
738 _stream = inStream; 1200 _stream = inStream;
739 } 1201 }
740 catch(...) { return S_FALSE; } 1202 // catch(...) { return S_FALSE; }
741 return S_OK; 1203 return S_OK;
742 COM_TRY_END 1204 COM_TRY_END
743} 1205}
@@ -775,52 +1237,57 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
775 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps; 1237 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
776 lps->Init(extractCallback, false); 1238 lps->Init(extractCallback, false);
777 1239
778 for (i = 0; i < numItems; i++) 1240 for (i = 0;; i++)
779 { 1241 {
780 lps->InSize = totalPackSize; 1242 lps->InSize = totalPackSize;
781 lps->OutSize = totalSize; 1243 lps->OutSize = totalSize;
782 RINOK(lps->SetCur()) 1244 RINOK(lps->SetCur())
1245 if (i >= numItems)
1246 break;
1247
783 const UInt32 index = allFilesMode ? i : indices[i]; 1248 const UInt32 index = allFilesMode ? i : indices[i];
784 const CItem &item = _db.Items[_db.Refs[index].Did]; 1249 const CItem &item = _db.Items[_db.Refs[index].Did];
785 Int32 res; 1250 Int32 res;
786 {
787 CMyComPtr<ISequentialOutStream> outStream;
788 const Int32 askMode = testMode ?
789 NExtract::NAskMode::kTest :
790 NExtract::NAskMode::kExtract;
791 RINOK(extractCallback->GetStream(index, &outStream, askMode))
792
793 if (item.IsDir())
794 { 1251 {
1252 CMyComPtr<ISequentialOutStream> outStream;
1253 const Int32 askMode = testMode ?
1254 NExtract::NAskMode::kTest :
1255 NExtract::NAskMode::kExtract;
1256 RINOK(extractCallback->GetStream(index, &outStream, askMode))
1257
1258 if (item.IsDir())
1259 {
1260 RINOK(extractCallback->PrepareOperation(askMode))
1261 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
1262 continue;
1263 }
1264
1265 totalPackSize += _db.GetItemPackSize(item.Size);
1266 totalSize += item.Size;
1267
1268 if (!testMode && !outStream)
1269 continue;
795 RINOK(extractCallback->PrepareOperation(askMode)) 1270 RINOK(extractCallback->PrepareOperation(askMode))
796 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
797 continue;
798 }
799
800 totalPackSize += _db.GetItemPackSize(item.Size);
801 totalSize += item.Size;
802
803 if (!testMode && !outStream)
804 continue;
805 RINOK(extractCallback->PrepareOperation(askMode))
806 res = NExtract::NOperationResult::kDataError;
807 CMyComPtr<ISequentialInStream> inStream;
808 HRESULT hres = GetStream(index, &inStream);
809 if (hres == S_FALSE)
810 res = NExtract::NOperationResult::kDataError; 1271 res = NExtract::NOperationResult::kDataError;
811 else if (hres == E_NOTIMPL) 1272 CMyComPtr<ISequentialInStream> inStream;
812 res = NExtract::NOperationResult::kUnsupportedMethod; 1273 const HRESULT hres = GetStream(index, &inStream);
813 else 1274 if (hres == S_FALSE)
814 { 1275 res = NExtract::NOperationResult::kDataError;
815 RINOK(hres) 1276 /*
816 if (inStream) 1277 else if (hres == E_NOTIMPL)
1278 res = NExtract::NOperationResult::kUnsupportedMethod;
1279 */
1280 else
817 { 1281 {
818 RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) 1282 RINOK(hres)
819 if (copyCoder->TotalSize == item.Size) 1283 if (inStream)
820 res = NExtract::NOperationResult::kOK; 1284 {
1285 RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps))
1286 if (copyCoder->TotalSize == item.Size)
1287 res = NExtract::NOperationResult::kOK;
1288 }
821 } 1289 }
822 } 1290 }
823 }
824 RINOK(extractCallback->SetOperationResult(res)) 1291 RINOK(extractCallback->SetOperationResult(res))
825 } 1292 }
826 return S_OK; 1293 return S_OK;
@@ -839,20 +1306,64 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
839 *stream = NULL; 1306 *stream = NULL;
840 const UInt32 itemIndex = _db.Refs[index].Did; 1307 const UInt32 itemIndex = _db.Refs[index].Did;
841 const CItem &item = _db.Items[itemIndex]; 1308 const CItem &item = _db.Items[itemIndex];
1309 if (item.IsDir())
1310 return S_FALSE;
1311 const bool isLargeStream = (itemIndex == 0 || IsLargeStream(item.Size));
1312 if (!isLargeStream)
1313 {
1314 CBufferInStream *streamSpec = new CBufferInStream;
1315 CMyComPtr<IInStream> streamTemp = streamSpec;
1316
1317 UInt32 size = (UInt32)item.Size;
1318 streamSpec->Buf.Alloc(size);
1319 streamSpec->Init();
1320
1321 UInt32 sid = item.Sid;
1322 Byte *dest = streamSpec->Buf;
1323
1324 UInt64 phyPos = 0;
1325 while (size)
1326 {
1327 if (sid >= _db.MatSize)
1328 return S_FALSE;
1329 const unsigned subBits = _db.SectorSizeBits - k_MiniSectorSizeBits;
1330 const UInt32 fid = sid >> subBits;
1331 if (fid >= _db.NumSectors_in_MiniStream)
1332 return false;
1333 const UInt64 offset = (((UInt64)_db.MiniSids[fid] + 1) << _db.SectorSizeBits) +
1334 ((sid & ((1u << subBits) - 1)) << k_MiniSectorSizeBits);
1335 if (phyPos != offset)
1336 {
1337 RINOK(InStream_SeekSet(_stream, offset))
1338 phyPos = offset;
1339 }
1340 UInt32 readSize = (UInt32)1 << k_MiniSectorSizeBits;
1341 if (readSize > size)
1342 readSize = size;
1343 RINOK(ReadStream_FALSE(_stream, dest, readSize))
1344 phyPos += readSize;
1345 dest += readSize;
1346 sid = _db.Mat[sid];
1347 size -= readSize;
1348 }
1349 if (sid != NFatID::kEndOfChain)
1350 return S_FALSE;
1351 *stream = streamTemp.Detach();
1352 return S_OK;
1353 }
1354
842 CClusterInStream *streamSpec = new CClusterInStream; 1355 CClusterInStream *streamSpec = new CClusterInStream;
843 CMyComPtr<ISequentialInStream> streamTemp = streamSpec; 1356 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
844 streamSpec->Stream = _stream; 1357 streamSpec->Stream = _stream;
845 streamSpec->StartOffset = 0; 1358 streamSpec->StartOffset = 0;
846 1359 const unsigned bsLog = _db.SectorSizeBits;
847 const bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size));
848 const unsigned bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
849 streamSpec->BlockSizeLog = bsLog; 1360 streamSpec->BlockSizeLog = bsLog;
850 streamSpec->Size = item.Size; 1361 streamSpec->Size = item.Size;
851 1362
852 const UInt32 clusterSize = (UInt32)1 << bsLog; 1363 const UInt32 clusterSize = (UInt32)1 << bsLog;
853 const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; 1364 const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
854 if (numClusters64 >= ((UInt32)1 << 31)) 1365 if (numClusters64 > _db.FatSize)
855 return E_NOTIMPL; 1366 return S_FALSE;
856 streamSpec->Vector.ClearAndReserve((unsigned)numClusters64); 1367 streamSpec->Vector.ClearAndReserve((unsigned)numClusters64);
857 UInt32 sid = item.Sid; 1368 UInt32 sid = item.Sid;
858 UInt64 size = item.Size; 1369 UInt64 size = item.Size;
@@ -861,21 +1372,10 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
861 { 1372 {
862 for (;; size -= clusterSize) 1373 for (;; size -= clusterSize)
863 { 1374 {
864 if (isLargeStream) 1375 if (sid >= _db.FatSize)
865 { 1376 return S_FALSE;
866 if (sid >= _db.FatSize) 1377 streamSpec->Vector.AddInReserved(sid + 1);
867 return S_FALSE; 1378 sid = _db.Fat[sid];
868 streamSpec->Vector.AddInReserved(sid + 1);
869 sid = _db.Fat[sid];
870 }
871 else
872 {
873 UInt64 val = 0;
874 if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
875 return S_FALSE;
876 streamSpec->Vector.AddInReserved((UInt32)val);
877 sid = _db.Mat[sid];
878 }
879 if (size <= clusterSize) 1379 if (size <= clusterSize)
880 break; 1380 break;
881 } 1381 }
@@ -889,7 +1389,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
889} 1389}
890 1390
891REGISTER_ARC_I( 1391REGISTER_ARC_I(
892 "Compound", "msi msp doc xls ppt", NULL, 0xE5, 1392 "Compound", "msi msp msm doc xls ppt aaf", NULL, 0xe5,
893 kSignature, 1393 kSignature,
894 0, 1394 0,
895 0, 1395 0,
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index 62184f0..e1d6d81 100644
--- a/CPP/7zip/Archive/CpioHandler.cpp
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -927,7 +927,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
927 { 927 {
928#ifdef _WIN32 928#ifdef _WIN32
929 UString u; 929 UString u;
930 ConvertUTF8ToUnicode(item.Name, u); 930 ConvertUTF8ToUnicode(s, u);
931#else 931#else
932 const UString u = MultiByteToUnicodeString(s, CP_OEMCP); 932 const UString u = MultiByteToUnicodeString(s, CP_OEMCP);
933#endif 933#endif
diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp
index b072880..6edf86d 100644
--- a/CPP/7zip/Archive/QcowHandler.cpp
+++ b/CPP/7zip/Archive/QcowHandler.cpp
@@ -482,6 +482,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
482 if (_phySize < headerSize) 482 if (_phySize < headerSize)
483 _phySize = headerSize; 483 _phySize = headerSize;
484 484
485 // we use 32 MiB limit for L1 size, as QEMU with QCOW_MAX_L1_SIZE limit.
486 if (l1Size > (1u << 22)) // if (l1Size > (1u << (sizeof(size_t) * 8 - 4)))
487 return S_FALSE;
488
485 _isArc = true; 489 _isArc = true;
486 { 490 {
487 const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8); 491 const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8);
@@ -519,7 +523,6 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
519 } 523 }
520 CObjArray<UInt64> table64(l1Size); 524 CObjArray<UInt64> table64(l1Size);
521 { 525 {
522 // if ((t1SizeBytes >> 3) != l1Size) return S_FALSE;
523 RINOK(InStream_SeekSet(stream, l1Offset)) 526 RINOK(InStream_SeekSet(stream, l1Offset))
524 RINOK(ReadStream_FALSE(stream, table64, t1SizeBytes)) 527 RINOK(ReadStream_FALSE(stream, table64, t1SizeBytes))
525 } 528 }
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
index a639d8b..c15ff52 100644
--- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -8,6 +8,7 @@
8#include "../../../Common/ComTry.h" 8#include "../../../Common/ComTry.h"
9#include "../../../Common/IntToString.h" 9#include "../../../Common/IntToString.h"
10#include "../../../Common/MyBuffer2.h" 10#include "../../../Common/MyBuffer2.h"
11#include "../../../Common/MyLinux.h"
11#include "../../../Common/UTFConvert.h" 12#include "../../../Common/UTFConvert.h"
12 13
13#include "../../../Windows/PropVariantUtils.h" 14#include "../../../Windows/PropVariantUtils.h"
@@ -1184,7 +1185,15 @@ HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSiz
1184 1185
1185 const UInt64 processedSize = outStream->GetPos(); 1186 const UInt64 processedSize = outStream->GetPos();
1186 if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size) 1187 if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size)
1187 res = S_FALSE; 1188 {
1189 // rar_v7.13-: linux archive contains symLink with (packSize == 0 && lastItem.Size != 0)
1190 // v25.02: we ignore such record in rar headers:
1191 if (packSize != 0
1192 || method != 0
1193 || lastItem.HostOS != kHost_Unix
1194 || !MY_LIN_S_ISLNK(lastItem.Attrib))
1195 res = S_FALSE;
1196 }
1188 1197
1189 // if (res == S_OK) 1198 // if (res == S_OK)
1190 { 1199 {
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index dfbad33..6c53847 100644
--- a/CPP/7zip/Archive/Rar/RarHandler.cpp
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -7,6 +7,7 @@
7#include "../../../Common/ComTry.h" 7#include "../../../Common/ComTry.h"
8#include "../../../Common/IntToString.h" 8#include "../../../Common/IntToString.h"
9#include "../../../Common/MyBuffer2.h" 9#include "../../../Common/MyBuffer2.h"
10#include "../../../Common/MyLinux.h"
10#include "../../../Common/UTFConvert.h" 11#include "../../../Common/UTFConvert.h"
11 12
12#include "../../../Windows/PropVariantUtils.h" 13#include "../../../Windows/PropVariantUtils.h"
@@ -70,8 +71,14 @@ bool CItem::IsDir() const
70 case NHeader::NFile::kHostMSDOS: 71 case NHeader::NFile::kHostMSDOS:
71 case NHeader::NFile::kHostOS2: 72 case NHeader::NFile::kHostOS2:
72 case NHeader::NFile::kHostWin32: 73 case NHeader::NFile::kHostWin32:
73 if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) 74 if (Attrib & FILE_ATTRIBUTE_DIRECTORY)
74 return true; 75 return true;
76 break;
77 case NHeader::NFile::kHostUnix:
78 case NHeader::NFile::kHostBeOS:
79 if (MY_LIN_S_ISDIR(Attrib))
80 return true;
81 break;
75 } 82 }
76 return false; 83 return false;
77} 84}
@@ -86,11 +93,20 @@ UInt32 CItem::GetWinAttrib() const
86 case NHeader::NFile::kHostWin32: 93 case NHeader::NFile::kHostWin32:
87 a = Attrib; 94 a = Attrib;
88 break; 95 break;
96 case NHeader::NFile::kHostUnix:
97 case NHeader::NFile::kHostBeOS:
98 a = Attrib << 16;
99 a |= 0x8000; // add posix mode marker
100 break;
101 // case NHeader::NFile::kHostMacOS:
102 // kHostMacOS was used only by some very old rare case rar.
103 // New rar4-rar7 for macos probably uses kHostUnix.
104 // So we process kHostMacOS without attribute parsing:
89 default: 105 default:
90 a = 0; // must be converted from unix value; 106 a = 0;
91 } 107 }
92 if (IsDir()) 108 if (IsDir())
93 a |= NHeader::NFile::kWinFileDirectoryAttributeMask; 109 a |= FILE_ATTRIBUTE_DIRECTORY;
94 return a; 110 return a;
95} 111}
96 112
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
index 29f28e8..5761ea3 100644
--- a/CPP/7zip/Archive/Tar/TarHandler.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -65,7 +65,7 @@ static const Byte kArcProps[] =
65 kpidComment 65 kpidComment
66}; 66};
67 67
68static const char *k_Characts_Prefix = "PREFIX"; 68static const char * const k_Characts_Prefix = "PREFIX";
69 69
70IMP_IInArchive_Props 70IMP_IInArchive_Props
71IMP_IInArchive_ArcProps 71IMP_IInArchive_ArcProps
@@ -684,10 +684,14 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
684 s.Add_OptSpaced("SCHILY.fflags="); 684 s.Add_OptSpaced("SCHILY.fflags=");
685 s += item->SCHILY_fflags; 685 s += item->SCHILY_fflags;
686 } 686 }
687 if (item->Is_Sparse())
688 s.Add_OptSpaced("SPARSE");
687 if (item->IsThereWarning()) 689 if (item->IsThereWarning())
688 s.Add_OptSpaced("WARNING"); 690 s.Add_OptSpaced("WARNING");
689 if (item->HeaderError) 691 if (item->HeaderError)
690 s.Add_OptSpaced("ERROR"); 692 s.Add_OptSpaced("ERROR");
693 if (item->Method_Error)
694 s.Add_OptSpaced("METHOD_ERROR");
691 if (item->Pax_Error) 695 if (item->Pax_Error)
692 s.Add_OptSpaced("PAX_error"); 696 s.Add_OptSpaced("PAX_error");
693 if (!item->PaxExtra.RawLines.IsEmpty()) 697 if (!item->PaxExtra.RawLines.IsEmpty())
@@ -812,11 +816,16 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
812 inStream2 = inStream; 816 inStream2 = inStream;
813 else 817 else
814 { 818 {
815 GetStream(index, &inStream2); 819 const HRESULT hres = GetStream(index, &inStream2);
816 if (!inStream2) 820 if (hres == E_NOTIMPL)
817 return E_FAIL; 821 opRes = NExtract::NOperationResult::kHeadersError; // kUnsupportedMethod
822 else if (!inStream2)
823 {
824 opRes = NExtract::NOperationResult::kDataError;
825 // return E_FAIL;
826 }
818 } 827 }
819 828 if (opRes == NExtract::NOperationResult::kOK)
820 { 829 {
821 if (item->Is_SymLink()) 830 if (item->Is_SymLink())
822 { 831 {
@@ -855,9 +864,9 @@ Z7_CLASS_IMP_IInStream(
855 bool _needStartSeek; 864 bool _needStartSeek;
856 865
857public: 866public:
867 unsigned ItemIndex;
858 CHandler *Handler; 868 CHandler *Handler;
859 CMyComPtr<IUnknown> HandlerRef; 869 CMyComPtr<IUnknown> HandlerRef;
860 unsigned ItemIndex;
861 CRecordVector<UInt64> PhyOffsets; 870 CRecordVector<UInt64> PhyOffsets;
862 871
863 void Init() 872 void Init()
@@ -879,7 +888,7 @@ Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
879 if (_virtPos >= item.Size) 888 if (_virtPos >= item.Size)
880 return S_OK; 889 return S_OK;
881 { 890 {
882 UInt64 rem = item.Size - _virtPos; 891 const UInt64 rem = item.Size - _virtPos;
883 if (size > rem) 892 if (size > rem)
884 size = (UInt32)rem; 893 size = (UInt32)rem;
885 } 894 }
@@ -903,17 +912,17 @@ Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
903 } 912 }
904 913
905 const CSparseBlock &sb = item.SparseBlocks[left]; 914 const CSparseBlock &sb = item.SparseBlocks[left];
906 UInt64 relat = _virtPos - sb.Offset; 915 const UInt64 relat = _virtPos - sb.Offset;
907 916
908 if (_virtPos >= sb.Offset && relat < sb.Size) 917 if (_virtPos >= sb.Offset && relat < sb.Size)
909 { 918 {
910 UInt64 rem = sb.Size - relat; 919 const UInt64 rem = sb.Size - relat;
911 if (size > rem) 920 if (size > rem)
912 size = (UInt32)rem; 921 size = (UInt32)rem;
913 UInt64 phyPos = PhyOffsets[left] + relat; 922 const UInt64 phyPos = PhyOffsets[left] + relat;
914 if (_needStartSeek || _phyPos != phyPos) 923 if (_needStartSeek || _phyPos != phyPos)
915 { 924 {
916 RINOK(InStream_SeekSet(Handler->_stream, (item.Get_DataPos() + phyPos))) 925 RINOK(InStream_SeekSet(Handler->_stream, item.Get_DataPos() + phyPos))
917 _needStartSeek = false; 926 _needStartSeek = false;
918 _phyPos = phyPos; 927 _phyPos = phyPos;
919 } 928 }
@@ -927,7 +936,7 @@ Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
927 next = sb.Offset; 936 next = sb.Offset;
928 else if (left + 1 < item.SparseBlocks.Size()) 937 else if (left + 1 < item.SparseBlocks.Size())
929 next = item.SparseBlocks[left + 1].Offset; 938 next = item.SparseBlocks[left + 1].Offset;
930 UInt64 rem = next - _virtPos; 939 const UInt64 rem = next - _virtPos;
931 if (size > rem) 940 if (size > rem)
932 size = (UInt32)rem; 941 size = (UInt32)rem;
933 memset(data, 0, size); 942 memset(data, 0, size);
@@ -965,6 +974,8 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
965 974
966 if (item.Is_Sparse()) 975 if (item.Is_Sparse())
967 { 976 {
977 if (item.Method_Error)
978 return E_NOTIMPL; // S_FALSE
968 CSparseStream *streamSpec = new CSparseStream; 979 CSparseStream *streamSpec = new CSparseStream;
969 CMyComPtr<IInStream> streamTemp = streamSpec; 980 CMyComPtr<IInStream> streamTemp = streamSpec;
970 streamSpec->Init(); 981 streamSpec->Init();
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
index 22b8902..e702b68 100644
--- a/CPP/7zip/Archive/Tar/TarIn.cpp
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -181,6 +181,7 @@ HRESULT CArchive::GetNextItemReal(CItemEx &item)
181{ 181{
182 char buf[NFileHeader::kRecordSize]; 182 char buf[NFileHeader::kRecordSize];
183 183
184 item.Method_Error = false;
184 error = k_ErrorType_OK; 185 error = k_ErrorType_OK;
185 filled = false; 186 filled = false;
186 187
@@ -218,10 +219,7 @@ HRESULT CArchive::GetNextItemReal(CItemEx &item)
218 break; 219 break;
219 item.HeaderSize += NFileHeader::kRecordSize; 220 item.HeaderSize += NFileHeader::kRecordSize;
220 thereAreEmptyRecords = true; 221 thereAreEmptyRecords = true;
221 if (OpenCallback) 222 RINOK(Progress(item, 0))
222 {
223 RINOK(Progress(item, 0))
224 }
225 } 223 }
226 if (thereAreEmptyRecords) 224 if (thereAreEmptyRecords)
227 { 225 {
@@ -335,84 +333,83 @@ HRESULT CArchive::GetNextItemReal(CItemEx &item)
335 333
336 if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) 334 if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse)
337 { 335 {
338 Byte isExtended = (Byte)buf[482]; 336 // OLD GNU format: parse sparse file information:
339 if (isExtended != 0 && isExtended != 1) 337 // PackSize = cumulative size of all non-empty blocks of the file.
340 return S_OK; 338 // We read actual file size from 'realsize' member of oldgnu_header:
341 RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin)) 339 RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin))
342 UInt64 min = 0; 340 if (item.Size < item.PackSize) // additional check
343 for (unsigned i = 0; i < 4; i++)
344 {
345 p = buf + 386 + 24 * i;
346 if (GetBe32(p) == 0)
347 {
348 if (isExtended != 0)
349 return S_OK;
350 break;
351 }
352 CSparseBlock sb;
353 RIF(ParseSize(p, sb.Offset))
354 RIF(ParseSize(p + 12, sb.Size))
355 item.SparseBlocks.Add(sb);
356 if (sb.Offset < min || sb.Offset > item.Size)
357 return S_OK;
358 if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
359 return S_OK;
360 min = sb.Offset + sb.Size;
361 if (min < sb.Offset)
362 return S_OK;
363 }
364 if (min > item.Size)
365 return S_OK; 341 return S_OK;
366 342
367 while (isExtended != 0) 343 p = buf + 386;
368 { 344
369 size_t processedSize = NFileHeader::kRecordSize; 345 UInt64 end = 0, packSum = 0;
370 RINOK(ReadStream(SeqStream, buf, &processedSize)) 346 unsigned numRecords = 4;
371 if (processedSize != NFileHeader::kRecordSize) 347 unsigned isExtended = (Byte)p[4 * 24]; // (Byte)p[numRecords * 24];
372 { 348 // the list of blocks contains non-empty blocks. All another data is empty.
373 error = k_ErrorType_UnexpectedEnd;
374 return S_OK;
375 }
376
377 item.HeaderSize += NFileHeader::kRecordSize;
378
379 if (OpenCallback)
380 {
381 RINOK(Progress(item, 0))
382 }
383 349
384 isExtended = (Byte)buf[21 * 24]; 350 for (;;)
385 if (isExtended != 0 && isExtended != 1) 351 {
352 // const unsigned isExtended = (Byte)p[numRecords * 24];
353 if (isExtended > 1)
386 return S_OK; 354 return S_OK;
387 for (unsigned i = 0; i < 21; i++) 355 do
388 { 356 {
389 p = buf + 24 * i;
390 if (GetBe32(p) == 0) 357 if (GetBe32(p) == 0)
391 { 358 {
392 if (isExtended != 0) 359 if (isExtended)
393 return S_OK; 360 return S_OK;
394 break; 361 break;
395 } 362 }
396 CSparseBlock sb; 363 CSparseBlock sb;
397 RIF(ParseSize(p, sb.Offset)) 364 RIF(ParseSize(p, sb.Offset))
398 RIF(ParseSize(p + 12, sb.Size)) 365 RIF(ParseSize(p + 12, sb.Size))
399 item.SparseBlocks.Add(sb); 366 p += 24;
400 if (sb.Offset < min || sb.Offset > item.Size) 367 /* for all non-last blocks we expect :
401 return S_OK; 368 ((sb.Size & 0x1ff) == 0) && ((sb.Offset & 0x1ff) == 0)
402 if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) 369 for last block : (sb.Size == 0) is possible.
403 return S_OK; 370 */
404 min = sb.Offset + sb.Size; 371 if (sb.Offset < end
405 if (min < sb.Offset) 372 || item.Size < sb.Offset
373 || item.Size - sb.Offset < sb.Size)
406 return S_OK; 374 return S_OK;
375 // optional check:
376 if (sb.Size && ((end & 0x1ff) || (sb.Offset & 0x1ff)))
377 {
378 item.Method_Error = true; // relaxed check
379 // return S_OK;
380 }
381 end = sb.Offset + sb.Size;
382 packSum += sb.Size;
383 item.SparseBlocks.Add(sb);
384 }
385 while (--numRecords);
386
387 if (!isExtended)
388 break;
389
390 size_t processedSize = NFileHeader::kRecordSize;
391 RINOK(ReadStream(SeqStream, buf, &processedSize))
392 if (processedSize != NFileHeader::kRecordSize)
393 {
394 error = k_ErrorType_UnexpectedEnd;
395 return S_OK;
407 } 396 }
397 item.HeaderSize += NFileHeader::kRecordSize;
398 RINOK(Progress(item, 0))
399 p = buf;
400 numRecords = 21;
401 isExtended = (Byte)p[21 * 24]; // (Byte)p[numRecords * 24];
402 }
403 // optional checks for strict size consistency:
404 if (end != item.Size || packSum != item.PackSize)
405 {
406 item.Method_Error = true; // relaxed check
407 // return S_OK;
408 } 408 }
409 if (min > item.Size)
410 return S_OK;
411 } 409 }
412 410
413 if (item.PackSize >= (UInt64)1 << 63) 411 if (item.PackSize >= (UInt64)1 << 63) // optional check. It was checked in ParseSize() already
414 return S_OK; 412 return S_OK;
415
416 filled = true; 413 filled = true;
417 error = k_ErrorType_OK; 414 error = k_ErrorType_OK;
418 return S_OK; 415 return S_OK;
@@ -421,6 +418,8 @@ HRESULT CArchive::GetNextItemReal(CItemEx &item)
421 418
422HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset) 419HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset)
423{ 420{
421 if (!OpenCallback)
422 return S_OK;
424 const UInt64 pos = item.Get_DataPos() + posOffset; 423 const UInt64 pos = item.Get_DataPos() + posOffset;
425 if (NumFiles - NumFiles_Prev < (1 << 16) 424 if (NumFiles - NumFiles_Prev < (1 << 16)
426 // && NumRecords - NumRecords_Prev < (1 << 16) 425 // && NumRecords - NumRecords_Prev < (1 << 16)
@@ -500,10 +499,7 @@ HRESULT CArchive::ReadDataToBuffer(const CItemEx &item,
500 499
501 do 500 do
502 { 501 {
503 if (OpenCallback) 502 RINOK(Progress(item, pos))
504 {
505 RINOK(Progress(item, pos))
506 }
507 503
508 unsigned size = kBufSize; 504 unsigned size = kBufSize;
509 if (size > packSize) 505 if (size > packSize)
@@ -813,6 +809,7 @@ HRESULT CArchive::ReadItem2(CItemEx &item)
813 item.LongLink_WasUsed_2 = false; 809 item.LongLink_WasUsed_2 = false;
814 810
815 item.HeaderError = false; 811 item.HeaderError = false;
812 item.Method_Error = false;
816 item.IsSignedChecksum = false; 813 item.IsSignedChecksum = false;
817 item.Prefix_WasUsed = false; 814 item.Prefix_WasUsed = false;
818 815
@@ -838,13 +835,8 @@ HRESULT CArchive::ReadItem2(CItemEx &item)
838 835
839 for (;;) 836 for (;;)
840 { 837 {
841 if (OpenCallback) 838 RINOK(Progress(item, 0))
842 {
843 RINOK(Progress(item, 0))
844 }
845
846 RINOK(GetNextItemReal(item)) 839 RINOK(GetNextItemReal(item))
847
848 // NumRecords++; 840 // NumRecords++;
849 841
850 if (!filled) 842 if (!filled)
@@ -1064,9 +1056,14 @@ HRESULT CArchive::ReadItem2(CItemEx &item)
1064 // GNU TAR ignores (item.Size) in that case 1056 // GNU TAR ignores (item.Size) in that case
1065 if (item.Size != 0 && item.Size != piSize) 1057 if (item.Size != 0 && item.Size != piSize)
1066 item.Pax_Error = true; 1058 item.Pax_Error = true;
1067 item.Size = piSize; 1059 if (piSize >= ((UInt64)1 << 63))
1068 item.PackSize = piSize; 1060 item.Pax_Error = true;
1069 item.pax_size_WasUsed = true; 1061 else
1062 {
1063 item.Size = piSize;
1064 item.PackSize = piSize;
1065 item.pax_size_WasUsed = true;
1066 }
1070 } 1067 }
1071 1068
1072 item.PaxTimes = paxInfo; 1069 item.PaxTimes = paxInfo;
diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h
index 112f38d..d4e2ea5 100644
--- a/CPP/7zip/Archive/Tar/TarItem.h
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -322,6 +322,7 @@ struct CPaxExtra
322struct CItemEx: public CItem 322struct CItemEx: public CItem
323{ 323{
324 bool HeaderError; 324 bool HeaderError;
325 bool Method_Error;
325 326
326 bool IsSignedChecksum; 327 bool IsSignedChecksum;
327 bool Prefix_WasUsed; 328 bool Prefix_WasUsed;
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index ce87c54..a9e4ebf 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -500,10 +500,15 @@ size_t CFileId::Parse(const Byte *p, size_t size)
500 processed += impLen; 500 processed += impLen;
501 Id.Parse(p + processed, idLen); 501 Id.Parse(p + processed, idLen);
502 processed += idLen; 502 processed += idLen;
503 // const size_t processed2 = processed;
503 for (;(processed & 3) != 0; processed++) 504 for (;(processed & 3) != 0; processed++)
504 if (p[processed] != 0) 505 if (p[processed] != 0)
505 return 0; 506 return 0;
506 if ((size_t)tag.CrcLen + 16 != processed) return 0; 507 // some program can create non-standard UDF file where CrcLen doesn't include Padding data
508 if ((size_t)tag.CrcLen + 16 != processed
509 // && (size_t)tag.CrcLen + 16 != processed2 // we can enable this check to support non-standard UDF
510 )
511 return 0;
507 return (processed <= size) ? processed : 0; 512 return (processed <= size) ? processed : 0;
508} 513}
509 514
@@ -577,15 +582,20 @@ HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDes
577 582
578 item.IcbTag.Parse(p + 16); 583 item.IcbTag.Parse(p + 16);
579 584
585 // maybe another FileType values are possible in rare cases.
586 // Shoud we ignore FileType here?
580 if (fsIndex < 0) 587 if (fsIndex < 0)
581 { 588 {
589 // if (item.IcbTag.FileType == ICB_FILE_TYPE_DIR) return S_FALSE;
582 if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA && 590 if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA &&
583 item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR) 591 item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR &&
592 item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_BITMAP)
584 return S_FALSE; 593 return S_FALSE;
585 } 594 }
586 else if ( 595 else if (
587 item.IcbTag.FileType != ICB_FILE_TYPE_DIR && 596 item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
588 item.IcbTag.FileType != ICB_FILE_TYPE_FILE) 597 item.IcbTag.FileType != ICB_FILE_TYPE_FILE &&
598 item.IcbTag.FileType != ICB_FILE_TYPE_REAL_TIME_FILE) // M2TS files in /BDMV/STREAM/ in Blu-ray movie
589 return S_FALSE; 599 return S_FALSE;
590 600
591 item.Parse(p); 601 item.Parse(p);
@@ -1210,7 +1220,7 @@ HRESULT CInArchive::Open2()
1210 if (tag.Id != DESC_TYPE_FileSet) 1220 if (tag.Id != DESC_TYPE_FileSet)
1211 return S_FALSE; 1221 return S_FALSE;
1212 1222
1213 PRF(printf("\n FileSet", volIndex)); 1223 PRF(printf("\n FileSet"));
1214 CFileSet fs; 1224 CFileSet fs;
1215 fs.RecordingTime.Parse(p + 16); 1225 fs.RecordingTime.Parse(p + 16);
1216 // fs.InterchangeLevel = Get16(p + 18); 1226 // fs.InterchangeLevel = Get16(p + 18);
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
index 9ccbf74..cbe1a27 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.h
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -250,9 +250,10 @@ enum EIcbFileType
250{ 250{
251 ICB_FILE_TYPE_DIR = 4, 251 ICB_FILE_TYPE_DIR = 4,
252 ICB_FILE_TYPE_FILE = 5, 252 ICB_FILE_TYPE_FILE = 5,
253 253 ICB_FILE_TYPE_REAL_TIME_FILE = 249, // 2.3.5.2.1
254 ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File 254 ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1
255 ICB_FILE_TYPE_METADATA_MIRROR = 251 255 ICB_FILE_TYPE_METADATA_MIRROR = 251, // 2.2.13.1
256 ICB_FILE_TYPE_METADATA_BITMAP = 252 // 2.2.13.2
256}; 257};
257 258
258enum EIcbDescriptorType 259enum EIcbDescriptorType
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
index 788810f..9d77e87 100644
--- a/CPP/7zip/Archive/Zip/ZipIn.cpp
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -1718,61 +1718,49 @@ HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
1718 1718
1719HRESULT CInArchive::FindCd(bool checkOffsetMode) 1719HRESULT CInArchive::FindCd(bool checkOffsetMode)
1720{ 1720{
1721 CCdInfo &cdInfo = Vols.ecd;
1722
1723 UInt64 endPos;
1724
1725 // There are no useful data in cache in most cases here. 1721 // There are no useful data in cache in most cases here.
1726 // So here we don't use cache data from previous operations . 1722 // So here we don't use cache data from previous operations.
1727
1728 InitBuf(); 1723 InitBuf();
1724 UInt64 endPos;
1729 RINOK(InStream_GetSize_SeekToEnd(Stream, endPos)) 1725 RINOK(InStream_GetSize_SeekToEnd(Stream, endPos))
1730 _streamPos = endPos; 1726 _streamPos = endPos;
1731 1727 const size_t kBufSizeMax = (size_t)1 << 17; // must be larger than
1732 // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; 1728 // (1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize
1733 const size_t kBufSizeMax = ((size_t)1 << 17); // must be larger than kBufSizeMax2
1734
1735 const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax; 1729 const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax;
1736 if (bufSize < kEcdSize) 1730 if (bufSize < kEcdSize)
1737 return S_FALSE; 1731 return S_FALSE;
1738 // CByteArr byteBuffer(bufSize);
1739
1740 RINOK(AllocateBuffer(kBufSizeMax)) 1732 RINOK(AllocateBuffer(kBufSizeMax))
1733 {
1734 RINOK(Seek_SavePos(endPos - bufSize))
1735 size_t processed = bufSize;
1736 const HRESULT res = ReadStream(Stream, Buffer, &processed);
1737 _streamPos += processed;
1738 _bufCached = processed;
1739 _bufPos = 0;
1740 _cnt += processed;
1741 if (res != S_OK)
1742 return res;
1743 if (processed != bufSize)
1744 return S_FALSE;
1745 }
1741 1746
1742 RINOK(Seek_SavePos(endPos - bufSize)) 1747 CCdInfo &cdInfo = Vols.ecd;
1743
1744 size_t processed = bufSize;
1745 HRESULT res = ReadStream(Stream, Buffer, &processed);
1746 _streamPos += processed;
1747 _bufCached = processed;
1748 _bufPos = 0;
1749 _cnt += processed;
1750 if (res != S_OK)
1751 return res;
1752 if (processed != bufSize)
1753 return S_FALSE;
1754
1755 1748
1756 for (size_t i = bufSize - kEcdSize + 1;;) 1749 for (size_t i = bufSize - kEcdSize + 1;;)
1757 { 1750 {
1758 if (i == 0)
1759 return S_FALSE;
1760
1761 const Byte *buf = Buffer; 1751 const Byte *buf = Buffer;
1762
1763 for (;;)
1764 { 1752 {
1765 i--; 1753 const Byte *p = buf + i;
1766 if (buf[i] == 0x50) 1754 do
1767 break; 1755 if (p == buf)
1768 if (i == 0) 1756 return S_FALSE;
1769 return S_FALSE; 1757 while (*(--p) != 0x50);
1770 }
1771
1772 if (Get32(buf + i) != NSignature::kEcd)
1773 continue;
1774 1758
1775 cdInfo.ParseEcd32(buf + i); 1759 i = (size_t)(p - buf);
1760 if (Get32(p) != NSignature::kEcd)
1761 continue;
1762 cdInfo.ParseEcd32(p);
1763 }
1776 1764
1777 if (i >= kEcd64Locator_Size) 1765 if (i >= kEcd64Locator_Size)
1778 { 1766 {
@@ -1793,29 +1781,24 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode)
1793 1781
1794 // Most of the zip64 use fixed size Zip64 ECD 1782 // Most of the zip64 use fixed size Zip64 ECD
1795 // we try relative backward reading. 1783 // we try relative backward reading.
1796 1784 const UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize);
1797 UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize);
1798 1785
1799 if (locatorIndex >= kEcd64_FullSize) 1786 if (locatorIndex >= kEcd64_FullSize)
1800 if (checkOffsetMode || absEcd64 == locator.Ecd64Offset) 1787 if (checkOffsetMode || absEcd64 == locator.Ecd64Offset)
1801 { 1788 {
1802 const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize; 1789 const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize;
1803 if (Get32(ecd64) == NSignature::kEcd64) 1790 if (Get32(ecd64) == NSignature::kEcd64 &&
1791 Get64(ecd64 + 4) == kEcd64_MainSize)
1804 { 1792 {
1805 UInt64 mainEcd64Size = Get64(ecd64 + 4); 1793 cdInfo.ParseEcd64e(ecd64 + 12);
1806 if (mainEcd64Size == kEcd64_MainSize) 1794 ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset);
1807 { 1795 // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
1808 cdInfo.ParseEcd64e(ecd64 + 12); 1796 return S_OK;
1809 ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset);
1810 // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
1811 return S_OK;
1812 }
1813 } 1797 }
1814 } 1798 }
1815 1799
1816 // some zip64 use variable size Zip64 ECD. 1800 // some zip64 use variable size Zip64 ECD.
1817 // we try to use absolute offset from locator. 1801 // we try to use absolute offset from locator.
1818
1819 if (absEcd64 != locator.Ecd64Offset) 1802 if (absEcd64 != locator.Ecd64Offset)
1820 { 1803 {
1821 if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK) 1804 if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK)
@@ -1881,6 +1864,9 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn
1881 items.Clear(); 1864 items.Clear();
1882 IsCdUnsorted = false; 1865 IsCdUnsorted = false;
1883 1866
1867 if ((Int64)cdOffset < 0)
1868 return S_FALSE;
1869
1884 // _startLocalFromCd_Disk = (UInt32)(Int32)-1; 1870 // _startLocalFromCd_Disk = (UInt32)(Int32)-1;
1885 // _startLocalFromCd_Offset = (UInt64)(Int64)-1; 1871 // _startLocalFromCd_Offset = (UInt64)(Int64)-1;
1886 1872
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp
index 63f1a71..e8a21c2 100644
--- a/CPP/7zip/Archive/Zip/ZipOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -49,42 +49,54 @@ void COutArchive::SeekToCurPos()
49// #define DOES_NEED_ZIP64(v) (v >= 0) 49// #define DOES_NEED_ZIP64(v) (v >= 0)
50 50
51 51
52Z7_NO_INLINE
52void COutArchive::WriteBytes(const void *data, size_t size) 53void COutArchive::WriteBytes(const void *data, size_t size)
53{ 54{
54 m_OutBuffer.WriteBytes(data, size); 55 m_OutBuffer.WriteBytes(data, size);
55 m_CurPos += size; 56 m_CurPos += size;
56} 57}
57 58
59Z7_NO_INLINE
58void COutArchive::Write8(Byte b) 60void COutArchive::Write8(Byte b)
59{ 61{
60 m_OutBuffer.WriteByte(b); 62 m_OutBuffer.WriteByte(b);
61 m_CurPos++; 63 m_CurPos++;
62} 64}
63 65
66Z7_NO_INLINE
64void COutArchive::Write16(UInt16 val) 67void COutArchive::Write16(UInt16 val)
65{ 68{
66 Write8((Byte)val); 69 Write8((Byte)val);
67 Write8((Byte)(val >> 8)); 70 Write8((Byte)(val >> 8));
68} 71}
69 72
73Z7_NO_INLINE
70void COutArchive::Write32(UInt32 val) 74void COutArchive::Write32(UInt32 val)
71{ 75{
72 for (int i = 0; i < 4; i++) 76 for (int i = 0; i < 4; i++)
73 { 77 {
74 Write8((Byte)val); 78 // Write8((Byte)val);
79 m_OutBuffer.WriteByte((Byte)val);
75 val >>= 8; 80 val >>= 8;
76 } 81 }
82 m_CurPos += 4;
77} 83}
78 84
85#define WRITE_CONST_PAIR_16_16(a, b) { Write32((a) | ((UInt32)(b) << 16)); }
86
87Z7_NO_INLINE
79void COutArchive::Write64(UInt64 val) 88void COutArchive::Write64(UInt64 val)
80{ 89{
81 for (int i = 0; i < 8; i++) 90 for (int i = 0; i < 8; i++)
82 { 91 {
83 Write8((Byte)val); 92 // Write8((Byte)val);
93 m_OutBuffer.WriteByte((Byte)val);
84 val >>= 8; 94 val >>= 8;
85 } 95 }
96 m_CurPos += 8;
86} 97}
87 98
99Z7_NO_INLINE
88void COutArchive::WriteExtra(const CExtraBlock &extra) 100void COutArchive::WriteExtra(const CExtraBlock &extra)
89{ 101{
90 FOR_VECTOR (i, extra.SubBlocks) 102 FOR_VECTOR (i, extra.SubBlocks)
@@ -134,11 +146,9 @@ void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
134 if (writeNtfs) 146 if (writeNtfs)
135 { 147 {
136 // windows explorer ignores that extra 148 // windows explorer ignores that extra
137 Write16(NFileHeader::NExtraID::kNTFS); 149 WRITE_CONST_PAIR_16_16(NFileHeader::NExtraID::kNTFS, k_Ntfs_ExtraSize)
138 Write16(k_Ntfs_ExtraSize);
139 Write32(0); // reserved 150 Write32(0); // reserved
140 Write16(NFileHeader::NNtfsExtra::kTagTime); 151 WRITE_CONST_PAIR_16_16(NFileHeader::NNtfsExtra::kTagTime, 8 * 3)
141 Write16(8 * 3);
142 WriteNtfsTime(item.Ntfs_MTime); 152 WriteNtfsTime(item.Ntfs_MTime);
143 WriteNtfsTime(item.Ntfs_ATime); 153 WriteNtfsTime(item.Ntfs_ATime);
144 WriteNtfsTime(item.Ntfs_CTime); 154 WriteNtfsTime(item.Ntfs_CTime);
@@ -148,8 +158,7 @@ void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
148 { 158 {
149 // windows explorer ignores that extra 159 // windows explorer ignores that extra
150 // by specification : should we write to local header also? 160 // by specification : should we write to local header also?
151 Write16(NFileHeader::NExtraID::kUnixTime); 161 WRITE_CONST_PAIR_16_16(NFileHeader::NExtraID::kUnixTime, k_UnixTime_ExtraSize)
152 Write16(k_UnixTime_ExtraSize);
153 const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime); 162 const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
154 Write8(flags); 163 Write8(flags);
155 UInt32 unixTime; 164 UInt32 unixTime;
@@ -217,8 +226,7 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
217 226
218 if (isZip64) 227 if (isZip64)
219 { 228 {
220 Write16(NFileHeader::NExtraID::kZip64); 229 WRITE_CONST_PAIR_16_16(NFileHeader::NExtraID::kZip64, 8 + 8)
221 Write16(8 + 8);
222 Write64(size); 230 Write64(size);
223 Write64(packSize); 231 Write64(packSize);
224 } 232 }
@@ -357,8 +365,9 @@ HRESULT COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const
357 const UInt64 cdSize = cd64EndOffset - cdOffset; 365 const UInt64 cdSize = cd64EndOffset - cdOffset;
358 const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); 366 const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
359 const bool cdSize64 = DOES_NEED_ZIP64(cdSize); 367 const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
360 const bool items64 = items.Size() >= 0xFFFF; 368 const bool need_Items_64 = items.Size() >= 0xFFFF;
361 const bool isZip64 = (cdOffset64 || cdSize64 || items64); 369 const unsigned items16 = (UInt16)(need_Items_64 ? 0xFFFF: items.Size());
370 const bool isZip64 = (cdOffset64 || cdSize64 || need_Items_64);
362 371
363 // isZip64 = true; // to test Zip64 372 // isZip64 = true; // to test Zip64
364 373
@@ -371,8 +380,8 @@ HRESULT COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const
371 // const UInt32 extraSize = 1 << 26; 380 // const UInt32 extraSize = 1 << 26;
372 // Write64(kEcd64_MainSize + extraSize); 381 // Write64(kEcd64_MainSize + extraSize);
373 382
374 Write16(45); // made by version 383 WRITE_CONST_PAIR_16_16(45, // made by version
375 Write16(45); // extract version 384 45) // extract version
376 Write32(0); // ThisDiskNumber 385 Write32(0); // ThisDiskNumber
377 Write32(0); // StartCentralDirectoryDiskNumber 386 Write32(0); // StartCentralDirectoryDiskNumber
378 Write64((UInt64)items.Size()); 387 Write64((UInt64)items.Size());
@@ -389,10 +398,9 @@ HRESULT COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const
389 } 398 }
390 399
391 Write32(NSignature::kEcd); 400 Write32(NSignature::kEcd);
392 Write16(0); // ThisDiskNumber 401 WRITE_CONST_PAIR_16_16(0, 0) // ThisDiskNumber, StartCentralDirectoryDiskNumber
393 Write16(0); // StartCentralDirectoryDiskNumber 402 Write16((UInt16)items16);
394 Write16((UInt16)(items64 ? 0xFFFF: items.Size())); 403 Write16((UInt16)items16);
395 Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
396 404
397 WRITE_32_VAL_SPEC(cdSize, cdSize64) 405 WRITE_32_VAL_SPEC(cdSize, cdSize64)
398 WRITE_32_VAL_SPEC(cdOffset, cdOffset64) 406 WRITE_32_VAL_SPEC(cdOffset, cdOffset64)
diff --git a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
index aac4e28..9e2d13d 100644
--- a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
+++ b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
@@ -153,7 +153,7 @@ namespace NCommandType
153 }; 153 };
154} 154}
155 155
156static const char *g_Commands = "txl"; 156static const char * const g_Commands = "txl";
157 157
158struct CArchiveCommand 158struct CArchiveCommand
159{ 159{
diff --git a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
index 0c09807..d4240d9 100644
--- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -48,72 +48,60 @@ static bool ReadDataString(CFSTR fileName, LPCSTR startID,
48 NIO::CInFile inFile; 48 NIO::CInFile inFile;
49 if (!inFile.Open(fileName)) 49 if (!inFile.Open(fileName))
50 return false; 50 return false;
51 const size_t kBufferSize = (1 << 12); 51 const size_t kBufferSize = 1 << 12;
52 52
53 Byte buffer[kBufferSize]; 53 Byte buffer[kBufferSize];
54 const unsigned signatureStartSize = MyStringLen(startID); 54 const size_t signatureStartSize = MyStringLen(startID + 1);
55 const unsigned signatureEndSize = MyStringLen(endID); 55 const size_t signatureEndSize = MyStringLen(endID + 1);
56 56
57 size_t numBytesPrev = 0; 57 size_t numBytesPrev = 0;
58 bool writeMode = false; 58 bool writeMode = false;
59 UInt64 posTotal = 0; 59 UInt32 posTotal = 0;
60 for (;;) 60 for (;;)
61 { 61 {
62 if (posTotal > (1 << 20))
63 return (stringResult.IsEmpty());
64 const size_t numReadBytes = kBufferSize - numBytesPrev; 62 const size_t numReadBytes = kBufferSize - numBytesPrev;
65 size_t processedSize; 63 size_t processedSize;
66 if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize)) 64 if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize))
67 return false; 65 return false;
68 if (processedSize == 0) 66 if (processedSize == 0)
69 return true; 67 return true;
70 const size_t numBytesInBuffer = numBytesPrev + processedSize; 68 numBytesPrev += processedSize;
71 UInt32 pos = 0; 69 size_t pos = 0;
72 for (;;) 70 for (;;)
73 { 71 {
74 if (writeMode) 72 if (writeMode)
75 { 73 {
76 if (pos + signatureEndSize > numBytesInBuffer) 74 if (pos + signatureEndSize > numBytesPrev)
77 break; 75 break;
78 if (memcmp(buffer + pos, endID, signatureEndSize) == 0) 76 const Byte b = buffer[pos++];
79 return true;
80 const Byte b = buffer[pos];
81 if (b == 0) 77 if (b == 0)
82 return false; 78 return false;
79 if (b == ';' && memcmp(buffer + pos, endID + 1, signatureEndSize) == 0)
80 return true;
83 stringResult += (char)b; 81 stringResult += (char)b;
84 pos++;
85 } 82 }
86 else 83 else
87 { 84 {
88 if (pos + signatureStartSize > numBytesInBuffer) 85 if (pos + signatureStartSize > numBytesPrev)
89 break; 86 break;
90 if (memcmp(buffer + pos, startID, signatureStartSize) == 0) 87 const Byte b = buffer[pos++];
88 if (b == ';' && memcmp(buffer + pos, startID + 1, signatureStartSize) == 0)
91 { 89 {
92 writeMode = true; 90 writeMode = true;
93 pos += signatureStartSize; 91 pos += signatureStartSize;
94 } 92 }
95 else
96 pos++;
97 } 93 }
98 } 94 }
99 numBytesPrev = numBytesInBuffer - pos; 95 posTotal += (UInt32)pos;
100 posTotal += pos; 96 if (posTotal > (1 << 21))
97 return stringResult.IsEmpty();
98 numBytesPrev -= pos;
101 memmove(buffer, buffer + pos, numBytesPrev); 99 memmove(buffer, buffer + pos, numBytesPrev);
102 } 100 }
103} 101}
104 102
105static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 }; 103static const char * const kStartID = ",!@Install@!UTF-8!";
106static char kEndID[] = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 }; 104static const char * const kEndID = ",!@InstallEnd@!";
107
108static struct CInstallIDInit
109{
110 CInstallIDInit()
111 {
112 kStartID[0] = ';';
113 kEndID[0] = ';';
114 }
115} g_CInstallIDInit;
116
117 105
118#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) 106#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
119#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1; 107#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp
index f90e280..b7e4fbe 100644
--- a/CPP/7zip/Common/FileStreams.cpp
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -753,7 +753,7 @@ Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
753 { 753 {
754 if (StoreOwnerName) 754 if (StoreOwnerName)
755 { 755 {
756 const uid_t gid = st.st_gid; 756 const gid_t gid = st.st_gid;
757 { 757 {
758 if (!OwnerGroup.IsEmpty() && _gid == gid) 758 if (!OwnerGroup.IsEmpty() && _gid == gid)
759 prop = OwnerGroup; 759 prop = OwnerGroup;
diff --git a/CPP/7zip/Common/FileStreams.h b/CPP/7zip/Common/FileStreams.h
index 212d4f0..7f465cf 100644
--- a/CPP/7zip/Common/FileStreams.h
+++ b/CPP/7zip/Common/FileStreams.h
@@ -84,8 +84,8 @@ public:
84 BY_HANDLE_FILE_INFORMATION _info; 84 BY_HANDLE_FILE_INFORMATION _info;
85 #else 85 #else
86 struct stat _info; 86 struct stat _info;
87 UInt32 _uid; 87 uid_t _uid; // uid_t can be unsigned or signed int
88 UInt32 _gid; 88 gid_t _gid;
89 UString OwnerName; 89 UString OwnerName;
90 UString OwnerGroup; 90 UString OwnerGroup;
91 bool StoreOwnerId; 91 bool StoreOwnerId;
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
index 7fe18fb..73974e6 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -426,7 +426,7 @@ static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
426 } 426 }
427} 427}
428 428
429static const char *g_Commands = "audtexlbih"; 429static const char * const g_Commands = "audtexlbih";
430 430
431static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command) 431static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
432{ 432{
diff --git a/CPP/7zip/UI/Common/ArchiveName.cpp b/CPP/7zip/UI/Common/ArchiveName.cpp
index 3c0976d..f859d94 100644
--- a/CPP/7zip/UI/Common/ArchiveName.cpp
+++ b/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -17,14 +17,14 @@ using namespace NWindows;
17using namespace NFile; 17using namespace NFile;
18 18
19 19
20static const char *g_ArcExts = 20static const char * const g_ArcExts =
21 "7z" 21 "7z"
22 "\0" "zip" 22 "\0" "zip"
23 "\0" "tar" 23 "\0" "tar"
24 "\0" "wim" 24 "\0" "wim"
25 "\0"; 25 "\0";
26 26
27static const char *g_HashExts = 27static const char * const g_HashExts =
28 "sha256" 28 "sha256"
29 "\0"; 29 "\0";
30 30
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp
index eb24e7f..316c980 100644
--- a/CPP/7zip/UI/Common/Bench.cpp
+++ b/CPP/7zip/UI/Common/Bench.cpp
@@ -3038,7 +3038,7 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
3038 FOR_VECTOR (i, ti.Groups.GroupSizes) 3038 FOR_VECTOR (i, ti.Groups.GroupSizes)
3039 { 3039 {
3040 if (i != 0) 3040 if (i != 0)
3041 s.Add_Char(' '); 3041 s.Add_Space();
3042 s.Add_UInt32(ti.Groups.GroupSizes[i]); 3042 s.Add_UInt32(ti.Groups.GroupSizes[i]);
3043 } 3043 }
3044 } 3044 }
@@ -3773,10 +3773,11 @@ HRESULT Bench(
3773 3773
3774 #ifndef Z7_ST 3774 #ifndef Z7_ST
3775 3775
3776 if (threadsInfo.Get() && threadsInfo.GetNumProcessThreads() != 0) 3776 if (!threadsInfo.Get()
3777 numCPUs = threadsInfo.GetNumProcessThreads(); 3777 || (numCPUs = threadsInfo.GetNumProcessThreads()) == 0)
3778 else
3779 numCPUs = NSystem::GetNumberOfProcessors(); 3778 numCPUs = NSystem::GetNumberOfProcessors();
3779 // numCPUs : is number of threads assigned to process with affinity,
3780 // or it's total number of threads in all groups, if IsGroupMode == true, and there is default affinity.
3780 3781
3781 #endif 3782 #endif
3782 3783
diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp
index 874caef..2d9f5a3 100644
--- a/CPP/7zip/UI/Console/List.cpp
+++ b/CPP/7zip/UI/Console/List.cpp
@@ -201,8 +201,8 @@ static const CFieldInfoInit kStandardFieldTable[] =
201 { kpidPath, "Name", kLeft, kLeft, 2, 24 } 201 { kpidPath, "Name", kLeft, kLeft, 2, 24 }
202}; 202};
203 203
204const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width 204static const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
205static const char *g_Spaces = 205static const char * const g_Spaces =
206" " ; 206" " ;
207 207
208static void PrintSpaces(unsigned numSpaces) 208static void PrintSpaces(unsigned numSpaces)
diff --git a/CPP/7zip/UI/FileManager/BrowseDialog2.cpp b/CPP/7zip/UI/FileManager/BrowseDialog2.cpp
index ee98ab4..9f083c5 100644
--- a/CPP/7zip/UI/FileManager/BrowseDialog2.cpp
+++ b/CPP/7zip/UI/FileManager/BrowseDialog2.cpp
@@ -9,6 +9,7 @@
9#include <windowsx.h> 9#include <windowsx.h>
10 10
11#include "../../../Common/IntToString.h" 11#include "../../../Common/IntToString.h"
12#include "../../../Common/MyCom.h"
12#include "../../../Common/StringConvert.h" 13#include "../../../Common/StringConvert.h"
13#include "../../../Common/Wildcard.h" 14#include "../../../Common/Wildcard.h"
14 15
@@ -19,6 +20,7 @@
19#include "../../../Windows/Menu.h" 20#include "../../../Windows/Menu.h"
20#include "../../../Windows/ProcessUtils.h" 21#include "../../../Windows/ProcessUtils.h"
21#include "../../../Windows/PropVariantConv.h" 22#include "../../../Windows/PropVariantConv.h"
23#include "../../../Windows/Shell.h"
22#include "../../../Windows/Control/ComboBox.h" 24#include "../../../Windows/Control/ComboBox.h"
23#include "../../../Windows/Control/Dialog.h" 25#include "../../../Windows/Control/Dialog.h"
24#include "../../../Windows/Control/Edit.h" 26#include "../../../Windows/Control/Edit.h"
@@ -57,7 +59,7 @@ static const int kParentIndex = -1;
57// static const UINT k_Message_RefreshPathEdit = WM_APP + 1; 59// static const UINT k_Message_RefreshPathEdit = WM_APP + 1;
58 60
59 61
60static const wchar_t *k_Message_Link_operation_was_Blocked = 62static const wchar_t * const k_Message_Link_operation_was_Blocked =
61 L"link openning was blocked by 7-Zip"; 63 L"link openning was blocked by 7-Zip";
62 64
63extern UString HResultToMessage(HRESULT errorCode); 65extern UString HResultToMessage(HRESULT errorCode);
@@ -978,35 +980,61 @@ void CBrowseDialog2::OnHelp()
978#endif 980#endif
979 981
980 982
983HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder,
984 HWND hwnd, const UString &path, LPITEMIDLIST *ppidl);
985
981HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process); 986HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process);
982HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process) 987HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process)
983{ 988{
984 UString path2 = path; 989 UString path2 = path;
985 990 UINT32 result;
986 #ifdef _WIN32 991 {
992#ifdef _WIN32
993 NShell::CItemIDList pidl;
994 // SHELLEXECUTEINFO::pidl is more accurate way than SHELLEXECUTEINFO::lpFile
995 {
996 CMyComPtr<IShellFolder> desktop;
997 if (SHGetDesktopFolder(&desktop) == S_OK && desktop)
998 if (ShellFolder_ParseDisplayName(desktop,
999 NULL, // HWND : do we need (window) or NULL here?
1000 path,
1001 &pidl) != S_OK)
1002 pidl.Detach();
1003 }
987 { 1004 {
988 const int dot = path2.ReverseFind_Dot(); 1005 const int dot = path2.ReverseFind_Dot();
989 const int separ = path2.ReverseFind_PathSepar(); 1006 const int separ = path2.ReverseFind_PathSepar();
990 if (dot < 0 || dot < separ) 1007 if (separ != (int)path2.Len() - 1)
991 path2.Add_Dot(); 1008 if (dot < 0 || dot < separ)
1009 path2.Add_Dot();
992 } 1010 }
993 #endif 1011#endif // _WIN32
994 1012
995 UINT32 result;
996
997#ifndef _UNICODE 1013#ifndef _UNICODE
998 if (g_IsNT) 1014 if (g_IsNT)
999 { 1015 {
1000 SHELLEXECUTEINFOW execInfo; 1016 SHELLEXECUTEINFOW execInfo;
1017 memset(&execInfo, 0, sizeof(execInfo));
1018 // execInfo.hwnd = NULL;
1019 // execInfo.lpVerb = NULL;
1020 // execInfo.lpFile = NULL;
1021 // execInfo.lpDirectory = NULL;
1022 // execInfo.lpParameters = NULL;
1023 // execInfo.hProcess = NULL;
1001 execInfo.cbSize = sizeof(execInfo); 1024 execInfo.cbSize = sizeof(execInfo);
1002 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; 1025 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
1003 execInfo.hwnd = NULL; 1026 if (!dir.IsEmpty())
1004 execInfo.lpVerb = NULL; 1027 execInfo.lpDirectory = dir;
1005 execInfo.lpFile = path2;
1006 execInfo.lpParameters = NULL;
1007 execInfo.lpDirectory = dir.IsEmpty() ? NULL : (LPCWSTR)dir;
1008 execInfo.nShow = SW_SHOWNORMAL; 1028 execInfo.nShow = SW_SHOWNORMAL;
1009 execInfo.hProcess = NULL; 1029
1030 if ((LPCITEMIDLIST)pidl)
1031 {
1032 execInfo.lpIDList = pidl;
1033 execInfo.fMask |= SEE_MASK_IDLIST;
1034 }
1035 else
1036 execInfo.lpFile = path2;
1037
1010typedef BOOL (WINAPI * Func_ShellExecuteExW)(LPSHELLEXECUTEINFOW lpExecInfo); 1038typedef BOOL (WINAPI * Func_ShellExecuteExW)(LPSHELLEXECUTEINFOW lpExecInfo);
1011Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION 1039Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
1012 const 1040 const
@@ -1024,34 +1052,40 @@ Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
1024#endif 1052#endif
1025 { 1053 {
1026 SHELLEXECUTEINFO execInfo; 1054 SHELLEXECUTEINFO execInfo;
1055 memset(&execInfo, 0, sizeof(execInfo));
1056 // execInfo.hwnd = NULL;
1057 // execInfo.lpVerb = NULL;
1058 // execInfo.lpFile = NULL;
1059 // execInfo.lpDirectory = NULL;
1060 // execInfo.lpParameters = NULL;
1061 // execInfo.hProcess = NULL;
1027 execInfo.cbSize = sizeof(execInfo); 1062 execInfo.cbSize = sizeof(execInfo);
1028 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS 1063 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
1029 #ifndef UNDER_CE 1064 #ifndef UNDER_CE
1030 | SEE_MASK_FLAG_DDEWAIT 1065 | SEE_MASK_FLAG_DDEWAIT
1031 #endif 1066 #endif
1032 ; 1067 ;
1033 execInfo.hwnd = NULL; 1068 execInfo.nShow = SW_SHOWNORMAL;
1034 execInfo.lpVerb = NULL;
1035 const CSysString sysPath (GetSystemString(path2)); 1069 const CSysString sysPath (GetSystemString(path2));
1036 const CSysString sysDir (GetSystemString(dir)); 1070 const CSysString sysDir (GetSystemString(dir));
1037 execInfo.lpFile = sysPath; 1071 #ifndef UNDER_CE
1038 execInfo.lpParameters = NULL; 1072 if (!sysDir.IsEmpty())
1039 execInfo.lpDirectory = 1073 execInfo.lpDirectory = sysDir;
1040 #ifdef UNDER_CE 1074 #endif
1041 NULL 1075
1042 #else 1076 if ((LPCITEMIDLIST)pidl)
1043 sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir 1077 {
1044 #endif 1078 execInfo.lpIDList = pidl;
1045 ; 1079 execInfo.fMask |= SEE_MASK_IDLIST;
1046 execInfo.nShow = SW_SHOWNORMAL; 1080 }
1047 execInfo.hProcess = NULL; 1081 else
1082 execInfo.lpFile = sysPath;
1048 ::ShellExecuteEx(&execInfo); 1083 ::ShellExecuteEx(&execInfo);
1049 result = (UINT32)(UINT_PTR)execInfo.hInstApp; 1084 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
1050 process.Attach(execInfo.hProcess); 1085 process.Attach(execInfo.hProcess);
1051 } 1086 }
1052
1053 // DEBUG_PRINT_NUM("-- ShellExecuteEx -- execInfo.hInstApp = ", result) 1087 // DEBUG_PRINT_NUM("-- ShellExecuteEx -- execInfo.hInstApp = ", result)
1054 1088 }
1055 if (result <= 32) 1089 if (result <= 32)
1056 { 1090 {
1057 switch (result) 1091 switch (result)
@@ -1063,10 +1097,8 @@ Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
1063 // L"There is no application associated with the given file name extension", 1097 // L"There is no application associated with the given file name extension",
1064 ); 1098 );
1065 } 1099 }
1066
1067 return E_FAIL; // fixed in 15.13. Can we use it for any Windows version? 1100 return E_FAIL; // fixed in 15.13. Can we use it for any Windows version?
1068 } 1101 }
1069
1070 return S_OK; 1102 return S_OK;
1071} 1103}
1072 1104
diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp
index 7956d86..51dfaa9 100644
--- a/CPP/7zip/UI/FileManager/FSFolder.cpp
+++ b/CPP/7zip/UI/FileManager/FSFolder.cpp
@@ -748,8 +748,8 @@ Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPI
748 case kpidMTime: return CompareFileTime(&fi1.MTime, &fi2.MTime); 748 case kpidMTime: return CompareFileTime(&fi1.MTime, &fi2.MTime);
749 case kpidIsDir: 749 case kpidIsDir:
750 { 750 {
751 bool isDir1 = /* ss1 ? false : */ fi1.IsDir(); 751 const bool isDir1 = /* ss1 ? false : */ fi1.IsDir();
752 bool isDir2 = /* ss2 ? false : */ fi2.IsDir(); 752 const bool isDir2 = /* ss2 ? false : */ fi2.IsDir();
753 if (isDir1 == isDir2) 753 if (isDir1 == isDir2)
754 return 0; 754 return 0;
755 return isDir1 ? -1 : 1; 755 return isDir1 ? -1 : 1;
@@ -798,7 +798,9 @@ Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPI
798 return MyStringCompareNoCase(comment1, comment2); 798 return MyStringCompareNoCase(comment1, comment2);
799 } 799 }
800 case kpidPrefix: 800 case kpidPrefix:
801 if (fi1.Parent < 0) return (fi2.Parent < 0) ? 0 : -1; 801 if (fi1.Parent == fi2.Parent)
802 return 0;
803 if (fi1.Parent < 0) return -1;
802 if (fi2.Parent < 0) return 1; 804 if (fi2.Parent < 0) return 1;
803 return CompareFileNames_ForFolderList( 805 return CompareFileNames_ForFolderList(
804 Folders[fi1.Parent], 806 Folders[fi1.Parent],
diff --git a/CPP/7zip/UI/FileManager/LangPage.cpp b/CPP/7zip/UI/FileManager/LangPage.cpp
index 3aeaf13..626c91b 100644
--- a/CPP/7zip/UI/FileManager/LangPage.cpp
+++ b/CPP/7zip/UI/FileManager/LangPage.cpp
@@ -253,8 +253,7 @@ bool CLangPage::OnInit()
253 temp += " "; 253 temp += " ";
254 temp += rec.Mark; 254 temp += rec.Mark;
255 } 255 }
256 const int index = (int)_langCombo.AddString(temp); 256 const int index = (int)_langCombo.AddString_SetItemData(temp, (LPARAM)rec.LangInfoIndex);
257 _langCombo.SetItemData(index, (LPARAM)rec.LangInfoIndex);
258 if (rec.IsSelected) 257 if (rec.IsSelected)
259 _langCombo.SetCurSel(index); 258 _langCombo.SetCurSel(index);
260 } 259 }
diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp
index e8736b8..61dd8cb 100644
--- a/CPP/7zip/UI/FileManager/MenuPage.cpp
+++ b/CPP/7zip/UI/FileManager/MenuPage.cpp
@@ -222,8 +222,7 @@ bool CMenuPage::OnInit()
222 s.Add_UInt32(val); 222 s.Add_UInt32(val);
223 if (i == 0) 223 if (i == 0)
224 s.Insert(0, L"* "); 224 s.Insert(0, L"* ");
225 const int index = (int)_zoneCombo.AddString(s); 225 const int index = (int)_zoneCombo.AddString_SetItemData(s, (LPARAM)val);
226 _zoneCombo.SetItemData(index, (LPARAM)val);
227 if (val == wz) 226 if (val == wz)
228 _zoneCombo.SetCurSel(index); 227 _zoneCombo.SetCurSel(index);
229 } 228 }
diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
index aa56ef5..9d78368 100644
--- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
@@ -825,7 +825,10 @@ void CPanel::EditItem(unsigned index, bool useEditor)
825 return; 825 return;
826 } 826 }
827 CProcess process; 827 CProcess process;
828 StartEditApplication(GetItemFullPath(index), useEditor, (HWND)*this, process); 828 StartEditApplication(GetItemFullPath(index), useEditor,
829 // (HWND)*this,
830 GetParent(),
831 process);
829} 832}
830 833
831 834
@@ -854,7 +857,10 @@ void CPanel::OpenFolderExternal(unsigned index)
854 path.Add_PathSepar(); 857 path.Add_PathSepar();
855 } 858 }
856 859
857 StartApplicationDontWait(prefix, path, (HWND)*this); 860 StartApplicationDontWait(prefix, path,
861 // (HWND)*this
862 GetParent()
863 );
858} 864}
859 865
860 866
@@ -981,7 +987,10 @@ void CPanel::OpenItem(unsigned index, bool tryInternal, bool tryExternal, const
981 { 987 {
982 // SetCurrentDirectory opens HANDLE to folder!!! 988 // SetCurrentDirectory opens HANDLE to folder!!!
983 // NDirectory::MySetCurrentDirectory(prefix); 989 // NDirectory::MySetCurrentDirectory(prefix);
984 StartApplicationDontWait(prefix, fullPath, (HWND)*this); 990 StartApplicationDontWait(prefix, fullPath,
991 // (HWND)*this
992 GetParent()
993 );
985 } 994 }
986} 995}
987 996
@@ -1732,9 +1741,15 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1732 CProcess process; 1741 CProcess process;
1733 HRESULT res; 1742 HRESULT res;
1734 if (editMode) 1743 if (editMode)
1735 res = StartEditApplication(fs2us(tempFilePath), useEditor, (HWND)*this, process); 1744 res = StartEditApplication(fs2us(tempFilePath), useEditor,
1745 // (HWND)*this,
1746 GetParent(),
1747 process);
1736 else 1748 else
1737 res = StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath), (HWND)*this, process); 1749 res = StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath),
1750 // (HWND)*this,
1751 GetParent(),
1752 process);
1738 1753
1739 if ((HANDLE)process == NULL) 1754 if ((HANDLE)process == NULL)
1740 { 1755 {
diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp
index 9086996..e655843 100644
--- a/CPP/7zip/UI/FileManager/PanelMenu.cpp
+++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp
@@ -488,7 +488,9 @@ struct CFolderPidls
488}; 488};
489 489
490 490
491static HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder, 491HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder,
492 HWND hwnd, const UString &path, LPITEMIDLIST *ppidl);
493HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder,
492 HWND hwnd, const UString &path, LPITEMIDLIST *ppidl) 494 HWND hwnd, const UString &path, LPITEMIDLIST *ppidl)
493{ 495{
494 ULONG eaten = 0; 496 ULONG eaten = 0;
diff --git a/CPP/7zip/UI/FileManager/PanelSort.cpp b/CPP/7zip/UI/FileManager/PanelSort.cpp
index f95f8ee..57ac877 100644
--- a/CPP/7zip/UI/FileManager/PanelSort.cpp
+++ b/CPP/7zip/UI/FileManager/PanelSort.cpp
@@ -82,7 +82,7 @@ static inline const wchar_t *GetExtensionPtr(const UString &name)
82 82
83void CPanel::SetSortRawStatus() 83void CPanel::SetSortRawStatus()
84{ 84{
85 _isRawSortProp = false; 85 _isRawSortProp = 0; // false;
86 FOR_VECTOR (i, _columns) 86 FOR_VECTOR (i, _columns)
87 { 87 {
88 const CPropColumn &prop = _columns[i]; 88 const CPropColumn &prop = _columns[i];
@@ -95,21 +95,15 @@ void CPanel::SetSortRawStatus()
95} 95}
96 96
97 97
98static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) 98static int CALLBACK CompareItems2(const LPARAM lParam1, const LPARAM lParam2,
99 const CPanel * const panel, const PROPID propID, const Int32 isRawProp)
99{ 100{
100 if (lpData == 0)
101 return 0;
102 CPanel *panel = (CPanel*)lpData;
103
104
105 PROPID propID = panel->_sortID;
106
107 if (propID == kpidNoProperty) 101 if (propID == kpidNoProperty)
108 return MyCompare(lParam1, lParam2); 102 return MyCompare(lParam1, lParam2);
109 103
110 if (panel->_isRawSortProp) 104 if (isRawProp)
111 { 105 {
112 // Sha1, NtSecurity, NtReparse 106 // Sha1, Checksum, NtSecurity, NtReparse
113 const void *data1; 107 const void *data1;
114 const void *data2; 108 const void *data2;
115 UInt32 dataSize1; 109 UInt32 dataSize1;
@@ -135,7 +129,7 @@ static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
135 } 129 }
136 130
137 if (panel->_folderCompare) 131 if (panel->_folderCompare)
138 return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp); 132 return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, isRawProp);
139 133
140 switch (propID) 134 switch (propID)
141 { 135 {
@@ -189,16 +183,41 @@ int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
189 if (lParam1 == (int)kParentIndex) return -1; 183 if (lParam1 == (int)kParentIndex) return -1;
190 if (lParam2 == (int)kParentIndex) return 1; 184 if (lParam2 == (int)kParentIndex) return 1;
191 185
192 CPanel *panel = (CPanel*)lpData; 186 const CPanel *panel = (CPanel*)lpData;
193 187
194 const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1); 188 const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1);
195 const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2); 189 const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2);
196 190 if (isDir1 != isDir2)
197 if (isDir1 && !isDir2) return -1; 191 return isDir1 ? -1 : 1;
198 if (isDir2 && !isDir1) return 1;
199 192
200 const int result = CompareItems2(lParam1, lParam2, lpData); 193 /*
201 return panel->_ascending ? result: (-result); 194 we have up to 3 iterations:
195 1: prop,
196 2: kpidName, kpidPrefix
197 3: prop, kpidName, kpidPrefix
198 3: kpidPrefix, kpidName, kpidPrefix : is some rare case
199 */
200 PROPID propID = panel->_sortID;
201 int res = 0;
202 for (unsigned iter = 0; iter < 3; iter++)
203 {
204 res = CompareItems2(lParam1, lParam2, panel, propID,
205 iter ? 0 : panel->_isRawSortProp);
206 if (res)
207 break;
208 if (propID == kpidName)
209 {
210 // if (!_flatMode.IsEmpty()) break; // !_flatMode ;
211 propID = kpidPrefix;
212 continue;
213 }
214 if (iter)
215 break;
216 propID = kpidName;
217 }
218 if (res == 0)
219 res = MyCompare(lParam1, lParam2); // order of LoadSubItems()
220 return panel->_ascending ? res: -res;
202} 221}
203 222
204 223
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
index 1686c69..980161f 100644
--- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
@@ -440,11 +440,9 @@ static const size_t kMaxDicSize = (size_t)1 << (22 + sizeof(size_t) / 4 * 5);
440 440
441static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v) 441static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v)
442{ 442{
443 TCHAR s[16]; 443 WCHAR s[16];
444 ConvertUInt32ToString(v, s); 444 ConvertUInt32ToString(v, s);
445 const int index = (int)cb.AddString(s); 445 return (int)cb.AddString_SetItemData(s, (LPARAM)v);
446 cb.SetItemData(index, (LPARAM)v);
447 return index;
448} 446}
449 447
450 448
@@ -481,21 +479,17 @@ bool CBenchmarkDialog::OnInit()
481 _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE); 479 _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE);
482 } 480 }
483 481
484 UInt32 numCPUs = 1; 482 UInt32 numCPUs = 1; // process threads
483 UInt32 numCPUs_Sys = 1; // system threads
485 484
486 { 485 {
487 AString s ("/ ");
488
489 NSystem::CProcessAffinity threadsInfo; 486 NSystem::CProcessAffinity threadsInfo;
490 threadsInfo.InitST(); 487 threadsInfo.InitST();
488#ifndef Z7_ST
489 threadsInfo.Get_and_return_NumProcessThreads_and_SysThreads(numCPUs, numCPUs_Sys);
490#endif
491 491
492 #ifndef Z7_ST 492 AString s ("/ ");
493 if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
494 numCPUs = threadsInfo.GetNumProcessThreads();
495 else
496 numCPUs = NSystem::GetNumberOfProcessors();
497 #endif
498
499 s.Add_UInt32(numCPUs); 493 s.Add_UInt32(numCPUs);
500 s += GetProcessThreadsInfo(threadsInfo); 494 s += GetProcessThreadsInfo(threadsInfo);
501 SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s); 495 SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s);
@@ -506,10 +500,8 @@ bool CBenchmarkDialog::OnInit()
506 SetItemTextA(IDT_BENCH_SYS1, s); 500 SetItemTextA(IDT_BENCH_SYS1, s);
507 if (s != s2 && !s2.IsEmpty()) 501 if (s != s2 && !s2.IsEmpty())
508 SetItemTextA(IDT_BENCH_SYS2, s2); 502 SetItemTextA(IDT_BENCH_SYS2, s2);
509 } 503
510 { 504 GetCpuName_MultiLine(s, s2); // s2==registers
511 AString registers;
512 GetCpuName_MultiLine(s, registers);
513 SetItemTextA(IDT_BENCH_CPU, s); 505 SetItemTextA(IDT_BENCH_CPU, s);
514 } 506 }
515 { 507 {
@@ -526,22 +518,18 @@ bool CBenchmarkDialog::OnInit()
526 518
527 // ----- Num Threads ---------- 519 // ----- Num Threads ----------
528 520
529 if (numCPUs < 1)
530 numCPUs = 1;
531 numCPUs = MyMin(numCPUs, (UInt32)(1 << 6)); // it's WIN32 limit
532
533 UInt32 numThreads = Sync.NumThreads; 521 UInt32 numThreads = Sync.NumThreads;
534
535 if (numThreads == (UInt32)(Int32)-1) 522 if (numThreads == (UInt32)(Int32)-1)
536 numThreads = numCPUs; 523 numThreads = numCPUs;
537 if (numThreads > 1) 524 numThreads &= ~(UInt32)1;
538 numThreads &= ~(UInt32)1; 525 if (numThreads == 0)
539 const UInt32 kNumThreadsMax = (1 << 12); 526 numThreads = 1;
540 if (numThreads > kNumThreadsMax) 527 numThreads = MyMin(numThreads, (UInt32)(1u << 14));
541 numThreads = kNumThreadsMax;
542 528
543 m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS)); 529 m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS));
544 const UInt32 numTheads_Combo = numCPUs * 2; 530 if (numCPUs_Sys == 0)
531 numCPUs_Sys = 1;
532 const UInt32 numTheads_Combo = numCPUs_Sys * 2;
545 UInt32 v = 1; 533 UInt32 v = 1;
546 int cur = 0; 534 int cur = 0;
547 for (; v <= numTheads_Combo;) 535 for (; v <= numTheads_Combo;)
@@ -1069,16 +1057,17 @@ static void AddUsageString(UString &s, const CTotalBenchRes &info)
1069 numIter = 1000000; 1057 numIter = 1000000;
1070 UInt64 usage = GetUsagePercents(info.Usage / numIter); 1058 UInt64 usage = GetUsagePercents(info.Usage / numIter);
1071 1059
1072 wchar_t w[64]; 1060 wchar_t w[32];
1073 ConvertUInt64ToString(usage, w); 1061 wchar_t *p = ConvertUInt64ToString(usage, w);
1074 unsigned len = MyStringLen(w); 1062 p[0] = '%';
1063 p[1] = 0;
1064 unsigned len = (unsigned)(size_t)(p - w);
1075 while (len < 5) 1065 while (len < 5)
1076 { 1066 {
1077 s.Add_Space(); 1067 s.Add_Space();
1078 len++; 1068 len++;
1079 } 1069 }
1080 s += w; 1070 s += w;
1081 s += "%";
1082} 1071}
1083 1072
1084 1073
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp
index 85d7186..53e56fe 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.cpp
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -506,8 +506,7 @@ bool CCompressDialog::OnInit()
506 { 506 {
507 const unsigned arcIndex = ArcIndices[i]; 507 const unsigned arcIndex = ArcIndices[i];
508 const CArcInfoEx &ai = (*ArcFormats)[arcIndex]; 508 const CArcInfoEx &ai = (*ArcFormats)[arcIndex];
509 const int index = (int)m_Format.AddString(ai.Name); 509 const int index = (int)m_Format.AddString_SetItemData(ai.Name, (LPARAM)arcIndex);
510 m_Format.SetItemData(index, (LPARAM)arcIndex);
511 if (!needSetMain) 510 if (!needSetMain)
512 { 511 {
513 if (Info.FormatIndex == (int)arcIndex) 512 if (Info.FormatIndex == (int)arcIndex)
@@ -540,11 +539,6 @@ bool CCompressDialog::OnInit()
540 AddComboItems(m_PathMode, k_PathMode_IDs, Z7_ARRAY_SIZE(k_PathMode_IDs), 539 AddComboItems(m_PathMode, k_PathMode_IDs, Z7_ARRAY_SIZE(k_PathMode_IDs),
541 k_PathMode_Vals, Info.PathMode); 540 k_PathMode_Vals, Info.PathMode);
542 541
543
544 TCHAR s[32] = { TEXT('/'), TEXT(' '), 0 };
545 ConvertUInt32ToString(NSystem::GetNumberOfProcessors(), s + 2);
546 SetItemText(IDT_COMPRESS_HARDWARE_THREADS, s);
547
548 CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite); 542 CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite);
549 CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing); 543 CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing);
550 544
@@ -653,7 +647,19 @@ void CCompressDialog::EnableMultiCombo(unsigned id)
653 EnableItem(id, enable); 647 EnableItem(id, enable);
654} 648}
655 649
656static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s); 650static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s)
651{
652 return cb.AddString((CSysString)s);
653}
654
655static LRESULT ComboBox_AddStringAscii_SetItemData(NControl::CComboBox &cb,
656 const char *s, LPARAM lParam)
657{
658 const LRESULT index = ComboBox_AddStringAscii(cb, s);
659 if (index >= 0) // optional check
660 cb.SetItemData((int)index, lParam);
661 return index;
662}
657 663
658static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res) 664static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res)
659{ 665{
@@ -1604,20 +1610,14 @@ void CCompressDialog::SetLevel2()
1604 AddLangString(s, langID); 1610 AddLangString(s, langID);
1605 } 1611 }
1606 } 1612 }
1607 const int index = (int)m_Level.AddString(s); 1613 m_Level.AddString_SetItemData(s, (LPARAM)i);
1608 m_Level.SetItemData(index, (LPARAM)i);
1609 } 1614 }
1610 } 1615 }
1611 SetNearestSelectComboBox(m_Level, level); 1616 SetNearestSelectComboBox(m_Level, level);
1612} 1617}
1613 1618
1614 1619
1615static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s) 1620static const char * const k_Auto_Prefix = "* ";
1616{
1617 return cb.AddString((CSysString)s);
1618}
1619
1620static const char *k_Auto_Prefix = "* ";
1621 1621
1622static void Modify_Auto(AString &s) 1622static void Modify_Auto(AString &s)
1623{ 1623{
@@ -1690,8 +1690,8 @@ void CCompressDialog::SetMethod2(int keepMethodId)
1690 writtenMethodId = -1; 1690 writtenMethodId = -1;
1691 Modify_Auto(s); 1691 Modify_Auto(s);
1692 } 1692 }
1693 const int itemIndex = (int)ComboBox_AddStringAscii(m_Method, s); 1693 const int itemIndex = (int)ComboBox_AddStringAscii_SetItemData(m_Method,
1694 m_Method.SetItemData(itemIndex, writtenMethodId); 1694 s, writtenMethodId);
1695 if (keepMethodId == methodID) 1695 if (keepMethodId == methodID)
1696 { 1696 {
1697 m_Method.SetCurSel(itemIndex); 1697 m_Method.SetCurSel(itemIndex);
@@ -1731,7 +1731,7 @@ void CCompressDialog::SetEncryptionMethod()
1731 } 1731 }
1732 else if (ai.Is_Zip()) 1732 else if (ai.Is_Zip())
1733 { 1733 {
1734 int index = FindRegistryFormat(ai.Name); 1734 const int index = FindRegistryFormat(ai.Name);
1735 UString encryptionMethod; 1735 UString encryptionMethod;
1736 if (index >= 0) 1736 if (index >= 0)
1737 { 1737 {
@@ -1836,9 +1836,7 @@ static int Combo_AddDict2(NWindows::NControl::CComboBox &cb, size_t sizeReal, si
1836 s.Add_Char('B'); 1836 s.Add_Char('B');
1837 if (sizeReal == k_Auto_Dict) 1837 if (sizeReal == k_Auto_Dict)
1838 Modify_Auto(s); 1838 Modify_Auto(s);
1839 const int index = (int)ComboBox_AddStringAscii(cb, s); 1839 return (int)ComboBox_AddStringAscii_SetItemData(cb, s, (LPARAM)sizeReal);
1840 cb.SetItemData(index, (LPARAM)sizeReal);
1841 return index;
1842} 1840}
1843 1841
1844int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow) 1842int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow)
@@ -2201,9 +2199,7 @@ int CCompressDialog::AddOrder(UInt32 size)
2201{ 2199{
2202 char s[32]; 2200 char s[32];
2203 ConvertUInt32ToString(size, s); 2201 ConvertUInt32ToString(size, s);
2204 const int index = (int)ComboBox_AddStringAscii(m_Order, s); 2202 return (int)ComboBox_AddStringAscii_SetItemData(m_Order, s, (LPARAM)size);
2205 m_Order.SetItemData(index, (LPARAM)size);
2206 return index;
2207} 2203}
2208 2204
2209int CCompressDialog::AddOrder_Auto() 2205int CCompressDialog::AddOrder_Auto()
@@ -2211,9 +2207,7 @@ int CCompressDialog::AddOrder_Auto()
2211 AString s; 2207 AString s;
2212 s.Add_UInt32(_auto_Order); 2208 s.Add_UInt32(_auto_Order);
2213 Modify_Auto(s); 2209 Modify_Auto(s);
2214 int index = (int)ComboBox_AddStringAscii(m_Order, s); 2210 return (int)ComboBox_AddStringAscii_SetItemData(m_Order, s, (LPARAM)(INT_PTR)(-1));
2215 m_Order.SetItemData(index, (LPARAM)(INT_PTR)(-1));
2216 return index;
2217} 2211}
2218 2212
2219void CCompressDialog::SetOrder2() 2213void CCompressDialog::SetOrder2()
@@ -2490,9 +2484,7 @@ void CCompressDialog::SetSolidBlockSize2()
2490 AString s; 2484 AString s;
2491 Add_Size(s, _auto_Solid); 2485 Add_Size(s, _auto_Solid);
2492 Modify_Auto(s); 2486 Modify_Auto(s);
2493 const int index = (int)ComboBox_AddStringAscii(m_Solid, s); 2487 curSel = (int)ComboBox_AddStringAscii_SetItemData(m_Solid, s, (LPARAM)(UInt32)(Int32)-1);
2494 m_Solid.SetItemData(index, (LPARAM)(UInt32)(Int32)-1);
2495 curSel = index;
2496 } 2488 }
2497 2489
2498 if (is7z) 2490 if (is7z)
@@ -2501,8 +2493,7 @@ void CCompressDialog::SetSolidBlockSize2()
2501 // kSolidLog_NoSolid = 0 for xz means default blockSize 2493 // kSolidLog_NoSolid = 0 for xz means default blockSize
2502 if (is7z) 2494 if (is7z)
2503 LangString(IDS_COMPRESS_NON_SOLID, s); 2495 LangString(IDS_COMPRESS_NON_SOLID, s);
2504 const int index = (int)m_Solid.AddString(s); 2496 const int index = (int)m_Solid.AddString_SetItemData(s, (LPARAM)(UInt32)kSolidLog_NoSolid);
2505 m_Solid.SetItemData(index, (LPARAM)(UInt32)kSolidLog_NoSolid);
2506 if (defaultBlockSize == kSolidLog_NoSolid) 2497 if (defaultBlockSize == kSolidLog_NoSolid)
2507 curSel = index; 2498 curSel = index;
2508 } 2499 }
@@ -2511,16 +2502,15 @@ void CCompressDialog::SetSolidBlockSize2()
2511 { 2502 {
2512 AString s; 2503 AString s;
2513 Add_Size(s, (UInt64)1 << i); 2504 Add_Size(s, (UInt64)1 << i);
2514 const int index = (int)ComboBox_AddStringAscii(m_Solid, s); 2505 const int index = (int)ComboBox_AddStringAscii_SetItemData(m_Solid, s, (LPARAM)(UInt32)i);
2515 m_Solid.SetItemData(index, (LPARAM)(UInt32)i);
2516 if (defaultBlockSize != (UInt32)(Int32)-1) 2506 if (defaultBlockSize != (UInt32)(Int32)-1)
2517 if (i <= defaultBlockSize || index <= 1) 2507 if (i <= defaultBlockSize || index <= 1)
2518 curSel = index; 2508 curSel = index;
2519 } 2509 }
2520 2510
2521 { 2511 {
2522 const int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); 2512 const int index = (int)m_Solid.AddString_SetItemData(
2523 m_Solid.SetItemData(index, (LPARAM)kSolidLog_FullSolid); 2513 LangString(IDS_COMPRESS_SOLID), (LPARAM)kSolidLog_FullSolid);
2524 if (defaultBlockSize == kSolidLog_FullSolid) 2514 if (defaultBlockSize == kSolidLog_FullSolid)
2525 curSel = index; 2515 curSel = index;
2526 } 2516 }
@@ -2564,7 +2554,7 @@ static bool Is_Zstd_Mt_Supported()
2564} 2554}
2565*/ 2555*/
2566 2556
2567static const char *k_ST_Threads = " (ST)"; 2557static const char * const k_ST_Threads = " (ST)";
2568 2558
2569void CCompressDialog::SetNumThreads2() 2559void CCompressDialog::SetNumThreads2()
2570{ 2560{
@@ -2575,15 +2565,31 @@ void CCompressDialog::SetNumThreads2()
2575 if (!fi.MultiThread_()) 2565 if (!fi.MultiThread_())
2576 return; 2566 return;
2577 2567
2578 const UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); 2568 UInt32 numCPUs = 1; // process threads
2579 // 64; // for debug: 2569 UInt32 numHardwareThreads = 1; // system threads
2570 NSystem::CProcessAffinity threadsInfo;
2571 threadsInfo.InitST();
2572#ifndef Z7_ST
2573 threadsInfo.Get_and_return_NumProcessThreads_and_SysThreads(numCPUs, numHardwareThreads);
2574#endif
2580 2575
2581 UInt32 defaultValue = numHardwareThreads; 2576 AString s ("/ ");
2577 {
2578 s.Add_UInt32(numCPUs);
2579 if (numCPUs != numHardwareThreads)
2580 {
2581 s += " / ";
2582 s.Add_UInt32(numHardwareThreads);
2583 }
2584 SetItemTextA(IDT_COMPRESS_HARDWARE_THREADS, s.Ptr());
2585 }
2586
2587 UInt32 defaultValue = numCPUs;
2582 bool useAutoThreads = true; 2588 bool useAutoThreads = true;
2583 2589
2584 { 2590 {
2585 const CArcInfoEx &ai = Get_ArcInfoEx(); 2591 const CArcInfoEx &ai = Get_ArcInfoEx();
2586 int index = FindRegistryFormat(ai.Name); 2592 const int index = FindRegistryFormat(ai.Name);
2587 if (index >= 0) 2593 if (index >= 0)
2588 { 2594 {
2589 const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; 2595 const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
@@ -2597,19 +2603,19 @@ void CCompressDialog::SetNumThreads2()
2597 2603
2598 // const UInt32 num_ZSTD_threads_MAX = Is_Zstd_Mt_Supported() ? MY_ZSTDMT_NBWORKERS_MAX : 0; 2604 // const UInt32 num_ZSTD_threads_MAX = Is_Zstd_Mt_Supported() ? MY_ZSTDMT_NBWORKERS_MAX : 0;
2599 2605
2600 UInt32 numAlgoThreadsMax = numHardwareThreads * 2;
2601 const int methodID = GetMethodID(); 2606 const int methodID = GetMethodID();
2602
2603 const bool isZip = IsZipFormat(); 2607 const bool isZip = IsZipFormat();
2608
2609 UInt32 numAlgoThreadsMax = numHardwareThreads * 2; // for unknow methods
2604 if (isZip) 2610 if (isZip)
2605 numAlgoThreadsMax = 2611 numAlgoThreadsMax =
2606 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit 2612 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit
2607 else if (IsXzFormat()) 2613 else if (IsXzFormat())
2608 numAlgoThreadsMax = 256 * 2; 2614 numAlgoThreadsMax = 256 * 2; // MTCODER_THREADS_MAX * 2
2609 else switch (methodID) 2615 else switch (methodID)
2610 { 2616 {
2611 case kLZMA: numAlgoThreadsMax = 2; break; 2617 case kLZMA: numAlgoThreadsMax = 2; break;
2612 case kLZMA2: numAlgoThreadsMax = 256; break; 2618 case kLZMA2: numAlgoThreadsMax = 256 * 2; break; // MTCODER_THREADS_MAX * 2
2613 case kBZip2: numAlgoThreadsMax = 64; break; 2619 case kBZip2: numAlgoThreadsMax = 64; break;
2614 // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; 2620 // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break;
2615 case kCopy: 2621 case kCopy:
@@ -2619,9 +2625,9 @@ void CCompressDialog::SetNumThreads2()
2619 case kPPMdZip: 2625 case kPPMdZip:
2620 numAlgoThreadsMax = 1; 2626 numAlgoThreadsMax = 1;
2621 } 2627 }
2622 UInt32 autoThreads = numHardwareThreads; 2628 UInt32 autoThreads = numCPUs;
2623 if (autoThreads > numAlgoThreadsMax) 2629 if (autoThreads > numAlgoThreadsMax)
2624 autoThreads = numAlgoThreadsMax; 2630 autoThreads = numAlgoThreadsMax;
2625 2631
2626 const UInt64 memUse_Limit = Get_MemUse_Bytes(); 2632 const UInt64 memUse_Limit = Get_MemUse_Bytes();
2627 2633
@@ -2676,13 +2682,12 @@ void CCompressDialog::SetNumThreads2()
2676 2682
2677 int curSel = -1; 2683 int curSel = -1;
2678 { 2684 {
2679 AString s; 2685 s.Empty();
2680 s.Add_UInt32(autoThreads); 2686 s.Add_UInt32(autoThreads);
2681 if (autoThreads == 0) s += k_ST_Threads; 2687 if (autoThreads == 0) s += k_ST_Threads;
2682 Modify_Auto(s); 2688 Modify_Auto(s);
2683 const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); 2689 const int index = (int)ComboBox_AddStringAscii_SetItemData(m_NumThreads,
2684 m_NumThreads.SetItemData(index, (LPARAM)(INT_PTR)(-1)); 2690 s, (LPARAM)(INT_PTR)(-1));
2685 // m_NumThreads.SetItemData(index, autoThreads);
2686 if (useAutoThreads) 2691 if (useAutoThreads)
2687 curSel = index; 2692 curSel = index;
2688 } 2693 }
@@ -2693,11 +2698,11 @@ void CCompressDialog::SetNumThreads2()
2693 1; 2698 1;
2694 i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) 2699 i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++)
2695 { 2700 {
2696 AString s; 2701 s.Empty();
2697 s.Add_UInt32(i); 2702 s.Add_UInt32(i);
2698 if (i == 0) s += k_ST_Threads; 2703 if (i == 0) s += k_ST_Threads;
2699 const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); 2704 const int index = (int)ComboBox_AddStringAscii_SetItemData(m_NumThreads,
2700 m_NumThreads.SetItemData(index, (LPARAM)(UInt32)i); 2705 s, (LPARAM)(UInt32)i);
2701 if (!useAutoThreads && i == defaultValue) 2706 if (!useAutoThreads && i == defaultValue)
2702 curSel = index; 2707 curSel = index;
2703 } 2708 }
@@ -2754,9 +2759,7 @@ int CCompressDialog::AddMemComboItem(UInt64 val, bool isPercent, bool isDefault)
2754 sRegistry.DeleteBack(); 2759 sRegistry.DeleteBack();
2755 } 2760 }
2756 const unsigned dataIndex = _memUse_Strings.Add(sRegistry); 2761 const unsigned dataIndex = _memUse_Strings.Add(sRegistry);
2757 const int index = (int)m_MemUse.AddString(sUser); 2762 return (int)m_MemUse.AddString_SetItemData(sUser, (LPARAM)dataIndex);
2758 m_MemUse.SetItemData(index, (LPARAM)dataIndex);
2759 return index;
2760} 2763}
2761 2764
2762 2765
@@ -3439,11 +3442,7 @@ static const unsigned kTimePrec_1ns = 3;
3439static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL) 3442static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL)
3440{ 3443{
3441 // s += " : "; 3444 // s += " : ";
3442 { 3445 s.Add_UInt32(val);
3443 AString s2;
3444 s2.Add_UInt32(val);
3445 s += s2;
3446 }
3447 s.Add_Space(); 3446 s.Add_Space();
3448 s += unit; 3447 s += unit;
3449 if (sys) 3448 if (sys)
@@ -3476,9 +3475,7 @@ int COptionsDialog::AddPrec(unsigned prec, bool isDefault)
3476 } 3475 }
3477 else 3476 else
3478 s.Add_UInt32(prec); 3477 s.Add_UInt32(prec);
3479 const int index = (int)m_Prec.AddString(s); 3478 return (int)m_Prec.AddString_SetItemData(s, (LPARAM)writePrec);
3480 m_Prec.SetItemData(index, (LPARAM)writePrec);
3481 return index;
3482} 3479}
3483 3480
3484 3481
diff --git a/CPP/7zip/UI/GUI/CompressDialog.rc b/CPP/7zip/UI/GUI/CompressDialog.rc
index 9c3ed88..df1516c 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.rc
+++ b/CPP/7zip/UI/GUI/CompressDialog.rc
@@ -87,8 +87,8 @@ BEGIN
87 COMBOBOX IDC_COMPRESS_SOLID, g1x, 144, g1xs, 140, MY_COMBO 87 COMBOBOX IDC_COMPRESS_SOLID, g1x, 144, g1xs, 140, MY_COMBO
88 88
89 LTEXT "Number of CPU &threads:", IDT_COMPRESS_THREADS, m, 167, g0xs, 8 89 LTEXT "Number of CPU &threads:", IDT_COMPRESS_THREADS, m, 167, g0xs, 8
90 COMBOBOX IDC_COMPRESS_THREADS, g1x, 165, g1xs - 35, 140, MY_COMBO 90 COMBOBOX IDC_COMPRESS_THREADS, g1x, 165, g1xs - 40, 140, MY_COMBO
91 RTEXT "", IDT_COMPRESS_HARDWARE_THREADS, g1x + g1xs - 35 + 10, 167, 25, MY_TEXT_NOPREFIX 91 RTEXT "", IDT_COMPRESS_HARDWARE_THREADS, g1x + g1xs - 40, 167, 40, 16, SS_NOPREFIX
92 92
93 93
94 LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 184, g2xs, 8 94 LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 184, g2xs, 8
diff --git a/CPP/7zip/UI/GUI/ExtractDialog.cpp b/CPP/7zip/UI/GUI/ExtractDialog.cpp
index 4628482..467cf18 100644
--- a/CPP/7zip/UI/GUI/ExtractDialog.cpp
+++ b/CPP/7zip/UI/GUI/ExtractDialog.cpp
@@ -102,8 +102,7 @@ void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned n
102 { 102 {
103 UString s = LangString(langIDs[i]); 103 UString s = LangString(langIDs[i]);
104 s.RemoveChar(L'&'); 104 s.RemoveChar(L'&');
105 const int index = (int)combo.AddString(s); 105 combo.AddString_SetItemData(s, (LPARAM)i);
106 combo.SetItemData(index, (LPARAM)i);
107 if (values[i] == curVal) 106 if (values[i] == curVal)
108 curSel = i; 107 curSel = i;
109 } 108 }
diff --git a/CPP/Common/Common0.h b/CPP/Common/Common0.h
index 55606cd..5781a95 100644
--- a/CPP/Common/Common0.h
+++ b/CPP/Common/Common0.h
@@ -126,8 +126,9 @@ if compiled with new GCC libstdc++, GCC libstdc++ can use:
126#pragma GCC diagnostic ignored "-Wglobal-constructors" 126#pragma GCC diagnostic ignored "-Wglobal-constructors"
127#pragma GCC diagnostic ignored "-Wexit-time-destructors" 127#pragma GCC diagnostic ignored "-Wexit-time-destructors"
128 128
129#if defined(Z7_LLVM_CLANG_VERSION) && __clang_major__ >= 18 // 18.1.0RC 129#if defined(Z7_LLVM_CLANG_VERSION) && __clang_major__ >= 18 /* 18.1.0RC */ \
130#pragma GCC diagnostic ignored "-Wswitch-default" 130 || defined(Z7_APPLE_CLANG_VERSION) && __clang_major__ >= 16 // for APPLE=17 (LLVM=19)
131 #pragma GCC diagnostic ignored "-Wswitch-default"
131#endif 132#endif
132// #pragma GCC diagnostic ignored "-Wunused-private-field" 133// #pragma GCC diagnostic ignored "-Wunused-private-field"
133// #pragma GCC diagnostic ignored "-Wnonportable-system-include-path" 134// #pragma GCC diagnostic ignored "-Wnonportable-system-include-path"
diff --git a/CPP/Common/MyBuffer.h b/CPP/Common/MyBuffer.h
index 80f0205..08c10a3 100644
--- a/CPP/Common/MyBuffer.h
+++ b/CPP/Common/MyBuffer.h
@@ -202,7 +202,53 @@ public:
202 } 202 }
203}; 203};
204 204
205typedef CObjArray<Byte> CByteArr; 205
206/* CSmallObjArray can be used for Byte arrays
207 or for arrays whose total size in bytes does not exceed size_t ranges.
208 So there is no need to use Z7_ARRAY_NEW macro in CSmallObjArray code. */
209template <class T> class CSmallObjArray
210{
211protected:
212 T *_items;
213private:
214 // we disable copy
215 CSmallObjArray(const CSmallObjArray &buffer);
216 void operator=(const CSmallObjArray &buffer);
217public:
218 void Free()
219 {
220 delete []_items;
221 _items = NULL;
222 }
223 CSmallObjArray(size_t size): _items(NULL)
224 {
225 if (size != 0)
226 {
227 // Z7_ARRAY_NEW(_items, T, size)
228 _items = new T[size];
229 }
230 }
231 CSmallObjArray(): _items(NULL) {}
232 ~CSmallObjArray() { delete []_items; }
233
234 operator T *() { return _items; }
235 operator const T *() const { return _items; }
236 const T* ConstData() const { return _items; }
237 T* NonConstData() const { return _items; }
238 T* NonConstData() { return _items; }
239 // const T* Data() const { return _items; }
240 // T* Data() { return _items; }
241
242 void Alloc(size_t newSize)
243 {
244 delete []_items;
245 _items = NULL;
246 // Z7_ARRAY_NEW(_items, T, newSize)
247 _items = new T[newSize];
248 }
249};
250
251typedef CSmallObjArray<Byte> CByteArr;
206typedef CObjArray<bool> CBoolArr; 252typedef CObjArray<bool> CBoolArr;
207typedef CObjArray<int> CIntArr; 253typedef CObjArray<int> CIntArr;
208typedef CObjArray<unsigned> CUIntArr; 254typedef CObjArray<unsigned> CUIntArr;
diff --git a/CPP/Windows/Control/ComboBox.cpp b/CPP/Windows/Control/ComboBox.cpp
index 8da487d..2e9c8cb 100644
--- a/CPP/Windows/Control/ComboBox.cpp
+++ b/CPP/Windows/Control/ComboBox.cpp
@@ -63,4 +63,13 @@ LRESULT CComboBox::GetLBText(int index, UString &s)
63} 63}
64#endif 64#endif
65 65
66LRESULT CComboBox::AddString_SetItemData(LPCWSTR s, LPARAM lParam)
67{
68 const LRESULT index = AddString(s);
69 // NOTE: SetItemData((int)-1, lParam) works as unexpected.
70 if (index >= 0) // optional check, because (index < 0) is not expected for normal inputs
71 SetItemData((int)index, lParam);
72 return index;
73}
74
66}} 75}}
diff --git a/CPP/Windows/Control/ComboBox.h b/CPP/Windows/Control/ComboBox.h
index 2a60b8a..224efca 100644
--- a/CPP/Windows/Control/ComboBox.h
+++ b/CPP/Windows/Control/ComboBox.h
@@ -21,6 +21,8 @@ public:
21 LRESULT AddString(LPCWSTR s); 21 LRESULT AddString(LPCWSTR s);
22 #endif 22 #endif
23 23
24 LRESULT AddString_SetItemData(LPCWSTR s, LPARAM lParam);
25
24 /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/ 26 /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/
25 LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY_int_TO_WPARAM(index), 0); } 27 LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY_int_TO_WPARAM(index), 0); }
26 LRESULT SetCurSel(unsigned index) { return SendMsg(CB_SETCURSEL, index, 0); } 28 LRESULT SetCurSel(unsigned index) { return SendMsg(CB_SETCURSEL, index, 0); }
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp
index 64075ab..669541e 100644
--- a/CPP/Windows/FileFind.cpp
+++ b/CPP/Windows/FileFind.cpp
@@ -1162,6 +1162,15 @@ void CFileInfoBase::SetFrom_stat(const struct stat &st)
1162 MTime = st.st_mtimespec; 1162 MTime = st.st_mtimespec;
1163 ATime = st.st_atimespec; 1163 ATime = st.st_atimespec;
1164 1164
1165 #elif defined(__QNXNTO__) && defined(__ARM__) && !defined(__aarch64__)
1166
1167 // CTime = ST_CTIME(st);
1168 // MTime = ST_MTIME(st);
1169 // ATime = ST_ATIME(st);
1170 CTime.tv_sec = st.st_ctime; CTime.tv_nsec = 0;
1171 MTime.tv_sec = st.st_mtime; MTime.tv_nsec = 0;
1172 ATime.tv_sec = st.st_atime; ATime.tv_nsec = 0;
1173
1165 #else 1174 #else
1166 // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100); 1175 // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100);
1167 // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100); 1176 // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100);
@@ -1312,7 +1321,7 @@ bool CDirEntry::IsDots() const throw()
1312 /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) 1321 /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN)
1313 we can call fstatat() for that case, but we use only (Name) check here */ 1322 we can call fstatat() for that case, but we use only (Name) check here */
1314 1323
1315#if !defined(_AIX) && !defined(__sun) 1324#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
1316 if (Type != DT_DIR && Type != DT_UNKNOWN) 1325 if (Type != DT_DIR && Type != DT_UNKNOWN)
1317 return false; 1326 return false;
1318#endif 1327#endif
@@ -1352,7 +1361,7 @@ bool CEnumerator::NextAny(CDirEntry &fi, bool &found)
1352 1361
1353 fi.iNode = de->d_ino; 1362 fi.iNode = de->d_ino;
1354 1363
1355#if !defined(_AIX) && !defined(__sun) 1364#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
1356 fi.Type = de->d_type; 1365 fi.Type = de->d_type;
1357 /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) 1366 /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN)
1358 we can set (Type) from fstatat() in that case. 1367 we can set (Type) from fstatat() in that case.
diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h
index f68673a..944bca2 100644
--- a/CPP/Windows/FileFind.h
+++ b/CPP/Windows/FileFind.h
@@ -277,13 +277,13 @@ typedef CFileInfo CDirEntry;
277struct CDirEntry 277struct CDirEntry
278{ 278{
279 ino_t iNode; 279 ino_t iNode;
280#if !defined(_AIX) && !defined(__sun) 280#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
281 Byte Type; 281 Byte Type;
282#endif 282#endif
283 FString Name; 283 FString Name;
284 284
285 /* 285 /*
286#if !defined(_AIX) && !defined(__sun) 286#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
287 bool IsDir() const 287 bool IsDir() const
288 { 288 {
289 // (Type == DT_UNKNOWN) on some systems 289 // (Type == DT_UNKNOWN) on some systems
@@ -310,7 +310,7 @@ public:
310 bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const; 310 bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const;
311 bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const 311 bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const
312 { 312 {
313#if !defined(_AIX) && !defined(__sun) 313#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
314 if (de.Type == DT_DIR) 314 if (de.Type == DT_DIR)
315 return true; 315 return true;
316 if (de.Type != DT_UNKNOWN) 316 if (de.Type != DT_UNKNOWN)
diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h
index 7219f06..022a8f3 100644
--- a/CPP/Windows/SecurityUtils.h
+++ b/CPP/Windows/SecurityUtils.h
@@ -3,7 +3,11 @@
3#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H 3#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H
4#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H 4#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H
5 5
6#if defined(__MINGW32__) || defined(__MINGW64__)
7#include <ntsecapi.h>
8#else
6#include <NTSecAPI.h> 9#include <NTSecAPI.h>
10#endif
7 11
8#include "Defs.h" 12#include "Defs.h"
9 13
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp
index 4745785..6999ef9 100644
--- a/CPP/Windows/System.cpp
+++ b/CPP/Windows/System.cpp
@@ -5,8 +5,9 @@
5#ifndef _WIN32 5#ifndef _WIN32
6#include <unistd.h> 6#include <unistd.h>
7#include <limits.h> 7#include <limits.h>
8#if defined(__APPLE__) || defined(__DragonFly__) || \ 8#if defined(__APPLE__) || defined(__DragonFly__) \
9 defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 9 || defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
10 || defined(__QNXNTO__)
10#include <sys/sysctl.h> 11#include <sys/sysctl.h>
11#else 12#else
12#include <sys/sysinfo.h> 13#include <sys/sysinfo.h>
@@ -299,8 +300,9 @@ bool GetRamSize(size_t &size)
299 size = (size_t)sizeof(size_t) << 29; 300 size = (size_t)sizeof(size_t) << 29;
300 size64 = size; 301 size64 = size;
301 302
302#if defined(__APPLE__) || defined(__DragonFly__) || \ 303#if defined(__APPLE__) || defined(__DragonFly__) \
303 defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 304 || defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
305 || defined(__QNXNTO__)
304 306
305 uint64_t val = 0; 307 uint64_t val = 0;
306 int mib[2]; 308 int mib[2];
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h
index 0c80373..041a44d 100644
--- a/CPP/Windows/System.h
+++ b/CPP/Windows/System.h
@@ -15,6 +15,8 @@
15namespace NWindows { 15namespace NWindows {
16namespace NSystem { 16namespace NSystem {
17 17
18UInt32 GetNumberOfProcessors();
19
18#ifdef _WIN32 20#ifdef _WIN32
19 21
20struct CCpuGroups 22struct CCpuGroups
@@ -103,6 +105,25 @@ struct CProcessAffinity
103 return CountAffinity(systemAffinityMask); 105 return CountAffinity(systemAffinityMask);
104 } 106 }
105 107
108 // it returns normilized number of threads
109 void Get_and_return_NumProcessThreads_and_SysThreads(UInt32 &numProcessThreads, UInt32 &numSysThreads)
110 {
111 UInt32 num1 = 0, num2 = 0;
112 if (Get())
113 {
114 num1 = GetNumProcessThreads();
115 num2 = GetNumSystemThreads();
116 }
117 if (num1 == 0)
118 num1 = NSystem::GetNumberOfProcessors();
119 if (num1 == 0)
120 num1 = 1;
121 if (num2 < num1)
122 num2 = num1;
123 numProcessThreads = num1;
124 numSysThreads = num2;
125 }
126
106 BOOL Get(); 127 BOOL Get();
107 128
108 BOOL SetProcAffinity() const 129 BOOL SetProcAffinity() const
@@ -177,8 +198,6 @@ struct CProcessAffinity
177#endif // _WIN32 198#endif // _WIN32
178 199
179 200
180UInt32 GetNumberOfProcessors();
181
182bool GetRamSize(size_t &size); // returns false, if unknown ram size 201bool GetRamSize(size_t &size); // returns false, if unknown ram size
183 202
184unsigned long Get_File_OPEN_MAX(); 203unsigned long Get_File_OPEN_MAX();
diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp
index 35846e0..2eced2a 100644
--- a/CPP/Windows/SystemInfo.cpp
+++ b/CPP/Windows/SystemInfo.cpp
@@ -22,7 +22,7 @@
22 22
23#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216) 23#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216)
24 #define Z7_GETAUXV_AVAILABLE 24 #define Z7_GETAUXV_AVAILABLE
25#else 25#elif !defined(__QNXNTO__)
26// #pragma message("=== is not NEW GLIBC === ") 26// #pragma message("=== is not NEW GLIBC === ")
27 #if defined __has_include 27 #if defined __has_include
28 #if __has_include (<sys/auxv.h>) 28 #if __has_include (<sys/auxv.h>)
@@ -58,7 +58,7 @@
58 58
59#ifdef USE_HWCAP 59#ifdef USE_HWCAP
60 60
61#if defined(__FreeBSD__) 61#if defined(__FreeBSD__) || defined(__OpenBSD__)
62 62
63// #if (__FreeBSD__ >= 13) // (FreeBSD 12.01 is required for elf_aux_info() ???) 63// #if (__FreeBSD__ >= 13) // (FreeBSD 12.01 is required for elf_aux_info() ???)
64static unsigned long MY_getauxval(int aux) 64static unsigned long MY_getauxval(int aux)
diff --git a/CPP/Windows/TimeUtils.h b/CPP/Windows/TimeUtils.h
index 4a9d0f2..8e1e478 100644
--- a/CPP/Windows/TimeUtils.h
+++ b/CPP/Windows/TimeUtils.h
@@ -65,6 +65,14 @@ inline bool FILETIME_IsZero(const FILETIME &ft)
65 #define ST_MTIME(st) st.st_mtimespec 65 #define ST_MTIME(st) st.st_mtimespec
66 #define ST_ATIME(st) st.st_atimespec 66 #define ST_ATIME(st) st.st_atimespec
67 #define ST_CTIME(st) st.st_ctimespec 67 #define ST_CTIME(st) st.st_ctimespec
68 #elif defined(__QNXNTO__) && defined(__ARM__) && !defined(__aarch64__)
69 // QNX armv7le (32-bit) for "struct stat" timestamps uses time_t instead of timespec
70 inline CFiTime ST_MTIME(const struct stat &st)
71 { timespec ts; ts.tv_sec = st.st_mtime; ts.tv_nsec = 0; return ts; }
72 inline CFiTime ST_ATIME(const struct stat &st)
73 { timespec ts; ts.tv_sec = st.st_atime; ts.tv_nsec = 0; return ts; }
74 inline CFiTime ST_CTIME(const struct stat &st)
75 { timespec ts; ts.tv_sec = st.st_ctime; ts.tv_nsec = 0; return ts; }
68 #else 76 #else
69 #define ST_MTIME(st) st.st_mtim 77 #define ST_MTIME(st) st.st_mtim
70 #define ST_ATIME(st) st.st_atim 78 #define ST_ATIME(st) st.st_atim
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs
index 703e22e..8c6ef4c 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 = "25" ?> 3<?define VerMajor = "26" ?>
4<?define VerMinor = "01" ?> 4<?define VerMinor = "00" ?>
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/License.txt b/DOC/License.txt
index bbb56a3..b1a421a 100644
--- a/DOC/License.txt
+++ b/DOC/License.txt
@@ -3,7 +3,7 @@
3 License for use and distribution 3 License for use and distribution
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 7-Zip Copyright (C) 1999-2025 Igor Pavlov. 6 7-Zip Copyright (C) 1999-2026 Igor Pavlov.
7 7
8 The licenses for files are: 8 The licenses for files are:
9 9
@@ -58,7 +58,7 @@ BSD 3-clause License in 7-Zip code
58 58
59 Copyright (c) 2015-2016, Apple Inc. All rights reserved. 59 Copyright (c) 2015-2016, Apple Inc. All rights reserved.
60 Copyright (c) Facebook, Inc. All rights reserved. 60 Copyright (c) Facebook, Inc. All rights reserved.
61 Copyright (c) 2023-2025 Igor Pavlov. 61 Copyright (c) 2023-2026 Igor Pavlov.
62 62
63Text of the "BSD 3-clause License" 63Text of the "BSD 3-clause License"
64---------------------------------- 64----------------------------------
@@ -102,7 +102,7 @@ BSD 2-clause License in 7-Zip code
102 XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet. 102 XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet.
103 103
104 Copyright (c) 2012-2021 Yann Collet. 104 Copyright (c) 2012-2021 Yann Collet.
105 Copyright (c) 2023-2025 Igor Pavlov. 105 Copyright (c) 2023-2026 Igor Pavlov.
106 106
107Text of the "BSD 2-clause License" 107Text of the "BSD 2-clause License"
108---------------------------------- 108----------------------------------
diff --git a/DOC/readme.txt b/DOC/readme.txt
index cc89a39..26d0f5a 100644
--- a/DOC/readme.txt
+++ b/DOC/readme.txt
@@ -1,15 +1,15 @@
17-Zip 25.01 Sources 17-Zip 26.00 Sources
2------------------- 2-------------------
3 3
47-Zip is a file archiver for Windows. 47-Zip is a file archiver for Windows.
5 5
67-Zip Copyright (C) 1999-2025 Igor Pavlov. 67-Zip Copyright (C) 1999-2026 Igor Pavlov.
7 7
8 8
9License Info 9License Info
10------------ 10------------
11 11
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 infomation about license.
@@ -27,7 +27,7 @@ Please check main restriction from unRar license:
27 not be used to develop a RAR (WinRAR) compatible archiver. 27 not be used to develop a RAR (WinRAR) compatible archiver.
28 28
29In brief it means: 29In brief it means:
301) You can compile and use compiled files under GNU LGPL rules, since 301) You can compile and use compiled files under GNU LGPL rules, since
31 unRAR license almost has no restrictions for compiled files. 31 unRAR license almost has no restrictions for compiled files.
32 You can link these compiled files to LGPL programs. 32 You can link these compiled files to LGPL programs.
332) You can fix bugs in source code and use compiled fixed version. 332) You can fix bugs in source code and use compiled fixed version.
@@ -60,7 +60,7 @@ Tools / Options / Directories
60 - Library files 60 - Library files
61 61
62Also you need Microsoft Macro Assembler: 62Also you need Microsoft Macro Assembler:
63 - ml.exe for x86 63 - ml.exe for x86
64 - ml64.exe for x64 64 - ml64.exe for x64
65You can use ml.exe from Windows SDK for Windows Vista or some later versions. 65You can use ml.exe from Windows SDK for Windows Vista or some later versions.
66 66
@@ -85,7 +85,7 @@ OLD_COMPILER
85 for old VC compiler, like MSCV 6.0. 85 for old VC compiler, like MSCV 6.0.
86 86
87MY_DYNAMIC_LINK 87MY_DYNAMIC_LINK
88 for dynamic linking to the run-time library (msvcrt.dll). 88 for dynamic linking to the run-time library (msvcrt.dll).
89 The default makefile option is static linking to the run-time library. 89 The default makefile option is static linking to the run-time library.
90 90
91To compile all 7-Zip files for x64 with Visual Studio 2022, 91To compile all 7-Zip files for x64 with Visual Studio 2022,
@@ -116,23 +116,23 @@ So if you compile the version with Assembeler code, you will get faster 7-Zip bi
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
1191) x86 and x86-64 (AMD64): MASM syntax. 1191) x86 and x86-64 (AMD64): MASM syntax.
120 Now there are 3 programs that supports MASM syntax in Linux. 120 Now there are 3 programs that supports MASM syntax in Linux.
121' 'Asmc Macro Assembler, JWasm, and UASM. Note that JWasm now doesn't support some 121' 'Asmc Macro Assembler, JWasm, and UASM. Note that JWasm now doesn't support some
122 cpu instructions used in 7-Zip. 122 cpu instructions used in 7-Zip.
123 So you must install Asmc Macro Assembler in Linux or UASM, if you want to compile 123 So you must install Asmc Macro Assembler in Linux or UASM, if you want to compile
124 fastest version of 7-Zip x86 and x86-64: 124 fastest version of 7-Zip x86 and x86-64:
125 https://github.com/nidud/asmc 125 https://github.com/nidud/asmc
126 https://github.com/Terraspace/UASM 126 https://github.com/Terraspace/UASM
127 127
128 128
1292) arm64: GNU assembler for ARM64 with preprocessor. 1292) arm64: GNU assembler for ARM64 with preprocessor.
130 That systax is supported by GCC and CLANG for ARM64. 130 That systax is supported by GCC and CLANG for ARM64.
131 131
132There are different binaries that can be compiled from 7-Zip source. 132There are different binaries that can be compiled from 7-Zip source.
133There are 2 main files in folder for compiling: 133There are 2 main files in folder for compiling:
134 makefile - that can be used for compiling Windows version of 7-Zip with nmake command 134 makefile - that can be used for compiling Windows version of 7-Zip with nmake command
135 makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip or Windows version 135 makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip or Windows version
136 with MINGW (GCC) with make command. 136 with MINGW (GCC) with make command.
137 137
138At first you must change the current folder to folder that contains `makefile.gcc`: 138At first you must change the current folder to folder that contains `makefile.gcc`:
@@ -143,7 +143,7 @@ Then you can compile `makefile.gcc` with the command:
143 143
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 optimzing options.
148 148
149To compile with GCC without assembler: 149To compile with GCC without assembler:
@@ -171,10 +171,10 @@ makefile.gcc supports some variables that can change compile options
171 171
172USE_JWASM=1 172USE_JWASM=1
173 use JWasm assembler instead of Asmc. 173 use JWasm assembler instead of Asmc.
174 Note that JWasm doesn't support AES instructions. So AES code from C version AesOpt.c 174 Note that JWasm doesn't support AES instructions. So AES code from C version AesOpt.c
175 will be used instead of assembler code from AesOpt.asm. 175 will be used instead of assembler code from AesOpt.asm.
176 176
177If you want to use UASM for x86-64 compiling, you can change 7zip_gcc.mak, 177If you want to use UASM for x86-64 compiling, you can change 7zip_gcc.mak,
178or send IS_X64=1 USE_ASM=1 MY_ASM="$UASM" to make command calling: 178or send IS_X64=1 USE_ASM=1 MY_ASM="$UASM" to make command calling:
179 UASM="$PWD/GccUnixR/uasm" 179 UASM="$PWD/GccUnixR/uasm"
180 cd "7zip-src/CPP/7zip/Bundles/Alone2" 180 cd "7zip-src/CPP/7zip/Bundles/Alone2"
@@ -187,11 +187,11 @@ DISABLE_RAR=1
187DISABLE_RAR_COMPRESS=1 187DISABLE_RAR_COMPRESS=1
188 removes "not fully free" code of RAR decompression codecs from compilation. 188 removes "not fully free" code of RAR decompression codecs from compilation.
189 189
190RAR decompression codecs in 7-Zip code has some additional license restrictions, 190RAR decompression codecs in 7-Zip code has some additional license restrictions,
191that can be treated as not fully compatible with free-software licenses. 191that can be treated as not fully compatible with free-software licenses.
192DISABLE_RAR_COMPRESS=1 allows to exclude such "not-fully-free" RAR code from compilation. 192DISABLE_RAR_COMPRESS=1 allows to exclude such "not-fully-free" RAR code from compilation.
193if DISABLE_RAR_COMPRESS=1 is specified, 7-zip will not be able to decompress files 193if DISABLE_RAR_COMPRESS=1 is specified, 7-zip will not be able to decompress files
194from rar archives, but 7-zip still will be able to open rar archives to get list of 194from rar archives, but 7-zip still will be able to open rar archives to get list of
195files or to extract files that are stored without compression. 195files or to extract files that are stored without compression.
196if DISABLE_RAR=1 is specified, 7-zip will not be able to work with RAR archives. 196if DISABLE_RAR=1 is specified, 7-zip will not be able to work with RAR archives.
197 197
@@ -203,11 +203,11 @@ Now there are two different ports of 7-Zip for Linux/macOS:
203 203
2041) p7zip - another port of 7-Zip for Linux, made by an independent developer. 2041) p7zip - another port of 7-Zip for Linux, made by an independent developer.
205 The latest version of p7zip now is 16.02, and that p7zip 16.02 is outdated now. 205 The latest version of p7zip now is 16.02, and that p7zip 16.02 is outdated now.
206 http://sourceforge.net/projects/p7zip/ 206 http://sourceforge.net/projects/p7zip/
207 207
2082) 7-Zip for Linux/macOS - this package - it's new code with all changes from latest 7-Zip for Windows. 2082) 7-Zip for Linux/macOS - this package - it's new code with all changes from latest 7-Zip for Windows.
209 209
210These two ports are not identical. 210These two ports are not identical.
211Note also that some Linux specific things can be implemented better in p7zip than in new 7-Zip for Linux. 211Note also that some Linux specific things can be implemented better in p7zip than in new 7-Zip for Linux.
212 212
213 213
@@ -218,13 +218,13 @@ Notes:
2187-Zip consists of COM modules (DLL files). 2187-Zip consists of COM modules (DLL files).
219But 7-Zip doesn't use standard COM interfaces for creating objects. 219But 7-Zip doesn't use standard COM interfaces for creating objects.
220Look at 220Look at
2217zip\UI\Client7z folder for example of using DLL files of 7-Zip. 2217zip\UI\Client7z folder for example of using DLL files of 7-Zip.
222Some DLL files can use other DLL files from 7-Zip. 222Some DLL files can use other DLL files from 7-Zip.
223If you don't like it, you must use standalone version of DLL. 223If you don't like it, you must use standalone version of DLL.
224To compile standalone version of DLL you must include all used parts 224To compile standalone version of DLL you must include all used parts
225to project and define some defs. 225to project and define some defs.
226For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll 226For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll
227that works with 7z format. So you can use such DLL in your project 227that works with 7z format. So you can use such DLL in your project
228without additional DLL files. 228without additional DLL files.
229 229
230 230
@@ -284,7 +284,7 @@ Windows common files for Windows related code
284 UI 284 UI
285 285
286 Agent Intermediary modules for FAR plugin and Explorer plugin 286 Agent Intermediary modules for FAR plugin and Explorer plugin
287 Client7z Test application for 7za.dll 287 Client7z Test application for 7za.dll
288 Common Common UI files 288 Common Common UI files
289 Console 7z.exe : Console version 289 Console 7z.exe : Console version
290 Explorer 7-zip.dll: 7-Zip Shell extension 290 Explorer 7-zip.dll: 7-Zip Shell extension
diff --git a/DOC/src-history.txt b/DOC/src-history.txt
index 48c9647..657f04f 100644
--- a/DOC/src-history.txt
+++ b/DOC/src-history.txt
@@ -1,11 +1,20 @@
1HISTORY of the 7-Zip source code 1HISTORY of the 7-Zip source code
2-------------------------------- 2--------------------------------
3 3
426.00 2026-02-12
5-------------------------
6- improved code for ZIP, CPIO, RAR, UFD, QCOW, Compound.
7- 7-Zip File Manager: improved sorting order of the file list. It uses file name as secondary sorting key.
8- 7-Zip File Manager: improved Benchmark to support systems with more than 64 CPU threads.
9- the bug was fixed: 7-Zip could not correctly extract TAR archives containing sparse files.
10- some bugs were fixed.
11
12
425.01 2025-08-03 1325.01 2025-08-03
5------------------------- 14-------------------------
6- The code for handling symbolic links has been changed 15- CVE-2025-55188 : The code for handling symbolic links has been changed
7 to provide greater security when extracting files from archives. 16 to provide greater security when extracting files from archives.
8 Command line switch -snld20 can be used to bypass default security 17 Command line switch -snld20 can be used to bypass default security
9 checks when creating symbolic links. 18 checks when creating symbolic links.
10 19
11 20
@@ -18,17 +27,19 @@ HISTORY of the 7-Zip source code
18- bzip2 compression speed was increased by 15-40%. 27- bzip2 compression speed was increased by 15-40%.
19- deflate (zip/gz) compression speed was increased by 1-3%. 28- deflate (zip/gz) compression speed was increased by 1-3%.
20- improved support for zip, cpio and fat archives. 29- improved support for zip, cpio and fat archives.
21- fixed some bugs and vulnerabilities. 30- fixed some bugs.
22- the bug was fixed : CVE-2025-53816 : 7-Zip could work incorrectly for some incorrect RAR archives. 31- CVE-2025-11001 and CVE-2025-11002 : A vulnerability was fixed for symbolic links processing,
23- the bug was fixed : CVE-2025-53817 : 7-Zip could crash for some incorrect COM (Compound File) archives. 32 when extracting files from archives.
33- the bug was fixed : CVE-2025-53816 : 7-Zip could work incorrectly for some incorrect RAR archives.
34- the bug was fixed : CVE-2025-53817 : 7-Zip could crash for some incorrect COM (Compound File) archives.
24 35
25 36
2624.09 2024-11-29 3724.09 2024-11-29
27------------------------- 38-------------------------
28- The default dictionary size values for LZMA/LZMA2 compression methods were increased: 39- The default dictionary size values for LZMA/LZMA2 compression methods were increased:
29 dictionary size compression level 40 dictionary size compression level
30 v24.08 v24.09 v24.09 41 v24.08 v24.09 v24.09
31 32-bit 64-bit 42 32-bit 64-bit
32 8 MB 16 MB 16 MB -mx4 43 8 MB 16 MB 16 MB -mx4
33 16 MB 32 MB 32 MB -mx5 : Normal 44 16 MB 32 MB 32 MB -mx5 : Normal
34 32 MB 64 MB 64 MB -mx6 45 32 MB 64 MB 64 MB -mx6
@@ -38,11 +49,11 @@ HISTORY of the 7-Zip source code
38 The default dictionary size values for 32-bit versions of LZMA/LZMA2 don't exceed 64 MB. 49 The default dictionary size values for 32-bit versions of LZMA/LZMA2 don't exceed 64 MB.
39- 7-Zip now can calculate the following hash checksums: SHA-512, SHA-384, SHA3-256 and MD5. 50- 7-Zip now can calculate the following hash checksums: SHA-512, SHA-384, SHA3-256 and MD5.
40- APM and HFS support was improved. 51- APM and HFS support was improved.
41- If an archive update operation uses a temporary archive folder and 52- If an archive update operation uses a temporary archive folder and
42 the archive is moved to the destination folder, 7-Zip shows the progress of moving 53 the archive is moved to the destination folder, 7-Zip shows the progress of moving
43 the archive file, as this operation can take a long time if the archive is large. 54 the archive file, as this operation can take a long time if the archive is large.
44- The bug was fixed: 7-Zip File Manager didn't propagate Zone.Identifier stream 55- The bug was fixed: 7-Zip File Manager didn't propagate Zone.Identifier stream
45 for extacted files from nested archives (if there is open archive inside another open archive). 56 for extracted files from nested archives (if there is open archive inside another open archive).
46- Some bugs were fixed. 57- Some bugs were fixed.
47 58
48 59
@@ -76,7 +87,7 @@ HISTORY of the 7-Zip source code
76------------------------- 87-------------------------
77- New switch -myv={MMNN} to set decoder compatibility version for 7z archive creating. 88- New switch -myv={MMNN} to set decoder compatibility version for 7z archive creating.
78 {MMNN} is 4-digit number that represents the version of 7-Zip without a dot. 89 {MMNN} is 4-digit number that represents the version of 7-Zip without a dot.
79 If -myv={MMNN} switch is specified, 7-Zip will only use compression methods that can 90 If -myv={MMNN} switch is specified, 7-Zip will only use compression methods that can
80 be decoded by the specified version {MMNN} of 7-Zip and newer versions. 91 be decoded by the specified version {MMNN} of 7-Zip and newer versions.
81 If -myv={MMNN} switch is not specified, -myv=2300 is used, and 7-Zip will only 92 If -myv={MMNN} switch is not specified, -myv=2300 is used, and 7-Zip will only
82 use compression methods that can be decoded by 7-Zip 23.00 and newer versions. 93 use compression methods that can be decoded by 7-Zip 23.00 and newer versions.
@@ -127,15 +138,15 @@ HISTORY of the 7-Zip source code
127 And some warning types are disabled in 2 files: 138 And some warning types are disabled in 2 files:
128 - C/Compiler.h for C/C++ code warnings. 139 - C/Compiler.h for C/C++ code warnings.
129 - CPP/Common/Common.h for C++ code warnings. 140 - CPP/Common/Common.h for C++ code warnings.
130- Linux/macOS versions of 7-Zip: IUnknown interface in new code doesn't use 141- Linux/macOS versions of 7-Zip: IUnknown interface in new code doesn't use
131 virtual destructor that was used in previous 7-Zip and p7zip: 142 virtual destructor that was used in previous 7-Zip and p7zip:
132 // virtual ~IUnknown() {} 143 // virtual ~IUnknown() {}
133 So 7-Zip's dynamically linked shared libraries (codecs) are not compatible 144 So 7-Zip's dynamically linked shared libraries (codecs) are not compatible
134 between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip). 145 between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip).
135- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers. 146- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers.
136- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp 147- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp
137 files in system's TEMP folder. 7-Zip uses temp file for additional compressed 148 files in system's TEMP folder. 7-Zip uses temp file for additional compressed
138 data stream, if size of such compressed stream is larger than predefined limit: 149 data stream, if size of such compressed stream is larger than predefined limit:
139 16 MiB in 32-bit version, 4 GiB in 64-bit version. 150 16 MiB in 32-bit version, 4 GiB in 64-bit version.
140- Some bugs were fixed. 151- Some bugs were fixed.
141 152
@@ -157,7 +168,7 @@ HISTORY of the 7-Zip source code
15721.06 2021-11-24 16821.06 2021-11-24
158------------------------- 169-------------------------
159- Bug in LZMA encoder in file LzmaEnc.c was fixed: 170- Bug in LZMA encoder in file LzmaEnc.c was fixed:
160 LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly, 171 LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly,
161 if size value for output buffer is smaller than size required for all compressed data. 172 if size value for output buffer is smaller than size required for all compressed data.
162 LzmaEnc_Encode() could work incorrectly, 173 LzmaEnc_Encode() could work incorrectly,
163 if callback ISeqOutStream::Write() doesn't write all compressed data. 174 if callback ISeqOutStream::Write() doesn't write all compressed data.
@@ -171,8 +182,8 @@ HISTORY of the 7-Zip source code
171------------------------- 182-------------------------
172- 7-Zip now reduces the number of working CPU threads for compression, 183- 7-Zip now reduces the number of working CPU threads for compression,
173 if RAM size is not enough for compression with big LZMA2 dictionary. 184 if RAM size is not enough for compression with big LZMA2 dictionary.
174- 7-Zip now can create and check "file.sha256" and "file.sha1" text files 185- 7-Zip now can create and check "file.sha256" and "file.sha1" text files
175 that contain the list of file names and SHA-1 / SHA-256 checksums in format 186 that contain the list of file names and SHA-1 / SHA-256 checksums in format
176 compatible with sha1sum/sha256sum programs. 187 compatible with sha1sum/sha256sum programs.
177 188
178 189
@@ -187,7 +198,7 @@ HISTORY of the 7-Zip source code
187- 7-Zip now writes additional field for filename in UTF-8 encoding to zip archives. 198- 7-Zip now writes additional field for filename in UTF-8 encoding to zip archives.
188 It allows to extract correct file name from zip archives on different systems. 199 It allows to extract correct file name from zip archives on different systems.
189- The command line version of 7-Zip for macOS was released. 200- The command line version of 7-Zip for macOS was released.
190- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux 201- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux
191 was increased by 20%-60%. 202 was increased by 20%-60%.
192- Some changes and improvements in ZIP, TAR and NSIS code. 203- Some changes and improvements in ZIP, TAR and NSIS code.
193 204
@@ -195,7 +206,7 @@ HISTORY of the 7-Zip source code
19521.01 alpha 2021-03-09 20621.01 alpha 2021-03-09
196------------------------- 207-------------------------
197- The command line version of 7-Zip for Linux was released. 208- The command line version of 7-Zip for Linux was released.
198- The improvements for speed of ARM64 version using hardware CPU instructions 209- The improvements for speed of ARM64 version using hardware CPU instructions
199 for AES, CRC-32, SHA-1 and SHA-256. 210 for AES, CRC-32, SHA-1 and SHA-256.
200- The bug in versions 18.02 - 21.00 was fixed: 211- The bug in versions 18.02 - 21.00 was fixed:
201 7-Zip could not correctly extract some ZIP archives created with xz compression method. 212 7-Zip could not correctly extract some ZIP archives created with xz compression method.
@@ -205,30 +216,30 @@ HISTORY of the 7-Zip source code
20520.02 alpha 2020-08-08 21620.02 alpha 2020-08-08
206------------------------- 217-------------------------
207- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64. 218- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64.
208 It allows to increase the compression speed for big 7z archives, if there is a big number 219 It allows to increase the compression speed for big 7z archives, if there is a big number
209 of CPU cores and threads. 220 of CPU cores and threads.
210- The speed of PPMd compressing/decompressing was increased for 7z/ZIP/RAR archives. 221- The speed of PPMd compressing/decompressing was increased for 7z/ZIP/RAR archives.
211- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system 222- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system
212 to modify "Last Access Time" property of source files for archiving and hashing operations. 223 to modify "Last Access Time" property of source files for archiving and hashing operations.
213- Some bugs were fixed. 224- Some bugs were fixed.
214 225
215 226
21620.00 alpha 2020-02-06 22720.00 alpha 2020-02-06
217------------------------- 228-------------------------
218- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5, 229- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5,
219 that can work faster than bt4 and hc4 match finders for the data with big redundancy. 230 that can work faster than bt4 and hc4 match finders for the data with big redundancy.
220- The compression ratio was improved for Fast and Fastest compression levels with the 231- The compression ratio was improved for Fast and Fastest compression levels with the
221 following default settings: 232 following default settings:
222 - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary. 233 - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary.
223 - Fast level (-mx3) : hc5 match finder with 4 MB dictionary. 234 - Fast level (-mx3) : hc5 match finder with 4 MB dictionary.
224- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra 235- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra
225 compression levels. 236 compression levels.
226- bzip2 decoding code was updated to support bzip2 archives, created by lbzip2 program. 237- bzip2 decoding code was updated to support bzip2 archives, created by lbzip2 program.
227 238
228 239
22919.02 2019-09-05 24019.02 2019-09-05
230------------------------- 241-------------------------
231- Support for SHA-1/SHA-256 optimized code in 242- Support for SHA-1/SHA-256 optimized code in
232 Sha1Opt.c, Sha256Opt.c, Sha256Opt.asm, Sha1Opt.asm. 243 Sha1Opt.c, Sha256Opt.c, Sha256Opt.asm, Sha1Opt.asm.
233 244
234 245
@@ -249,7 +260,7 @@ HISTORY of the 7-Zip source code
249 There was memory leak in multithreading xz decoder - XzDecMt_Decode(), 260 There was memory leak in multithreading xz decoder - XzDecMt_Decode(),
250 if xz stream contains only one block. 261 if xz stream contains only one block.
251- 7-Zip 18.02-18.05 used only one CPU thread for bz2 archive creation. 262- 7-Zip 18.02-18.05 used only one CPU thread for bz2 archive creation.
252- The changes for MSVS compiler makefiles: 263- The changes for MSVS compiler makefiles:
253 - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64) 264 - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64)
254 instead of "CPU" macroname with values (AMD64, ARM64). 265 instead of "CPU" macroname with values (AMD64, ARM64).
255 - the makefiles by default now use static version of the run-time library. 266 - the makefiles by default now use static version of the run-time library.
@@ -257,17 +268,17 @@ HISTORY of the 7-Zip source code
257 268
25818.05 2018-04-30 26918.05 2018-04-30
259------------------------- 270-------------------------
260- The speed for LZMA/LZMA2 compressing was increased 271- The speed for LZMA/LZMA2 compressing was increased
261 by 8% for fastest/fast compression levels and 272 by 8% for fastest/fast compression levels and
262 by 3% for normal/maximum compression levels. 273 by 3% for normal/maximum compression levels.
263- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in 274- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
264 Windows 10 because of some BUG with "Large Pages" in Windows 10. 275 Windows 10 because of some BUG with "Large Pages" in Windows 10.
265 Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299). 276 Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
266 277
267 278
26818.03 beta 2018-03-04 27918.03 beta 2018-03-04
269------------------------- 280-------------------------
270- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm 281- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm
271 for x64 with about 30% higher speed than main version of LZMA decoder written in C. 282 for x64 with about 30% higher speed than main version of LZMA decoder written in C.
272- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%. 283- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
273- 7-Zip now can use multi-threading for 7z/LZMA2 decoding, 284- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
@@ -278,7 +289,7 @@ HISTORY of the 7-Zip source code
278 289
27917.00 beta 2017-04-29 29017.00 beta 2017-04-29
280------------------------- 291-------------------------
281- NewHandler.h / NewHandler.cpp: 292- NewHandler.h / NewHandler.cpp:
282 now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900). 293 now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
283- C/7zTypes.h : the names of variables in interface structures were changed (vt). 294- C/7zTypes.h : the names of variables in interface structures were changed (vt).
284- Some bugs were fixed. 7-Zip could crash in some cases. 295- Some bugs were fixed. 7-Zip could crash in some cases.
@@ -288,53 +299,53 @@ HISTORY of the 7-Zip source code
28816.02 2016-05-21 29916.02 2016-05-21
289------------------------- 300-------------------------
290- The BUG in 16.00 - 16.01 was fixed: 301- The BUG in 16.00 - 16.01 was fixed:
291 Split Handler (SplitHandler.cpp) returned incorrect 302 Split Handler (SplitHandler.cpp) returned incorrect
292 total size value (kpidSize) for split archives. 303 total size value (kpidSize) for split archives.
293 304
294 305
29516.01 2016-05-19 30616.01 2016-05-19
296------------------------- 307-------------------------
297- Some bugs were fixed, 308- Some bugs were fixed,
298- Some internal changes to reduce the number of compiler warnings. 309- Some internal changes to reduce the number of compiler warnings.
299 310
300 311
30116.00 2016-05-10 31216.00 2016-05-10
302------------------------- 313-------------------------
303- 7-Zip now can extract multivolume ZIP archives (z01, z02, ... , zip). 314- 7-Zip now can extract multivolume ZIP archives (z01, z02, ... , zip).
304- Some bugs were fixed, 315- Some bugs were fixed,
305 316
306 317
30715.12 2015-11-19 31815.12 2015-11-19
308------------------------- 319-------------------------
309- The BUG in C version of 7z decoder was fixed: 320- The BUG in C version of 7z decoder was fixed:
310 7zDec.c : SzDecodeLzma2() 321 7zDec.c : SzDecodeLzma2()
311 7z decoder could mistakenly report about decoding error for some 7z archives 322 7z decoder could mistakenly report about decoding error for some 7z archives
312 that use LZMA2 compression method. 323 that use LZMA2 compression method.
313 The probability to get that mistaken decoding error report was about 324 The probability to get that mistaken decoding error report was about
314 one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size). 325 one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
315- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed: 326- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
316 7zArcIn.c : SzReadHeader2() 327 7zArcIn.c : SzReadHeader2()
317 7z decoder worked incorrectly for 7z archives that contain 328 7z decoder worked incorrectly for 7z archives that contain
318 empty solid blocks, that can be placed to 7z archive, if some file is 329 empty solid blocks, that can be placed to 7z archive, if some file is
319 unavailable for reading during archive creation. 330 unavailable for reading during archive creation.
320 331
321 332
32215.09 beta 2015-10-16 33315.09 beta 2015-10-16
323------------------------- 334-------------------------
324- The BUG in LZMA / LZMA2 encoding code was fixed. 335- The BUG in LZMA / LZMA2 encoding code was fixed.
325 The BUG in LzFind.c::MatchFinder_ReadBlock() function. 336 The BUG in LzFind.c::MatchFinder_ReadBlock() function.
326 If input data size is larger than (4 GiB - dictionary_size), 337 If input data size is larger than (4 GiB - dictionary_size),
327 the following code worked incorrectly: 338 the following code worked incorrectly:
328 - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions 339 - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
329 for compressing from memory to memory. 340 for compressing from memory to memory.
330 That BUG is not related to LZMA encoder version that works via streams. 341 That BUG is not related to LZMA encoder version that works via streams.
331 - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if 342 - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
332 default value of chunk size (CLzma2EncProps::blockSize) is changed 343 default value of chunk size (CLzma2EncProps::blockSize) is changed
333 to value larger than (4 GiB - dictionary_size). 344 to value larger than (4 GiB - dictionary_size).
334 345
335 346
3369.38 beta 2015-01-03 3479.38 beta 2015-01-03
337------------------------- 348-------------------------
338- The BUG in 9.31-9.37 was fixed: 349- The BUG in 9.31-9.37 was fixed:
339 IArchiveGetRawProps interface was disabled for 7z archives. 350 IArchiveGetRawProps interface was disabled for 7z archives.
340- The BUG in 9.26-9.36 was fixed: 351- The BUG in 9.26-9.36 was fixed:
@@ -342,10 +353,10 @@ HISTORY of the 7-Zip source code
342 353
343 354
3449.36 beta 2014-12-26 3559.36 beta 2014-12-26
345------------------------- 356-------------------------
346- The BUG in command line version was fixed: 357- The BUG in command line version was fixed:
347 7-Zip created temporary archive in current folder during update archive 358 7-Zip created temporary archive in current folder during update archive
348 operation, if -w{Path} switch was not specified. 359 operation, if -w{Path} switch was not specified.
349 The fixed 7-Zip creates temporary archive in folder that contains updated archive. 360 The fixed 7-Zip creates temporary archive in folder that contains updated archive.
350- The BUG in 9.33-9.35 was fixed: 361- The BUG in 9.33-9.35 was fixed:
351 7-Zip silently ignored file reading errors during 7z or gz archive creation, 362 7-Zip silently ignored file reading errors during 7z or gz archive creation,
@@ -355,8 +366,8 @@ HISTORY of the 7-Zip source code
355 366
3569.31 2012-10-31 3679.31 2012-10-31
357------------------------- 368-------------------------
358- InBuffer.h : CInBuffer uses ISequentialInStream *_stream; instead of CMyComPtr<ISequentialInStream> 369- InBuffer.h : CInBuffer uses ISequentialInStream *_stream; instead of CMyComPtr<ISequentialInStream>
359 OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr<ISequentialOutStream> 370 OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr<ISequentialOutStream>
360 371
361 372
3629.26 2011-04-11 3739.26 2011-04-11
@@ -366,13 +377,13 @@ HISTORY of the 7-Zip source code
366 377
367 378
3689.21 2011-04-11 3799.21 2011-04-11
369------------------------- 380-------------------------
370- New class FString for file names at file systems. 381- New class FString for file names at file systems.
371- Speed optimization in CRC code for big-endian CPUs. 382- Speed optimization in CRC code for big-endian CPUs.
372 383
373 384
3749.18 2010-11-02 3859.18 2010-11-02
375------------------------- 386-------------------------
376- New small SFX module for installers (C/Util/SfxSetup). 387- New small SFX module for installers (C/Util/SfxSetup).
377 388
378 389
@@ -409,7 +420,7 @@ HISTORY of the 7-Zip source code
4094.61 2008-11-23 4204.61 2008-11-23
410------------------------- 421-------------------------
411- Bug in ver. 4.58+ was fixed: 422- Bug in ver. 4.58+ was fixed:
412 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives. 423 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives.
413- Bug in .CAB code was fixed. 7-Zip didn't show some empty files, 424- Bug in .CAB code was fixed. 7-Zip didn't show some empty files,
414 if .CAB archive contains more than one empty file. 425 if .CAB archive contains more than one empty file.
415 426
@@ -417,13 +428,13 @@ HISTORY of the 7-Zip source code
4174.59 2008-07-27 4284.59 2008-07-27
418------------------------- 429-------------------------
419- Bug was fixed: 430- Bug was fixed:
420 LZMA Encoder in fast compression mode could access memory outside of 431 LZMA Encoder in fast compression mode could access memory outside of
421 allocated range in some rare cases. 432 allocated range in some rare cases.
422 433
423 434
4244.59 alpha 2008-05-30 4354.59 alpha 2008-05-30
425------------------------- 436-------------------------
426- BUGS was fixed: 437- BUGS was fixed:
427 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases. 438 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases.
428 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties. 439 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties.
429 440
@@ -440,13 +451,13 @@ HISTORY of the 7-Zip source code
440 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols. 451 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols.
441 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols. 452 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols.
442 3) -mcl switch: 7-Zip uses local code page. 453 3) -mcl switch: 7-Zip uses local code page.
443- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on 454- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on
444 455
445 456
4464.58 alpha 7 2008-04-08 4574.58 alpha 7 2008-04-08
447------------------------- 458-------------------------
448- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without 459- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without
449 creating, when BZip2 code was called with one thread (with -mmt1 switch or with 460 creating, when BZip2 code was called with one thread (with -mmt1 switch or with
450 default switches on single thread CPU). 461 default switches on single thread CPU).
451- .lzma support. 462- .lzma support.
452- RPM and NSIS support was improved. 463- RPM and NSIS support was improved.
@@ -472,7 +483,7 @@ HISTORY of the 7-Zip source code
472- 7-Zip now has 128 MB dictionary limit for 32-bit version: 483- 7-Zip now has 128 MB dictionary limit for 32-bit version:
473 It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2; 484 It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2;
474- TAR: 'D' link flag support. 485- TAR: 'D' link flag support.
475- 7-Zip now can unpack multivolume RAR archives created with 486- 7-Zip now can unpack multivolume RAR archives created with
476 "old style volume names" scheme (-vn switch) and names *.001, *.002, ... 487 "old style volume names" scheme (-vn switch) and names *.001, *.002, ...
477- Fixed bugs: 488- Fixed bugs:
478 - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\ 489 - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\
@@ -484,7 +495,7 @@ HISTORY of the 7-Zip source code
484 7-zip tries to delete all extra fileds (except for WzAES). 495 7-zip tries to delete all extra fileds (except for WzAES).
485 And that code could hang. 496 And that code could hang.
486 - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run. 497 - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run.
487 - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp 498 - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp
488 as modification time stamp. 499 as modification time stamp.
489 500
4904.58 alpha 2 2007-12-31 5014.58 alpha 2 2007-12-31
@@ -531,7 +542,7 @@ HISTORY of the 7-Zip source code
531 542
5324.45 beta 2007-04-16 5434.45 beta 2007-04-16
533------------------------- 544-------------------------
534- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at 545- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at
535 stratup code, or you must add CPP/Common/CRC.cpp to your project. 546 stratup code, or you must add CPP/Common/CRC.cpp to your project.
536- Method ID in .7z now is 63-bit integer (UInt64). 547- Method ID in .7z now is 63-bit integer (UInt64).
537- Open error messages 548- Open error messages
@@ -606,7 +617,7 @@ HISTORY of the 7-Zip source code
606 617
6074.07 beta 2004-10-03 6184.07 beta 2004-10-03
608------------------------- 619-------------------------
609- some interfaces were changed slightly to support 620- some interfaces were changed slightly to support
610 -stdin -stdout mode. 621 -stdin -stdout mode.
611- FilterCoder for simple filters 622- FilterCoder for simple filters
612- Wildcard censor class was changed. 623- Wildcard censor class was changed.
@@ -682,7 +693,7 @@ HISTORY of the 7-Zip source code
682 693
6832.30 Beta 24 2002-11-01 6942.30 Beta 24 2002-11-01
684------------------------- 695-------------------------
685 SDK/Windows/Synchronization.h 696 SDK/Windows/Synchronization.h
686 SDK/Windows/Synchronization.cpp 697 SDK/Windows/Synchronization.cpp
687 - some changes. 698 - some changes.
688 699
@@ -711,9 +722,9 @@ HISTORY of the 7-Zip source code
711 722
7122.30 Beta 20 2002-07-01 7232.30 Beta 20 2002-07-01
713------------------------- 724-------------------------
714- SDK/Stream/WindowOut.h 725- SDK/Stream/WindowOut.h
715 now it uses only required memory (dictionary size). 726 now it uses only required memory (dictionary size).
716- Project/Archiver/Resource 727- Project/Archiver/Resource
717 contains common resurces 728 contains common resurces
718 729
719 730
@@ -727,8 +738,8 @@ HISTORY of the 7-Zip source code
727- SDK/Archive/Cab/MSZipDecoder.cpp 738- SDK/Archive/Cab/MSZipDecoder.cpp
728 SDK/Archive/Cab/LZXDecoder.cpp: 739 SDK/Archive/Cab/LZXDecoder.cpp:
729 bug with corrupted archives was fixed 740 bug with corrupted archives was fixed
730- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h 741- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
731- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h 742- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
732 some speed optimization (using prefetching) 743 some speed optimization (using prefetching)
733 744
734 745
@@ -743,7 +754,7 @@ HISTORY of the 7-Zip source code
743 Bug was fixed: LZMA could not extract more than 4 GB. 754 Bug was fixed: LZMA could not extract more than 4 GB.
744- RPM and CPIO formats. 755- RPM and CPIO formats.
745- Project/Compress/LZ/LZMA/Encoder.* 756- Project/Compress/LZ/LZMA/Encoder.*
746 Project/Archiver/Format/7z/OutHandler.cpp 757 Project/Archiver/Format/7z/OutHandler.cpp
747 New fast compression mode for LZMA: -m0a=0. 758 New fast compression mode for LZMA: -m0a=0.
748- New match finders for LZMA: bt4b, hc3, hc4. 759- New match finders for LZMA: bt4b, hc3, hc4.
749 760
@@ -752,23 +763,23 @@ HISTORY of the 7-Zip source code
752------------------------- 763-------------------------
753- Compression ratio in LZMA was slightly improved: 764- Compression ratio in LZMA was slightly improved:
754 Project/Compress/LZ/LZMA/Encoder.* 765 Project/Compress/LZ/LZMA/Encoder.*
755 Project/Archiver/Format/7z/OutHandler.cpp 766 Project/Archiver/Format/7z/OutHandler.cpp
756 767
757 768
7582.30 Beta 14 2002-02-10 7692.30 Beta 14 2002-02-10
759------------------------- 770-------------------------
760- Supporting multithreading for LZMA: 771- Supporting multithreading for LZMA:
761 Project/Compress/LZ/MatchFinder/MT 772 Project/Compress/LZ/MatchFinder/MT
762- Common/String.h: 773- Common/String.h:
763 CStringBase::Replace function was fixed. 774 CStringBase::Replace function was fixed.
764 775
765 776
7662.30 Beta 13 2002-01-27 7772.30 Beta 13 2002-01-27
767------------------------- 778-------------------------
768- Compress/LZ/MatchFinder/BinTree3.h: 779- Compress/LZ/MatchFinder/BinTree3.h:
769 method 780 method
770- Compress/LZ/MatchFinder/BinTreemain.h: 781- Compress/LZ/MatchFinder/BinTreemain.h:
771 - one VirtualAlloc array was splitted to 782 - one VirtualAlloc array was splitted to
772 the for 3 arrays. 783 the for 3 arrays.
773 - Hash-functions were changed. 784 - Hash-functions were changed.
774 785
@@ -776,23 +787,23 @@ HISTORY of the 7-Zip source code
776 787
7772.30 Beta 12 2002-01-16 7882.30 Beta 12 2002-01-16
778------------------------- 789-------------------------
779- Compress/LZ/MatchFinder/BinTreemain.h: 790- Compress/LZ/MatchFinder/BinTreemain.h:
780 Compress/LZ/MatchFinder/Patricia.h: 791 Compress/LZ/MatchFinder/Patricia.h:
781 Compress/PPM/PPMd/SubAlloc.h: 792 Compress/PPM/PPMd/SubAlloc.h:
782 Beta 11 bugs were fixed: 793 Beta 11 bugs were fixed:
783 - VirtualFree was used incorrectly 794 - VirtualFree was used incorrectly
784 - checking WIN32 instead _WINDOWS. 795 - checking WIN32 instead _WINDOWS.
785 Compress/LZ/MatchFinder/Patricia.h: 796 Compress/LZ/MatchFinder/Patricia.h:
786 Beta 11 bug with deleting m_Hash2Descendants was fixed. 797 Beta 11 bug with deleting m_Hash2Descendants was fixed.
787 798
788 799
7892.30 Beta 11 2002-01-15 8002.30 Beta 11 2002-01-15
790------------------------- 801-------------------------
791- Compress/LZ/MatchFinder/BinTreemain.h: 802- Compress/LZ/MatchFinder/BinTreemain.h:
792 Compress/LZ/MatchFinder/Patricia.h: 803 Compress/LZ/MatchFinder/Patricia.h:
793 Compress/PPM/PPMd/SubAlloc.h: 804 Compress/PPM/PPMd/SubAlloc.h:
794 using VirtualAlloc for memory allocating 805 using VirtualAlloc for memory allocating
795- Exlorer/ContextMenu.cpp: 806- Exlorer/ContextMenu.cpp:
796 Testing supporting. 807 Testing supporting.
797 CreateProcess instead WinExec 808 CreateProcess instead WinExec
798- Format/Common/IArchiveHandler.h: 809- Format/Common/IArchiveHandler.h:
@@ -808,9 +819,9 @@ HISTORY of the 7-Zip source code
808 819
8092.30 Beta 10 2002-01-11 8202.30 Beta 10 2002-01-11
810------------------------- 821-------------------------
811- Exlorer/ContextMenu.cpp: bug with context menu on 822- Exlorer/ContextMenu.cpp: bug with context menu on
812 Windows NT4 in Unicode version was fixed. 823 Windows NT4 in Unicode version was fixed.
813- Format/7z/UpdateArchiveEngine.cpp: bug was fixed - 824- Format/7z/UpdateArchiveEngine.cpp: bug was fixed -
814 Updating in Beta 8 and 9 didn't work. 825 Updating in Beta 8 and 9 didn't work.
815- Exlorer/CCompressDialog.cpp: history growing bug was fixed. 826- Exlorer/CCompressDialog.cpp: history growing bug was fixed.
816 827
@@ -823,4 +834,3 @@ HISTORY of the 7-Zip source code
823- SDK/Archive/Zip/InEngine.cpp: bug was fixed. 834- SDK/Archive/Zip/InEngine.cpp: bug was fixed.
824- SDK/Windows/FileDir.cpp: function CreateComplexDirectory 835- SDK/Windows/FileDir.cpp: function CreateComplexDirectory
825 was changed. 836 was changed.
826