aboutsummaryrefslogtreecommitdiff
path: root/CPP
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2026-02-12 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2026-02-12 17:38:49 +0500
commit839151eaaad24771892afaae6bac690e31e58384 (patch)
treee292449d621f7a1d503b975984a2aca240dd2d8f /CPP
parent5e96a8279489832924056b1fa82f29d5837c9469 (diff)
download7zip-26.00.tar.gz
7zip-26.00.tar.bz2
7zip-26.00.zip
Diffstat (limited to 'CPP')
-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
44 files changed, 1494 insertions, 810 deletions
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