aboutsummaryrefslogtreecommitdiff
path: root/CPP
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CPP/7zip/7zip_gcc.mak20
-rw-r--r--CPP/7zip/Archive/7z/7zCompressionMode.h2
-rw-r--r--CPP/7zip/Archive/7z/7zHandlerOut.cpp30
-rw-r--r--CPP/7zip/Archive/ApmHandler.cpp182
-rw-r--r--CPP/7zip/Archive/ArHandler.cpp14
-rw-r--r--CPP/7zip/Archive/Bz2Handler.cpp8
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp48
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.cpp8
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.h37
-rw-r--r--CPP/7zip/Archive/Common/ItemNameUtils.cpp35
-rw-r--r--CPP/7zip/Archive/Common/ItemNameUtils.h3
-rw-r--r--CPP/7zip/Archive/CpioHandler.cpp42
-rw-r--r--CPP/7zip/Archive/DmgHandler.cpp6
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp801
-rw-r--r--CPP/7zip/Archive/HfsHandler.cpp256
-rw-r--r--CPP/7zip/Archive/LpHandler.cpp4
-rw-r--r--CPP/7zip/Archive/Nsis/NsisIn.cpp8
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp2
-rw-r--r--CPP/7zip/Archive/PeHandler.cpp4
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp27
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.h8
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp4
-rw-r--r--CPP/7zip/Archive/RpmHandler.cpp6
-rw-r--r--CPP/7zip/Archive/VmdkHandler.cpp9
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.cpp2
-rw-r--r--CPP/7zip/Archive/XarHandler.cpp113
-rw-r--r--CPP/7zip/Archive/XzHandler.cpp18
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp47
-rw-r--r--CPP/7zip/Bundles/Alone/Alone.dsp20
-rw-r--r--CPP/7zip/Bundles/Alone/makefile3
-rw-r--r--CPP/7zip/Bundles/Alone7z/makefile2
-rw-r--r--CPP/7zip/Bundles/Format7z/makefile2
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc.mak10
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc_gcc.mak8
-rw-r--r--CPP/7zip/Bundles/Format7zF/Format7z.dsp92
-rw-r--r--CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp21
-rw-r--r--CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp4
-rw-r--r--CPP/7zip/Common/CreateCoder.cpp2
-rw-r--r--CPP/7zip/Common/InBuffer.h10
-rw-r--r--CPP/7zip/Common/MethodProps.cpp34
-rw-r--r--CPP/7zip/Common/MethodProps.h18
-rw-r--r--CPP/7zip/Common/OutBuffer.h29
-rw-r--r--CPP/7zip/Compress/BZip2Const.h2
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.cpp707
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.h136
-rw-r--r--CPP/7zip/Compress/BitlEncoder.h1
-rw-r--r--CPP/7zip/Compress/BitmEncoder.h61
-rw-r--r--CPP/7zip/Compress/DeflateDecoder.cpp16
-rw-r--r--CPP/7zip/Compress/DeflateEncoder.cpp100
-rw-r--r--CPP/7zip/Compress/Lzma2Encoder.cpp10
-rw-r--r--CPP/7zip/Compress/LzmaEncoder.cpp18
-rw-r--r--CPP/7zip/Compress/Mtf8.h13
-rw-r--r--CPP/7zip/Compress/Rar5Decoder.cpp125
-rw-r--r--CPP/7zip/Crypto/MyAes.cpp27
-rw-r--r--CPP/7zip/Crypto/Rar5Aes.cpp117
-rw-r--r--CPP/7zip/Crypto/Rar5Aes.h57
-rw-r--r--CPP/7zip/Crypto/RarAes.cpp12
-rw-r--r--CPP/7zip/Crypto/ZipStrong.cpp43
-rw-r--r--CPP/7zip/GuiCommon.rc2
-rw-r--r--CPP/7zip/Guid.txt2
-rw-r--r--CPP/7zip/ICoder.h3
-rw-r--r--CPP/7zip/Sort.mak6
-rw-r--r--CPP/7zip/UI/Agent/Agent.cpp2
-rw-r--r--CPP/7zip/UI/Agent/Agent.h33
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.cpp2
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolder.cpp6
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolderOut.cpp76
-rw-r--r--CPP/7zip/UI/Agent/IFolderArchive.h16
-rw-r--r--CPP/7zip/UI/Client7z/makefile.gcc5
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp80
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp1260
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.h328
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp135
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp59
-rw-r--r--CPP/7zip/UI/Common/Extract.cpp2
-rw-r--r--CPP/7zip/UI/Common/ExtractingFilePath.cpp2
-rw-r--r--CPP/7zip/UI/Common/HashCalc.cpp325
-rw-r--r--CPP/7zip/UI/Common/HashCalc.h21
-rw-r--r--CPP/7zip/UI/Common/LoadCodecs.cpp6
-rw-r--r--CPP/7zip/UI/Common/TempFiles.cpp3
-rw-r--r--CPP/7zip/UI/Common/TempFiles.h3
-rw-r--r--CPP/7zip/UI/Common/Update.cpp72
-rw-r--r--CPP/7zip/UI/Common/Update.h7
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp110
-rw-r--r--CPP/7zip/UI/Common/WorkDir.cpp16
-rw-r--r--CPP/7zip/UI/Common/WorkDir.h8
-rw-r--r--CPP/7zip/UI/Common/ZipRegistry.cpp37
-rw-r--r--CPP/7zip/UI/Console/ConsoleClose.cpp10
-rw-r--r--CPP/7zip/UI/Console/ConsoleClose.h2
-rw-r--r--CPP/7zip/UI/Console/ExtractCallbackConsole.cpp2
-rw-r--r--CPP/7zip/UI/Console/Main.cpp9
-rw-r--r--CPP/7zip/UI/Console/MainAr.cpp2
-rw-r--r--CPP/7zip/UI/Console/PercentPrinter.h18
-rw-r--r--CPP/7zip/UI/Console/UpdateCallbackConsole.cpp113
-rw-r--r--CPP/7zip/UI/Console/UpdateCallbackConsole.h36
-rw-r--r--CPP/7zip/UI/Console/makefile2
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.cpp10
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.h4
-rw-r--r--CPP/7zip/UI/Explorer/makefile2
-rw-r--r--CPP/7zip/UI/Far/Far.cpp7
-rw-r--r--CPP/7zip/UI/Far/FarUtils.cpp4
-rw-r--r--CPP/7zip/UI/Far/Plugin.cpp9
-rw-r--r--CPP/7zip/UI/Far/ProgressBox.h10
-rw-r--r--CPP/7zip/UI/Far/UpdateCallbackFar.cpp90
-rw-r--r--CPP/7zip/UI/Far/UpdateCallbackFar.h16
-rw-r--r--CPP/7zip/UI/Far/makefile2
-rw-r--r--CPP/7zip/UI/FileManager/App.cpp14
-rw-r--r--CPP/7zip/UI/FileManager/App.h2
-rw-r--r--CPP/7zip/UI/FileManager/ExtractCallback.cpp272
-rw-r--r--CPP/7zip/UI/FileManager/ExtractCallback.h190
-rw-r--r--CPP/7zip/UI/FileManager/FM.cpp19
-rw-r--r--CPP/7zip/UI/FileManager/LangUtils.cpp12
-rw-r--r--CPP/7zip/UI/FileManager/LinkDialog.cpp30
-rw-r--r--CPP/7zip/UI/FileManager/MemDialog.cpp10
-rw-r--r--CPP/7zip/UI/FileManager/MemDialog.h2
-rw-r--r--CPP/7zip/UI/FileManager/MyLoadMenu.cpp8
-rw-r--r--CPP/7zip/UI/FileManager/OpenCallback.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/Panel.cpp11
-rw-r--r--CPP/7zip/UI/FileManager/Panel.h293
-rw-r--r--CPP/7zip/UI/FileManager/PanelCopy.cpp54
-rw-r--r--CPP/7zip/UI/FileManager/PanelDrag.cpp8
-rw-r--r--CPP/7zip/UI/FileManager/PanelFolderChange.cpp14
-rw-r--r--CPP/7zip/UI/FileManager/PanelItemOpen.cpp105
-rw-r--r--CPP/7zip/UI/FileManager/PanelItems.cpp17
-rw-r--r--CPP/7zip/UI/FileManager/PanelListNotify.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/PanelOperations.cpp6
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2.cpp105
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2.h57
-rw-r--r--CPP/7zip/UI/FileManager/RegistryUtils.cpp8
-rw-r--r--CPP/7zip/UI/FileManager/RootFolder.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/SettingsPage.cpp6
-rw-r--r--CPP/7zip/UI/FileManager/SysIconUtils.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/UpdateCallback100.cpp23
-rw-r--r--CPP/7zip/UI/FileManager/UpdateCallback100.h5
-rw-r--r--CPP/7zip/UI/FileManager/ViewSettings.cpp17
-rw-r--r--CPP/7zip/UI/FileManager/makefile2
-rw-r--r--CPP/7zip/UI/FileManager/resource.h11
-rw-r--r--CPP/7zip/UI/FileManager/resource.rc6
-rw-r--r--CPP/7zip/UI/FileManager/resourceGui.h2
-rw-r--r--CPP/7zip/UI/FileManager/resourceGui.rc2
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.cpp81
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.rc2
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp90
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.h20
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp15
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp73
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI2.h31
-rw-r--r--CPP/7zip/UI/GUI/makefile3
-rw-r--r--CPP/7zip/warn_gcc.mak17
-rw-r--r--CPP/Build.mak8
-rw-r--r--CPP/Common/Md5Reg.cpp44
-rw-r--r--CPP/Common/MyCom.h37
-rw-r--r--CPP/Common/MyString.cpp29
-rw-r--r--CPP/Common/MyString.h13
-rw-r--r--CPP/Common/MyXml.cpp4
-rw-r--r--CPP/Common/Sha3Reg.cpp76
-rw-r--r--CPP/Common/Sha512Prepare.cpp7
-rw-r--r--CPP/Common/Sha512Reg.cpp83
-rw-r--r--CPP/Common/Wildcard.cpp13
-rw-r--r--CPP/Windows/FileDir.cpp211
-rw-r--r--CPP/Windows/FileDir.h41
-rw-r--r--CPP/Windows/FileFind.cpp9
-rw-r--r--CPP/Windows/FileIO.h43
-rw-r--r--CPP/Windows/FileLink.cpp244
-rw-r--r--CPP/Windows/FileName.cpp79
-rw-r--r--CPP/Windows/FileName.h13
-rw-r--r--CPP/Windows/Registry.cpp295
-rw-r--r--CPP/Windows/Registry.h48
-rw-r--r--CPP/Windows/System.cpp169
-rw-r--r--CPP/Windows/System.h63
-rw-r--r--CPP/Windows/SystemInfo.cpp125
-rw-r--r--CPP/Windows/SystemInfo.h2
-rw-r--r--CPP/Windows/Thread.h8
-rw-r--r--CPP/Windows/TimeUtils.cpp3
174 files changed, 6542 insertions, 3197 deletions
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
index 45c9ab3..12f1ef2 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -302,6 +302,8 @@ $O/ListFileUtils.o: ../../../Common/ListFileUtils.cpp
302 $(CXX) $(CXXFLAGS) $< 302 $(CXX) $(CXXFLAGS) $<
303$O/LzFindPrepare.o: ../../../Common/LzFindPrepare.cpp 303$O/LzFindPrepare.o: ../../../Common/LzFindPrepare.cpp
304 $(CXX) $(CXXFLAGS) $< 304 $(CXX) $(CXXFLAGS) $<
305$O/Md5Reg.o: ../../../Common/Md5Reg.cpp
306 $(CXX) $(CXXFLAGS) $<
305$O/MyMap.o: ../../../Common/MyMap.cpp 307$O/MyMap.o: ../../../Common/MyMap.cpp
306 $(CXX) $(CXXFLAGS) $< 308 $(CXX) $(CXXFLAGS) $<
307$O/MyString.o: ../../../Common/MyString.cpp 309$O/MyString.o: ../../../Common/MyString.cpp
@@ -326,6 +328,12 @@ $O/Sha256Prepare.o: ../../../Common/Sha256Prepare.cpp
326 $(CXX) $(CXXFLAGS) $< 328 $(CXX) $(CXXFLAGS) $<
327$O/Sha256Reg.o: ../../../Common/Sha256Reg.cpp 329$O/Sha256Reg.o: ../../../Common/Sha256Reg.cpp
328 $(CXX) $(CXXFLAGS) $< 330 $(CXX) $(CXXFLAGS) $<
331$O/Sha3Reg.o: ../../../Common/Sha3Reg.cpp
332 $(CXX) $(CXXFLAGS) $<
333$O/Sha512Prepare.o: ../../../Common/Sha512Prepare.cpp
334 $(CXX) $(CXXFLAGS) $<
335$O/Sha512Reg.o: ../../../Common/Sha512Reg.cpp
336 $(CXX) $(CXXFLAGS) $<
329$O/StdInStream.o: ../../../Common/StdInStream.cpp 337$O/StdInStream.o: ../../../Common/StdInStream.cpp
330 $(CXX) $(CXXFLAGS) $< 338 $(CXX) $(CXXFLAGS) $<
331$O/StdOutStream.o: ../../../Common/StdOutStream.cpp 339$O/StdOutStream.o: ../../../Common/StdOutStream.cpp
@@ -1207,6 +1215,8 @@ $O/Lzma2Enc.o: ../../../../C/Lzma2Enc.c
1207 $(CC) $(CFLAGS) $< 1215 $(CC) $(CFLAGS) $<
1208$O/LzmaLib.o: ../../../../C/LzmaLib.c 1216$O/LzmaLib.o: ../../../../C/LzmaLib.c
1209 $(CC) $(CFLAGS) $< 1217 $(CC) $(CFLAGS) $<
1218$O/Md5.o: ../../../../C/Md5.c
1219 $(CC) $(CFLAGS) $<
1210$O/MtCoder.o: ../../../../C/MtCoder.c 1220$O/MtCoder.o: ../../../../C/MtCoder.c
1211 $(CC) $(CFLAGS) $< 1221 $(CC) $(CFLAGS) $<
1212$O/MtDec.o: ../../../../C/MtDec.c 1222$O/MtDec.o: ../../../../C/MtDec.c
@@ -1229,7 +1239,11 @@ $O/Sha1.o: ../../../../C/Sha1.c
1229 $(CC) $(CFLAGS) $< 1239 $(CC) $(CFLAGS) $<
1230$O/Sha256.o: ../../../../C/Sha256.c 1240$O/Sha256.o: ../../../../C/Sha256.c
1231 $(CC) $(CFLAGS) $< 1241 $(CC) $(CFLAGS) $<
1232$O/Sort.o: ../../../../C/Sort.c 1242$O/Sha3.o: ../../../../C/Sha3.c
1243 $(CC) $(CFLAGS) $<
1244$O/Sha512.o: ../../../../C/Sha512.c
1245 $(CC) $(CFLAGS) $<
1246$O/Sha512Opt.o: ../../../../C/Sha512Opt.c
1233 $(CC) $(CFLAGS) $< 1247 $(CC) $(CFLAGS) $<
1234$O/SwapBytes.o: ../../../../C/SwapBytes.c 1248$O/SwapBytes.o: ../../../../C/SwapBytes.c
1235 $(CC) $(CFLAGS) $< 1249 $(CC) $(CFLAGS) $<
@@ -1269,6 +1283,8 @@ $O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm
1269 $(MY_ASM) $(AFLAGS) $< 1283 $(MY_ASM) $(AFLAGS) $<
1270$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm 1284$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm
1271 $(MY_ASM) $(AFLAGS) $< 1285 $(MY_ASM) $(AFLAGS) $<
1286$O/Sort.o: ../../../../Asm/x86/Sort.asm
1287 $(MY_ASM) $(AFLAGS) $<
1272 1288
1273ifndef USE_JWASM 1289ifndef USE_JWASM
1274USE_X86_ASM_AES=1 1290USE_X86_ASM_AES=1
@@ -1283,6 +1299,8 @@ $O/Sha1Opt.o: ../../../../C/Sha1Opt.c
1283 $(CC) $(CFLAGS) $< 1299 $(CC) $(CFLAGS) $<
1284$O/Sha256Opt.o: ../../../../C/Sha256Opt.c 1300$O/Sha256Opt.o: ../../../../C/Sha256Opt.c
1285 $(CC) $(CFLAGS) $< 1301 $(CC) $(CFLAGS) $<
1302$O/Sort.o: ../../../../C/Sort.c
1303 $(CC) $(CFLAGS) $<
1286endif 1304endif
1287 1305
1288 1306
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h
index 737722d..ecfee7c 100644
--- a/CPP/7zip/Archive/7z/7zCompressionMode.h
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.h
@@ -59,6 +59,7 @@ struct CCompressionMethodMode
59 bool NumThreads_WasForced; 59 bool NumThreads_WasForced;
60 bool MultiThreadMixer; 60 bool MultiThreadMixer;
61 UInt32 NumThreads; 61 UInt32 NumThreads;
62 UInt32 NumThreadGroups;
62 #endif 63 #endif
63 64
64 UString Password; // _Wipe 65 UString Password; // _Wipe
@@ -74,6 +75,7 @@ struct CCompressionMethodMode
74 , NumThreads_WasForced(false) 75 , NumThreads_WasForced(false)
75 , MultiThreadMixer(true) 76 , MultiThreadMixer(true)
76 , NumThreads(1) 77 , NumThreads(1)
78 , NumThreadGroups(0)
77 #endif 79 #endif
78 , MemoryUsageLimit((UInt64)1 << 30) 80 , MemoryUsageLimit((UInt64)1 << 30)
79 {} 81 {}
diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
index ea5ea0f..c1c2b63 100644
--- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp
+++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -111,8 +111,8 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
111 } 111 }
112 } 112 }
113 113
114 const UInt64 kSolidBytes_Min = (1 << 24); 114 const UInt64 kSolidBytes_Min = 1 << 24;
115 const UInt64 kSolidBytes_Max = ((UInt64)1 << 32); 115 const UInt64 kSolidBytes_Max = (UInt64)1 << 32; // for non-LZMA2 methods
116 116
117 bool needSolid = false; 117 bool needSolid = false;
118 118
@@ -122,22 +122,24 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
122 122
123 SetGlobalLevelTo(oneMethodInfo); 123 SetGlobalLevelTo(oneMethodInfo);
124 124
125 #ifndef Z7_ST 125#ifndef Z7_ST
126 const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); 126 const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
127 if (!numThreads_WasSpecifiedInMethod) 127 if (!numThreads_WasSpecifiedInMethod)
128 { 128 {
129 // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already 129 // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
130 CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads); 130 CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads);
131 } 131 }
132 #endif 132 if (methodMode.NumThreadGroups > 1)
133 CMultiMethodProps::Set_Method_NumThreadGroups_IfNotFinded(oneMethodInfo, methodMode.NumThreadGroups);
134#endif
133 135
134 CMethodFull &methodFull = methodMode.Methods.AddNew(); 136 CMethodFull &methodFull = methodMode.Methods.AddNew();
135 RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)) 137 RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo))
136 138
137 #ifndef Z7_ST 139#ifndef Z7_ST
138 methodFull.Set_NumThreads = true; 140 methodFull.Set_NumThreads = true;
139 methodFull.NumThreads = methodMode.NumThreads; 141 methodFull.NumThreads = methodMode.NumThreads;
140 #endif 142#endif
141 143
142 if (methodFull.Id != k_Copy) 144 if (methodFull.Id != k_Copy)
143 needSolid = true; 145 needSolid = true;
@@ -217,19 +219,18 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
217 // here we get real chunkSize 219 // here we get real chunkSize
218 cs = oneMethodInfo.Get_Xz_BlockSize(); 220 cs = oneMethodInfo.Get_Xz_BlockSize();
219 if (dicSize > cs) 221 if (dicSize > cs)
220 dicSize = cs; 222 dicSize = cs;
221 223
222 const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34); 224 const UInt64 kSolidBytes_Lzma2_Max = (UInt64)1 << 34;
223 if (numSolidBytes > kSolidBytes_Lzma2_Max) 225 if (numSolidBytes > kSolidBytes_Lzma2_Max)
224 numSolidBytes = kSolidBytes_Lzma2_Max; 226 numSolidBytes = kSolidBytes_Lzma2_Max;
225 227
226 methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder 228 methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
227 229
228 #ifndef Z7_ST 230 #ifndef Z7_ST
229 if (!numThreads_WasSpecifiedInMethod 231 if (!numThreads_WasSpecifiedInMethod
230 && !methodMode.NumThreads_WasForced 232 && !methodMode.NumThreads_WasForced
231 && methodMode.MemoryUsageLimit_WasSet 233 && methodMode.MemoryUsageLimit_WasSet)
232 )
233 { 234 {
234 const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); 235 const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
235 const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads; 236 const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads;
@@ -273,14 +274,14 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
273 { 274 {
274 numSolidBytes = (UInt64)dicSize << 7; 275 numSolidBytes = (UInt64)dicSize << 7;
275 if (numSolidBytes > kSolidBytes_Max) 276 if (numSolidBytes > kSolidBytes_Max)
276 numSolidBytes = kSolidBytes_Max; 277 numSolidBytes = kSolidBytes_Max;
277 } 278 }
278 279
279 if (_numSolidBytesDefined) 280 if (_numSolidBytesDefined)
280 continue; 281 continue;
281 282
282 if (numSolidBytes < kSolidBytes_Min) 283 if (numSolidBytes < kSolidBytes_Min)
283 numSolidBytes = kSolidBytes_Min; 284 numSolidBytes = kSolidBytes_Min;
284 _numSolidBytes = numSolidBytes; 285 _numSolidBytes = numSolidBytes;
285 _numSolidBytesDefined = true; 286 _numSolidBytesDefined = true;
286 } 287 }
@@ -704,6 +705,9 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
704 methodMode.NumThreads = numThreads; 705 methodMode.NumThreads = numThreads;
705 methodMode.NumThreads_WasForced = _numThreads_WasForced; 706 methodMode.NumThreads_WasForced = _numThreads_WasForced;
706 methodMode.MultiThreadMixer = _useMultiThreadMixer; 707 methodMode.MultiThreadMixer = _useMultiThreadMixer;
708#ifdef _WIN32
709 methodMode.NumThreadGroups = _numThreadGroups; // _change it
710#endif
707 // headerMethod.NumThreads = 1; 711 // headerMethod.NumThreads = 1;
708 headerMethod.MultiThreadMixer = _useMultiThreadMixer; 712 headerMethod.MultiThreadMixer = _useMultiThreadMixer;
709 } 713 }
diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp
index 56d9b6e..e88d2fe 100644
--- a/CPP/7zip/Archive/ApmHandler.cpp
+++ b/CPP/7zip/Archive/ApmHandler.cpp
@@ -6,7 +6,6 @@
6 6
7#include "../../Common/ComTry.h" 7#include "../../Common/ComTry.h"
8 8
9#include "../../Windows/PropVariant.h"
10#include "../../Windows/PropVariantUtils.h" 9#include "../../Windows/PropVariantUtils.h"
11 10
12#include "../Common/RegisterArc.h" 11#include "../Common/RegisterArc.h"
@@ -14,8 +13,7 @@
14 13
15#include "HandlerCont.h" 14#include "HandlerCont.h"
16 15
17// #define Get16(p) GetBe16(p) 16#define Get32(p) GetBe32a(p)
18#define Get32(p) GetBe32(p)
19 17
20using namespace NWindows; 18using namespace NWindows;
21 19
@@ -41,8 +39,8 @@ static const CUInt32PCharPair k_Flags[] =
41 { 5, "WRITABLE" }, 39 { 5, "WRITABLE" },
42 { 6, "OS_PIC_CODE" }, 40 { 6, "OS_PIC_CODE" },
43 // { 7, "OS_SPECIFIC_2" }, // "Unused" 41 // { 7, "OS_SPECIFIC_2" }, // "Unused"
44 // { 8, "ChainCompatible" }, // "OS_SPECIFIC_1" 42 { 8, "ChainCompatible" }, // "OS_SPECIFIC_1"
45 // { 9, "RealDeviceDriver" }, 43 { 9, "RealDeviceDriver" },
46 // { 10, "CanChainToNext" }, 44 // { 10, "CanChainToNext" },
47 { 30, "MOUNTED_AT_STARTUP" }, 45 { 30, "MOUNTED_AT_STARTUP" },
48 { 31, "STARTUP" } 46 { 31, "STARTUP" }
@@ -74,16 +72,16 @@ struct CItem
74 bool Is_Valid_and_Allocated() const 72 bool Is_Valid_and_Allocated() const
75 { return (Flags & (DPME_FLAGS_VALID | DPME_FLAGS_ALLOCATED)) != 0; } 73 { return (Flags & (DPME_FLAGS_VALID | DPME_FLAGS_ALLOCATED)) != 0; }
76 74
77 bool Parse(const Byte *p, UInt32 &numBlocksInMap) 75 bool Parse(const UInt32 *p32, UInt32 &numBlocksInMap)
78 { 76 {
79 numBlocksInMap = Get32(p + 4); 77 if (GetUi32a(p32) != 0x4d50) // "PM"
80 StartBlock = Get32(p + 8);
81 NumBlocks = Get32(p + 0xc);
82 Flags = Get32(p + 0x58);
83 memcpy(Name, p + 0x10, k_Str_Size);
84 memcpy(Type, p + 0x30, k_Str_Size);
85 if (GetUi32(p) != 0x4d50) // "PM"
86 return false; 78 return false;
79 numBlocksInMap = Get32(p32 + 4 / 4);
80 StartBlock = Get32(p32 + 8 / 4);
81 NumBlocks = Get32(p32 + 0xc / 4);
82 Flags = Get32(p32 + 0x58 / 4);
83 memcpy(Name, p32 + 0x10 / 4, k_Str_Size);
84 memcpy(Type, p32 + 0x30 / 4, k_Str_Size);
87 /* 85 /*
88 DataStartBlock = Get32(p + 0x50); 86 DataStartBlock = Get32(p + 0x50);
89 NumDataBlocks = Get32(p + 0x54); 87 NumDataBlocks = Get32(p + 0x54);
@@ -96,7 +94,7 @@ struct CItem
96 if (Get32(p + 0x70) != 0) 94 if (Get32(p + 0x70) != 0)
97 return false; 95 return false;
98 BootChecksum = Get32(p + 0x74); 96 BootChecksum = Get32(p + 0x74);
99 memcpy(Processor, p + 0x78, 16); 97 memcpy(Processor, p32 + 0x78 / 4, 16);
100 */ 98 */
101 return true; 99 return true;
102 } 100 }
@@ -109,9 +107,9 @@ Z7_class_CHandler_final: public CHandlerCont
109 107
110 CRecordVector<CItem> _items; 108 CRecordVector<CItem> _items;
111 unsigned _blockSizeLog; 109 unsigned _blockSizeLog;
112 UInt32 _numBlocks;
113 UInt64 _phySize;
114 bool _isArc; 110 bool _isArc;
111 // UInt32 _numBlocks;
112 UInt64 _phySize;
115 113
116 UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } 114 UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
117 115
@@ -132,11 +130,11 @@ API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size)
132{ 130{
133 if (size < kSectorSize) 131 if (size < kSectorSize)
134 return k_IsArc_Res_NEED_MORE; 132 return k_IsArc_Res_NEED_MORE;
135 if (GetUi64(p + 8) != 0) 133 if (GetUi32(p + 12) != 0)
136 return k_IsArc_Res_NO; 134 return k_IsArc_Res_NO;
137 UInt32 v = GetUi32(p); // we read as little-endian 135 UInt32 v = GetUi32(p); // we read as little-endian
138 v ^= (kSig0 | (unsigned)kSig1 << 8); 136 v ^= kSig0 | (unsigned)kSig1 << 8;
139 if ((v & ~((UInt32)0xf << 17))) 137 if (v & ~((UInt32)0xf << 17))
140 return k_IsArc_Res_NO; 138 return k_IsArc_Res_NO;
141 if ((0x116u >> (v >> 17)) & 1) 139 if ((0x116u >> (v >> 17)) & 1)
142 return k_IsArc_Res_YES; 140 return k_IsArc_Res_YES;
@@ -149,55 +147,103 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
149 COM_TRY_BEGIN 147 COM_TRY_BEGIN
150 Close(); 148 Close();
151 149
152 Byte buf[kSectorSize]; 150 UInt32 buf32[kSectorSize / 4];
153 unsigned numSectors_in_Cluster; 151 unsigned numPadSectors, blockSizeLog_from_Header;
154 { 152 {
155 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 153 // Driver Descriptor Map (DDM)
156 if (GetUi64(buf + 8) != 0) 154 RINOK(ReadStream_FALSE(stream, buf32, kSectorSize))
155 // 8: UInt16 sbDevType : =0 (usually), =1 in Apple Mac OS X 10.3.0 iso
156 // 10: UInt16 sbDevId : =0 (usually), =1 in Apple Mac OS X 10.3.0 iso
157 // 12: UInt32 sbData : =0
158 if (buf32[3] != 0)
157 return S_FALSE; 159 return S_FALSE;
158 UInt32 v = GetUi32(buf); // we read as little-endian 160 UInt32 v = GetUi32a(buf32); // we read as little-endian
159 v ^= (kSig0 | (unsigned)kSig1 << 8); 161 v ^= kSig0 | (unsigned)kSig1 << 8;
160 if ((v & ~((UInt32)0xf << 17))) 162 if (v & ~((UInt32)0xf << 17))
161 return S_FALSE; 163 return S_FALSE;
162 v >>= 16; 164 v >>= 16;
163 if (v == 0) 165 if (v == 0)
164 return S_FALSE; 166 return S_FALSE;
165 if (v & (v - 1)) 167 if (v & (v - 1))
166 return S_FALSE; 168 return S_FALSE;
167 const unsigned a = (0x30210u >> v) & 3; 169 // v == { 16,8,4,2 } : block size (x256 bytes)
168 // a = 0; // for debug 170 const unsigned a =
169 numSectors_in_Cluster = 1u << a; 171#if 1
170 _blockSizeLog = 9 + a; 172 (0x30210u >> v) & 3;
173#else
174 0; // for debug : hardcoded switch to 512-bytes mode
175#endif
176 numPadSectors = (1u << a) - 1;
177 _blockSizeLog = blockSizeLog_from_Header = 9 + a;
171 } 178 }
172 179
173 UInt32 numBlocks = Get32(buf + 4); 180/*
174 _numBlocks = numBlocks; 181 some APMs (that are ".iso" macOS installation files) contain
175 182 (blockSizeLog == 11) in DDM header,
183 and contain 2 overlapping maps:
184 1) map for 512-bytes-step
185 2) map for 2048-bytes-step
186 512-bytes-step map is correct.
187 2048-bytes-step map can be incorrect in some cases.
188
189 macos 8 / OSX DP2 iso:
190 There is shared "hfs" item in both maps.
191 And correct (offset/size) values for "hfs" partition
192 can be calculated only in 512-bytes mode (ignoring blockSizeLog == 11).
193 But some records (Macintosh.Apple_Driver*_)
194 can be correct on both modes: 512-bytes mode / 2048-bytes-step.
195
196 macos 921 ppc / Apple Mac OS X 10.3.0 iso:
197 Both maps are correct.
198 If we use 512-bytes-step, each 4th item is (Apple_Void) with zero size.
199 And these zero size (Apple_Void) items will be first items in 2048-bytes-step map.
200*/
201
202// we define Z7_APM_SWITCH_TO_512_BYTES, because
203// we want to support old MACOS APMs that contain correct value only
204// for 512-bytes-step mode
205#define Z7_APM_SWITCH_TO_512_BYTES
206
207 const UInt32 numBlocks_from_Header = Get32(buf32 + 1);
208 UInt32 numBlocks = 0;
176 { 209 {
177 for (unsigned k = numSectors_in_Cluster; --k != 0;) 210 for (unsigned k = 0; k < numPadSectors; k++)
178 { 211 {
179 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 212 RINOK(ReadStream_FALSE(stream, buf32, kSectorSize))
213#ifdef Z7_APM_SWITCH_TO_512_BYTES
214 if (k == 0)
215 {
216 if (GetUi32a(buf32) == 0x4d50 // "PM"
217 // && (Get32(buf32 + 0x58 / 4) & 1) // Flags::VALID
218 // some old APMs don't use VALID flag for Apple_partition_map item
219 && Get32(buf32 + 8 / 4) == 1) // StartBlock
220 {
221 // we switch the mode to 512-bytes-step map reading:
222 numPadSectors = 0;
223 _blockSizeLog = 9;
224 break;
225 }
226 }
227#endif
180 } 228 }
181 } 229 }
182 230
183 UInt32 numBlocksInMap = 0;
184
185 for (unsigned i = 0;;) 231 for (unsigned i = 0;;)
186 { 232 {
187 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 233#ifdef Z7_APM_SWITCH_TO_512_BYTES
234 if (i != 0 || _blockSizeLog == blockSizeLog_from_Header)
235#endif
236 {
237 RINOK(ReadStream_FALSE(stream, buf32, kSectorSize))
238 }
188 239
189 CItem item; 240 CItem item;
190 241 UInt32 numBlocksInMap = 0;
191 UInt32 numBlocksInMap2 = 0; 242 if (!item.Parse(buf32, numBlocksInMap))
192 if (!item.Parse(buf, numBlocksInMap2))
193 return S_FALSE; 243 return S_FALSE;
194 if (i == 0) 244 // v24.09: we don't check that all entries have same (numBlocksInMap) values,
195 { 245 // because some APMs have different (numBlocksInMap) values, if (Apple_Void) is used.
196 numBlocksInMap = numBlocksInMap2; 246 if (numBlocksInMap > (1 << 8) || numBlocksInMap <= i)
197 if (numBlocksInMap > (1 << 8) || numBlocksInMap == 0)
198 return S_FALSE;
199 }
200 else if (numBlocksInMap2 != numBlocksInMap)
201 return S_FALSE; 247 return S_FALSE;
202 248
203 const UInt32 finish = item.StartBlock + item.NumBlocks; 249 const UInt32 finish = item.StartBlock + item.NumBlocks;
@@ -207,15 +253,19 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
207 numBlocks = finish; 253 numBlocks = finish;
208 254
209 _items.Add(item); 255 _items.Add(item);
210 for (unsigned k = numSectors_in_Cluster; --k != 0;) 256 if (numPadSectors != 0)
211 { 257 {
212 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 258 RINOK(stream->Seek(numPadSectors << 9, STREAM_SEEK_CUR, NULL))
213 } 259 }
214 if (++i == numBlocksInMap) 260 if (++i == numBlocksInMap)
215 break; 261 break;
216 } 262 }
217 263
218 _phySize = BlocksToBytes(numBlocks); 264 _phySize = BlocksToBytes(numBlocks);
265 // _numBlocks = numBlocks;
266 const UInt64 physSize = (UInt64)numBlocks_from_Header << blockSizeLog_from_Header;
267 if (_phySize < physSize)
268 _phySize = physSize;
219 _isArc = true; 269 _isArc = true;
220 _stream = stream; 270 _stream = stream;
221 271
@@ -240,22 +290,21 @@ static const Byte kProps[] =
240 kpidSize, 290 kpidSize,
241 kpidOffset, 291 kpidOffset,
242 kpidCharacts 292 kpidCharacts
293 // , kpidCpu
243}; 294};
244 295
245static const Byte kArcProps[] = 296static const Byte kArcProps[] =
246{ 297{
247 kpidClusterSize, 298 kpidClusterSize
248 kpidNumBlocks 299 // , kpidNumBlocks
249}; 300};
250 301
251IMP_IInArchive_Props 302IMP_IInArchive_Props
252IMP_IInArchive_ArcProps 303IMP_IInArchive_ArcProps
253 304
254static AString GetString(const char *s) 305static void GetString(AString &dest, const char *src)
255{ 306{
256 AString res; 307 dest.SetFrom_CalcLen(src, k_Str_Size);
257 res.SetFrom_CalcLen(s, k_Str_Size);
258 return res;
259} 308}
260 309
261Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) 310Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
@@ -272,7 +321,8 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
272 const CItem &item = _items[i]; 321 const CItem &item = _items[i];
273 if (!item.Is_Valid_and_Allocated()) 322 if (!item.Is_Valid_and_Allocated())
274 continue; 323 continue;
275 AString s (GetString(item.Type)); 324 AString s;
325 GetString(s, item.Type);
276 if (NDmg::Is_Apple_FS_Or_Unknown(s)) 326 if (NDmg::Is_Apple_FS_Or_Unknown(s))
277 { 327 {
278 if (mainIndex != -1) 328 if (mainIndex != -1)
@@ -289,7 +339,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
289 } 339 }
290 case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; 340 case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
291 case kpidPhySize: prop = _phySize; break; 341 case kpidPhySize: prop = _phySize; break;
292 case kpidNumBlocks: prop = _numBlocks; break; 342 // case kpidNumBlocks: prop = _numBlocks; break;
293 343
294 case kpidErrorFlags: 344 case kpidErrorFlags:
295 { 345 {
@@ -319,10 +369,12 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
319 { 369 {
320 case kpidPath: 370 case kpidPath:
321 { 371 {
322 AString s (GetString(item.Name)); 372 AString s;
373 GetString(s, item.Name);
323 if (s.IsEmpty()) 374 if (s.IsEmpty())
324 s.Add_UInt32(index); 375 s.Add_UInt32(index);
325 AString type (GetString(item.Type)); 376 AString type;
377 GetString(type, item.Type);
326 { 378 {
327 const char *ext = NDmg::Find_Apple_FS_Ext(type); 379 const char *ext = NDmg::Find_Apple_FS_Ext(type);
328 if (ext) 380 if (ext)
@@ -336,6 +388,16 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
336 prop = s; 388 prop = s;
337 break; 389 break;
338 } 390 }
391/*
392 case kpidCpu:
393 {
394 AString s;
395 s.SetFrom_CalcLen(item.Processor, sizeof(item.Processor));
396 if (!s.IsEmpty())
397 prop = s;
398 break;
399 }
400*/
339 case kpidSize: 401 case kpidSize:
340 case kpidPackSize: 402 case kpidPackSize:
341 prop = BlocksToBytes(item.NumBlocks); 403 prop = BlocksToBytes(item.NumBlocks);
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp
index 95e4719..944eec4 100644
--- a/CPP/7zip/Archive/ArHandler.cpp
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -325,7 +325,7 @@ HRESULT CHandler::ParseLongNames(IInStream *stream)
325{ 325{
326 unsigned i; 326 unsigned i;
327 for (i = 0; i < _items.Size(); i++) 327 for (i = 0; i < _items.Size(); i++)
328 if (_items[i].Name == "//") 328 if (_items[i].Name.IsEqualTo("//"))
329 break; 329 break;
330 if (i == _items.Size()) 330 if (i == _items.Size())
331 return S_OK; 331 return S_OK;
@@ -378,7 +378,7 @@ void CHandler::ChangeDuplicateNames()
378 if (item.Name[0] == '/') 378 if (item.Name[0] == '/')
379 continue; 379 continue;
380 CItem &prev = _items[i - 1]; 380 CItem &prev = _items[i - 1];
381 if (item.Name == prev.Name) 381 if (item.Name.IsEqualTo(prev.Name))
382 { 382 {
383 if (prev.SameNameIndex < 0) 383 if (prev.SameNameIndex < 0)
384 prev.SameNameIndex = 0; 384 prev.SameNameIndex = 0;
@@ -448,9 +448,9 @@ static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); ret
448HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) 448HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex)
449{ 449{
450 CItem &item = _items[fileIndex]; 450 CItem &item = _items[fileIndex];
451 if (item.Name != "/" && 451 if (!item.Name.IsEqualTo("/") &&
452 item.Name != "__.SYMDEF" && 452 !item.Name.IsEqualTo("__.SYMDEF") &&
453 item.Name != "__.SYMDEF SORTED") 453 !item.Name.IsEqualTo("__.SYMDEF SORTED"))
454 return S_OK; 454 return S_OK;
455 if (item.Size > ((UInt32)1 << 30) || 455 if (item.Size > ((UInt32)1 << 30) ||
456 item.Size < 4) 456 item.Size < 4)
@@ -462,7 +462,7 @@ HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex)
462 462
463 size_t pos = 0; 463 size_t pos = 0;
464 464
465 if (item.Name != "/") 465 if (!item.Name.IsEqualTo("/"))
466 { 466 {
467 // "__.SYMDEF" parsing (BSD) 467 // "__.SYMDEF" parsing (BSD)
468 unsigned be; 468 unsigned be;
@@ -603,7 +603,7 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
603 if (_longNames_FileIndex >= 0) 603 if (_longNames_FileIndex >= 0)
604 _items.Delete((unsigned)_longNames_FileIndex); 604 _items.Delete((unsigned)_longNames_FileIndex);
605 605
606 if (!_items.IsEmpty() && _items[0].Name == "debian-binary") 606 if (!_items.IsEmpty() && _items[0].Name.IsEqualTo("debian-binary"))
607 { 607 {
608 _type = kType_Deb; 608 _type = kType_Deb;
609 _items.DeleteFrontal(1); 609 _items.DeleteFrontal(1);
diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp
index ffd7ad0..02eeee6 100644
--- a/CPP/7zip/Archive/Bz2Handler.cpp
+++ b/CPP/7zip/Archive/Bz2Handler.cpp
@@ -427,9 +427,13 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
427 } 427 }
428 428
429 CMethodProps props2 = _props; 429 CMethodProps props2 = _props;
430 #ifndef Z7_ST 430#ifndef Z7_ST
431 props2.AddProp_NumThreads(_props._numThreads); 431 props2.AddProp_NumThreads(_props._numThreads);
432 #endif 432#ifdef _WIN32
433 if (_props._numThreadGroups > 1)
434 props2.AddProp32(NCoderPropID::kNumThreadGroups, _props._numThreadGroups);
435#endif
436#endif
433 437
434 return UpdateArchive(size, outStream, props2, updateCallback); 438 return UpdateArchive(size, outStream, props2, updateCallback);
435 } 439 }
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
index 82d939d..144369e 100644
--- a/CPP/7zip/Archive/ComHandler.cpp
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -68,7 +68,7 @@ namespace NItemType
68 static const Byte kRootStorage = 5; 68 static const Byte kRootStorage = 5;
69} 69}
70 70
71static const UInt32 kNameSizeMax = 64; 71static const unsigned kNameSizeMax = 64;
72 72
73struct CItem 73struct CItem
74{ 74{
@@ -98,30 +98,30 @@ struct CRef
98 98
99class CDatabase 99class CDatabase
100{ 100{
101 UInt32 NumSectorsInMiniStream;
102 CObjArray<UInt32> MiniSids; 101 CObjArray<UInt32> MiniSids;
103 102
104 HRESULT AddNode(int parent, UInt32 did); 103 HRESULT AddNode(int parent, UInt32 did);
105public:
106 104
105public:
107 CObjArray<UInt32> Fat; 106 CObjArray<UInt32> Fat;
108 UInt32 FatSize;
109
110 CObjArray<UInt32> Mat; 107 CObjArray<UInt32> Mat;
111 UInt32 MatSize;
112
113 CObjectVector<CItem> Items; 108 CObjectVector<CItem> Items;
114 CRecordVector<CRef> Refs; 109 CRecordVector<CRef> Refs;
110private:
111 UInt32 NumSectorsInMiniStream;
112public:
113 UInt32 MatSize;
114 UInt32 FatSize;
115 115
116 UInt32 LongStreamMinSize; 116 UInt32 LongStreamMinSize;
117 unsigned SectorSizeBits; 117 unsigned SectorSizeBits;
118 unsigned MiniSectorSizeBits; 118 unsigned MiniSectorSizeBits;
119 119
120 Int32 MainSubfile; 120 Int32 MainSubfile;
121 EType Type;
121 122
122 UInt64 PhySize; 123 UInt64 PhySize;
123 UInt64 PhySize_Aligned; 124 UInt64 PhySize_Aligned;
124 EType Type;
125 125
126 bool IsNotArcType() const 126 bool IsNotArcType() const
127 { 127 {
@@ -148,14 +148,14 @@ public:
148 148
149 UInt64 GetItemPackSize(UInt64 size) const 149 UInt64 GetItemPackSize(UInt64 size) const
150 { 150 {
151 UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; 151 const UInt64 mask = ((UInt32)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
152 return (size + mask) & ~mask; 152 return (size + mask) & ~mask;
153 } 153 }
154 154
155 bool GetMiniCluster(UInt32 sid, UInt64 &res) const 155 bool GetMiniCluster(UInt32 sid, UInt64 &res) const
156 { 156 {
157 unsigned subBits = SectorSizeBits - MiniSectorSizeBits; 157 const unsigned subBits = SectorSizeBits - MiniSectorSizeBits;
158 UInt32 fid = sid >> subBits; 158 const UInt32 fid = sid >> subBits;
159 if (fid >= NumSectorsInMiniStream) 159 if (fid >= NumSectorsInMiniStream)
160 return false; 160 return false;
161 res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); 161 res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
@@ -177,7 +177,7 @@ HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSiz
177HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) 177HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest)
178{ 178{
179 RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)) 179 RINOK(ReadSector(inStream, buf, sectorSizeBits, sid))
180 UInt32 sectorSize = (UInt32)1 << sectorSizeBits; 180 const UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
181 for (UInt32 t = 0; t < sectorSize; t += 4) 181 for (UInt32 t = 0; t < sectorSize; t += 4)
182 *dest++ = Get32(buf + t); 182 *dest++ = Get32(buf + t);
183 return S_OK; 183 return S_OK;
@@ -373,7 +373,7 @@ UString CDatabase::GetItemPath(UInt32 index) const
373HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) 373HRESULT CDatabase::Update_PhySize_WithItem(unsigned index)
374{ 374{
375 const CItem &item = Items[index]; 375 const CItem &item = Items[index];
376 bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); 376 const bool isLargeStream = (index == 0 || IsLargeStream(item.Size));
377 if (!isLargeStream) 377 if (!isLargeStream)
378 return S_OK; 378 return S_OK;
379 const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; 379 const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits;
@@ -527,6 +527,10 @@ HRESULT CDatabase::Open(IInStream *inStream)
527 { 527 {
528 CItem item; 528 CItem item;
529 item.Parse(sect + i, mode64bit); 529 item.Parse(sect + i, mode64bit);
530 // we use (item.Size) check here.
531 // so we don't need additional overflow checks for (item.Size +) in another code
532 if (item.Size >= ((UInt64)1 << 63))
533 return S_FALSE;
530 Items.Add(item); 534 Items.Add(item);
531 } 535 }
532 sid = Fat[sid]; 536 sid = Fat[sid];
@@ -767,11 +771,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
767 UInt64 totalPackSize; 771 UInt64 totalPackSize;
768 totalSize = totalPackSize = 0; 772 totalSize = totalPackSize = 0;
769 773
770 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); 774 CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
771 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; 775 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
772
773 CLocalProgress *lps = new CLocalProgress;
774 CMyComPtr<ICompressProgressInfo> progress = lps;
775 lps->Init(extractCallback, false); 776 lps->Init(extractCallback, false);
776 777
777 for (i = 0; i < numItems; i++) 778 for (i = 0; i < numItems; i++)
@@ -781,7 +782,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
781 RINOK(lps->SetCur()) 782 RINOK(lps->SetCur())
782 const UInt32 index = allFilesMode ? i : indices[i]; 783 const UInt32 index = allFilesMode ? i : indices[i];
783 const CItem &item = _db.Items[_db.Refs[index].Did]; 784 const CItem &item = _db.Items[_db.Refs[index].Did];
784 785 Int32 res;
786 {
785 CMyComPtr<ISequentialOutStream> outStream; 787 CMyComPtr<ISequentialOutStream> outStream;
786 const Int32 askMode = testMode ? 788 const Int32 askMode = testMode ?
787 NExtract::NAskMode::kTest : 789 NExtract::NAskMode::kTest :
@@ -801,7 +803,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
801 if (!testMode && !outStream) 803 if (!testMode && !outStream)
802 continue; 804 continue;
803 RINOK(extractCallback->PrepareOperation(askMode)) 805 RINOK(extractCallback->PrepareOperation(askMode))
804 Int32 res = NExtract::NOperationResult::kDataError; 806 res = NExtract::NOperationResult::kDataError;
805 CMyComPtr<ISequentialInStream> inStream; 807 CMyComPtr<ISequentialInStream> inStream;
806 HRESULT hres = GetStream(index, &inStream); 808 HRESULT hres = GetStream(index, &inStream);
807 if (hres == S_FALSE) 809 if (hres == S_FALSE)
@@ -813,12 +815,12 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
813 RINOK(hres) 815 RINOK(hres)
814 if (inStream) 816 if (inStream)
815 { 817 {
816 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) 818 RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps))
817 if (copyCoderSpec->TotalSize == item.Size) 819 if (copyCoder->TotalSize == item.Size)
818 res = NExtract::NOperationResult::kOK; 820 res = NExtract::NOperationResult::kOK;
819 } 821 }
820 } 822 }
821 outStream.Release(); 823 }
822 RINOK(extractCallback->SetOperationResult(res)) 824 RINOK(extractCallback->SetOperationResult(res))
823 } 825 }
824 return S_OK; 826 return S_OK;
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 17fed67..5a11e30 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -4,8 +4,6 @@
4 4
5#include "../../../Common/StringToInt.h" 5#include "../../../Common/StringToInt.h"
6 6
7#include "../Common/ParseProperties.h"
8
9#include "HandlerOut.h" 7#include "HandlerOut.h"
10 8
11namespace NArchive { 9namespace NArchive {
@@ -82,6 +80,7 @@ bool ParseSizeString(const wchar_t *s, const PROPVARIANT &prop, UInt64 percentsB
82 return true; 80 return true;
83} 81}
84 82
83
85bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres) 84bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres)
86{ 85{
87 hres = S_OK; 86 hres = S_OK;
@@ -151,6 +150,11 @@ void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo,
151 SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); 150 SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
152} 151}
153 152
153void CMultiMethodProps::Set_Method_NumThreadGroups_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreadGroups)
154{
155 SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreadGroups, numThreadGroups);
156}
157
154#endif // Z7_ST 158#endif // Z7_ST
155 159
156 160
diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h
index cfba46e..3122b05 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -17,12 +17,22 @@ protected:
17 void InitCommon() 17 void InitCommon()
18 { 18 {
19 // _Write_MTime = true; 19 // _Write_MTime = true;
20 #ifndef Z7_ST 20 {
21 _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); 21#ifndef Z7_ST
22 _numThreads_WasForced = false; 22 _numThreads_WasForced = false;
23 #endif 23 UInt32 numThreads;
24 24#ifdef _WIN32
25 UInt64 memAvail = (UInt64)(sizeof(size_t)) << 28; 25 NWindows::NSystem::CProcessAffinity aff;
26 numThreads = aff.Load_and_GetNumberOfThreads();
27 _numThreadGroups = aff.IsGroupMode ? aff.Groups.GroupSizes.Size() : 0;
28#else
29 numThreads = NWindows::NSystem::GetNumberOfProcessors();
30#endif // _WIN32
31 _numProcessors = _numThreads = numThreads;
32#endif // Z7_ST
33 }
34
35 size_t memAvail = (size_t)sizeof(size_t) << 28;
26 _memAvail = memAvail; 36 _memAvail = memAvail;
27 _memUsage_Compress = memAvail; 37 _memUsage_Compress = memAvail;
28 _memUsage_Decompress = memAvail; 38 _memUsage_Decompress = memAvail;
@@ -46,16 +56,19 @@ protected:
46 } 56 }
47 57
48public: 58public:
49 #ifndef Z7_ST 59#ifndef Z7_ST
50 UInt32 _numThreads; 60 UInt32 _numThreads;
51 UInt32 _numProcessors; 61 UInt32 _numProcessors;
62#ifdef _WIN32
63 UInt32 _numThreadGroups;
64#endif
52 bool _numThreads_WasForced; 65 bool _numThreads_WasForced;
53 #endif 66#endif
54 67
55 bool _memUsage_WasSet; 68 bool _memUsage_WasSet;
56 UInt64 _memUsage_Compress; 69 UInt64 _memUsage_Compress;
57 UInt64 _memUsage_Decompress; 70 UInt64 _memUsage_Decompress;
58 UInt64 _memAvail; 71 size_t _memAvail;
59 72
60 bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres); 73 bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres);
61 74
@@ -80,10 +93,12 @@ public:
80 93
81 void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; 94 void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const;
82 95
83 #ifndef Z7_ST 96#ifndef Z7_ST
84 static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads); 97 static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads);
85 static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads); 98 static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads);
86 #endif 99
100 static void Set_Method_NumThreadGroups_IfNotFinded(CMethodProps &props, UInt32 numThreadGroups);
101#endif
87 102
88 103
89 unsigned GetNumEmptyMethods() const 104 unsigned GetNumEmptyMethods() const
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
index 8caf1d1..150efc9 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -47,6 +47,25 @@ UString GetOsPath_Remove_TailSlash(const UString &name)
47} 47}
48 48
49 49
50#if WCHAR_PATH_SEPARATOR != L'/'
51void ReplaceToWinSlashes(UString &name, bool useBackslashReplacement)
52{
53 // name.Replace(kUnixPathSepar, kOsPathSepar);
54 const unsigned len = name.Len();
55 for (unsigned i = 0; i < len; i++)
56 {
57 wchar_t c = name[i];
58 if (c == L'/')
59 c = WCHAR_PATH_SEPARATOR;
60 else if (useBackslashReplacement && c == L'\\')
61 c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
62 else
63 continue;
64 name.ReplaceOneCharAtPos(i, c);
65 }
66}
67#endif
68
50void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool 69void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool
51 #if WCHAR_PATH_SEPARATOR != L'/' 70 #if WCHAR_PATH_SEPARATOR != L'/'
52 useBackslashReplacement 71 useBackslashReplacement
@@ -57,21 +76,7 @@ void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool
57 return; 76 return;
58 77
59 #if WCHAR_PATH_SEPARATOR != L'/' 78 #if WCHAR_PATH_SEPARATOR != L'/'
60 { 79 ReplaceToWinSlashes(name, useBackslashReplacement);
61 // name.Replace(kUnixPathSepar, kOsPathSepar);
62 const unsigned len = name.Len();
63 for (unsigned i = 0; i < len; i++)
64 {
65 wchar_t c = name[i];
66 if (c == L'/')
67 c = WCHAR_PATH_SEPARATOR;
68 else if (useBackslashReplacement && c == L'\\')
69 c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
70 else
71 continue;
72 name.ReplaceOneCharAtPos(i, c);
73 }
74 }
75 #endif 80 #endif
76 81
77 if (name.Back() == kOsPathSepar) 82 if (name.Back() == kOsPathSepar)
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h
index 8ab9b61..cea8dcc 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.h
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -13,6 +13,9 @@ void ReplaceSlashes_OsToUnix(UString &name);
13UString GetOsPath(const UString &name); 13UString GetOsPath(const UString &name);
14UString GetOsPath_Remove_TailSlash(const UString &name); 14UString GetOsPath_Remove_TailSlash(const UString &name);
15 15
16#if WCHAR_PATH_SEPARATOR != L'/'
17void ReplaceToWinSlashes(UString &name, bool useBackslashReplacement);
18#endif
16void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); 19void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false);
17void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len); 20void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len);
18void NormalizeSlashes_in_FileName_for_OsPath(UString &name); 21void NormalizeSlashes_in_FileName_for_OsPath(UString &name);
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index 2228040..62184f0 100644
--- a/CPP/7zip/Archive/CpioHandler.cpp
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -437,7 +437,14 @@ HRESULT CInArchive::GetNextItem()
437 return S_OK; 437 return S_OK;
438 438
439 /* v23.02: we have disabled rDevMinor check because real file 439 /* v23.02: we have disabled rDevMinor check because real file
440 from Apple contains rDevMinor==255 by some unknown reason */ 440 from Apple contains rDevMinor==255 by some unknown reason
441 cpio 2.13 and older versions: it copies stat::st_rdev to archive.
442 and stat::st_rdev can be non-zero for some old linux/filesystems cases for regular files.
443 cpio 2.14 (2023) copies st_rdev to archive only if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode))
444 v25.00: we have disabled RDevMajor check here to support some rare case created by cpio 2.13- with old linux.
445 But we still keep full check in IsArc_Cpio() to reduce false cpio detection cases.
446 */
447#if 0 // 0 : to disable check to support some old linux cpio archives.
441 if (item.RDevMajor != 0 448 if (item.RDevMajor != 0
442 // || item.RDevMinor != 0 449 // || item.RDevMinor != 0
443 ) 450 )
@@ -446,6 +453,7 @@ HRESULT CInArchive::GetNextItem()
446 !MY_LIN_S_ISBLK(item.Mode)) 453 !MY_LIN_S_ISBLK(item.Mode))
447 return S_OK; 454 return S_OK;
448 } 455 }
456#endif
449 457
450 // Size must be 0 for FIFOs and directories 458 // Size must be 0 for FIFOs and directories
451 if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode)) 459 if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode))
@@ -873,17 +881,13 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
873 { 881 {
874 case kpidPath: 882 case kpidPath:
875 { 883 {
876 UString res; 884#ifdef _WIN32
877 bool needConvert = true; 885 UString u;
878 #ifdef _WIN32 886 ConvertUTF8ToUnicode(item.Name, u);
879 // if ( 887#else
880 ConvertUTF8ToUnicode(item.Name, res); 888 const UString u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
881 // ) 889#endif
882 needConvert = false; 890 prop = NItemName::GetOsPath(u);
883 #endif
884 if (needConvert)
885 res = MultiByteToUnicodeString(item.Name, CP_OEMCP);
886 prop = NItemName::GetOsPath(res);
887 break; 891 break;
888 } 892 }
889 case kpidIsDir: prop = item.IsDir(); break; 893 case kpidIsDir: prop = item.IsDir(); break;
@@ -921,16 +925,12 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
921 s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size()); 925 s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size());
922 if (s.Len() == item.Data.Size()) 926 if (s.Len() == item.Data.Size())
923 { 927 {
928#ifdef _WIN32
924 UString u; 929 UString u;
925 bool needConvert = true; 930 ConvertUTF8ToUnicode(item.Name, u);
926 #ifdef _WIN32 931#else
927 // if ( 932 const UString u = MultiByteToUnicodeString(s, CP_OEMCP);
928 ConvertUTF8ToUnicode(item.Name, u); 933#endif
929 // )
930 needConvert = false;
931 #endif
932 if (needConvert)
933 u = MultiByteToUnicodeString(s, CP_OEMCP);
934 prop = u; 934 prop = u;
935 } 935 }
936 } 936 }
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp
index 3901192..9079dc7 100644
--- a/CPP/7zip/Archive/DmgHandler.cpp
+++ b/CPP/7zip/Archive/DmgHandler.cpp
@@ -444,7 +444,7 @@ const char *Find_Apple_FS_Ext(const AString &name)
444 { 444 {
445 const CAppleName &a = k_Names[i]; 445 const CAppleName &a = k_Names[i];
446 if (a.Ext) 446 if (a.Ext)
447 if (name == a.AppleName) 447 if (name.IsEqualTo(a.AppleName))
448 return a.Ext; 448 return a.Ext;
449 } 449 }
450 return NULL; 450 return NULL;
@@ -784,7 +784,7 @@ static const CXmlItem *FindKeyPair(const CXmlItem &item, const char *key, const
784 for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) 784 for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++)
785 { 785 {
786 const CXmlItem &si = item.SubItems[i]; 786 const CXmlItem &si = item.SubItems[i];
787 if (si.IsTagged("key") && si.GetSubString() == key) 787 if (si.IsTagged("key") && si.GetSubString().IsEqualTo(key))
788 { 788 {
789 const CXmlItem *si_1 = &item.SubItems[i + 1]; 789 const CXmlItem *si_1 = &item.SubItems[i + 1];
790 if (si_1->IsTagged(nextTag)) 790 if (si_1->IsTagged(nextTag))
@@ -1251,7 +1251,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCall
1251#endif 1251#endif
1252 } 1252 }
1253 1253
1254 if (xml.Root.Name != "plist") 1254 if (!xml.Root.Name.IsEqualTo("plist"))
1255 return S_FALSE; 1255 return S_FALSE;
1256 1256
1257 const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict"); 1257 const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict");
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index b31ee4f..18fce91 100644
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -2,13 +2,12 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5// #include <stdio.h>
6
7#include "../../../C/CpuArch.h" 5#include "../../../C/CpuArch.h"
8 6
9#include "../../Common/ComTry.h" 7#include "../../Common/ComTry.h"
10#include "../../Common/IntToString.h" 8#include "../../Common/IntToString.h"
11#include "../../Common/MyBuffer.h" 9#include "../../Common/MyBuffer.h"
10#include "../../Common/MyBuffer2.h"
12#include "../../Common/MyCom.h" 11#include "../../Common/MyCom.h"
13#include "../../Common/StringConvert.h" 12#include "../../Common/StringConvert.h"
14 13
@@ -22,14 +21,19 @@
22 21
23#include "../Compress/CopyCoder.h" 22#include "../Compress/CopyCoder.h"
24 23
25#include "Common/DummyOutStream.h" 24#include "Common/ItemNameUtils.h"
26 25
27#define Get16(p) GetUi16(p) 26#define Get16(p) GetUi16(p)
28#define Get32(p) GetUi32(p) 27#define Get32(p) GetUi32(p)
29#define Get16a(p) GetUi16a(p) 28#define Get16a(p) GetUi16a(p)
30#define Get32a(p) GetUi32a(p) 29#define Get32a(p) GetUi32a(p)
31 30
32#define PRF(x) /* x */ 31#if 0
32#include <stdio.h>
33#define PRF(x) x
34#else
35#define PRF(x)
36#endif
33 37
34namespace NArchive { 38namespace NArchive {
35namespace NFat { 39namespace NFat {
@@ -38,35 +42,34 @@ static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31;
38 42
39struct CHeader 43struct CHeader
40{ 44{
41 UInt32 NumSectors; 45 Byte NumFatBits;
42 UInt16 NumReservedSectors; 46 Byte SectorSizeLog;
47 Byte SectorsPerClusterLog;
48 Byte ClusterSizeLog;
43 Byte NumFats; 49 Byte NumFats;
50 Byte MediaType;
51
52 bool VolFieldsDefined;
53 bool HeadersWarning;
54
55 UInt32 FatSize;
56 UInt32 BadCluster;
57
58 UInt16 NumReservedSectors;
59 UInt32 NumSectors;
44 UInt32 NumFatSectors; 60 UInt32 NumFatSectors;
45 UInt32 RootDirSector; 61 UInt32 RootDirSector;
46 UInt32 NumRootDirSectors; 62 UInt32 NumRootDirSectors;
47 UInt32 DataSector; 63 UInt32 DataSector;
48 64
49 UInt32 FatSize;
50 UInt32 BadCluster;
51
52 Byte NumFatBits;
53 Byte SectorSizeLog;
54 Byte SectorsPerClusterLog;
55 Byte ClusterSizeLog;
56
57 UInt16 SectorsPerTrack; 65 UInt16 SectorsPerTrack;
58 UInt16 NumHeads; 66 UInt16 NumHeads;
59 UInt32 NumHiddenSectors; 67 UInt32 NumHiddenSectors;
60
61 bool VolFieldsDefined;
62 bool HeadersWarning;
63 68
64 UInt32 VolId; 69 UInt32 VolId;
65 // Byte VolName[11]; 70 // Byte VolName[11];
66 // Byte FileSys[8]; 71 // Byte FileSys[8];
67
68 // Byte OemName[5]; 72 // Byte OemName[5];
69 Byte MediaType;
70 73
71 // 32-bit FAT 74 // 32-bit FAT
72 UInt16 Flags; 75 UInt16 Flags;
@@ -104,15 +107,8 @@ struct CHeader
104 bool Parse(const Byte *p); 107 bool Parse(const Byte *p);
105}; 108};
106 109
107static int GetLog(UInt32 num)
108{
109 for (int i = 0; i < 31; i++)
110 if (((UInt32)1 << i) == num)
111 return i;
112 return -1;
113}
114 110
115static const UInt32 kHeaderSize = 512; 111static const unsigned kHeaderSize = 512;
116 112
117API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); 113API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
118API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) 114API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
@@ -125,7 +121,7 @@ API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
125 121
126bool CHeader::Parse(const Byte *p) 122bool CHeader::Parse(const Byte *p)
127{ 123{
128 if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) 124 if (Get16(p + 0x1FE) != 0xAA55)
129 return false; 125 return false;
130 126
131 HeadersWarning = false; 127 HeadersWarning = false;
@@ -139,22 +135,40 @@ bool CHeader::Parse(const Byte *p)
139 } 135 }
140 { 136 {
141 { 137 {
142 const UInt32 val32 = Get16(p + 11); 138 const unsigned num = Get16(p + 11);
143 const int s = GetLog(val32); 139 unsigned i = 9;
144 if (s < 9 || s > 12) 140 unsigned m = 1 << i;
145 return false; 141 for (;;)
146 SectorSizeLog = (Byte)s; 142 {
143 if (m == num)
144 break;
145 m <<= 1;
146 if (++i > 12)
147 return false;
148 }
149 SectorSizeLog = (Byte)i;
147 } 150 }
148 { 151 {
149 const UInt32 val32 = p[13]; 152 const unsigned num = p[13];
150 const int s = GetLog(val32); 153 unsigned i = 0;
151 if (s < 0) 154 unsigned m = 1 << i;
155 for (;;)
156 {
157 if (m == num)
158 break;
159 m <<= 1;
160 if (++i > 7)
161 return false;
162 }
163 SectorsPerClusterLog = (Byte)i;
164 i += SectorSizeLog;
165 ClusterSizeLog = (Byte)i;
166 // (2^15 = 32 KB is safe cluster size that is suported by all system.
167 // (2^16 = 64 KB is supported by some systems
168 // (128 KB / 256 KB) can be created by some tools, but it is not supported by many tools.
169 if (i > 18) // 256 KB
152 return false; 170 return false;
153 SectorsPerClusterLog = (Byte)s;
154 } 171 }
155 ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog);
156 if (ClusterSizeLog > 24)
157 return false;
158 } 172 }
159 173
160 NumReservedSectors = Get16(p + 14); 174 NumReservedSectors = Get16(p + 14);
@@ -169,7 +183,7 @@ bool CHeader::Parse(const Byte *p)
169 const bool isOkOffset = (codeOffset == 0) 183 const bool isOkOffset = (codeOffset == 0)
170 || (codeOffset == (p[0] == 0xEB ? 2 : 3)); 184 || (codeOffset == (p[0] == 0xEB ? 2 : 3));
171 185
172 const UInt16 numRootDirEntries = Get16(p + 17); 186 const unsigned numRootDirEntries = Get16(p + 17);
173 if (numRootDirEntries == 0) 187 if (numRootDirEntries == 0)
174 { 188 {
175 if (codeOffset < 90 && !isOkOffset) 189 if (codeOffset < 90 && !isOkOffset)
@@ -183,10 +197,10 @@ bool CHeader::Parse(const Byte *p)
183 if (codeOffset < 62 - 24 && !isOkOffset) 197 if (codeOffset < 62 - 24 && !isOkOffset)
184 return false; 198 return false;
185 NumFatBits = 0; 199 NumFatBits = 0;
186 const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; 200 const unsigned mask = (1u << (SectorSizeLog - 5)) - 1;
187 if ((numRootDirEntries & mask) != 0) 201 if (numRootDirEntries & mask)
188 return false; 202 return false;
189 NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); 203 NumRootDirSectors = (numRootDirEntries /* + mask */) >> (SectorSizeLog - 5);
190 } 204 }
191 205
192 NumSectors = Get16(p + 19); 206 NumSectors = Get16(p + 19);
@@ -198,7 +212,6 @@ bool CHeader::Parse(const Byte *p)
198 else if (IsFat32()) 212 else if (IsFat32())
199 return false; 213 return false;
200 */ 214 */
201
202 MediaType = p[21]; 215 MediaType = p[21];
203 NumFatSectors = Get16(p + 22); 216 NumFatSectors = Get16(p + 22);
204 SectorsPerTrack = Get16(p + 24); 217 SectorsPerTrack = Get16(p + 24);
@@ -222,7 +235,7 @@ bool CHeader::Parse(const Byte *p)
222 return false; 235 return false;
223 RootCluster = Get32(p + 8); 236 RootCluster = Get32(p + 8);
224 FsInfoSector = Get16(p + 12); 237 FsInfoSector = Get16(p + 12);
225 for (int i = 16; i < 28; i++) 238 for (unsigned i = 16; i < 28; i++)
226 if (p[i] != 0) 239 if (p[i] != 0)
227 return false; 240 return false;
228 p += 28; 241 p += 28;
@@ -260,7 +273,7 @@ bool CHeader::Parse(const Byte *p)
260 if (numClusters >= 0xFFF5) 273 if (numClusters >= 0xFFF5)
261 return false; 274 return false;
262 NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); 275 NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16);
263 BadCluster &= ((1 << NumFatBits) - 1); 276 BadCluster &= (((UInt32)1 << NumFatBits) - 1);
264 } 277 }
265 278
266 FatSize = numClusters + 2; 279 FatSize = numClusters + 2;
@@ -283,103 +296,157 @@ bool CHeader::Parse(const Byte *p)
283 return true; 296 return true;
284} 297}
285 298
286struct CItem 299
300
301class CItem
287{ 302{
288 UString UName; 303 Z7_CLASS_NO_COPY(CItem)
289 char DosName[11]; 304public:
305 UInt32 Size;
306 Byte Attrib;
290 Byte CTime2; 307 Byte CTime2;
291 UInt32 CTime;
292 UInt32 MTime;
293 UInt16 ADate; 308 UInt16 ADate;
294 Byte Attrib; 309 CByteBuffer LongName; // if LongName.Size() == 0 : no long name
310 // if LongName.Size() != 0 : it's NULL terminated UTF16-LE string.
311 char DosName[11];
295 Byte Flags; 312 Byte Flags;
296 UInt32 Size; 313 UInt32 MTime;
314 UInt32 CTime;
297 UInt32 Cluster; 315 UInt32 Cluster;
298 Int32 Parent; 316 Int32 Parent;
299 317
318 CItem() {}
319
300 // NT uses Flags to store Low Case status 320 // NT uses Flags to store Low Case status
301 bool NameIsLow() const { return (Flags & 0x8) != 0; } 321 bool NameIsLow() const { return (Flags & 0x8) != 0; }
302 bool ExtIsLow() const { return (Flags & 0x10) != 0; } 322 bool ExtIsLow() const { return (Flags & 0x10) != 0; }
303 bool IsDir() const { return (Attrib & 0x10) != 0; } 323 bool IsDir() const { return (Attrib & 0x10) != 0; }
304 UString GetShortName() const; 324 void GetShortName(UString &dest) const;
305 UString GetName() const; 325 void GetName(UString &name) const;
306 UString GetVolName() const;
307}; 326};
308 327
309static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower) 328
329static char *CopyAndTrim(char *dest, const char *src,
330 unsigned size, unsigned toLower)
310{ 331{
311 memcpy(dest, src, size); 332 do
312 if (toLower)
313 { 333 {
314 for (unsigned i = 0; i < size; i++) 334 if (src[(size_t)size - 1] != ' ')
315 { 335 {
316 char c = dest[i]; 336 const unsigned range = toLower ? 'Z' - 'A' + 1 : 0;
317 if (c >= 'A' && c <= 'Z') 337 do
318 dest[i] = (char)(c + 0x20); 338 {
339 unsigned c = (Byte)*src++;
340 if ((unsigned)(c - 'A') < range)
341 c += 0x20;
342 *dest++ = (char)c;
343 }
344 while (--size);
345 break;
319 } 346 }
320 } 347 }
321 348 while (--size);
322 for (unsigned i = size;;) 349 *dest = 0;
323 { 350 return dest;
324 if (i == 0)
325 return 0;
326 if (dest[i - 1] != ' ')
327 return i;
328 i--;
329 }
330} 351}
331 352
332static UString FatStringToUnicode(const char *s) 353
354static void FatStringToUnicode(UString &dest, const char *s)
333{ 355{
334 return MultiByteToUnicodeString(s, CP_OEMCP); 356 MultiByteToUnicodeString2(dest, AString(s), CP_OEMCP);
335} 357}
336 358
337UString CItem::GetShortName() const 359void CItem::GetShortName(UString &shortName) const
338{ 360{
339 char s[16]; 361 char s[16];
340 unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow()); 362 char *dest = CopyAndTrim(s, DosName, 8, NameIsLow());
341 s[i++] = '.'; 363 *dest++ = '.';
342 unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); 364 char *dest2 = CopyAndTrim(dest, DosName + 8, 3, ExtIsLow());
343 if (j == 0) 365 if (dest == dest2)
344 i--; 366 dest[-1] = 0;
345 s[i + j] = 0; 367 FatStringToUnicode(shortName, s);
346 return FatStringToUnicode(s);
347} 368}
348 369
349UString CItem::GetName() const 370
371
372// numWords != 0
373static unsigned ParseLongName(UInt16 *buf, unsigned numWords)
350{ 374{
351 if (!UName.IsEmpty()) 375 unsigned i;
352 return UName; 376 for (i = 0; i < numWords; i++)
353 return GetShortName(); 377 {
378 const unsigned c = buf[i];
379 if (c == 0)
380 break;
381 if (c == 0xFFFF)
382 return 0;
383 }
384 if (i == 0)
385 return 0;
386 buf[i] = 0;
387 numWords -= i;
388 i++;
389 if (numWords > 1)
390 {
391 numWords--;
392 buf += i;
393 do
394 if (*buf++ != 0xFFFF)
395 return 0;
396 while (--numWords);
397 }
398 return i; // it includes NULL terminator
399}
400
401
402void CItem::GetName(UString &name) const
403{
404 if (LongName.Size() >= 2)
405 {
406 const Byte * const p = LongName;
407 const unsigned numWords = ((unsigned)LongName.Size() - 2) / 2;
408 wchar_t *dest = name.GetBuf(numWords);
409 for (unsigned i = 0; i < numWords; i++)
410 dest[i] = (wchar_t)Get16(p + (size_t)i * 2);
411 name.ReleaseBuf_SetEnd(numWords);
412 }
413 else
414 GetShortName(name);
415 if (name.IsEmpty()) // it's unexpected
416 name = '_';
417 NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
354} 418}
355 419
356UString CItem::GetVolName() const 420
421static void GetVolName(const char dosName[11], NWindows::NCOM::CPropVariant &prop)
357{ 422{
358 if (!UName.IsEmpty())
359 return UName;
360 char s[12]; 423 char s[12];
361 unsigned i = CopyAndTrim(s, DosName, 11, false); 424 CopyAndTrim(s, dosName, 11, false);
362 s[i] = 0; 425 UString u;
363 return FatStringToUnicode(s); 426 FatStringToUnicode(u, AString(s));
427 prop = u;
364} 428}
365 429
430
366struct CDatabase 431struct CDatabase
367{ 432{
368 CHeader Header;
369 CObjectVector<CItem> Items; 433 CObjectVector<CItem> Items;
370 UInt32 *Fat; 434 UInt32 *Fat;
435 CHeader Header;
371 CMyComPtr<IInStream> InStream; 436 CMyComPtr<IInStream> InStream;
372 IArchiveOpenCallback *OpenCallback; 437 IArchiveOpenCallback *OpenCallback;
438 CAlignedBuffer ByteBuf;
439 CByteBuffer LfnBuf;
373 440
374 UInt32 NumFreeClusters; 441 UInt32 NumFreeClusters;
375 bool VolItemDefined;
376 CItem VolItem;
377 UInt32 NumDirClusters; 442 UInt32 NumDirClusters;
378 CByteBuffer ByteBuf;
379 UInt64 NumCurUsedBytes; 443 UInt64 NumCurUsedBytes;
380
381 UInt64 PhySize; 444 UInt64 PhySize;
382 445
446 UInt32 Vol_MTime;
447 char VolLabel[11];
448 bool VolItem_Defined;
449
383 CDatabase(): Fat(NULL) {} 450 CDatabase(): Fat(NULL) {}
384 ~CDatabase() { ClearAndClose(); } 451 ~CDatabase() { ClearAndClose(); }
385 452
@@ -388,7 +455,7 @@ struct CDatabase
388 HRESULT OpenProgressFat(bool changeTotal = true); 455 HRESULT OpenProgressFat(bool changeTotal = true);
389 HRESULT OpenProgress(); 456 HRESULT OpenProgress();
390 457
391 UString GetItemPath(UInt32 index) const; 458 void GetItemPath(UInt32 index, UString &s) const;
392 HRESULT Open(); 459 HRESULT Open();
393 HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level); 460 HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level);
394 461
@@ -400,6 +467,7 @@ struct CDatabase
400 HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); } 467 HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
401}; 468};
402 469
470
403HRESULT CDatabase::SeekToSector(UInt32 sector) 471HRESULT CDatabase::SeekToSector(UInt32 sector)
404{ 472{
405 return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog); 473 return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog);
@@ -408,7 +476,7 @@ HRESULT CDatabase::SeekToSector(UInt32 sector)
408void CDatabase::Clear() 476void CDatabase::Clear()
409{ 477{
410 PhySize = 0; 478 PhySize = 0;
411 VolItemDefined = false; 479 VolItem_Defined = false;
412 NumDirClusters = 0; 480 NumDirClusters = 0;
413 NumCurUsedBytes = 0; 481 NumCurUsedBytes = 0;
414 482
@@ -440,49 +508,35 @@ HRESULT CDatabase::OpenProgress()
440{ 508{
441 if (!OpenCallback) 509 if (!OpenCallback)
442 return S_OK; 510 return S_OK;
443 UInt64 numItems = Items.Size(); 511 const UInt64 numItems = Items.Size();
444 return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); 512 return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
445} 513}
446 514
447UString CDatabase::GetItemPath(UInt32 index) const 515void CDatabase::GetItemPath(UInt32 index, UString &s) const
448{ 516{
449 const CItem *item = &Items[index]; 517 UString name;
450 UString name = item->GetName();
451 for (;;) 518 for (;;)
452 { 519 {
453 index = (UInt32)item->Parent; 520 const CItem &item = Items[index];
454 if (item->Parent < 0) 521 item.GetName(name);
455 return name; 522 if (item.Parent >= 0)
456 item = &Items[index]; 523 name.InsertAtFront(WCHAR_PATH_SEPARATOR);
457 name.InsertAtFront(WCHAR_PATH_SEPARATOR); 524 s.Insert(0, name);
458 if (item->UName.IsEmpty()) 525 index = (UInt32)item.Parent;
459 name.Insert(0, item->GetShortName()); 526 if (item.Parent < 0)
460 else 527 break;
461 name.Insert(0, item->UName);
462 } 528 }
463} 529}
464 530
465static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars)
466{
467 for (unsigned i = 0; i < numChars; i++)
468 {
469 wchar_t c = Get16(p + i * 2);
470 if (c != 0 && c != 0xFFFF)
471 *dest++ = c;
472 }
473 *dest = 0;
474 return dest;
475}
476 531
477HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) 532HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
478{ 533{
479 unsigned startIndex = Items.Size(); 534 const unsigned startIndex = Items.Size();
480 if (startIndex >= (1 << 30) || level > 256) 535 if (startIndex >= (1 << 30) || level > 256)
481 return S_FALSE; 536 return S_FALSE;
482 537
483 UInt32 sectorIndex = 0;
484 UInt32 blockSize = Header.ClusterSize(); 538 UInt32 blockSize = Header.ClusterSize();
485 bool clusterMode = (Header.IsFat32() || parent >= 0); 539 const bool clusterMode = (Header.IsFat32() || parent >= 0);
486 if (!clusterMode) 540 if (!clusterMode)
487 { 541 {
488 blockSize = Header.SectorSize(); 542 blockSize = Header.SectorSize();
@@ -490,21 +544,26 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
490 } 544 }
491 545
492 ByteBuf.Alloc(blockSize); 546 ByteBuf.Alloc(blockSize);
493 UString curName; 547
494 int checkSum = -1; 548 const unsigned k_NumLfnRecords_MAX = 20; // 260 symbols limit (strict limit)
495 int numLongRecords = -1; 549 // const unsigned k_NumLfnRecords_MAX = 0x40 - 1; // 1260 symbols limit (relaxed limit)
550 const unsigned k_NumLfnBytes_in_Record = 13 * 2;
551 // we reserve 2 additional bytes for NULL terminator
552 LfnBuf.Alloc(k_NumLfnRecords_MAX * k_NumLfnBytes_in_Record + 2 * 1);
496 553
554 UInt32 curDirBytes_read = 0;
555 UInt32 sectorIndex = 0;
556 unsigned num_lfn_records = 0;
557 unsigned lfn_RecordIndex = 0;
558 int checkSum = -1;
559 bool is_record_error = false;
560
497 for (UInt32 pos = blockSize;; pos += 32) 561 for (UInt32 pos = blockSize;; pos += 32)
498 { 562 {
499 if (pos == blockSize) 563 if (pos == blockSize)
500 { 564 {
501 pos = 0; 565 pos = 0;
502 566
503 if ((NumDirClusters & 0xFF) == 0)
504 {
505 RINOK(OpenProgress())
506 }
507
508 if (clusterMode) 567 if (clusterMode)
509 { 568 {
510 if (Header.IsEoc(cluster)) 569 if (Header.IsEoc(cluster))
@@ -514,21 +573,37 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
514 PRF(printf("\nCluster = %4X", cluster)); 573 PRF(printf("\nCluster = %4X", cluster));
515 RINOK(SeekToCluster(cluster)) 574 RINOK(SeekToCluster(cluster))
516 const UInt32 newCluster = Fat[cluster]; 575 const UInt32 newCluster = Fat[cluster];
517 if ((newCluster & kFatItemUsedByDirMask) != 0) 576 if (newCluster & kFatItemUsedByDirMask)
518 return S_FALSE; 577 return S_FALSE;
519 Fat[cluster] |= kFatItemUsedByDirMask; 578 Fat[cluster] |= kFatItemUsedByDirMask;
520 cluster = newCluster; 579 cluster = newCluster;
521 NumDirClusters++; 580 NumDirClusters++;
581 if ((NumDirClusters & 0xFF) == 0)
582 {
583 RINOK(OpenProgress())
584 }
522 NumCurUsedBytes += Header.ClusterSize(); 585 NumCurUsedBytes += Header.ClusterSize();
523 } 586 }
524 else if (sectorIndex++ >= Header.NumRootDirSectors) 587 else if (sectorIndex++ >= Header.NumRootDirSectors)
525 break; 588 break;
526 589
590 // if (curDirBytes_read > (1u << 28)) // do we need some relaxed limit for non-MS FATs?
591 if (curDirBytes_read >= (1u << 21)) // 2MB limit from FAT specification.
592 return S_FALSE;
527 RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)) 593 RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize))
594 curDirBytes_read += blockSize;
528 } 595 }
529 596
530 const Byte *p = ByteBuf + pos; 597 if (is_record_error)
531 598 {
599 Header.HeadersWarning = true;
600 num_lfn_records = 0;
601 lfn_RecordIndex = 0;
602 checkSum = -1;
603 }
604
605 const Byte * const p = ByteBuf + pos;
606
532 if (p[0] == 0) 607 if (p[0] == 0)
533 { 608 {
534 /* 609 /*
@@ -538,125 +613,191 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
538 */ 613 */
539 break; 614 break;
540 } 615 }
541 616
617 is_record_error = true;
618
542 if (p[0] == 0xE5) 619 if (p[0] == 0xE5)
543 { 620 {
544 if (numLongRecords > 0) 621 // deleted entry
545 return S_FALSE; 622 if (num_lfn_records == 0)
623 is_record_error = false;
546 continue; 624 continue;
547 } 625 }
548 626 // else
549 Byte attrib = p[11];
550 if ((attrib & 0x3F) == 0xF)
551 { 627 {
552 if (p[0] > 0x7F || Get16(p + 26) != 0) 628 const Byte attrib = p[11];
553 return S_FALSE; 629 // maybe we can use more strick check : (attrib == 0xF) ?
554 int longIndex = p[0] & 0x3F; 630 if ((attrib & 0x3F) == 0xF)
555 if (longIndex == 0)
556 return S_FALSE;
557 bool isLast = (p[0] & 0x40) != 0;
558 if (numLongRecords < 0)
559 { 631 {
560 if (!isLast) 632 // long file name (LFN) entry
633 const unsigned longIndex = p[0] & 0x3F;
634 if (longIndex == 0
635 || longIndex > k_NumLfnRecords_MAX
636 || p[0] > 0x7F
637 || Get16a(p + 26) != 0 // LDIR_FstClusLO
638 )
639 {
561 return S_FALSE; 640 return S_FALSE;
562 numLongRecords = longIndex; 641 // break;
642 }
643 const bool isLast = (p[0] & 0x40) != 0;
644 if (num_lfn_records == 0)
645 {
646 if (!isLast)
647 continue; // orphan
648 num_lfn_records = longIndex;
649 }
650 else if (isLast || longIndex != lfn_RecordIndex)
651 {
652 return S_FALSE;
653 // break;
654 }
655
656 lfn_RecordIndex = longIndex - 1;
657
658 if (p[12] == 0)
659 {
660 Byte * const dest = LfnBuf + k_NumLfnBytes_in_Record * lfn_RecordIndex;
661 memcpy(dest, p + 1, 5 * 2);
662 memcpy(dest + 5 * 2, p + 14, 6 * 2);
663 memcpy(dest + 11 * 2, p + 28, 2 * 2);
664 if (isLast)
665 checkSum = p[13];
666 if (checkSum == p[13])
667 is_record_error = false;
668 // else return S_FALSE;
669 continue;
670 }
671 // else
672 checkSum = -1; // we will ignore LfnBuf in this case
673 continue;
563 } 674 }
564 else if (isLast || numLongRecords != longIndex)
565 return S_FALSE;
566
567 numLongRecords--;
568 675
569 if (p[12] == 0) 676 if (lfn_RecordIndex)
570 { 677 {
571 wchar_t nameBuf[14]; 678 Header.HeadersWarning = true;
572 wchar_t *dest; 679 // return S_FALSE;
573
574 dest = AddSubStringToName(nameBuf, p + 1, 5);
575 dest = AddSubStringToName(dest, p + 14, 6);
576 AddSubStringToName(dest, p + 28, 2);
577 curName = nameBuf + curName;
578 if (isLast)
579 checkSum = p[13];
580 if (checkSum != p[13])
581 return S_FALSE;
582 } 680 }
583 } 681 // lfn_RecordIndex = 0;
584 else
585 {
586 if (numLongRecords > 0)
587 return S_FALSE;
588 CItem item;
589 memcpy(item.DosName, p, 11);
590 682
591 if (checkSum >= 0) 683 const unsigned type_in_attrib = attrib & 0x18;
684 if (type_in_attrib == 0x18)
592 { 685 {
593 Byte sum = 0; 686 // invalid directory record (both flags are set: dir_flag and volume_flag)
594 for (unsigned i = 0; i < 11; i++) 687 return S_FALSE;
595 sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]); 688 // break;
596 if (sum == checkSum) 689 // continue;
597 item.UName = curName;
598 } 690 }
599 691 if (type_in_attrib == 8) // volume_flag
600 if (item.DosName[0] == 5)
601 item.DosName[0] = (char)(Byte)0xE5;
602 item.Attrib = attrib;
603 item.Flags = p[12];
604 item.Size = Get32(p + 28);
605 item.Cluster = Get16(p + 26);
606 if (Header.NumFatBits > 16)
607 item.Cluster |= ((UInt32)Get16(p + 20) << 16);
608 else
609 { 692 {
610 // OS/2 and WinNT probably can store EA (extended atributes) in that field. 693 if (!VolItem_Defined && level == 0)
694 {
695 VolItem_Defined = true;
696 memcpy(VolLabel, p, 11);
697 Vol_MTime = Get32(p + 22);
698 is_record_error = false;
699 }
611 } 700 }
612 701 else if (memcmp(p, ". ", 11) == 0
613 item.CTime = Get32(p + 14); 702 || memcmp(p, ".. ", 11) == 0)
614 item.CTime2 = p[13];
615 item.ADate = Get16(p + 18);
616 item.MTime = Get32(p + 22);
617 item.Parent = parent;
618
619 if (attrib == 8)
620 { 703 {
621 VolItem = item; 704 if (num_lfn_records == 0 && type_in_attrib == 0x10) // dir_flag
622 VolItemDefined = true; 705 is_record_error = false;
623 } 706 }
624 else 707 else
625 if (memcmp(item.DosName, ". ", 11) != 0 &&
626 memcmp(item.DosName, ".. ", 11) != 0)
627 { 708 {
628 if (!item.IsDir()) 709 CItem &item = Items.AddNew();
629 NumCurUsedBytes += Header.GetFilePackSize(item.Size); 710 memcpy(item.DosName, p, 11);
630 Items.Add(item); 711 if (item.DosName[0] == 5)
631 PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1))); 712 item.DosName[0] = (char)(Byte)0xE5; // 0xE5 is valid KANJI lead byte value.
713 item.Attrib = attrib;
714 item.Flags = p[12];
715 item.Size = Get32a(p + 28);
716 item.Cluster = Get16a(p + 26);
717 if (Header.NumFatBits > 16)
718 item.Cluster |= ((UInt32)Get16a(p + 20) << 16);
719 else
720 {
721 // OS/2 and WinNT probably can store EA (extended atributes) in that field.
722 }
723 item.CTime = Get32(p + 14);
724 item.CTime2 = p[13];
725 item.ADate = Get16a(p + 18);
726 item.MTime = Get32(p + 22);
727 item.Parent = parent;
728 {
729 if (!item.IsDir())
730 NumCurUsedBytes += Header.GetFilePackSize(item.Size);
731 // PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
732 PRF(printf("\n%7d" /* ": %S" */, Items.Size() /* , item.GetShortName() */ );)
733 }
734 if (num_lfn_records == 0)
735 is_record_error = false;
736 else if (checkSum >= 0 && lfn_RecordIndex == 0)
737 {
738 Byte sum = 0;
739 for (unsigned i = 0; i < 11; i++)
740 sum = (Byte)((sum << 7) + (sum >> 1) + (Byte)item.DosName[i]);
741 if (sum == checkSum)
742 {
743 const unsigned numWords = ParseLongName((UInt16 *)(void *)(Byte *)LfnBuf,
744 num_lfn_records * k_NumLfnBytes_in_Record / 2);
745 if (numWords > 1)
746 {
747 // numWords includes NULL terminator
748 item.LongName.CopyFrom(LfnBuf, numWords * 2);
749 is_record_error = false;
750 }
751 }
752 }
753
754 if (
755 // item.LongName.Size() < 20 || // for debug
756 item.LongName.Size() <= 2 * 1
757 && memcmp(p, " ", 11) == 0)
758 {
759 char s[16 + 16];
760 const size_t numChars = (size_t)(ConvertUInt32ToString(
761 Items.Size() - 1 - startIndex,
762 MyStpCpy(s, "[NONAME]-")) - s) + 1;
763 item.LongName.Alloc(numChars * 2);
764 for (size_t i = 0; i < numChars; i++)
765 {
766 SetUi16a(item.LongName + i * 2, (Byte)s[i])
767 }
768 Header.HeadersWarning = true;
769 }
632 } 770 }
633 numLongRecords = -1; 771 num_lfn_records = 0;
634 curName.Empty();
635 checkSum = -1;
636 } 772 }
637 } 773 }
638 774
639 unsigned finishIndex = Items.Size(); 775 if (is_record_error)
776 Header.HeadersWarning = true;
777
778 const unsigned finishIndex = Items.Size();
640 for (unsigned i = startIndex; i < finishIndex; i++) 779 for (unsigned i = startIndex; i < finishIndex; i++)
641 { 780 {
642 const CItem &item = Items[i]; 781 const CItem &item = Items[i];
643 if (item.IsDir()) 782 if (item.IsDir())
644 { 783 {
645 PRF(printf("\n%S", GetItemPath(i))); 784 PRF(printf("\n---- %c%c%c%c%c", item.DosName[0], item.DosName[1], item.DosName[2], item.DosName[3], item.DosName[4]));
646 RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1)) 785 RINOK(ReadDir((int)i, item.Cluster, level + 1))
647 } 786 }
648 } 787 }
649 return S_OK; 788 return S_OK;
650} 789}
651 790
791
792
652HRESULT CDatabase::Open() 793HRESULT CDatabase::Open()
653{ 794{
654 Clear(); 795 Clear();
655 bool numFreeClustersDefined = false; 796 bool numFreeClusters_Defined = false;
656 { 797 {
657 Byte buf[kHeaderSize]; 798 UInt32 buf32[kHeaderSize / 4];
658 RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)) 799 RINOK(ReadStream_FALSE(InStream, buf32, kHeaderSize))
659 if (!Header.Parse(buf)) 800 if (!Header.Parse((Byte *)(void *)buf32))
660 return S_FALSE; 801 return S_FALSE;
661 UInt64 fileSize; 802 UInt64 fileSize;
662 RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) 803 RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize))
@@ -671,21 +812,21 @@ HRESULT CDatabase::Open()
671 { 812 {
672 if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize 813 if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize
673 && SeekToSector(Header.FsInfoSector) == S_OK 814 && SeekToSector(Header.FsInfoSector) == S_OK
674 && ReadStream_FALSE(InStream, buf, kHeaderSize) == S_OK 815 && ReadStream_FALSE(InStream, buf32, kHeaderSize) == S_OK
675 && 0xaa550000 == Get32(buf + 508) 816 && 0xaa550000 == Get32a(buf32 + 508 / 4)
676 && 0x41615252 == Get32(buf) 817 && 0x41615252 == Get32a(buf32)
677 && 0x61417272 == Get32(buf + 484)) 818 && 0x61417272 == Get32a(buf32 + 484 / 4))
678 { 819 {
679 NumFreeClusters = Get32(buf + 488); 820 NumFreeClusters = Get32a(buf32 + 488 / 4);
680 numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); 821 numFreeClusters_Defined = (NumFreeClusters <= Header.FatSize);
681 } 822 }
682 else 823 else
683 Header.HeadersWarning = true; 824 Header.HeadersWarning = true;
684 } 825 }
685 } 826 }
686 827
687 // numFreeClustersDefined = false; // to recalculate NumFreeClusters 828 // numFreeClusters_Defined = false; // to recalculate NumFreeClusters
688 if (!numFreeClustersDefined) 829 if (!numFreeClusters_Defined)
689 NumFreeClusters = 0; 830 NumFreeClusters = 0;
690 831
691 CByteBuffer byteBuf; 832 CByteBuffer byteBuf;
@@ -695,7 +836,7 @@ HRESULT CDatabase::Open()
695 RINOK(SeekToSector(Header.GetFatSector())) 836 RINOK(SeekToSector(Header.GetFatSector()))
696 if (Header.NumFatBits == 32) 837 if (Header.NumFatBits == 32)
697 { 838 {
698 const UInt32 kBufSize = (1 << 15); 839 const UInt32 kBufSize = 1 << 15;
699 byteBuf.Alloc(kBufSize); 840 byteBuf.Alloc(kBufSize);
700 for (UInt32 i = 0;;) 841 for (UInt32 i = 0;;)
701 { 842 {
@@ -712,7 +853,7 @@ HRESULT CDatabase::Open()
712 const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf; 853 const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf;
713 UInt32 *dest = Fat + i; 854 UInt32 *dest = Fat + i;
714 const UInt32 *srcLim = src + size; 855 const UInt32 *srcLim = src + size;
715 if (numFreeClustersDefined) 856 if (numFreeClusters_Defined)
716 do 857 do
717 *dest++ = Get32a(src) & 0x0FFFFFFF; 858 *dest++ = Get32a(src) & 0x0FFFFFFF;
718 while (++src != srcLim); 859 while (++src != srcLim);
@@ -731,7 +872,7 @@ HRESULT CDatabase::Open()
731 i += size; 872 i += size;
732 if ((i & 0xFFFFF) == 0) 873 if ((i & 0xFFFFF) == 0)
733 { 874 {
734 RINOK(OpenProgressFat(!numFreeClustersDefined)) 875 RINOK(OpenProgressFat(!numFreeClusters_Defined))
735 } 876 }
736 } 877 }
737 } 878 }
@@ -751,7 +892,7 @@ HRESULT CDatabase::Open()
751 for (UInt32 j = 0; j < fatSize; j++) 892 for (UInt32 j = 0; j < fatSize; j++)
752 fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF; 893 fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
753 894
754 if (!numFreeClustersDefined) 895 if (!numFreeClusters_Defined)
755 { 896 {
756 UInt32 numFreeClusters = 0; 897 UInt32 numFreeClusters = 0;
757 for (UInt32 i = 0; i < fatSize; i++) 898 for (UInt32 i = 0; i < fatSize; i++)
@@ -781,11 +922,12 @@ HRESULT CDatabase::Open()
781 922
782Z7_class_CHandler_final: 923Z7_class_CHandler_final:
783 public IInArchive, 924 public IInArchive,
925 public IArchiveGetRawProps,
784 public IInArchiveGetStream, 926 public IInArchiveGetStream,
785 public CMyUnknownImp, 927 public CMyUnknownImp,
786 CDatabase 928 CDatabase
787{ 929{
788 Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream) 930 Z7_IFACES_IMP_UNK_3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream)
789}; 931};
790 932
791Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) 933Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
@@ -831,6 +973,8 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
831 COM_TRY_END 973 COM_TRY_END
832} 974}
833 975
976
977
834static const Byte kProps[] = 978static const Byte kProps[] =
835{ 979{
836 kpidPath, 980 kpidPath,
@@ -842,6 +986,7 @@ static const Byte kProps[] =
842 kpidATime, 986 kpidATime,
843 kpidAttrib, 987 kpidAttrib,
844 kpidShortName 988 kpidShortName
989 // , kpidCharacts
845}; 990};
846 991
847enum 992enum
@@ -922,15 +1067,16 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
922 case kpidPhySize: prop = PhySize; break; 1067 case kpidPhySize: prop = PhySize; break;
923 case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; 1068 case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
924 case kpidHeadersSize: prop = GetHeadersSize(); break; 1069 case kpidHeadersSize: prop = GetHeadersSize(); break;
925 case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break; 1070 case kpidMTime: if (VolItem_Defined) PropVariant_SetFrom_DosTime(prop, Vol_MTime); break;
926 case kpidShortComment: 1071 case kpidShortComment:
927 case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; 1072 case kpidVolumeName: if (VolItem_Defined) GetVolName(VolLabel, prop); break;
928 case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; 1073 case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
929 case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; 1074 case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
930 // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; 1075 // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
931 // case kpidNumHeads: prop = Header.NumHeads; break; 1076 // case kpidNumHeads: prop = Header.NumHeads; break;
932 // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break; 1077 // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
933 case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break; 1078 case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
1079 case kpidIsTree: prop = true; break;
934 // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break; 1080 // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
935 // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break; 1081 // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
936 // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; 1082 // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
@@ -948,6 +1094,52 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
948 COM_TRY_END 1094 COM_TRY_END
949} 1095}
950 1096
1097
1098Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
1099{
1100 *numProps = 0;
1101 return S_OK;
1102}
1103
1104Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */ , BSTR *name, PROPID *propID))
1105{
1106 *name = NULL;
1107 *propID = 0;
1108 return S_OK;
1109}
1110
1111Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
1112{
1113 *parentType = NParentType::kDir;
1114 int par = -1;
1115 if (index < Items.Size())
1116 par = Items[index].Parent;
1117 *parent = (UInt32)(Int32)par;
1118 return S_OK;
1119}
1120
1121Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1122{
1123 *data = NULL;
1124 *dataSize = 0;
1125 *propType = 0;
1126
1127 if (index < Items.Size()
1128 && propID == kpidName)
1129 {
1130 CByteBuffer &buf = Items[index].LongName;
1131 const UInt32 size = (UInt32)buf.Size();
1132 if (size != 0)
1133 {
1134 *dataSize = size;
1135 *propType = NPropDataType::kUtf16z;
1136 *data = (const void *)(const Byte *)buf;
1137 }
1138 }
1139 return S_OK;
1140}
1141
1142
951Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) 1143Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
952{ 1144{
953 COM_TRY_BEGIN 1145 COM_TRY_BEGIN
@@ -955,8 +1147,28 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
955 const CItem &item = Items[index]; 1147 const CItem &item = Items[index];
956 switch (propID) 1148 switch (propID)
957 { 1149 {
958 case kpidPath: prop = GetItemPath(index); break; 1150 case kpidPath:
959 case kpidShortName: prop = item.GetShortName(); break; 1151 case kpidName:
1152 case kpidShortName:
1153 {
1154 UString s;
1155 if (propID == kpidPath)
1156 GetItemPath(index, s);
1157 else if (propID == kpidName)
1158 item.GetName(s);
1159 else
1160 item.GetShortName(s);
1161 prop = s;
1162 break;
1163 }
1164/*
1165 case kpidCharacts:
1166 {
1167 if (item.LongName.Size())
1168 prop = "LFN";
1169 break;
1170 }
1171*/
960 case kpidIsDir: prop = item.IsDir(); break; 1172 case kpidIsDir: prop = item.IsDir(); break;
961 case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break; 1173 case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
962 case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; 1174 case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
@@ -1004,34 +1216,44 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1004 Int32 testMode, IArchiveExtractCallback *extractCallback)) 1216 Int32 testMode, IArchiveExtractCallback *extractCallback))
1005{ 1217{
1006 COM_TRY_BEGIN 1218 COM_TRY_BEGIN
1007 const bool allFilesMode = (numItems == (UInt32)(Int32)-1); 1219 if (numItems == (UInt32)(Int32)-1)
1008 if (allFilesMode) 1220 {
1221 indices = NULL;
1009 numItems = Items.Size(); 1222 numItems = Items.Size();
1010 if (numItems == 0) 1223 if (numItems == 0)
1011 return S_OK; 1224 return S_OK;
1012 UInt32 i; 1225 }
1226 else
1227 {
1228 if (numItems == 0)
1229 return S_OK;
1230 if (!indices)
1231 return E_INVALIDARG;
1232 }
1013 UInt64 totalSize = 0; 1233 UInt64 totalSize = 0;
1014 for (i = 0; i < numItems; i++)
1015 { 1234 {
1016 const CItem &item = Items[allFilesMode ? i : indices[i]]; 1235 UInt32 i = 0;
1017 if (!item.IsDir()) 1236 do
1018 totalSize += item.Size; 1237 {
1238 UInt32 index = i;
1239 if (indices)
1240 index = indices[i];
1241 const CItem &item = Items[index];
1242 if (!item.IsDir())
1243 totalSize += item.Size;
1244 }
1245 while (++i != numItems);
1019 } 1246 }
1020 RINOK(extractCallback->SetTotal(totalSize)) 1247 RINOK(extractCallback->SetTotal(totalSize))
1021 1248
1022 UInt64 totalPackSize; 1249 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1023 totalSize = totalPackSize = 0;
1024
1025 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
1026 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
1027
1028 CLocalProgress *lps = new CLocalProgress;
1029 CMyComPtr<ICompressProgressInfo> progress = lps;
1030 lps->Init(extractCallback, false); 1250 lps->Init(extractCallback, false);
1251 CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1031 1252
1032 CDummyOutStream *outStreamSpec = new CDummyOutStream; 1253 UInt64 totalPackSize;
1033 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); 1254 totalSize = totalPackSize = 0;
1034 1255
1256 UInt32 i;
1035 for (i = 0;; i++) 1257 for (i = 0;; i++)
1036 { 1258 {
1037 lps->InSize = totalPackSize; 1259 lps->InSize = totalPackSize;
@@ -1039,46 +1261,45 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1039 RINOK(lps->SetCur()) 1261 RINOK(lps->SetCur())
1040 if (i == numItems) 1262 if (i == numItems)
1041 break; 1263 break;
1042 CMyComPtr<ISequentialOutStream> realOutStream; 1264 int res;
1043 const Int32 askMode = testMode ?
1044 NExtract::NAskMode::kTest :
1045 NExtract::NAskMode::kExtract;
1046 const UInt32 index = allFilesMode ? i : indices[i];
1047 const CItem &item = Items[index];
1048 RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1049
1050 if (item.IsDir())
1051 { 1265 {
1266 CMyComPtr<ISequentialOutStream> realOutStream;
1267 const Int32 askMode = testMode ?
1268 NExtract::NAskMode::kTest :
1269 NExtract::NAskMode::kExtract;
1270 UInt32 index = i;
1271 if (indices)
1272 index = indices[i];
1273 const CItem &item = Items[index];
1274 RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1275
1276 if (item.IsDir())
1277 {
1278 RINOK(extractCallback->PrepareOperation(askMode))
1279 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
1280 continue;
1281 }
1282
1283 totalPackSize += Header.GetFilePackSize(item.Size);
1284 totalSize += item.Size;
1285
1286 if (!testMode && !realOutStream)
1287 continue;
1052 RINOK(extractCallback->PrepareOperation(askMode)) 1288 RINOK(extractCallback->PrepareOperation(askMode))
1053 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) 1289 res = NExtract::NOperationResult::kDataError;
1054 continue; 1290 CMyComPtr<ISequentialInStream> inStream;
1055 } 1291 const HRESULT hres = GetStream(index, &inStream);
1056 1292 if (hres != S_FALSE)
1057 totalPackSize += Header.GetFilePackSize(item.Size);
1058 totalSize += item.Size;
1059
1060 if (!testMode && !realOutStream)
1061 continue;
1062 RINOK(extractCallback->PrepareOperation(askMode))
1063
1064 outStreamSpec->SetStream(realOutStream);
1065 realOutStream.Release();
1066 outStreamSpec->Init();
1067
1068 int res = NExtract::NOperationResult::kDataError;
1069 CMyComPtr<ISequentialInStream> inStream;
1070 HRESULT hres = GetStream(index, &inStream);
1071 if (hres != S_FALSE)
1072 {
1073 RINOK(hres)
1074 if (inStream)
1075 { 1293 {
1076 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) 1294 RINOK(hres)
1077 if (copyCoderSpec->TotalSize == item.Size) 1295 if (inStream)
1078 res = NExtract::NOperationResult::kOK; 1296 {
1297 RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
1298 if (copyCoder->TotalSize == item.Size)
1299 res = NExtract::NOperationResult::kOK;
1300 }
1079 } 1301 }
1080 } 1302 }
1081 outStreamSpec->ReleaseStream();
1082 RINOK(extractCallback->SetOperationResult(res)) 1303 RINOK(extractCallback->SetOperationResult(res))
1083 } 1304 }
1084 return S_OK; 1305 return S_OK;
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
index 4049fbc..46e0239 100644
--- a/CPP/7zip/Archive/HfsHandler.cpp
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -25,6 +25,9 @@
25#define Get32(p) GetBe32(p) 25#define Get32(p) GetBe32(p)
26#define Get64(p) GetBe64(p) 26#define Get64(p) GetBe64(p)
27 27
28#define Get16a(p) GetBe16a(p)
29#define Get32a(p) GetBe32a(p)
30
28namespace NArchive { 31namespace NArchive {
29namespace NHfs { 32namespace NHfs {
30 33
@@ -104,23 +107,21 @@ UInt32 CFork::Calc_NumBlocks_from_Extents() const
104{ 107{
105 UInt32 num = 0; 108 UInt32 num = 0;
106 FOR_VECTOR (i, Extents) 109 FOR_VECTOR (i, Extents)
107 {
108 num += Extents[i].NumBlocks; 110 num += Extents[i].NumBlocks;
109 }
110 return num; 111 return num;
111} 112}
112 113
113bool CFork::Check_NumBlocks() const 114bool CFork::Check_NumBlocks() const
114{ 115{
115 UInt32 num = 0; 116 UInt32 num = NumBlocks;
116 FOR_VECTOR (i, Extents) 117 FOR_VECTOR (i, Extents)
117 { 118 {
118 UInt32 next = num + Extents[i].NumBlocks; 119 const UInt32 cur = Extents[i].NumBlocks;
119 if (next < num) 120 if (num < cur)
120 return false; 121 return false;
121 num = next; 122 num -= cur;
122 } 123 }
123 return num == NumBlocks; 124 return num == 0;
124} 125}
125 126
126struct CIdIndexPair 127struct CIdIndexPair
@@ -175,7 +176,7 @@ static int Find_in_IdExtents(const CObjectVector<CIdExtents> &items, UInt32 id)
175 176
176bool CFork::Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id) 177bool CFork::Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id)
177{ 178{
178 int index = Find_in_IdExtents(items, id); 179 const int index = Find_in_IdExtents(items, id);
179 if (index < 0) 180 if (index < 0)
180 return true; 181 return true;
181 const CIdExtents &item = items[index]; 182 const CIdExtents &item = items[index];
@@ -188,8 +189,13 @@ bool CFork::Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id)
188 189
189struct CVolHeader 190struct CVolHeader
190{ 191{
191 Byte Header[2]; 192 unsigned BlockSizeLog;
192 UInt16 Version; 193 UInt32 NumFiles;
194 UInt32 NumFolders;
195 UInt32 NumBlocks;
196 UInt32 NumFreeBlocks;
197
198 bool Is_Hsfx_ver5;
193 // UInt32 Attr; 199 // UInt32 Attr;
194 // UInt32 LastMountedVersion; 200 // UInt32 LastMountedVersion;
195 // UInt32 JournalInfoBlock; 201 // UInt32 JournalInfoBlock;
@@ -199,19 +205,13 @@ struct CVolHeader
199 // UInt32 BackupTime; 205 // UInt32 BackupTime;
200 // UInt32 CheckedTime; 206 // UInt32 CheckedTime;
201 207
202 UInt32 NumFiles;
203 UInt32 NumFolders;
204 unsigned BlockSizeLog;
205 UInt32 NumBlocks;
206 UInt32 NumFreeBlocks;
207
208 // UInt32 WriteCount; 208 // UInt32 WriteCount;
209 // UInt32 FinderInfo[8]; 209 // UInt32 FinderInfo[8];
210 // UInt64 VolID; 210 // UInt64 VolID;
211 211
212 UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; } 212 UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; }
213 UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; } 213 UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; }
214 bool IsHfsX() const { return Version > 4; } 214 bool IsHfsX() const { return Is_Hsfx_ver5; }
215}; 215};
216 216
217inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft) 217inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
@@ -463,18 +463,18 @@ public:
463 bool UnsupportedFeature; 463 bool UnsupportedFeature;
464 bool ThereAreAltStreams; 464 bool ThereAreAltStreams;
465 // bool CaseSensetive; 465 // bool CaseSensetive;
466 UInt32 MethodsMask;
466 UString ResFileName; 467 UString ResFileName;
467 468
468 UInt64 SpecOffset; 469 UInt64 SpecOffset;
469 UInt64 PhySize; 470 // UInt64 PhySize;
470 UInt64 PhySize2; 471 UInt64 PhySize2;
471 UInt64 ArcFileSize; 472 UInt64 ArcFileSize;
472 UInt32 MethodsMask;
473 473
474 void Clear() 474 void Clear()
475 { 475 {
476 SpecOffset = 0; 476 SpecOffset = 0;
477 PhySize = 0; 477 // PhySize = 0;
478 PhySize2 = 0; 478 PhySize2 = 0;
479 ArcFileSize = 0; 479 ArcFileSize = 0;
480 MethodsMask = 0; 480 MethodsMask = 0;
@@ -596,7 +596,7 @@ HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inSt
596{ 596{
597 if (fork.NumBlocks >= Header.NumBlocks) 597 if (fork.NumBlocks >= Header.NumBlocks)
598 return S_FALSE; 598 return S_FALSE;
599 if ((ArcFileSize >> Header.BlockSizeLog) + 1 < fork.NumBlocks) 599 if (((ArcFileSize - SpecOffset) >> Header.BlockSizeLog) + 1 < fork.NumBlocks)
600 return S_FALSE; 600 return S_FALSE;
601 601
602 const size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog; 602 const size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
@@ -1328,28 +1328,26 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1328 return S_OK; 1328 return S_OK;
1329} 1329}
1330 1330
1331static const unsigned kHeaderPadSize = (1 << 10); 1331static const unsigned kHeaderPadSize = 1 << 10;
1332static const unsigned kMainHeaderSize = 512; 1332static const unsigned kMainHeaderSize = 512;
1333static const unsigned kHfsHeaderSize = kHeaderPadSize + kMainHeaderSize; 1333static const unsigned kHfsHeaderSize = kHeaderPadSize + kMainHeaderSize;
1334 1334
1335static const unsigned k_Signature_LE16_HFS_BD = 'B' + ((unsigned)'D' << 8);
1336static const unsigned k_Signature_LE16_HPLUS = 'H' + ((unsigned)'+' << 8);
1337static const UInt32 k_Signature_LE32_HFSP_VER4 = 'H' + ((UInt32)'+' << 8) + ((UInt32)4 << 24);
1338static const UInt32 k_Signature_LE32_HFSX_VER5 = 'H' + ((UInt32)'X' << 8) + ((UInt32)5 << 24);
1339
1335API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size) 1340API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size)
1336{ 1341{
1337 if (size < kHfsHeaderSize) 1342 if (size < kHfsHeaderSize)
1338 return k_IsArc_Res_NEED_MORE; 1343 return k_IsArc_Res_NEED_MORE;
1339 p += kHeaderPadSize; 1344 p += kHeaderPadSize;
1340 if (p[0] == 'B' && p[1] == 'D') 1345 const UInt32 sig = GetUi32(p);
1341 { 1346 if (sig != k_Signature_LE32_HFSP_VER4)
1342 if (p[0x7C] != 'H' || p[0x7C + 1] != '+') 1347 if (sig != k_Signature_LE32_HFSX_VER5)
1343 return k_IsArc_Res_NO; 1348 if ((UInt16)sig != k_Signature_LE16_HFS_BD
1344 } 1349 || GetUi16(p + 0x7c) != k_Signature_LE16_HPLUS)
1345 else 1350 return k_IsArc_Res_NO;
1346 {
1347 if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
1348 return k_IsArc_Res_NO;
1349 UInt32 version = Get16(p + 2);
1350 if (version < 4 || version > 5)
1351 return k_IsArc_Res_NO;
1352 }
1353 return k_IsArc_Res_YES; 1351 return k_IsArc_Res_YES;
1354} 1352}
1355} 1353}
@@ -1357,30 +1355,42 @@ API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size)
1357HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) 1355HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
1358{ 1356{
1359 Clear(); 1357 Clear();
1360 Byte buf[kHfsHeaderSize]; 1358 UInt32 buf32[kHfsHeaderSize / 4];
1361 RINOK(ReadStream_FALSE(inStream, buf, kHfsHeaderSize)) 1359 RINOK(ReadStream_FALSE(inStream, buf32, kHfsHeaderSize))
1362 { 1360 const Byte *p = (const Byte *)buf32 + kHeaderPadSize;
1363 for (unsigned i = 0; i < kHeaderPadSize; i++)
1364 if (buf[i] != 0)
1365 return S_FALSE;
1366 }
1367 const Byte *p = buf + kHeaderPadSize;
1368 CVolHeader &h = Header; 1361 CVolHeader &h = Header;
1369 1362
1370 h.Header[0] = p[0]; 1363 if (GetUi16a(p) == k_Signature_LE16_HFS_BD)
1371 h.Header[1] = p[1];
1372
1373 if (p[0] == 'B' && p[1] == 'D')
1374 { 1364 {
1375 /* 1365 /*
1376 It's header for old HFS format. 1366 It's header for old HFS format.
1377 We don't support old HFS format, but we support 1367 We don't support old HFS format, but we support
1378 special HFS volume that contains embedded HFS+ volume 1368 special HFS volume that contains embedded HFS+ volume.
1369 HFS MDB : Master directory block
1370 HFS VIB : Volume information block
1371 some old images contain boot data with "LK" signature at start of buf32.
1379 */ 1372 */
1380 1373#if 1
1381 if (p[0x7C] != 'H' || p[0x7C + 1] != '+') 1374 // here we check first bytes of archive,
1375 // because start data can contain signature of some another
1376 // archive type that could have priority over HFS.
1377 const void *buf_ptr = (const void *)buf32;
1378 const unsigned sig = GetUi16a(buf_ptr);
1379 if (sig != 'L' + ((unsigned)'K' << 8))
1380 {
1381 // some old HFS (non HFS+) files have no "LK" signature,
1382 // but have non-zero data after 2 first bytes in start 1 KiB.
1383 if (sig != 0)
1384 return S_FALSE;
1385/*
1386 for (unsigned i = 0; i < kHeaderPadSize / 4; i++)
1387 if (buf32[i] != 0)
1388 return S_FALSE;
1389*/
1390 }
1391#endif
1392 if (GetUi16a(p + 0x7c) != k_Signature_LE16_HPLUS) // signature of embedded HFS+ volume
1382 return S_FALSE; 1393 return S_FALSE;
1383
1384 /* 1394 /*
1385 h.CTime = Get32(p + 0x2); 1395 h.CTime = Get32(p + 0x2);
1386 h.MTime = Get32(p + 0x6); 1396 h.MTime = Get32(p + 0x6);
@@ -1399,80 +1409,104 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
1399 h.NumFreeBlocks = Get16(p + 0x22); 1409 h.NumFreeBlocks = Get16(p + 0x22);
1400 */ 1410 */
1401 1411
1402 UInt32 blockSize = Get32(p + 0x14); 1412 // v24.09: blockSize in old HFS image can be non-power of 2.
1403 1413 const UInt32 blockSize = Get32a(p + 0x14); // drAlBlkSiz
1404 { 1414 if (blockSize == 0 || (blockSize & 0x1ff))
1405 unsigned i; 1415 return S_FALSE;
1406 for (i = 9; ((UInt32)1 << i) != blockSize; i++) 1416 const unsigned numBlocks = Get16a(p + 0x12); // drNmAlBlks
1407 if (i == 31) 1417 // UInt16 drFreeBks = Get16a(p + 0x22); // number of unused allocation blocks
1408 return S_FALSE;
1409 h.BlockSizeLog = i;
1410 }
1411
1412 h.NumBlocks = Get16(p + 0x12);
1413 /* 1418 /*
1414 we suppose that it has the follwing layout 1419 we suppose that it has the following layout:
1415 { 1420 {
1416 start block with header 1421 start data with header
1417 [h.NumBlocks] 1422 blocks[h.NumBlocks]
1418 end block with header 1423 end data with header (probably size_of_footer <= blockSize).
1419 } 1424 }
1420 */ 1425 */
1421 PhySize2 = ((UInt64)h.NumBlocks + 2) << h.BlockSizeLog; 1426 // PhySize2 = ((UInt64)numBlocks + 2) * blockSize;
1422 1427 const unsigned sector_of_FirstBlock = Get16a(p + 0x1c); // drAlBlSt : first allocation block in volume
1423 UInt32 startBlock = Get16(p + 0x7C + 2); 1428 const UInt32 startBlock = Get16a(p + 0x7c + 2);
1424 UInt32 blockCount = Get16(p + 0x7C + 4); 1429 const UInt32 blockCount = Get16a(p + 0x7c + 4);
1425 SpecOffset = (UInt64)(1 + startBlock) << h.BlockSizeLog; 1430 SpecOffset = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here
1426 UInt64 phy = SpecOffset + ((UInt64)blockCount << h.BlockSizeLog); 1431 PhySize2 = SpecOffset + (UInt64)numBlocks * blockSize;
1432 SpecOffset += (UInt64)startBlock * blockSize;
1433 // before v24.09: // SpecOffset = (UInt64)(1 + startBlock) * blockSize;
1434 const UInt64 phy = SpecOffset + (UInt64)blockCount * blockSize;
1427 if (PhySize2 < phy) 1435 if (PhySize2 < phy)
1428 PhySize2 = phy; 1436 PhySize2 = phy;
1437 UInt32 tail = 1 << 10; // at least 1 KiB tail (for footer MDB) is expected.
1438 if (tail < blockSize)
1439 tail = blockSize;
1440 RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize))
1441 if (ArcFileSize > PhySize2 &&
1442 ArcFileSize - PhySize2 <= tail)
1443 {
1444 // data after blocks[h.NumBlocks] must contain another copy of MDB.
1445 // In example where blockSize is not power of 2, we have
1446 // (ArcFileSize - PhySize2) < blockSize.
1447 // We suppose that data after blocks[h.NumBlocks] is part of HFS archive.
1448 // Maybe we should scan for footer MDB data (in last 1 KiB)?
1449 PhySize2 = ArcFileSize;
1450 }
1429 RINOK(InStream_SeekSet(inStream, SpecOffset)) 1451 RINOK(InStream_SeekSet(inStream, SpecOffset))
1430 RINOK(ReadStream_FALSE(inStream, buf, kHfsHeaderSize)) 1452 RINOK(ReadStream_FALSE(inStream, buf32, kHfsHeaderSize))
1431 } 1453 }
1432 1454
1433 if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X')) 1455 // HFS+ / HFSX volume header (starting from offset==1024):
1434 return S_FALSE;
1435 h.Version = Get16(p + 2);
1436 if (h.Version < 4 || h.Version > 5)
1437 return S_FALSE;
1438
1439 // h.Attr = Get32(p + 4);
1440 // h.LastMountedVersion = Get32(p + 8);
1441 // h.JournalInfoBlock = Get32(p + 0xC);
1442
1443 h.CTime = Get32(p + 0x10);
1444 h.MTime = Get32(p + 0x14);
1445 // h.BackupTime = Get32(p + 0x18);
1446 // h.CheckedTime = Get32(p + 0x1C);
1447
1448 h.NumFiles = Get32(p + 0x20);
1449 h.NumFolders = Get32(p + 0x24);
1450
1451 if (h.NumFolders > ((UInt32)1 << 29) ||
1452 h.NumFiles > ((UInt32)1 << 30))
1453 return S_FALSE;
1454
1455 RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize))
1456
1457 if (progress)
1458 { 1456 {
1459 const UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1; 1457 // v24.09: we use strict condition test for pair signature(Version):
1460 RINOK(progress->SetTotal(&numFiles, NULL)) 1458 // H+(4), HX(5):
1459 const UInt32 sig = GetUi32a(p);
1460 // h.Version = Get16(p + 2);
1461 h.Is_Hsfx_ver5 = false;
1462 if (sig != k_Signature_LE32_HFSP_VER4)
1463 {
1464 if (sig != k_Signature_LE32_HFSX_VER5)
1465 return S_FALSE;
1466 h.Is_Hsfx_ver5 = true;
1467 }
1461 } 1468 }
1462
1463 UInt32 blockSize = Get32(p + 0x28);
1464
1465 { 1469 {
1470 const UInt32 blockSize = Get32a(p + 0x28);
1466 unsigned i; 1471 unsigned i;
1467 for (i = 9; ((UInt32)1 << i) != blockSize; i++) 1472 for (i = 9; ((UInt32)1 << i) != blockSize; i++)
1468 if (i == 31) 1473 if (i == 31)
1469 return S_FALSE; 1474 return S_FALSE;
1470 h.BlockSizeLog = i; 1475 h.BlockSizeLog = i;
1471 } 1476 }
1477#if 1
1478 // HFS Plus DOCs: The first 1024 bytes are reserved for use as boot blocks
1479 // v24.09: we don't check starting 1 KiB before old (HFS MDB) block ("BD" signture) .
1480 // but we still check starting 1 KiB before HFS+ / HFSX volume header.
1481 // are there HFS+ / HFSX images with non-zero data in this reserved area?
1482 {
1483 for (unsigned i = 0; i < kHeaderPadSize / 4; i++)
1484 if (buf32[i] != 0)
1485 return S_FALSE;
1486 }
1487#endif
1488 // h.Attr = Get32a(p + 4);
1489 // h.LastMountedVersion = Get32a(p + 8);
1490 // h.JournalInfoBlock = Get32a(p + 0xC);
1491 h.CTime = Get32a(p + 0x10);
1492 h.MTime = Get32a(p + 0x14);
1493 // h.BackupTime = Get32a(p + 0x18);
1494 // h.CheckedTime = Get32a(p + 0x1C);
1495 h.NumFiles = Get32a(p + 0x20);
1496 h.NumFolders = Get32a(p + 0x24);
1497 if (h.NumFolders > ((UInt32)1 << 29) ||
1498 h.NumFiles > ((UInt32)1 << 30))
1499 return S_FALSE;
1472 1500
1473 h.NumBlocks = Get32(p + 0x2C); 1501 RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize))
1474 h.NumFreeBlocks = Get32(p + 0x30); 1502 if (progress)
1503 {
1504 const UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1;
1505 RINOK(progress->SetTotal(&numFiles, NULL))
1506 }
1475 1507
1508 h.NumBlocks = Get32a(p + 0x2C);
1509 h.NumFreeBlocks = Get32a(p + 0x30);
1476 /* 1510 /*
1477 h.NextCalatlogNodeID = Get32(p + 0x40); 1511 h.NextCalatlogNodeID = Get32(p + 0x40);
1478 h.WriteCount = Get32(p + 0x44); 1512 h.WriteCount = Get32(p + 0x44);
@@ -1495,7 +1529,7 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
1495 HeadersError = true; 1529 HeadersError = true;
1496 else 1530 else
1497 { 1531 {
1498 HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents); 1532 const HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents);
1499 if (res == S_FALSE) 1533 if (res == S_FALSE)
1500 HeadersError = true; 1534 HeadersError = true;
1501 else if (res != S_OK) 1535 else if (res != S_OK)
@@ -1515,7 +1549,7 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
1515 1549
1516 RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress)) 1550 RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress))
1517 1551
1518 PhySize = Header.GetPhySize(); 1552 // PhySize = Header.GetPhySize();
1519 return S_OK; 1553 return S_OK;
1520} 1554}
1521 1555
@@ -1591,7 +1625,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1591 case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break; 1625 case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break;
1592 case kpidPhySize: 1626 case kpidPhySize:
1593 { 1627 {
1594 UInt64 v = SpecOffset + PhySize; 1628 UInt64 v = SpecOffset + Header.GetPhySize(); // PhySize;
1595 if (v < PhySize2) 1629 if (v < PhySize2)
1596 v = PhySize2; 1630 v = PhySize2;
1597 prop = v; 1631 prop = v;
@@ -2529,7 +2563,7 @@ HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream)
2529 return S_FALSE; 2563 return S_FALSE;
2530 } 2564 }
2531 CSeekExtent se; 2565 CSeekExtent se;
2532 se.Phy = (UInt64)e.Pos << Header.BlockSizeLog; 2566 se.Phy = SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog);
2533 se.Virt = virt; 2567 se.Virt = virt;
2534 virt += cur; 2568 virt += cur;
2535 rem -= cur; 2569 rem -= cur;
@@ -2540,7 +2574,7 @@ HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream)
2540 return S_FALSE; 2574 return S_FALSE;
2541 2575
2542 CSeekExtent se; 2576 CSeekExtent se;
2543 se.Phy = 0; 2577 se.Phy = 0; // = SpecOffset ?
2544 se.Virt = virt; 2578 se.Virt = virt;
2545 extentStream->Extents.Add(se); 2579 extentStream->Extents.Add(se);
2546 extentStream->Stream = _stream; 2580 extentStream->Stream = _stream;
diff --git a/CPP/7zip/Archive/LpHandler.cpp b/CPP/7zip/Archive/LpHandler.cpp
index c1a76b4..926b654 100644
--- a/CPP/7zip/Archive/LpHandler.cpp
+++ b/CPP/7zip/Archive/LpHandler.cpp
@@ -460,9 +460,11 @@ struct LpMetadataHeader
460 460
461static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum) 461static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum)
462{ 462{
463 MY_ALIGN (16)
463 CSha256 sha; 464 CSha256 sha;
464 Sha256_Init(&sha); 465 Sha256_Init(&sha);
465 Sha256_Update(&sha, data, size); 466 Sha256_Update(&sha, data, size);
467 MY_ALIGN (16)
466 Byte calced[32]; 468 Byte calced[32];
467 Sha256_Final(&sha, calced); 469 Sha256_Final(&sha, calced);
468 return memcmp(checksum, calced, 32) == 0; 470 return memcmp(checksum, calced, 32) == 0;
@@ -470,6 +472,7 @@ static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum)
470 472
471static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset) 473static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset)
472{ 474{
475 MY_ALIGN (4)
473 Byte checksum[32]; 476 Byte checksum[32];
474 Byte *shaData = &data[hashOffset]; 477 Byte *shaData = &data[hashOffset];
475 memcpy(checksum, shaData, 32); 478 memcpy(checksum, shaData, 32);
@@ -528,6 +531,7 @@ HRESULT CHandler::Open2(IInStream *stream)
528{ 531{
529 RINOK(InStream_SeekSet(stream, LP_PARTITION_RESERVED_BYTES)) 532 RINOK(InStream_SeekSet(stream, LP_PARTITION_RESERVED_BYTES))
530 { 533 {
534 MY_ALIGN (4)
531 Byte buf[k_Geometry_Size]; 535 Byte buf[k_Geometry_Size];
532 RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size)) 536 RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size))
533 if (memcmp(buf, k_Signature, k_SignatureSize) != 0) 537 if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp
index c9e2c01..194e5bf 100644
--- a/CPP/7zip/Archive/Nsis/NsisIn.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -4005,7 +4005,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
4005 AddParam_Var(params[0]); 4005 AddParam_Var(params[0]);
4006 AString temp; 4006 AString temp;
4007 ReadString2(temp, params[1]); 4007 ReadString2(temp, params[1]);
4008 if (temp != "$TEMP") 4008 if (!temp.IsEqualTo("$TEMP"))
4009 SpaceQuStr(temp); 4009 SpaceQuStr(temp);
4010 break; 4010 break;
4011 } 4011 }
@@ -4410,7 +4410,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
4410 } 4410 }
4411 else 4411 else
4412 { 4412 {
4413 if (func == "DllUnregisterServer") 4413 if (func.IsEqualTo("DllUnregisterServer"))
4414 { 4414 {
4415 s += "UnRegDLL"; 4415 s += "UnRegDLL";
4416 printFunc = false; 4416 printFunc = false;
@@ -4418,7 +4418,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
4418 else 4418 else
4419 { 4419 {
4420 s += "RegDLL"; 4420 s += "RegDLL";
4421 if (func == "DllRegisterServer") 4421 if (func.IsEqualTo("DllRegisterServer"))
4422 printFunc = false; 4422 printFunc = false;
4423 } 4423 }
4424 AddParam(params[0]); 4424 AddParam(params[0]);
@@ -4886,7 +4886,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
4886 AddParam_Var(params[1]); 4886 AddParam_Var(params[1]);
4887 AddParam(params[2]); 4887 AddParam(params[2]);
4888 AddParam(params[4]); 4888 AddParam(params[4]);
4889 // if (params[2] == "0") AddCommentAndString("GetWinVer"); 4889 // if (params[2].IsEqualTo("0")) AddCommentAndString("GetWinVer");
4890 } 4890 }
4891 else 4891 else
4892 s += "GetOsInfo"; 4892 s += "GetOsInfo";
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index d55521d..05c177f 100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -1907,7 +1907,7 @@ HRESULT CDatabase::Open()
1907 for (i = 0; i < SecurityAttrs.Size(); i++) 1907 for (i = 0; i < SecurityAttrs.Size(); i++)
1908 { 1908 {
1909 const CAttr &attr = SecurityAttrs[i]; 1909 const CAttr &attr = SecurityAttrs[i];
1910 if (attr.Name == L"$SII") 1910 if (attr.Name.IsEqualTo("$SII"))
1911 { 1911 {
1912 if (attr.Type == ATTR_TYPE_INDEX_ROOT) 1912 if (attr.Type == ATTR_TYPE_INDEX_ROOT)
1913 { 1913 {
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
index 8a0ff05..79f89ef 100644
--- a/CPP/7zip/Archive/PeHandler.cpp
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -2638,7 +2638,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
2638 { 2638 {
2639 const CSection &sect = _sections[i]; 2639 const CSection &sect = _sections[i];
2640 if (IsOpt()) 2640 if (IsOpt())
2641 if (_parseResources && sect.Name == ".rsrc") 2641 if (_parseResources && sect.Name.IsEqualTo(".rsrc"))
2642 { 2642 {
2643 // 20.01: we try to parse only first copy of .rsrc section. 2643 // 20.01: we try to parse only first copy of .rsrc section.
2644 _parseResources = false; 2644 _parseResources = false;
@@ -2727,7 +2727,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
2727 for (i = 0; i < _mixItems.Size(); i++) 2727 for (i = 0; i < _mixItems.Size(); i++)
2728 { 2728 {
2729 const CMixItem &mixItem = _mixItems[i]; 2729 const CMixItem &mixItem = _mixItems[i];
2730 if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_") 2730 if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name.IsEqualTo("_winzip_"))
2731 { 2731 {
2732 _mainSubfile = (Int32)(int)i; 2732 _mainSubfile = (Int32)(int)i;
2733 break; 2733 break;
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
index 34615c2..a639d8b 100644
--- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -393,6 +393,7 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop)
393 if (!FindExtra_Link(link)) 393 if (!FindExtra_Link(link))
394 return; 394 return;
395 395
396 bool isWindows = (HostOS == kHost_Windows);
396 if (link.Type != linkType) 397 if (link.Type != linkType)
397 { 398 {
398 if (linkType != NLinkType::kUnixSymLink) 399 if (linkType != NLinkType::kUnixSymLink)
@@ -400,8 +401,11 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop)
400 switch ((unsigned)link.Type) 401 switch ((unsigned)link.Type)
401 { 402 {
402 case NLinkType::kUnixSymLink: 403 case NLinkType::kUnixSymLink:
404 isWindows = false;
405 break;
403 case NLinkType::kWinSymLink: 406 case NLinkType::kWinSymLink:
404 case NLinkType::kWinJunction: 407 case NLinkType::kWinJunction:
408 isWindows = true;
405 break; 409 break;
406 default: return; 410 default: return;
407 } 411 }
@@ -409,10 +413,15 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop)
409 413
410 AString s; 414 AString s;
411 s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen); 415 s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen);
412
413 UString unicode; 416 UString unicode;
414 ConvertUTF8ToUnicode(s, unicode); 417 ConvertUTF8ToUnicode(s, unicode);
415 prop = NItemName::GetOsPath(unicode); 418 // rar5.0 used '\\' separator for windows symlinks and \??\ prefix for abs paths.
419 // rar5.1+ uses '/' separator for windows symlinks and /??/ prefix for abs paths.
420 // v25.00: we convert Windows slashes to Linux slashes:
421 if (isWindows)
422 unicode.Replace(L'\\', L'/');
423 prop = unicode;
424 // prop = NItemName::GetOsPath(unicode);
416} 425}
417 426
418bool CItem::GetAltStreamName(AString &name) const 427bool CItem::GetAltStreamName(AString &name) const
@@ -658,6 +667,9 @@ HRESULT CInArchive::ReadBlockHeader(CHeader &h)
658 RINOK(ReadStream_Check(_buf, AES_BLOCK_SIZE * 2)) 667 RINOK(ReadStream_Check(_buf, AES_BLOCK_SIZE * 2))
659 memcpy(m_CryptoDecoder->_iv, _buf, AES_BLOCK_SIZE); 668 memcpy(m_CryptoDecoder->_iv, _buf, AES_BLOCK_SIZE);
660 RINOK(m_CryptoDecoder->Init()) 669 RINOK(m_CryptoDecoder->Init())
670 // we call RAR5_AES_Filter with:
671 // data_ptr == aligned_ptr + 16
672 // data_size == 16
661 if (m_CryptoDecoder->Filter(_buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) 673 if (m_CryptoDecoder->Filter(_buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE) != AES_BLOCK_SIZE)
662 return E_FAIL; 674 return E_FAIL;
663 memcpy(buf, _buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE); 675 memcpy(buf, _buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
@@ -689,10 +701,14 @@ HRESULT CInArchive::ReadBlockHeader(CHeader &h)
689 return E_OUTOFMEMORY; 701 return E_OUTOFMEMORY;
690 memcpy(_buf, buf, filled); 702 memcpy(_buf, buf, filled);
691 const size_t rem = size - filled; 703 const size_t rem = size - filled;
704 // if (m_CryptoMode), we add AES_BLOCK_SIZE here, because _iv is not included to size.
692 AddToSeekValue(size + (m_CryptoMode ? AES_BLOCK_SIZE : 0)); 705 AddToSeekValue(size + (m_CryptoMode ? AES_BLOCK_SIZE : 0));
693 RINOK(ReadStream_Check(_buf + filled, rem)) 706 RINOK(ReadStream_Check(_buf + filled, rem))
694 if (m_CryptoMode) 707 if (m_CryptoMode)
695 { 708 {
709 // we call RAR5_AES_Filter with:
710 // data_ptr == aligned_ptr + 16
711 // (rem) can be big
696 if (m_CryptoDecoder->Filter(_buf + filled, (UInt32)rem) != rem) 712 if (m_CryptoDecoder->Filter(_buf + filled, (UInt32)rem) != rem)
697 return E_FAIL; 713 return E_FAIL;
698#if 1 714#if 1
@@ -1065,7 +1081,8 @@ HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS
1065 1081
1066 CMyComPtr<ICompressSetDecoderProperties2> csdp; 1082 CMyComPtr<ICompressSetDecoderProperties2> csdp;
1067 RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp)) 1083 RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp))
1068 1084 if (!csdp)
1085 return E_NOTIMPL;
1069 const unsigned ver = item.Get_AlgoVersion_HuffRev(); 1086 const unsigned ver = item.Get_AlgoVersion_HuffRev();
1070 if (ver > 1) 1087 if (ver > 1)
1071 return E_NOTIMPL; 1088 return E_NOTIMPL;
@@ -3343,9 +3360,9 @@ Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
3343 } 3360 }
3344 else if (name.IsPrefixedBy_Ascii_NoCase("memx")) 3361 else if (name.IsPrefixedBy_Ascii_NoCase("memx"))
3345 { 3362 {
3346 UInt64 memAvail; 3363 size_t memAvail;
3347 if (!NWindows::NSystem::GetRamSize(memAvail)) 3364 if (!NWindows::NSystem::GetRamSize(memAvail))
3348 memAvail = (UInt64)(sizeof(size_t)) << 28; 3365 memAvail = (size_t)sizeof(size_t) << 28;
3349 UInt64 v; 3366 UInt64 v;
3350 if (!ParseSizeString(name.Ptr(4), prop, memAvail, v)) 3367 if (!ParseSizeString(name.Ptr(4), prop, memAvail, v))
3351 return E_INVALIDARG; 3368 return E_INVALIDARG;
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h
index 8f6581a..913ba85 100644
--- a/CPP/7zip/Archive/Rar/Rar5Handler.h
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.h
@@ -286,10 +286,10 @@ struct CItem
286 286
287 bool IsService() const { return RecordType == NHeaderType::kService; } 287 bool IsService() const { return RecordType == NHeaderType::kService; }
288 288
289 bool Is_STM() const { return IsService() && Name == "STM"; } 289 bool Is_STM() const { return IsService() && Name.IsEqualTo("STM"); }
290 bool Is_CMT() const { return IsService() && Name == "CMT"; } 290 bool Is_CMT() const { return IsService() && Name.IsEqualTo("CMT"); }
291 bool Is_ACL() const { return IsService() && Name == "ACL"; } 291 bool Is_ACL() const { return IsService() && Name.IsEqualTo("ACL"); }
292 // bool Is_QO() const { return IsService() && Name == "QO"; } 292 // bool Is_QO() const { return IsService() && Name.IsEqualTo("QO"); }
293 293
294 int FindExtra(unsigned extraID, unsigned &recordDataSize) const; 294 int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
295 void PrintInfo(AString &s) const; 295 void PrintInfo(AString &s) const;
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index 9157acc..dfbad33 100644
--- a/CPP/7zip/Archive/Rar/RarHandler.cpp
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -435,13 +435,13 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
435 size -= sizeof(item.Salt); 435 size -= sizeof(item.Salt);
436 p += sizeof(item.Salt); 436 p += sizeof(item.Salt);
437 } 437 }
438 if (item.Name == "ACL" && size == 0) 438 if (item.Name.IsEqualTo("ACL") && size == 0)
439 { 439 {
440 item.IsAltStream = true; 440 item.IsAltStream = true;
441 item.Name.Empty(); 441 item.Name.Empty();
442 item.UnicodeName.SetFromAscii(".ACL"); 442 item.UnicodeName.SetFromAscii(".ACL");
443 } 443 }
444 else if (item.Name == "STM" && size != 0 && (size & 1) == 0) 444 else if (item.Name.IsEqualTo("STM") && size != 0 && (size & 1) == 0)
445 { 445 {
446 item.IsAltStream = true; 446 item.IsAltStream = true;
447 item.Name.Empty(); 447 item.Name.Empty();
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
index da2b6ee..4f8aaaa 100644
--- a/CPP/7zip/Archive/RpmHandler.cpp
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -330,11 +330,11 @@ void CHandler::AddSubFileExtension(AString &res) const
330 if (!_compressor.IsEmpty()) 330 if (!_compressor.IsEmpty())
331 { 331 {
332 s = _compressor; 332 s = _compressor;
333 if (_compressor == "bzip2") 333 if (_compressor.IsEqualTo("bzip2"))
334 s = "bz2"; 334 s = "bz2";
335 else if (_compressor == "gzip") 335 else if (_compressor.IsEqualTo("gzip"))
336 s = "gz"; 336 s = "gz";
337 else if (_compressor == "zstd") 337 else if (_compressor.IsEqualTo("zstd"))
338 s = "zst"; 338 s = "zst";
339 } 339 }
340 else 340 else
diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp
index 9c293a3..221af21 100644
--- a/CPP/7zip/Archive/VmdkHandler.cpp
+++ b/CPP/7zip/Archive/VmdkHandler.cpp
@@ -202,9 +202,12 @@ struct CExtentInfo
202 // PartitionUUID 202 // PartitionUUID
203 // DeviceIdentifier 203 // DeviceIdentifier
204 204
205 bool IsType_ZERO() const { return Type == "ZERO"; } 205 bool IsType_ZERO() const { return Type.IsEqualTo("ZERO"); }
206 // bool IsType_FLAT() const { return Type == "FLAT"; } 206 // bool IsType_FLAT() const { return Type.IsEqualTo("FLAT"); }
207 bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; } 207 bool IsType_Flat() const
208 { return Type.IsEqualTo("FLAT")
209 || Type.IsEqualTo("VMFS")
210 || Type.IsEqualTo("VMFSRAW"); }
208 211
209 bool Parse(const char *s); 212 bool Parse(const char *s);
210}; 213};
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
index 614755a..a748e99 100644
--- a/CPP/7zip/Archive/Wim/WimIn.cpp
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -1814,7 +1814,7 @@ bool CWimXml::Parse()
1814 1814
1815 if (!Xml.Parse(utf)) 1815 if (!Xml.Parse(utf))
1816 return false; 1816 return false;
1817 if (Xml.Root.Name != "WIM") 1817 if (!Xml.Root.Name.IsEqualTo("WIM"))
1818 return false; 1818 return false;
1819 1819
1820 FOR_VECTOR (i, Xml.Root.SubItems) 1820 FOR_VECTOR (i, Xml.Root.SubItems)
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
index 5112a16..cba546e 100644
--- a/CPP/7zip/Archive/XarHandler.cpp
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -3,6 +3,7 @@
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#include "../../../C/Sha256.h" 5#include "../../../C/Sha256.h"
6#include "../../../C/Sha512.h"
6#include "../../../C/CpuArch.h" 7#include "../../../C/CpuArch.h"
7 8
8#include "../../Common/ComTry.h" 9#include "../../Common/ComTry.h"
@@ -41,22 +42,33 @@ Z7_CLASS_IMP_NOQIB_1(
41 CInStreamWithSha256 42 CInStreamWithSha256
42 , ISequentialInStream 43 , ISequentialInStream
43) 44)
45 bool _sha512Mode;
44 CMyComPtr<ISequentialInStream> _stream; 46 CMyComPtr<ISequentialInStream> _stream;
45 CAlignedBuffer1 _sha; 47 CAlignedBuffer1 _sha256;
48 CAlignedBuffer1 _sha512;
46 UInt64 _size; 49 UInt64 _size;
47 50
48 CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; } 51 CSha256 *Sha256() { return (CSha256 *)(void *)(Byte *)_sha256; }
52 CSha512 *Sha512() { return (CSha512 *)(void *)(Byte *)_sha512; }
49public: 53public:
50 CInStreamWithSha256(): _sha(sizeof(CSha256)) {} 54 CInStreamWithSha256():
55 _sha256(sizeof(CSha256)),
56 _sha512(sizeof(CSha512))
57 {}
51 void SetStream(ISequentialInStream *stream) { _stream = stream; } 58 void SetStream(ISequentialInStream *stream) { _stream = stream; }
52 void Init() 59 void Init(bool sha512Mode)
53 { 60 {
61 _sha512Mode = sha512Mode;
54 _size = 0; 62 _size = 0;
55 Sha256_Init(Sha()); 63 if (sha512Mode)
64 Sha512_Init(Sha512(), SHA512_DIGEST_SIZE);
65 else
66 Sha256_Init(Sha256());
56 } 67 }
57 void ReleaseStream() { _stream.Release(); } 68 void ReleaseStream() { _stream.Release(); }
58 UInt64 GetSize() const { return _size; } 69 UInt64 GetSize() const { return _size; }
59 void Final(Byte *digest) { Sha256_Final(Sha(), digest); } 70 void Final256(Byte *digest) { Sha256_Final(Sha256(), digest); }
71 void Final512(Byte *digest) { Sha512_Final(Sha512(), digest, SHA512_DIGEST_SIZE); }
60}; 72};
61 73
62Z7_COM7F_IMF(CInStreamWithSha256::Read(void *data, UInt32 size, UInt32 *processedSize)) 74Z7_COM7F_IMF(CInStreamWithSha256::Read(void *data, UInt32 size, UInt32 *processedSize))
@@ -64,7 +76,10 @@ Z7_COM7F_IMF(CInStreamWithSha256::Read(void *data, UInt32 size, UInt32 *processe
64 UInt32 realProcessedSize; 76 UInt32 realProcessedSize;
65 const HRESULT result = _stream->Read(data, size, &realProcessedSize); 77 const HRESULT result = _stream->Read(data, size, &realProcessedSize);
66 _size += realProcessedSize; 78 _size += realProcessedSize;
67 Sha256_Update(Sha(), (const Byte *)data, realProcessedSize); 79 if (_sha512Mode)
80 Sha512_Update(Sha512(), (const Byte *)data, realProcessedSize);
81 else
82 Sha256_Update(Sha256(), (const Byte *)data, realProcessedSize);
68 if (processedSize) 83 if (processedSize)
69 *processedSize = realProcessedSize; 84 *processedSize = realProcessedSize;
70 return result; 85 return result;
@@ -75,25 +90,33 @@ Z7_CLASS_IMP_NOQIB_1(
75 COutStreamWithSha256 90 COutStreamWithSha256
76 , ISequentialOutStream 91 , ISequentialOutStream
77) 92)
78 // bool _calculate; 93 bool _sha512Mode;
79 CMyComPtr<ISequentialOutStream> _stream; 94 CMyComPtr<ISequentialOutStream> _stream;
80 CAlignedBuffer1 _sha; 95 CAlignedBuffer1 _sha256;
96 CAlignedBuffer1 _sha512;
81 UInt64 _size; 97 UInt64 _size;
82 98
83 CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; } 99 CSha256 *Sha256() { return (CSha256 *)(void *)(Byte *)_sha256; }
100 CSha512 *Sha512() { return (CSha512 *)(void *)(Byte *)_sha512; }
84public: 101public:
85 COutStreamWithSha256(): _sha(sizeof(CSha256)) {} 102 COutStreamWithSha256():
103 _sha256(sizeof(CSha256)),
104 _sha512(sizeof(CSha512))
105 {}
86 void SetStream(ISequentialOutStream *stream) { _stream = stream; } 106 void SetStream(ISequentialOutStream *stream) { _stream = stream; }
87 void ReleaseStream() { _stream.Release(); } 107 void ReleaseStream() { _stream.Release(); }
88 void Init(/* bool calculate = true */ ) 108 void Init(bool sha512Mode)
89 { 109 {
90 // _calculate = calculate; 110 _sha512Mode = sha512Mode;
91 _size = 0; 111 _size = 0;
92 Sha256_Init(Sha()); 112 if (sha512Mode)
113 Sha512_Init(Sha512(), SHA512_DIGEST_SIZE);
114 else
115 Sha256_Init(Sha256());
93 } 116 }
94 void InitSha256() { Sha256_Init(Sha()); }
95 UInt64 GetSize() const { return _size; } 117 UInt64 GetSize() const { return _size; }
96 void Final(Byte *digest) { Sha256_Final(Sha(), digest); } 118 void Final256(Byte *digest) { Sha256_Final(Sha256(), digest); }
119 void Final512(Byte *digest) { Sha512_Final(Sha512(), digest, SHA512_DIGEST_SIZE); }
97}; 120};
98 121
99Z7_COM7F_IMF(COutStreamWithSha256::Write(const void *data, UInt32 size, UInt32 *processedSize)) 122Z7_COM7F_IMF(COutStreamWithSha256::Write(const void *data, UInt32 size, UInt32 *processedSize))
@@ -102,7 +125,10 @@ Z7_COM7F_IMF(COutStreamWithSha256::Write(const void *data, UInt32 size, UInt32 *
102 if (_stream) 125 if (_stream)
103 result = _stream->Write(data, size, &size); 126 result = _stream->Write(data, size, &size);
104 // if (_calculate) 127 // if (_calculate)
105 Sha256_Update(Sha(), (const Byte *)data, size); 128 if (_sha512Mode)
129 Sha512_Update(Sha512(), (const Byte *)data, size);
130 else
131 Sha256_Update(Sha256(), (const Byte *)data, size);
106 _size += size; 132 _size += size;
107 if (processedSize) 133 if (processedSize)
108 *processedSize = size; 134 *processedSize = size;
@@ -240,7 +266,7 @@ struct CFile
240 266
241 bool IsCopyMethod() const 267 bool IsCopyMethod() const
242 { 268 {
243 return Method.IsEmpty() || Method == "octet-stream"; 269 return Method.IsEmpty() || Method.IsEqualTo("octet-stream");
244 } 270 }
245 271
246 void UpdateTotalPackSize(UInt64 &totalSize) const 272 void UpdateTotalPackSize(UInt64 &totalSize) const
@@ -390,7 +416,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
390 return true; 416 return true;
391 if (level >= 1024) 417 if (level >= 1024)
392 return false; 418 return false;
393 if (item.Name == "file") 419 if (item.Name.IsEqualTo("file"))
394 { 420 {
395 CFile file(parent); 421 CFile file(parent);
396 parent = (int)files.Size(); 422 parent = (int)files.Size();
@@ -409,19 +435,19 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
409 { 435 {
410 file.Type = typeItem->GetSubString(); 436 file.Type = typeItem->GetSubString();
411 // file.LinkFrom = typeItem->GetPropVal("link"); 437 // file.LinkFrom = typeItem->GetPropVal("link");
412 if (file.Type == "directory") 438 if (file.Type.IsEqualTo("directory"))
413 file.IsDir = true; 439 file.IsDir = true;
414 else 440 else
415 { 441 {
416 // file.IsDir = false; 442 // file.IsDir = false;
417 /* 443 /*
418 else if (file.Type == "file") 444 else if (file.Type.IsEqualTo("file"))
419 {} 445 {}
420 else if (file.Type == "hardlink") 446 else if (file.Type.IsEqualTo("hardlink"))
421 {} 447 {}
422 else 448 else
423 */ 449 */
424 if (file.Type == "symlink") 450 if (file.Type.IsEqualTo("symlink"))
425 file.Is_SymLink = true; 451 file.Is_SymLink = true;
426 // file.IsDir = false; 452 // file.IsDir = false;
427 } 453 }
@@ -463,7 +489,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
463 if (s.IsPrefixedBy(xx)) 489 if (s.IsPrefixedBy(xx))
464 { 490 {
465 s.DeleteFrontal(xx.Len()); 491 s.DeleteFrontal(xx.Len());
466 if (s == "gzip") 492 if (s.IsEqualTo("gzip"))
467 s = METHOD_NAME_ZLIB; 493 s = METHOD_NAME_ZLIB;
468 } 494 }
469 } 495 }
@@ -521,10 +547,11 @@ void CInStreamWithHash::SetStreamAndInit(ISequentialInStream *stream, int algo)
521 inStreamSha1->Init(); 547 inStreamSha1->Init();
522 stream = inStreamSha1; 548 stream = inStreamSha1;
523 } 549 }
524 else if (algo == XAR_CKSUM_SHA256) 550 else if (algo == XAR_CKSUM_SHA256
551 || algo == XAR_CKSUM_SHA512)
525 { 552 {
526 inStreamSha256->SetStream(stream); 553 inStreamSha256->SetStream(stream);
527 inStreamSha256->Init(); 554 inStreamSha256->Init(algo == XAR_CKSUM_SHA512);
528 stream = inStreamSha256; 555 stream = inStreamSha256;
529 } 556 }
530 inStreamLim->SetStream(stream); 557 inStreamLim->SetStream(stream);
@@ -542,7 +569,14 @@ bool CInStreamWithHash::CheckHash(int algo, const Byte *digest_from_arc) const
542 else if (algo == XAR_CKSUM_SHA256) 569 else if (algo == XAR_CKSUM_SHA256)
543 { 570 {
544 Byte digest[SHA256_DIGEST_SIZE]; 571 Byte digest[SHA256_DIGEST_SIZE];
545 inStreamSha256->Final(digest); 572 inStreamSha256->Final256(digest);
573 if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0)
574 return false;
575 }
576 else if (algo == XAR_CKSUM_SHA512)
577 {
578 Byte digest[SHA512_DIGEST_SIZE];
579 inStreamSha256->Final512(digest);
546 if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0) 580 if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0)
547 return false; 581 return false;
548 } 582 }
@@ -658,12 +692,13 @@ HRESULT CHandler::Open2(IInStream *stream)
658 file.UpdateTotalPackSize(totalPackSize); 692 file.UpdateTotalPackSize(totalPackSize);
659 if (file.Parent == -1) 693 if (file.Parent == -1)
660 { 694 {
661 if (file.Name == "Payload" || file.Name == "Content") 695 if (file.Name.IsEqualTo("Payload") ||
696 file.Name.IsEqualTo("Content"))
662 { 697 {
663 _mainSubfile = (Int32)(int)i; 698 _mainSubfile = (Int32)(int)i;
664 numMainFiles++; 699 numMainFiles++;
665 } 700 }
666 else if (file.Name == "PackageInfo") 701 else if (file.Name.IsEqualTo("PackageInfo"))
667 _is_pkg = true; 702 _is_pkg = true;
668 } 703 }
669 } 704 }
@@ -1151,11 +1186,12 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1151 outStreamSha1->SetStream(realOutStream); 1186 outStreamSha1->SetStream(realOutStream);
1152 outStreamSha1->Init(); 1187 outStreamSha1->Init();
1153 } 1188 }
1154 else if (checksum_method == XAR_CKSUM_SHA256) 1189 else if (checksum_method == XAR_CKSUM_SHA256
1190 || checksum_method == XAR_CKSUM_SHA512)
1155 { 1191 {
1156 outStreamLim->SetStream(outStreamSha256); 1192 outStreamLim->SetStream(outStreamSha256);
1157 outStreamSha256->SetStream(realOutStream); 1193 outStreamSha256->SetStream(realOutStream);
1158 outStreamSha256->Init(); 1194 outStreamSha256->Init(checksum_method == XAR_CKSUM_SHA512);
1159 } 1195 }
1160 else 1196 else
1161 outStreamLim->SetStream(realOutStream); 1197 outStreamLim->SetStream(realOutStream);
@@ -1175,9 +1211,9 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1175 else 1211 else
1176 opRes = NExtract::NOperationResult::kUnsupportedMethod; 1212 opRes = NExtract::NOperationResult::kUnsupportedMethod;
1177 } 1213 }
1178 else if (item.Method == METHOD_NAME_ZLIB) 1214 else if (item.Method.IsEqualTo(METHOD_NAME_ZLIB))
1179 coder = zlibCoder; 1215 coder = zlibCoder;
1180 else if (item.Method == "bzip2") 1216 else if (item.Method.IsEqualTo("bzip2"))
1181 coder = bzip2Coder; 1217 coder = bzip2Coder;
1182 else 1218 else
1183 opRes = NExtract::NOperationResult::kUnsupportedMethod; 1219 opRes = NExtract::NOperationResult::kUnsupportedMethod;
@@ -1209,8 +1245,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1209 else if (checksum_method == XAR_CKSUM_SHA256) 1245 else if (checksum_method == XAR_CKSUM_SHA256)
1210 { 1246 {
1211 Byte digest[SHA256_DIGEST_SIZE]; 1247 Byte digest[SHA256_DIGEST_SIZE];
1212 outStreamSha256->Final(digest); 1248 outStreamSha256->Final256(digest);
1213 if (memcmp(digest, item.extracted_checksum.Data, SHA256_DIGEST_SIZE) != 0) 1249 if (memcmp(digest, item.extracted_checksum.Data, sizeof(digest)) != 0)
1250 opRes = NExtract::NOperationResult::kCRCError;
1251 }
1252 else if (checksum_method == XAR_CKSUM_SHA512)
1253 {
1254 Byte digest[SHA512_DIGEST_SIZE];
1255 outStreamSha256->Final512(digest);
1256 if (memcmp(digest, item.extracted_checksum.Data, sizeof(digest)) != 0)
1214 opRes = NExtract::NOperationResult::kCRCError; 1257 opRes = NExtract::NOperationResult::kCRCError;
1215 } 1258 }
1216 if (opRes == NExtract::NOperationResult::kOK) 1259 if (opRes == NExtract::NOperationResult::kOK)
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp
index 7ced4e1..5aaa405 100644
--- a/CPP/7zip/Archive/XzHandler.cpp
+++ b/CPP/7zip/Archive/XzHandler.cpp
@@ -446,7 +446,7 @@ void COpenCallbackWrap::Init(IArchiveOpenCallback *callback)
446struct CXzsCPP 446struct CXzsCPP
447{ 447{
448 CXzs p; 448 CXzs p;
449 CXzsCPP() { Xzs_Construct(&p); } 449 CXzsCPP() { Xzs_CONSTRUCT(&p) }
450 ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } 450 ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
451}; 451};
452 452
@@ -536,6 +536,9 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
536 536
537 if (res2 == SZ_ERROR_ARCHIVE) 537 if (res2 == SZ_ERROR_ARCHIVE)
538 return S_FALSE; 538 return S_FALSE;
539 // what codes are possible here ?
540 // ?? res2 == SZ_ERROR_MEM : is possible here
541 // ?? res2 == SZ_ERROR_UNSUPPORTED : is possible here
539 } 542 }
540 else if (!isIndex) 543 else if (!isIndex)
541 { 544 {
@@ -967,9 +970,9 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
967 || _maxBlocksSize != (size_t)_maxBlocksSize) 970 || _maxBlocksSize != (size_t)_maxBlocksSize)
968 return S_FALSE; 971 return S_FALSE;
969 972
970 UInt64 memSize; 973 size_t memSize;
971 if (!NSystem::GetRamSize(memSize)) 974 if (!NSystem::GetRamSize(memSize))
972 memSize = (UInt64)(sizeof(size_t)) << 28; 975 memSize = (size_t)sizeof(size_t) << 28;
973 { 976 {
974 if (_maxBlocksSize > memSize / 4) 977 if (_maxBlocksSize > memSize / 4)
975 return S_FALSE; 978 return S_FALSE;
@@ -1159,6 +1162,13 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1159 */ 1162 */
1160 1163
1161 #ifndef Z7_ST 1164 #ifndef Z7_ST
1165
1166#ifdef _WIN32
1167 // we don't use chunk multithreading inside lzma2 stream.
1168 // so we don't set xzProps.lzma2Props.numThreadGroups.
1169 if (_numThreadGroups > 1)
1170 xzProps.numThreadGroups = _numThreadGroups;
1171#endif
1162 1172
1163 UInt32 numThreads = _numThreads; 1173 UInt32 numThreads = _numThreads;
1164 1174
@@ -1183,6 +1193,8 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1183 CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads); 1193 CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads);
1184 } 1194 }
1185 1195
1196 // printf("\n====== GetProcessGroupAffinity : \n");
1197
1186 UInt64 cs = _numSolidBytes; 1198 UInt64 cs = _numSolidBytes;
1187 if (cs != XZ_PROPS_BLOCK_SIZE_AUTO) 1199 if (cs != XZ_PROPS_BLOCK_SIZE_AUTO)
1188 oneMethodInfo.AddProp_BlockSize2(cs); 1200 oneMethodInfo.AddProp_BlockSize2(cs);
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
index bc047b7..b2684dc 100644
--- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -250,13 +250,26 @@ struct CThreadInfo
250 250
251 HRESULT CreateEvents() 251 HRESULT CreateEvents()
252 { 252 {
253 WRes wres = CompressEvent.CreateIfNotCreated_Reset(); 253 const WRes wres = CompressEvent.CreateIfNotCreated_Reset();
254 return HRESULT_FROM_WIN32(wres); 254 return HRESULT_FROM_WIN32(wres);
255 } 255 }
256 256
257 HRESULT CreateThread() 257 // (group < 0) means no_group.
258 HRESULT CreateThread_with_group(
259#ifdef _WIN32
260 int group
261#endif
262 )
258 { 263 {
259 WRes wres = Thread.Create(CoderThread, this); 264 // tested in win10: If thread is created by another thread,
265 // child thread probably uses same group as parent thread.
266 // So we don't need to send (group) to encoder in created thread.
267 const WRes wres =
268#ifdef _WIN32
269 group >= 0 ?
270 Thread.Create_With_Group(CoderThread, this, (unsigned)group) :
271#endif
272 Thread.Create(CoderThread, this);
260 return HRESULT_FROM_WIN32(wres); 273 return HRESULT_FROM_WIN32(wres);
261 } 274 }
262 275
@@ -450,8 +463,12 @@ static HRESULT UpdateItemOldData(
450 if (ui.NewProps) 463 if (ui.NewProps)
451 { 464 {
452 if (item.HasDescriptor()) 465 if (item.HasDescriptor())
453 return E_NOTIMPL; 466 {
454 467 // we know compressed / uncompressed sizes and crc.
468 // so we remove descriptor here
469 item.Flags = (UInt16)(item.Flags & ~NFileHeader::NFlags::kDescriptorUsedMask);
470 // return E_NOTIMPL;
471 }
455 // we keep ExternalAttrib and some another properties from old archive 472 // we keep ExternalAttrib and some another properties from old archive
456 // item.ExternalAttrib = ui.Attrib; 473 // item.ExternalAttrib = ui.Attrib;
457 // if we don't change Comment, we keep Comment from OldProperties 474 // if we don't change Comment, we keep Comment from OldProperties
@@ -1000,6 +1017,9 @@ static HRESULT Update2(
1000 #ifndef Z7_ST 1017 #ifndef Z7_ST
1001 1018
1002 UInt32 numThreads = options._numThreads; 1019 UInt32 numThreads = options._numThreads;
1020#ifdef _WIN32
1021 const UInt32 numThreadGroups = options._numThreadGroups;
1022#endif
1003 1023
1004 UInt32 numZipThreads_limit = numThreads; 1024 UInt32 numZipThreads_limit = numThreads;
1005 if (numZipThreads_limit > numFilesToCompress) 1025 if (numZipThreads_limit > numFilesToCompress)
@@ -1014,12 +1034,10 @@ static HRESULT Update2(
1014 } 1034 }
1015 1035
1016 { 1036 {
1037 // we reduce number of threads for 32-bit to reduce memory usege to 256 MB
1017 const UInt32 kNumMaxThreads = 1038 const UInt32 kNumMaxThreads =
1018 #ifdef _WIN32 1039 // _WIN32 (64-bit) supports only 64 threads in one group.
1019 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here 1040 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit
1020 #else
1021 128;
1022 #endif
1023 if (numThreads > kNumMaxThreads) 1041 if (numThreads > kNumMaxThreads)
1024 numThreads = kNumMaxThreads; 1042 numThreads = kNumMaxThreads;
1025 } 1043 }
@@ -1264,7 +1282,14 @@ static HRESULT Update2(
1264 threadInfo.Progress = threadInfo.ProgressSpec; 1282 threadInfo.Progress = threadInfo.ProgressSpec;
1265 threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i); 1283 threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i);
1266 threadInfo.MtSem = &mtSem; 1284 threadInfo.MtSem = &mtSem;
1267 RINOK(threadInfo.CreateThread()) 1285 const HRESULT hres =
1286 threadInfo.CreateThread_with_group(
1287#ifdef _WIN32
1288 (numThreadGroups > 1 && numThreads > 1) ?
1289 (int)(i % numThreadGroups) : -1
1290#endif
1291 );
1292 RINOK(hres)
1268 } 1293 }
1269 } 1294 }
1270 1295
diff --git a/CPP/7zip/Bundles/Alone/Alone.dsp b/CPP/7zip/Bundles/Alone/Alone.dsp
index beed5a7..558c41e 100644
--- a/CPP/7zip/Bundles/Alone/Alone.dsp
+++ b/CPP/7zip/Bundles/Alone/Alone.dsp
@@ -1148,26 +1148,6 @@ SOURCE=..\..\Compress\PpmdZip.cpp
1148SOURCE=..\..\Compress\PpmdZip.h 1148SOURCE=..\..\Compress\PpmdZip.h
1149# End Source File 1149# End Source File
1150# End Group 1150# End Group
1151# Begin Group "RangeCoder"
1152
1153# PROP Default_Filter ""
1154# Begin Source File
1155
1156SOURCE=..\..\Compress\RangeCoder.h
1157# End Source File
1158# Begin Source File
1159
1160SOURCE=..\..\Compress\RangeCoderBit.h
1161# End Source File
1162# Begin Source File
1163
1164SOURCE=..\..\Compress\RangeCoderBitTree.h
1165# End Source File
1166# Begin Source File
1167
1168SOURCE=..\..\Compress\RangeCoderOpt.h
1169# End Source File
1170# End Group
1171# Begin Group "Shrink" 1151# Begin Group "Shrink"
1172 1152
1173# PROP Default_Filter "" 1153# PROP Default_Filter ""
diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile
index 7547590..9f81f9e 100644
--- a/CPP/7zip/Bundles/Alone/makefile
+++ b/CPP/7zip/Bundles/Alone/makefile
@@ -5,6 +5,7 @@ CFLAGS = $(CFLAGS) -DZ7_ZIP_LZFSE_DISABLE
5# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A 5# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A
6# ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE 6# ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE
7 7
8# USE_C_SORT=1
8# USE_C_AES = 1 9# USE_C_AES = 1
9# USE_C_SHA = 1 10# USE_C_SHA = 1
10# USE_C_LZFINDOPT = 1 11# USE_C_LZFINDOPT = 1
@@ -221,7 +222,6 @@ C_OBJS = \
221 $O\Ppmd8.obj \ 222 $O\Ppmd8.obj \
222 $O\Ppmd8Dec.obj \ 223 $O\Ppmd8Dec.obj \
223 $O\Ppmd8Enc.obj \ 224 $O\Ppmd8Enc.obj \
224 $O\Sort.obj \
225 $O\SwapBytes.obj \ 225 $O\SwapBytes.obj \
226 $O\Threads.obj \ 226 $O\Threads.obj \
227 $O\Xxh64.obj \ 227 $O\Xxh64.obj \
@@ -240,5 +240,6 @@ C_OBJS = \
240!include "../../LzmaDec.mak" 240!include "../../LzmaDec.mak"
241!include "../../Sha1.mak" 241!include "../../Sha1.mak"
242!include "../../Sha256.mak" 242!include "../../Sha256.mak"
243!include "../../Sort.mak"
243 244
244!include "../../7zip.mak" 245!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Alone7z/makefile b/CPP/7zip/Bundles/Alone7z/makefile
index 89584e1..f0a813a 100644
--- a/CPP/7zip/Bundles/Alone7z/makefile
+++ b/CPP/7zip/Bundles/Alone7z/makefile
@@ -148,7 +148,6 @@ C_OBJS = \
148 $O\LzmaEnc.obj \ 148 $O\LzmaEnc.obj \
149 $O\MtCoder.obj \ 149 $O\MtCoder.obj \
150 $O\MtDec.obj \ 150 $O\MtDec.obj \
151 $O\Sort.obj \
152 $O\SwapBytes.obj \ 151 $O\SwapBytes.obj \
153 $O\Threads.obj \ 152 $O\Threads.obj \
154 $O\Xz.obj \ 153 $O\Xz.obj \
@@ -164,5 +163,6 @@ C_OBJS = \
164!include "../../LzFindOpt.mak" 163!include "../../LzFindOpt.mak"
165!include "../../LzmaDec.mak" 164!include "../../LzmaDec.mak"
166!include "../../Sha256.mak" 165!include "../../Sha256.mak"
166!include "../../Sort.mak"
167 167
168!include "../../7zip.mak" 168!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7z/makefile b/CPP/7zip/Bundles/Format7z/makefile
index fe6f94d..3d4754c 100644
--- a/CPP/7zip/Bundles/Format7z/makefile
+++ b/CPP/7zip/Bundles/Format7z/makefile
@@ -135,7 +135,6 @@ C_OBJS = \
135 $O\Ppmd7.obj \ 135 $O\Ppmd7.obj \
136 $O\Ppmd7Dec.obj \ 136 $O\Ppmd7Dec.obj \
137 $O\Ppmd7Enc.obj \ 137 $O\Ppmd7Enc.obj \
138 $O\Sort.obj \
139 $O\SwapBytes.obj \ 138 $O\SwapBytes.obj \
140 $O\Threads.obj \ 139 $O\Threads.obj \
141 140
@@ -144,5 +143,6 @@ C_OBJS = \
144!include "../../LzFindOpt.mak" 143!include "../../LzFindOpt.mak"
145!include "../../LzmaDec.mak" 144!include "../../LzmaDec.mak"
146!include "../../Sha256.mak" 145!include "../../Sha256.mak"
146!include "../../Sort.mak"
147 147
148!include "../../7zip.mak" 148!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak
index 3d8a430..b1c6fe2 100644
--- a/CPP/7zip/Bundles/Format7zF/Arc.mak
+++ b/CPP/7zip/Bundles/Format7zF/Arc.mak
@@ -4,6 +4,7 @@ COMMON_OBJS = \
4 $O\DynLimBuf.obj \ 4 $O\DynLimBuf.obj \
5 $O\IntToString.obj \ 5 $O\IntToString.obj \
6 $O\LzFindPrepare.obj \ 6 $O\LzFindPrepare.obj \
7 $O\Md5Reg.obj \
7 $O\MyMap.obj \ 8 $O\MyMap.obj \
8 $O\MyString.obj \ 9 $O\MyString.obj \
9 $O\MyVector.obj \ 10 $O\MyVector.obj \
@@ -11,6 +12,9 @@ COMMON_OBJS = \
11 $O\NewHandler.obj \ 12 $O\NewHandler.obj \
12 $O\Sha1Reg.obj \ 13 $O\Sha1Reg.obj \
13 $O\Sha256Reg.obj \ 14 $O\Sha256Reg.obj \
15 $O\Sha3Reg.obj \
16 $O\Sha512Reg.obj \
17 $O\Sha512Prepare.obj \
14 $O\StringConvert.obj \ 18 $O\StringConvert.obj \
15 $O\StringToInt.obj \ 19 $O\StringToInt.obj \
16 $O\UTFConvert.obj \ 20 $O\UTFConvert.obj \
@@ -274,6 +278,7 @@ C_OBJS = \
274 $O\Lzma2Enc.obj \ 278 $O\Lzma2Enc.obj \
275 $O\LzmaDec.obj \ 279 $O\LzmaDec.obj \
276 $O\LzmaEnc.obj \ 280 $O\LzmaEnc.obj \
281 $O\Md5.obj \
277 $O\MtCoder.obj \ 282 $O\MtCoder.obj \
278 $O\MtDec.obj \ 283 $O\MtDec.obj \
279 $O\Ppmd7.obj \ 284 $O\Ppmd7.obj \
@@ -283,7 +288,9 @@ C_OBJS = \
283 $O\Ppmd8.obj \ 288 $O\Ppmd8.obj \
284 $O\Ppmd8Dec.obj \ 289 $O\Ppmd8Dec.obj \
285 $O\Ppmd8Enc.obj \ 290 $O\Ppmd8Enc.obj \
286 $O\Sort.obj \ 291 $O\Sha3.obj \
292 $O\Sha512.obj \
293 $O\Sha512Opt.obj \
287 $O\SwapBytes.obj \ 294 $O\SwapBytes.obj \
288 $O\Threads.obj \ 295 $O\Threads.obj \
289 $O\Xxh64.obj \ 296 $O\Xxh64.obj \
@@ -300,3 +307,4 @@ C_OBJS = \
300!include "../../LzmaDec.mak" 307!include "../../LzmaDec.mak"
301!include "../../Sha1.mak" 308!include "../../Sha1.mak"
302!include "../../Sha256.mak" 309!include "../../Sha256.mak"
310!include "../../Sort.mak"
diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
index ff5a3f9..746aaff 100644
--- a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
+++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
@@ -45,6 +45,7 @@ COMMON_OBJS = \
45 $O/DynLimBuf.o \ 45 $O/DynLimBuf.o \
46 $O/IntToString.o \ 46 $O/IntToString.o \
47 $O/LzFindPrepare.o \ 47 $O/LzFindPrepare.o \
48 $O/Md5Reg.o \
48 $O/MyMap.o \ 49 $O/MyMap.o \
49 $O/MyString.o \ 50 $O/MyString.o \
50 $O/MyVector.o \ 51 $O/MyVector.o \
@@ -54,6 +55,9 @@ COMMON_OBJS = \
54 $O/Sha1Reg.o \ 55 $O/Sha1Reg.o \
55 $O/Sha256Prepare.o \ 56 $O/Sha256Prepare.o \
56 $O/Sha256Reg.o \ 57 $O/Sha256Reg.o \
58 $O/Sha3Reg.o \
59 $O/Sha512Prepare.o \
60 $O/Sha512Reg.o \
57 $O/StringConvert.o \ 61 $O/StringConvert.o \
58 $O/StringToInt.o \ 62 $O/StringToInt.o \
59 $O/UTFConvert.o \ 63 $O/UTFConvert.o \
@@ -337,6 +341,7 @@ C_OBJS = \
337 $O/Lzma2Enc.o \ 341 $O/Lzma2Enc.o \
338 $O/LzmaDec.o \ 342 $O/LzmaDec.o \
339 $O/LzmaEnc.o \ 343 $O/LzmaEnc.o \
344 $O/Md5.o \
340 $O/MtCoder.o \ 345 $O/MtCoder.o \
341 $O/MtDec.o \ 346 $O/MtDec.o \
342 $O/Ppmd7.o \ 347 $O/Ppmd7.o \
@@ -350,6 +355,9 @@ C_OBJS = \
350 $O/Sha1Opt.o \ 355 $O/Sha1Opt.o \
351 $O/Sha256.o \ 356 $O/Sha256.o \
352 $O/Sha256Opt.o \ 357 $O/Sha256Opt.o \
358 $O/Sha3.o \
359 $O/Sha512.o \
360 $O/Sha512Opt.o \
353 $O/Sort.o \ 361 $O/Sort.o \
354 $O/SwapBytes.o \ 362 $O/SwapBytes.o \
355 $O/Xxh64.o \ 363 $O/Xxh64.o \
diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
index 6e28288..0bf976c 100644
--- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
@@ -287,6 +287,10 @@ SOURCE=..\..\..\Common\LzFindPrepare.cpp
287# End Source File 287# End Source File
288# Begin Source File 288# Begin Source File
289 289
290SOURCE=..\..\..\Common\Md5Reg.cpp
291# End Source File
292# Begin Source File
293
290SOURCE=..\..\..\Common\MyBuffer.h 294SOURCE=..\..\..\Common\MyBuffer.h
291# End Source File 295# End Source File
292# Begin Source File 296# Begin Source File
@@ -383,6 +387,18 @@ SOURCE=..\..\..\Common\Sha256Reg.cpp
383# End Source File 387# End Source File
384# Begin Source File 388# Begin Source File
385 389
390SOURCE=..\..\..\Common\Sha3Reg.cpp
391# End Source File
392# Begin Source File
393
394SOURCE=..\..\..\Common\Sha512Prepare.cpp
395# End Source File
396# Begin Source File
397
398SOURCE=..\..\..\Common\Sha512Reg.cpp
399# End Source File
400# Begin Source File
401
386SOURCE=..\..\..\Common\StringConvert.cpp 402SOURCE=..\..\..\Common\StringConvert.cpp
387# End Source File 403# End Source File
388# Begin Source File 404# Begin Source File
@@ -2029,6 +2045,26 @@ SOURCE=..\..\..\..\C\LzmaEnc.h
2029# End Source File 2045# End Source File
2030# Begin Source File 2046# Begin Source File
2031 2047
2048SOURCE=..\..\..\..\C\Md5.c
2049
2050!IF "$(CFG)" == "7z - Win32 Release"
2051
2052# ADD CPP /O2
2053# SUBTRACT CPP /YX /Yc /Yu
2054
2055!ELSEIF "$(CFG)" == "7z - Win32 Debug"
2056
2057# SUBTRACT CPP /YX /Yc /Yu
2058
2059!ENDIF
2060
2061# End Source File
2062# Begin Source File
2063
2064SOURCE=..\..\..\..\C\Md5.h
2065# End Source File
2066# Begin Source File
2067
2032SOURCE=..\..\..\..\C\MtCoder.c 2068SOURCE=..\..\..\..\C\MtCoder.c
2033# SUBTRACT CPP /YX /Yc /Yu 2069# SUBTRACT CPP /YX /Yc /Yu
2034# End Source File 2070# End Source File
@@ -2230,6 +2266,62 @@ SOURCE=..\..\..\..\C\Sha256.h
2230# End Source File 2266# End Source File
2231# Begin Source File 2267# Begin Source File
2232 2268
2269SOURCE=..\..\..\..\C\Sha3.c
2270
2271!IF "$(CFG)" == "7z - Win32 Release"
2272
2273# ADD CPP /O2
2274# SUBTRACT CPP /YX /Yc /Yu
2275
2276!ELSEIF "$(CFG)" == "7z - Win32 Debug"
2277
2278# SUBTRACT CPP /YX /Yc /Yu
2279
2280!ENDIF
2281
2282# End Source File
2283# Begin Source File
2284
2285SOURCE=..\..\..\..\C\Sha3.h
2286# End Source File
2287# Begin Source File
2288
2289SOURCE=..\..\..\..\C\Sha512.c
2290
2291!IF "$(CFG)" == "7z - Win32 Release"
2292
2293# ADD CPP /O2
2294# SUBTRACT CPP /YX /Yc /Yu
2295
2296!ELSEIF "$(CFG)" == "7z - Win32 Debug"
2297
2298# SUBTRACT CPP /YX /Yc /Yu
2299
2300!ENDIF
2301
2302# End Source File
2303# Begin Source File
2304
2305SOURCE=..\..\..\..\C\Sha512.h
2306# End Source File
2307# Begin Source File
2308
2309SOURCE=..\..\..\..\C\Sha512Opt.c
2310
2311!IF "$(CFG)" == "7z - Win32 Release"
2312
2313# ADD CPP /O2
2314# SUBTRACT CPP /YX /Yc /Yu
2315
2316!ELSEIF "$(CFG)" == "7z - Win32 Debug"
2317
2318# SUBTRACT CPP /YX /Yc /Yu
2319
2320!ENDIF
2321
2322# End Source File
2323# Begin Source File
2324
2233SOURCE=..\..\..\..\C\Sort.c 2325SOURCE=..\..\..\..\C\Sort.c
2234 2326
2235!IF "$(CFG)" == "7z - Win32 Release" 2327!IF "$(CFG)" == "7z - Win32 Release"
diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
index b4bd2de..e43e8b1 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
@@ -59,13 +59,13 @@ static const char * const kHelpString =
59 " b : Benchmark\n" 59 " b : Benchmark\n"
60 "<switches>\n" 60 "<switches>\n"
61 " -a{N} : set compression mode : [0, 1] : default = 1 (max)\n" 61 " -a{N} : set compression mode : [0, 1] : default = 1 (max)\n"
62 " -d{N} : set dictionary size : [12, 30] : default = 24 (16 MiB)\n" 62 " -d{N} : set dictionary size : [12, 31] : default = 24 (16 MiB)\n"
63 " -fb{N} : set number of fast bytes : [5, 273] : default = 128\n" 63 " -fb{N} : set number of fast bytes : [5, 273] : default = 128\n"
64 " -mc{N} : set number of cycles for match finder\n" 64 " -mc{N} : set number of cycles for match finder\n"
65 " -lc{N} : set number of literal context bits : [0, 8] : default = 3\n" 65 " -lc{N} : set number of literal context bits : [0, 8] : default = 3\n"
66 " -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n" 66 " -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n"
67 " -pb{N} : set number of pos bits : [0, 4] : default = 2\n" 67 " -pb{N} : set number of pos bits : [0, 4] : default = 2\n"
68 " -mf{M} : set match finder: [hc4, bt2, bt3, bt4] : default = bt4\n" 68 " -mf{M} : set match finder: [hc4, hc5, bt2, bt3, bt4, bt5] : default = bt4\n"
69 " -mt{N} : set number of CPU threads\n" 69 " -mt{N} : set number of CPU threads\n"
70 " -eos : write end of stream marker\n" 70 " -eos : write end of stream marker\n"
71 " -si : read data from stdin\n" 71 " -si : read data from stdin\n"
@@ -372,8 +372,8 @@ static int main2(int numArgs, const char *args[])
372 return 0; 372 return 0;
373 } 373 }
374 374
375 bool stdInMode = parser[NKey::kStdIn].ThereIs; 375 const bool stdInMode = parser[NKey::kStdIn].ThereIs;
376 bool stdOutMode = parser[NKey::kStdOut].ThereIs; 376 const bool stdOutMode = parser[NKey::kStdOut].ThereIs;
377 377
378 if (!stdOutMode) 378 if (!stdOutMode)
379 PrintTitle(); 379 PrintTitle();
@@ -394,7 +394,16 @@ static int main2(int numArgs, const char *args[])
394 UInt32 dictLog; 394 UInt32 dictLog;
395 const UString &s = parser[NKey::kDict].PostStrings[0]; 395 const UString &s = parser[NKey::kDict].PostStrings[0];
396 dictLog = GetNumber(s); 396 dictLog = GetNumber(s);
397 dict = 1 << dictLog; 397 if (dictLog >= 32)
398 throw "unsupported dictionary size";
399 // we only want to use dictionary sizes that are powers of 2,
400 // because 7-zip only recognizes such dictionary sizes in the lzma header.#if 0
401#if 0
402 if (dictLog == 32)
403 dict = (UInt32)3840 << 20;
404 else
405#endif
406 dict = (UInt32)1 << dictLog;
398 dictDefined = true; 407 dictDefined = true;
399 AddProp(props2, "d", s); 408 AddProp(props2, "d", s);
400 } 409 }
@@ -522,7 +531,7 @@ static int main2(int numArgs, const char *args[])
522 531
523 if (encodeMode && !dictDefined) 532 if (encodeMode && !dictDefined)
524 { 533 {
525 dict = 1 << kDictSizeLog; 534 dict = (UInt32)1 << kDictSizeLog;
526 if (fileSizeDefined) 535 if (fileSizeDefined)
527 { 536 {
528 unsigned i; 537 unsigned i;
diff --git a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
index eb28f5d..0c09807 100644
--- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -229,7 +229,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
229 } 229 }
230 230
231 const FString tempDirPath = tempDir.GetPath(); 231 const FString tempDirPath = tempDir.GetPath();
232 // tempDirPath = L"M:\\1\\"; // to test low disk space 232 // tempDirPath = "M:\\1\\"; // to test low disk space
233 { 233 {
234 bool isCorrupt = false; 234 bool isCorrupt = false;
235 UString errorMessage; 235 UString errorMessage;
@@ -308,7 +308,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
308 { 308 {
309 if (appLaunched.IsEmpty()) 309 if (appLaunched.IsEmpty())
310 { 310 {
311 appLaunched = L"setup.exe"; 311 appLaunched = "setup.exe";
312 if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched))) 312 if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched)))
313 { 313 {
314 if (!assumeYes) 314 if (!assumeYes)
diff --git a/CPP/7zip/Common/CreateCoder.cpp b/CPP/7zip/Common/CreateCoder.cpp
index bf7b04e..93113a0 100644
--- a/CPP/7zip/Common/CreateCoder.cpp
+++ b/CPP/7zip/Common/CreateCoder.cpp
@@ -35,7 +35,7 @@ void RegisterCodec(const CCodecInfo *codecInfo) throw()
35 g_Codecs[g_NumCodecs++] = codecInfo; 35 g_Codecs[g_NumCodecs++] = codecInfo;
36} 36}
37 37
38static const unsigned kNumHashersMax = 16; 38static const unsigned kNumHashersMax = 32;
39extern 39extern
40unsigned g_NumHashers; 40unsigned g_NumHashers;
41unsigned g_NumHashers = 0; 41unsigned g_NumHashers = 0;
diff --git a/CPP/7zip/Common/InBuffer.h b/CPP/7zip/Common/InBuffer.h
index a8ccb40..13ec088 100644
--- a/CPP/7zip/Common/InBuffer.h
+++ b/CPP/7zip/Common/InBuffer.h
@@ -97,6 +97,16 @@ public:
97 97
98 size_t ReadBytesPart(Byte *buf, size_t size); 98 size_t ReadBytesPart(Byte *buf, size_t size);
99 size_t ReadBytes(Byte *buf, size_t size); 99 size_t ReadBytes(Byte *buf, size_t size);
100 const Byte *Lookahead(size_t &rem)
101 {
102 rem = (size_t)(_bufLim - _buf);
103 if (!rem)
104 {
105 ReadBlock();
106 rem = (size_t)(_bufLim - _buf);
107 }
108 return _buf;
109 }
100 size_t Skip(size_t size); 110 size_t Skip(size_t size);
101}; 111};
102 112
diff --git a/CPP/7zip/Common/MethodProps.cpp b/CPP/7zip/Common/MethodProps.cpp
index d87884c..a5d90cf 100644
--- a/CPP/7zip/Common/MethodProps.cpp
+++ b/CPP/7zip/Common/MethodProps.cpp
@@ -324,15 +324,22 @@ void CCoderProps::AddProp(const CProp &prop)
324 324
325HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const 325HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
326{ 326{
327 return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL); 327 return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL, NULL, NULL);
328} 328}
329 329
330HRESULT CProps::SetCoderProps_DSReduce_Aff( 330HRESULT CProps::SetCoderProps_DSReduce_Aff(
331 ICompressSetCoderProperties *scp, 331 ICompressSetCoderProperties *scp,
332 const UInt64 *dataSizeReduce, 332 const UInt64 *dataSizeReduce,
333 const UInt64 *affinity) const 333 const UInt64 *affinity,
334{ 334 const UInt32 *affinityGroup,
335 CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) ); 335 const UInt64 *affinityInGroup) const
336{
337 CCoderProps coderProps(Props.Size()
338 + (dataSizeReduce ? 1 : 0)
339 + (affinity ? 1 : 0)
340 + (affinityGroup ? 1 : 0)
341 + (affinityInGroup ? 1 : 0)
342 );
336 FOR_VECTOR (i, Props) 343 FOR_VECTOR (i, Props)
337 coderProps.AddProp(Props[i]); 344 coderProps.AddProp(Props[i]);
338 if (dataSizeReduce) 345 if (dataSizeReduce)
@@ -349,6 +356,20 @@ HRESULT CProps::SetCoderProps_DSReduce_Aff(
349 prop.Value = *affinity; 356 prop.Value = *affinity;
350 coderProps.AddProp(prop); 357 coderProps.AddProp(prop);
351 } 358 }
359 if (affinityGroup)
360 {
361 CProp prop;
362 prop.Id = NCoderPropID::kThreadGroup;
363 prop.Value = *affinityGroup;
364 coderProps.AddProp(prop);
365 }
366 if (affinityInGroup)
367 {
368 CProp prop;
369 prop.Id = NCoderPropID::kAffinityInGroup;
370 prop.Value = *affinityInGroup;
371 coderProps.AddProp(prop);
372 }
352 return coderProps.SetProps(scp); 373 return coderProps.SetProps(scp);
353} 374}
354 375
@@ -409,6 +430,11 @@ static const CNameToPropID g_NameToPropID[] =
409 { VT_UI4, "offset" }, 430 { VT_UI4, "offset" },
410 { VT_UI4, "zhb" } 431 { VT_UI4, "zhb" }
411 /* 432 /*
433 , { VT_UI4, "tgn" }, // kNumThreadGroups
434 , { VT_UI4, "tgi" }, // kThreadGroup
435 , { VT_UI8, "tga" }, // kAffinityInGroup
436 */
437 /*
412 , 438 ,
413 // { VT_UI4, "zhc" }, 439 // { VT_UI4, "zhc" },
414 // { VT_UI4, "zhd" }, 440 // { VT_UI4, "zhd" },
diff --git a/CPP/7zip/Common/MethodProps.h b/CPP/7zip/Common/MethodProps.h
index 3c332d6..be108fa 100644
--- a/CPP/7zip/Common/MethodProps.h
+++ b/CPP/7zip/Common/MethodProps.h
@@ -80,7 +80,11 @@ struct CProps
80 } 80 }
81 81
82 HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const; 82 HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const;
83 HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce, const UInt64 *affinity) const; 83 HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp,
84 const UInt64 *dataSizeReduce,
85 const UInt64 *affinity,
86 const UInt32 *affinityGroup,
87 const UInt64 *affinityInGroup) const;
84}; 88};
85 89
86class CMethodProps: public CProps 90class CMethodProps: public CProps
@@ -125,7 +129,7 @@ public:
125 129
126 UInt32 Get_Lzma_Algo() const 130 UInt32 Get_Lzma_Algo() const
127 { 131 {
128 int i = FindProp(NCoderPropID::kAlgorithm); 132 const int i = FindProp(NCoderPropID::kAlgorithm);
129 if (i >= 0) 133 if (i >= 0)
130 { 134 {
131 const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; 135 const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
@@ -141,11 +145,11 @@ public:
141 if (Get_DicSize(v)) 145 if (Get_DicSize(v))
142 return v; 146 return v;
143 const unsigned level = GetLevel(); 147 const unsigned level = GetLevel();
144 const UInt32 dictSize = 148 const UInt32 dictSize = level <= 4 ?
145 ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : 149 (UInt32)1 << (level * 2 + 16) :
146 ( level <= 6 ? ((UInt32)1 << (level + 19)) : 150 level <= sizeof(size_t) / 2 + 4 ?
147 ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) 151 (UInt32)1 << (level + 20) :
148 ))); 152 (UInt32)1 << (sizeof(size_t) / 2 + 24);
149 return dictSize; 153 return dictSize;
150 } 154 }
151 155
diff --git a/CPP/7zip/Common/OutBuffer.h b/CPP/7zip/Common/OutBuffer.h
index 88f5787..af78c4f 100644
--- a/CPP/7zip/Common/OutBuffer.h
+++ b/CPP/7zip/Common/OutBuffer.h
@@ -45,6 +45,7 @@ public:
45 HRESULT Flush() throw(); 45 HRESULT Flush() throw();
46 void FlushWithCheck(); 46 void FlushWithCheck();
47 47
48 Z7_FORCE_INLINE
48 void WriteByte(Byte b) 49 void WriteByte(Byte b)
49 { 50 {
50 UInt32 pos = _pos; 51 UInt32 pos = _pos;
@@ -54,10 +55,34 @@ public:
54 if (pos == _limitPos) 55 if (pos == _limitPos)
55 FlushWithCheck(); 56 FlushWithCheck();
56 } 57 }
58
57 void WriteBytes(const void *data, size_t size) 59 void WriteBytes(const void *data, size_t size)
58 { 60 {
59 for (size_t i = 0; i < size; i++) 61 while (size)
60 WriteByte(((const Byte *)data)[i]); 62 {
63 UInt32 pos = _pos;
64 size_t cur = (size_t)(_limitPos - pos);
65 if (cur >= size)
66 cur = size;
67 size -= cur;
68 Byte *dest = _buf + pos;
69 pos += (UInt32)cur;
70 _pos = pos;
71#if 0
72 memcpy(dest, data, cur);
73 data = (const void *)((const Byte *)data + cur);
74#else
75 const Byte * const lim = (const Byte *)data + cur;
76 do
77 {
78 *dest++ = *(const Byte *)data;
79 data = (const void *)((const Byte *)data + 1);
80 }
81 while (data != lim);
82#endif
83 if (pos == _limitPos)
84 FlushWithCheck();
85 }
61 } 86 }
62 87
63 Byte *GetOutBuffer(size_t &avail) 88 Byte *GetOutBuffer(size_t &avail)
diff --git a/CPP/7zip/Compress/BZip2Const.h b/CPP/7zip/Compress/BZip2Const.h
index 0dfcfe5..3380aaf 100644
--- a/CPP/7zip/Compress/BZip2Const.h
+++ b/CPP/7zip/Compress/BZip2Const.h
@@ -46,7 +46,7 @@ const UInt32 kBlockSizeStep = 100000;
46const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep; 46const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep;
47 47
48const unsigned kNumSelectorsBits = 15; 48const unsigned kNumSelectorsBits = 15;
49const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize)); 49const unsigned kNumSelectorsMax = 2 + kBlockSizeMax / kGroupSize;
50 50
51const unsigned kRleModeRepSize = 4; 51const unsigned kRleModeRepSize = 4;
52 52
diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp
index ef2555a..af0b312 100644
--- a/CPP/7zip/Compress/BZip2Encoder.cpp
+++ b/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -6,18 +6,20 @@
6#include "../../../C/BwtSort.h" 6#include "../../../C/BwtSort.h"
7#include "../../../C/HuffEnc.h" 7#include "../../../C/HuffEnc.h"
8 8
9#include "BZip2Crc.h"
10#include "BZip2Encoder.h" 9#include "BZip2Encoder.h"
11#include "Mtf8.h"
12 10
13namespace NCompress { 11namespace NCompress {
14namespace NBZip2 { 12namespace NBZip2 {
15 13
16const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20 14#define HUFFMAN_LEN 16
17 15#if HUFFMAN_LEN > Z7_HUFFMAN_LEN_MAX
18static const UInt32 kBufferSize = (1 << 17); 16 #error Stop_Compiling_Bad_HUFFMAN_LEN_BZip2Encoder
17#endif
18
19static const size_t kBufferSize = 1 << 17;
19static const unsigned kNumHuffPasses = 4; 20static const unsigned kNumHuffPasses = 4;
20 21
22
21bool CThreadInfo::Alloc() 23bool CThreadInfo::Alloc()
22{ 24{
23 if (!m_BlockSorterIndex) 25 if (!m_BlockSorterIndex)
@@ -27,11 +29,15 @@ bool CThreadInfo::Alloc()
27 return false; 29 return false;
28 } 30 }
29 31
30 if (!m_Block) 32 if (!m_Block_Base)
31 { 33 {
32 m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); 34 const unsigned kPadSize = 1 << 7; // we need at least 1 byte backward padding, becuase we use (m_Block - 1) pointer;
33 if (!m_Block) 35 m_Block_Base = (Byte *)::MidAlloc(kBlockSizeMax * 5
36 + kBlockSizeMax / 10 + (20 << 10)
37 + kPadSize);
38 if (!m_Block_Base)
34 return false; 39 return false;
40 m_Block = m_Block_Base + kPadSize;
35 m_MtfArray = m_Block + kBlockSizeMax; 41 m_MtfArray = m_Block + kBlockSizeMax;
36 m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; 42 m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
37 } 43 }
@@ -42,8 +48,8 @@ void CThreadInfo::Free()
42{ 48{
43 ::BigFree(m_BlockSorterIndex); 49 ::BigFree(m_BlockSorterIndex);
44 m_BlockSorterIndex = NULL; 50 m_BlockSorterIndex = NULL;
45 ::MidFree(m_Block); 51 ::MidFree(m_Block_Base);
46 m_Block = NULL; 52 m_Block_Base = NULL;
47} 53}
48 54
49#ifndef Z7_ST 55#ifndef Z7_ST
@@ -60,10 +66,14 @@ HRESULT CThreadInfo::Create()
60 if (wres == 0) { wres = CanWriteEvent.Create(); 66 if (wres == 0) { wres = CanWriteEvent.Create();
61 if (wres == 0) 67 if (wres == 0)
62 { 68 {
63 if (Encoder->_props.Affinity != 0) 69 wres =
64 wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); 70#ifdef _WIN32
65 else 71 Encoder->_props.NumThreadGroups > 1 ?
66 wres = Thread.Create(MFThread, this); 72 Thread.Create_With_Group(MFThread, this, ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup), 0) : // affinity
73#endif
74 Encoder->_props.Affinity != 0 ?
75 Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity) :
76 Thread.Create(MFThread, this);
67 }}} 77 }}}
68 return HRESULT_FROM_WIN32(wres); 78 return HRESULT_FROM_WIN32(wres);
69} 79}
@@ -216,94 +226,251 @@ void CEncoder::Free()
216} 226}
217#endif 227#endif
218 228
229struct CRleEncoder
230{
231 const Byte *_src;
232 const Byte *_srcLim;
233 Byte *_dest;
234 const Byte *_destLim;
235 Byte _prevByte;
236 unsigned _numReps;
237
238 void Encode();
239};
240
241Z7_NO_INLINE
242void CRleEncoder::Encode()
243{
244 const Byte *src = _src;
245 const Byte * const srcLim = _srcLim;
246 Byte *dest = _dest;
247 const Byte * const destLim = _destLim;
248 Byte prev = _prevByte;
249 unsigned numReps = _numReps;
250 // (dest < destLim)
251 // src = srcLim; // for debug
252 while (dest < destLim)
253 {
254 if (src == srcLim)
255 break;
256 const Byte b = *src++;
257 if (b != prev)
258 {
259 if (numReps >= kRleModeRepSize)
260 *dest++ = (Byte)(numReps - kRleModeRepSize);
261 *dest++ = b;
262 numReps = 1;
263 prev = b;
264 /*
265 { // speed optimization code:
266 if (dest >= destLim || src == srcLim)
267 break;
268 const Byte b2 = *src++;
269 *dest++ = b2;
270 numReps += (prev == b2);
271 prev = b2;
272 }
273 */
274 continue;
275 }
276 numReps++;
277 if (numReps <= kRleModeRepSize)
278 *dest++ = b;
279 else if (numReps == kRleModeRepSize + 255)
280 {
281 *dest++ = (Byte)(numReps - kRleModeRepSize);
282 numReps = 0;
283 }
284 }
285 _src = src;
286 _dest = dest;
287 _prevByte = prev;
288 _numReps = numReps;
289 // (dest <= destLim + 1)
290}
291
292
293// out: return value is blockSize: size of data filled in buffer[]:
294// (returned_blockSize <= _props.BlockSizeMult * kBlockSizeStep)
219UInt32 CEncoder::ReadRleBlock(Byte *buffer) 295UInt32 CEncoder::ReadRleBlock(Byte *buffer)
220{ 296{
297 CRleEncoder rle;
221 UInt32 i = 0; 298 UInt32 i = 0;
222 Byte prevByte; 299 if (m_InStream.ReadByte(rle._prevByte))
223 if (m_InStream.ReadByte(prevByte))
224 { 300 {
225 NumBlocks++; 301 NumBlocks++;
226 const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; 302 const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; // -1 for RLE
227 unsigned numReps = 1; 303 rle._destLim = buffer + blockSize;
228 buffer[i++] = prevByte; 304 rle._numReps = 1;
229 while (i < blockSize) // "- 1" to support RLE 305 buffer[i++] = rle._prevByte;
306 while (i < blockSize)
230 { 307 {
231 Byte b; 308 rle._dest = buffer + i;
232 if (!m_InStream.ReadByte(b)) 309 size_t rem;
310 const Byte * const ptr = m_InStream.Lookahead(rem);
311 if (rem == 0)
233 break; 312 break;
234 if (b != prevByte) 313 rle._src = ptr;
235 { 314 rle._srcLim = ptr + rem;
236 if (numReps >= kRleModeRepSize) 315 rle.Encode();
237 buffer[i++] = (Byte)(numReps - kRleModeRepSize); 316 m_InStream.Skip((size_t)(rle._src - ptr));
238 buffer[i++] = b; 317 i = (UInt32)(size_t)(rle._dest - buffer);
239 numReps = 1; 318 // (i <= blockSize + 1)
240 prevByte = b;
241 continue;
242 }
243 numReps++;
244 if (numReps <= kRleModeRepSize)
245 buffer[i++] = b;
246 else if (numReps == kRleModeRepSize + 255)
247 {
248 buffer[i++] = (Byte)(numReps - kRleModeRepSize);
249 numReps = 0;
250 }
251 } 319 }
252 // it's to support original BZip2 decoder 320 const int n = (int)rle._numReps - (int)kRleModeRepSize;
253 if (numReps >= kRleModeRepSize) 321 if (n >= 0)
254 buffer[i++] = (Byte)(numReps - kRleModeRepSize); 322 buffer[i++] = (Byte)n;
255 } 323 }
256 return i; 324 return i;
257} 325}
258 326
259void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); } 327
260void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); } 328
261void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); } 329Z7_NO_INLINE
262void CThreadInfo::WriteCrc2(UInt32 v) 330void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits)
263{ 331 { m_OutStreamCurrent.WriteBits(value, numBits); }
264 for (unsigned i = 0; i < 4; i++) 332/*
265 WriteByte2(((Byte)(v >> (24 - i * 8)))); 333Z7_NO_INLINE
334void CThreadInfo::WriteByte2(unsigned b)
335 { m_OutStreamCurrent.WriteByte(b); }
336*/
337// void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
338Z7_NO_INLINE
339void CEncoder::WriteByte(Byte b) { m_OutStream.WriteByte(b); }
340
341
342#define WRITE_BITS_UPDATE(value, numBits) \
343{ \
344 numBits -= _bitPos; \
345 const UInt32 hi = value >> numBits; \
346 *_buf++ = (Byte)(_curByte | hi); \
347 value -= hi << numBits; \
348 _bitPos = 8; \
349 _curByte = 0; \
266} 350}
267 351
268void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); } 352#if HUFFMAN_LEN > 16
269void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); } 353
270// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); } 354#define WRITE_BITS_HUFF(value2, numBits2) \
271void CEncoder::WriteCrc(UInt32 v) 355{ \
272{ 356 UInt32 value = value2; \
273 for (unsigned i = 0; i < 4; i++) 357 unsigned numBits = numBits2; \
274 WriteByte(((Byte)(v >> (24 - i * 8)))); 358 while (numBits >= _bitPos) { \
359 WRITE_BITS_UPDATE(value, numBits) \
360 } \
361 _bitPos -= numBits; \
362 _curByte |= (value << _bitPos); \
363}
364
365#else // HUFFMAN_LEN <= 16
366
367// numBits2 <= 16 is supported
368#define WRITE_BITS_HUFF(value2, numBits2) \
369{ \
370 UInt32 value = value2; \
371 unsigned numBits = numBits2; \
372 if (numBits >= _bitPos) \
373 { \
374 WRITE_BITS_UPDATE(value, numBits) \
375 if (numBits >= _bitPos) \
376 { \
377 numBits -= _bitPos; \
378 const UInt32 hi = value >> numBits; \
379 *_buf++ = (Byte)hi; \
380 value -= hi << numBits; \
381 } \
382 } \
383 _bitPos -= numBits; \
384 _curByte |= (value << _bitPos); \
385}
386
387#endif
388
389#define WRITE_BITS_8(value2, numBits2) \
390{ \
391 UInt32 value = value2; \
392 unsigned numBits = numBits2; \
393 if (numBits >= _bitPos) \
394 { \
395 WRITE_BITS_UPDATE(value, numBits) \
396 } \
397 _bitPos -= numBits; \
398 _curByte |= (value << _bitPos); \
399}
400
401#define WRITE_BIT_PRE \
402 { _bitPos--; }
403
404#define WRITE_BIT_POST \
405{ \
406 if (_bitPos == 0) \
407 { \
408 *_buf++ = (Byte)_curByte; \
409 _curByte = 0; \
410 _bitPos = 8; \
411 } \
412}
413
414#define WRITE_BIT_0 \
415{ \
416 WRITE_BIT_PRE \
417 WRITE_BIT_POST \
418}
419
420#define WRITE_BIT_1 \
421{ \
422 WRITE_BIT_PRE \
423 _curByte |= 1u << _bitPos; \
424 WRITE_BIT_POST \
275} 425}
276 426
277 427
278// blockSize > 0 428// blockSize > 0
279void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) 429void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
280{ 430{
281 WriteBit2(0); // Randomised = false 431 // WriteBit2(0); // Randomised = false
282
283 { 432 {
284 UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize); 433 const UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
285 // if (m_BlockSorterIndex[origPtr] != 0) throw 1; 434 // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
286 m_BlockSorterIndex[origPtr] = blockSize; 435 m_BlockSorterIndex[origPtr] = blockSize;
287 WriteBits2(origPtr, kNumOrigBits); 436 WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false)
288 } 437 }
289 438 Byte mtfBuf[256];
290 CMtf8Encoder mtf; 439 // memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning
291 unsigned numInUse = 0; 440 unsigned numInUse;
292 { 441 {
293 Byte inUse[256]; 442 Byte inUse[256];
294 Byte inUse16[16]; 443 Byte inUse16[16];
295 UInt32 i; 444 unsigned i;
296 for (i = 0; i < 256; i++) 445 for (i = 0; i < 256; i++)
297 inUse[i] = 0; 446 inUse[i] = 0;
298 for (i = 0; i < 16; i++) 447 for (i = 0; i < 16; i++)
299 inUse16[i] = 0; 448 inUse16[i] = 0;
300 for (i = 0; i < blockSize; i++) 449 {
301 inUse[block[i]] = 1; 450 const Byte * cur = block;
451 block = block + (size_t)blockSize - 1;
452 if (cur != block)
453 {
454 do
455 {
456 const unsigned b0 = cur[0];
457 const unsigned b1 = cur[1];
458 cur += 2;
459 inUse[b0] = 1;
460 inUse[b1] = 1;
461 }
462 while (cur < block);
463 }
464 if (cur == block)
465 inUse[cur[0]] = 1;
466 block -= blockSize; // block pointer is (original_block - 1)
467 }
468 numInUse = 0;
302 for (i = 0; i < 256; i++) 469 for (i = 0; i < 256; i++)
303 if (inUse[i]) 470 if (inUse[i])
304 { 471 {
305 inUse16[i >> 4] = 1; 472 inUse16[i >> 4] = 1;
306 mtf.Buf[numInUse++] = (Byte)i; 473 mtfBuf[numInUse++] = (Byte)i;
307 } 474 }
308 for (i = 0; i < 16; i++) 475 for (i = 0; i < 16; i++)
309 WriteBit2(inUse16[i]); 476 WriteBit2(inUse16[i]);
@@ -311,65 +478,88 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
311 if (inUse16[i >> 4]) 478 if (inUse16[i >> 4])
312 WriteBit2(inUse[i]); 479 WriteBit2(inUse[i]);
313 } 480 }
314 unsigned alphaSize = numInUse + 2; 481 const unsigned alphaSize = numInUse + 2;
315 482
316 Byte *mtfs = m_MtfArray;
317 UInt32 mtfArraySize = 0;
318 UInt32 symbolCounts[kMaxAlphaSize]; 483 UInt32 symbolCounts[kMaxAlphaSize];
319 { 484 {
320 for (unsigned i = 0; i < kMaxAlphaSize; i++) 485 for (unsigned i = 0; i < kMaxAlphaSize; i++)
321 symbolCounts[i] = 0; 486 symbolCounts[i] = 0;
487 symbolCounts[(size_t)alphaSize - 1] = 1;
322 } 488 }
323 489
490 Byte *mtfs = m_MtfArray;
324 { 491 {
325 UInt32 rleSize = 0;
326 UInt32 i = 0;
327 const UInt32 *bsIndex = m_BlockSorterIndex; 492 const UInt32 *bsIndex = m_BlockSorterIndex;
328 block--; 493 const UInt32 *bsIndex_rle = bsIndex;
494 const UInt32 * const bsIndex_end = bsIndex + blockSize;
495 // block--; // backward fix
496 // block pointer is (original_block - 1)
329 do 497 do
330 { 498 {
331 unsigned pos = mtf.FindAndMove(block[bsIndex[i]]); 499 const Byte v = block[*bsIndex++];
332 if (pos == 0) 500 Byte a = mtfBuf[0];
333 rleSize++; 501 if (v != a)
334 else
335 { 502 {
336 while (rleSize != 0) 503 mtfBuf[0] = v;
337 { 504 {
338 rleSize--; 505 UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle) - 1;
339 mtfs[mtfArraySize++] = (Byte)(rleSize & 1); 506 bsIndex_rle = bsIndex;
340 symbolCounts[rleSize & 1]++; 507 while (rleSize)
341 rleSize >>= 1; 508 {
509 const unsigned sym = (unsigned)(--rleSize & 1);
510 *mtfs++ = (Byte)sym;
511 symbolCounts[sym]++;
512 rleSize >>= 1;
513 }
342 } 514 }
343 if (pos >= 0xFE) 515 unsigned pos1 = 2; // = real_pos + 1
516 Byte b;
517 b = mtfBuf[1]; mtfBuf[1] = a; if (v != b)
518 { a = mtfBuf[2]; mtfBuf[2] = b; if (v == a) pos1 = 3;
519 else { b = mtfBuf[3]; mtfBuf[3] = a; if (v == b) pos1 = 4;
520 else
521 {
522 Byte *m = mtfBuf + 7;
523 for (;;)
524 {
525 a = m[-3]; m[-3] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 2)); break; }
526 b = m[-2]; m[-2] = a; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 1)); break; }
527 a = m[-1]; m[-1] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf )); break; }
528 b = m[ 0]; m[ 0] = a; m += 4; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 3)); break; }
529 }
530 }}}
531 symbolCounts[pos1]++;
532 if (pos1 >= 0xff)
344 { 533 {
345 mtfs[mtfArraySize++] = 0xFF; 534 *mtfs++ = 0xff;
346 mtfs[mtfArraySize++] = (Byte)(pos - 0xFE); 535 // pos1 -= 0xff;
536 pos1++; // we need only low byte
347 } 537 }
348 else 538 *mtfs++ = (Byte)pos1;
349 mtfs[mtfArraySize++] = (Byte)(pos + 1);
350 symbolCounts[(size_t)pos + 1]++;
351 } 539 }
352 } 540 }
353 while (++i < blockSize); 541 while (bsIndex < bsIndex_end);
354 542
355 while (rleSize != 0) 543 UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle);
544 while (rleSize)
356 { 545 {
357 rleSize--; 546 const unsigned sym = (unsigned)(--rleSize & 1);
358 mtfs[mtfArraySize++] = (Byte)(rleSize & 1); 547 *mtfs++ = (Byte)sym;
359 symbolCounts[rleSize & 1]++; 548 symbolCounts[sym]++;
360 rleSize >>= 1; 549 rleSize >>= 1;
361 } 550 }
362 551
363 if (alphaSize < 256) 552 unsigned d = alphaSize - 1;
364 mtfs[mtfArraySize++] = (Byte)(alphaSize - 1); 553 if (alphaSize >= 256)
365 else
366 { 554 {
367 mtfs[mtfArraySize++] = 0xFF; 555 *mtfs++ = 0xff;
368 mtfs[mtfArraySize++] = (Byte)(alphaSize - 256); 556 d = alphaSize; // (-256)
369 } 557 }
370 symbolCounts[(size_t)alphaSize - 1]++; 558 *mtfs++ = (Byte)d;
371 } 559 }
372 560
561 const Byte * const mtf_lim = mtfs;
562
373 UInt32 numSymbols = 0; 563 UInt32 numSymbols = 0;
374 { 564 {
375 for (unsigned i = 0; i < kMaxAlphaSize; i++) 565 for (unsigned i = 0; i < kMaxAlphaSize; i++)
@@ -378,34 +568,30 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
378 568
379 unsigned bestNumTables = kNumTablesMin; 569 unsigned bestNumTables = kNumTablesMin;
380 UInt32 bestPrice = 0xFFFFFFFF; 570 UInt32 bestPrice = 0xFFFFFFFF;
381 UInt32 startPos = m_OutStreamCurrent->GetPos(); 571 const UInt32 startPos = m_OutStreamCurrent.GetPos();
382 Byte startCurByte = m_OutStreamCurrent->GetCurByte(); 572 const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
383 for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) 573 for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
384 { 574 {
385 unsigned numTables; 575 unsigned numTables;
386 576
387 if (m_OptimizeNumTables) 577 if (m_OptimizeNumTables)
388 { 578 {
389 m_OutStreamCurrent->SetPos(startPos); 579 m_OutStreamCurrent.SetPos(startPos);
390 m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); 580 m_OutStreamCurrent.SetCurState(startPos & 7, startCurByte);
391 if (nt <= kNumTablesMax) 581 numTables = (nt <= kNumTablesMax ? nt : bestNumTables);
392 numTables = nt;
393 else
394 numTables = bestNumTables;
395 } 582 }
396 else 583 else
397 { 584 {
398 if (numSymbols < 200) numTables = 2; 585 if (numSymbols < 200) numTables = 2;
399 else if (numSymbols < 600) numTables = 3; 586 else if (numSymbols < 600) numTables = 3;
400 else if (numSymbols < 1200) numTables = 4; 587 else if (numSymbols < 1200) numTables = 4;
401 else if (numSymbols < 2400) numTables = 5; 588 else if (numSymbols < 2400) numTables = 5;
402 else numTables = 6; 589 else numTables = 6;
403 } 590 }
404 591
405 WriteBits2(numTables, kNumTablesBits); 592 WriteBits2(numTables, kNumTablesBits);
406 593 const unsigned numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
407 UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; 594 WriteBits2((UInt32)numSelectors, kNumSelectorsBits);
408 WriteBits2(numSelectors, kNumSelectorsBits);
409 595
410 { 596 {
411 UInt32 remFreq = numSymbols; 597 UInt32 remFreq = numSymbols;
@@ -436,28 +622,23 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
436 622
437 for (unsigned pass = 0; pass < kNumHuffPasses; pass++) 623 for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
438 { 624 {
625 memset(Freqs, 0, sizeof(Freqs[0]) * numTables);
626 // memset(Freqs, 0, sizeof(Freqs));
439 { 627 {
440 unsigned t = 0; 628 mtfs = m_MtfArray;
441 do
442 memset(Freqs[t], 0, sizeof(Freqs[t]));
443 while (++t < numTables);
444 }
445
446 {
447 UInt32 mtfPos = 0;
448 UInt32 g = 0; 629 UInt32 g = 0;
449 do 630 do
450 { 631 {
451 UInt32 symbols[kGroupSize]; 632 unsigned symbols[kGroupSize];
452 unsigned i = 0; 633 unsigned i = 0;
453 do 634 do
454 { 635 {
455 UInt32 symbol = mtfs[mtfPos++]; 636 UInt32 symbol = *mtfs++;
456 if (symbol >= 0xFF) 637 if (symbol >= 0xFF)
457 symbol += mtfs[mtfPos++]; 638 symbol += *mtfs++;
458 symbols[i] = symbol; 639 symbols[i] = symbol;
459 } 640 }
460 while (++i < kGroupSize && mtfPos < mtfArraySize); 641 while (++i < kGroupSize && mtfs < mtf_lim);
461 642
462 UInt32 bestPrice2 = 0xFFFFFFFF; 643 UInt32 bestPrice2 = 0xFFFFFFFF;
463 unsigned t = 0; 644 unsigned t = 0;
@@ -482,7 +663,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
482 freqs[symbols[j]]++; 663 freqs[symbols[j]]++;
483 while (++j < i); 664 while (++j < i);
484 } 665 }
485 while (mtfPos < mtfArraySize); 666 while (mtfs < mtf_lim);
486 } 667 }
487 668
488 unsigned t = 0; 669 unsigned t = 0;
@@ -494,11 +675,15 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
494 if (freqs[i] == 0) 675 if (freqs[i] == 0)
495 freqs[i] = 1; 676 freqs[i] = 1;
496 while (++i < alphaSize); 677 while (++i < alphaSize);
497 Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding); 678 Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, HUFFMAN_LEN);
498 } 679 }
499 while (++t < numTables); 680 while (++t < numTables);
500 } 681 }
501 682
683 unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
684 unsigned _curByte; // low (_bitPos) bits are zeros
685 // high (8 - _bitPos) bits are filled
686 Byte *_buf;
502 { 687 {
503 Byte mtfSel[kNumTablesMax]; 688 Byte mtfSel[kNumTablesMax];
504 { 689 {
@@ -507,81 +692,97 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
507 mtfSel[t] = (Byte)t; 692 mtfSel[t] = (Byte)t;
508 while (++t < numTables); 693 while (++t < numTables);
509 } 694 }
695
696 _bitPos = m_OutStreamCurrent._bitPos;
697 _curByte = m_OutStreamCurrent._curByte;
698 _buf = m_OutStreamCurrent._buf;
699 // stream.Init_from_Global(m_OutStreamCurrent);
510 700
511 UInt32 i = 0; 701 const Byte *selectors = m_Selectors;
702 const Byte * const selectors_lim = selectors + numSelectors;
703 Byte prev = 0; // mtfSel[0];
512 do 704 do
513 { 705 {
514 Byte sel = m_Selectors[i]; 706 const Byte sel = *selectors++;
515 unsigned pos; 707 if (prev != sel)
516 for (pos = 0; mtfSel[pos] != sel; pos++) 708 {
517 WriteBit2(1); 709 Byte *mtfSel_cur = &mtfSel[1];
518 WriteBit2(0); 710 for (;;)
519 for (; pos > 0; pos--) 711 {
520 mtfSel[pos] = mtfSel[(size_t)pos - 1]; 712 WRITE_BIT_1
521 mtfSel[0] = sel; 713 const Byte next = *mtfSel_cur;
714 *mtfSel_cur++ = prev;
715 prev = next;
716 if (next == sel)
717 break;
718 }
719 // mtfSel[0] = sel;
720 }
721 WRITE_BIT_0
522 } 722 }
523 while (++i < numSelectors); 723 while (selectors != selectors_lim);
524 } 724 }
525
526 { 725 {
527 unsigned t = 0; 726 unsigned t = 0;
528 do 727 do
529 { 728 {
530 const Byte *lens = Lens[t]; 729 const Byte *lens = Lens[t];
531 UInt32 len = lens[0]; 730 unsigned len = lens[0];
532 WriteBits2(len, kNumLevelsBits); 731 WRITE_BITS_8(len, kNumLevelsBits)
533 unsigned i = 0; 732 unsigned i = 0;
534 do 733 do
535 { 734 {
536 UInt32 level = lens[i]; 735 const unsigned level = lens[i];
537 while (len != level) 736 while (len != level)
538 { 737 {
539 WriteBit2(1); 738 WRITE_BIT_1
540 if (len < level) 739 if (len < level)
541 { 740 {
542 WriteBit2(0);
543 len++; 741 len++;
742 WRITE_BIT_0
544 } 743 }
545 else 744 else
546 { 745 {
547 WriteBit2(1);
548 len--; 746 len--;
747 WRITE_BIT_1
549 } 748 }
550 } 749 }
551 WriteBit2(0); 750 WRITE_BIT_0
552 } 751 }
553 while (++i < alphaSize); 752 while (++i < alphaSize);
554 } 753 }
555 while (++t < numTables); 754 while (++t < numTables);
556 } 755 }
557
558 { 756 {
559 UInt32 groupSize = 0; 757 UInt32 groupSize = 1;
560 UInt32 groupIndex = 0; 758 const Byte *selectors = m_Selectors;
561 const Byte *lens = NULL; 759 const Byte *lens = NULL;
562 const UInt32 *codes = NULL; 760 const UInt32 *codes = NULL;
563 UInt32 mtfPos = 0; 761 mtfs = m_MtfArray;
564 do 762 do
565 { 763 {
566 UInt32 symbol = mtfs[mtfPos++]; 764 unsigned symbol = *mtfs++;
567 if (symbol >= 0xFF) 765 if (symbol >= 0xFF)
568 symbol += mtfs[mtfPos++]; 766 symbol += *mtfs++;
569 if (groupSize == 0) 767 if (--groupSize == 0)
570 { 768 {
571 groupSize = kGroupSize; 769 groupSize = kGroupSize;
572 unsigned t = m_Selectors[groupIndex++]; 770 const unsigned t = *selectors++;
573 lens = Lens[t]; 771 lens = Lens[t];
574 codes = Codes[t]; 772 codes = Codes[t];
575 } 773 }
576 groupSize--; 774 WRITE_BITS_HUFF(codes[symbol], lens[symbol])
577 m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
578 } 775 }
579 while (mtfPos < mtfArraySize); 776 while (mtfs < mtf_lim);
580 } 777 }
778 // Restore_from_Local:
779 m_OutStreamCurrent._bitPos = _bitPos;
780 m_OutStreamCurrent._curByte = _curByte;
781 m_OutStreamCurrent._buf = _buf;
581 782
582 if (!m_OptimizeNumTables) 783 if (!m_OptimizeNumTables)
583 break; 784 break;
584 UInt32 price = m_OutStreamCurrent->GetPos() - startPos; 785 const UInt32 price = m_OutStreamCurrent.GetPos() - startPos;
585 if (price <= bestPrice) 786 if (price <= bestPrice)
586 { 787 {
587 if (nt == kNumTablesMax) 788 if (nt == kNumTablesMax)
@@ -592,6 +793,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
592 } 793 }
593} 794}
594 795
796
595// blockSize > 0 797// blockSize > 0
596UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) 798UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
597{ 799{
@@ -603,142 +805,126 @@ UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
603 WriteByte2(kBlockSig5); 805 WriteByte2(kBlockSig5);
604 806
605 CBZip2Crc crc; 807 CBZip2Crc crc;
606 unsigned numReps = 0; 808 const Byte * const lim = block + blockSize;
607 Byte prevByte = block[0]; 809 unsigned b = *block++;
608 UInt32 i = 0; 810 crc.UpdateByte(b);
609 do 811 for (;;)
610 { 812 {
611 Byte b = block[i]; 813 const unsigned prev = b;
612 if (numReps == kRleModeRepSize) 814 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
613 { 815 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
614 for (; b > 0; b--) 816 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
615 crc.UpdateByte(prevByte); 817 if (block >= lim) { break; } b = *block++; if (b) do crc.UpdateByte(prev); while (--b);
616 numReps = 0; 818 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b);
617 continue;
618 }
619 if (prevByte == b)
620 numReps++;
621 else
622 {
623 numReps = 1;
624 prevByte = b;
625 }
626 crc.UpdateByte(b);
627 } 819 }
628 while (++i < blockSize); 820 const UInt32 crcRes = crc.GetDigest();
629 UInt32 crcRes = crc.GetDigest(); 821 for (int i = 24; i >= 0; i -= 8)
630 WriteCrc2(crcRes); 822 WriteByte2((Byte)(crcRes >> i));
631 EncodeBlock(block, blockSize); 823 EncodeBlock(lim - blockSize, blockSize);
632 return crcRes; 824 return crcRes;
633} 825}
634 826
827
635void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses) 828void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
636{ 829{
637 UInt32 numCrcs = m_NumCrcs; 830 const UInt32 numCrcs = m_NumCrcs;
638 bool needCompare = false; 831
639 832 const UInt32 startBytePos = m_OutStreamCurrent.GetBytePos();
640 UInt32 startBytePos = m_OutStreamCurrent->GetBytePos(); 833 const UInt32 startPos = m_OutStreamCurrent.GetPos();
641 UInt32 startPos = m_OutStreamCurrent->GetPos(); 834 const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
642 Byte startCurByte = m_OutStreamCurrent->GetCurByte(); 835 unsigned endCurByte = 0;
643 Byte endCurByte = 0; 836 UInt32 endPos = 0; // 0 means no no additional passes
644 UInt32 endPos = 0;
645 if (numPasses > 1 && blockSize >= (1 << 10)) 837 if (numPasses > 1 && blockSize >= (1 << 10))
646 { 838 {
647 UInt32 blockSize0 = blockSize / 2; // ???? 839 UInt32 bs0 = blockSize / 2;
648 840 for (; bs0 < blockSize &&
649 for (; (block[blockSize0] == block[(size_t)blockSize0 - 1] 841 (block[ bs0 ] ==
650 || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2]) 842 block[(size_t)bs0 - 1] ||
651 && blockSize0 < blockSize; 843 block[(size_t)bs0 - 1] ==
652 blockSize0++); 844 block[(size_t)bs0 - 2]);
845 bs0++)
846 {}
653 847
654 if (blockSize0 < blockSize) 848 if (bs0 < blockSize)
655 { 849 {
656 EncodeBlock2(block, blockSize0, numPasses - 1); 850 EncodeBlock2(block, bs0, numPasses - 1);
657 EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1); 851 EncodeBlock2(block + bs0, blockSize - bs0, numPasses - 1);
658 endPos = m_OutStreamCurrent->GetPos(); 852 endPos = m_OutStreamCurrent.GetPos();
659 endCurByte = m_OutStreamCurrent->GetCurByte(); 853 endCurByte = m_OutStreamCurrent.GetCurByte();
660 if ((endPos & 7) > 0) 854 // we prepare next byte as identical byte to starting byte for main encoding attempt:
855 if (endPos & 7)
661 WriteBits2(0, 8 - (endPos & 7)); 856 WriteBits2(0, 8 - (endPos & 7));
662 m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); 857 m_OutStreamCurrent.SetCurState((startPos & 7), startCurByte);
663 needCompare = true;
664 } 858 }
665 } 859 }
666 860
667 UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos(); 861 const UInt32 startBytePos2 = m_OutStreamCurrent.GetBytePos();
668 UInt32 startPos2 = m_OutStreamCurrent->GetPos(); 862 const UInt32 startPos2 = m_OutStreamCurrent.GetPos();
669 UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize); 863 const UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
670 UInt32 endPos2 = m_OutStreamCurrent->GetPos();
671 864
672 if (needCompare) 865 if (endPos)
673 { 866 {
674 UInt32 size2 = endPos2 - startPos2; 867 const UInt32 size2 = m_OutStreamCurrent.GetPos() - startPos2;
675 if (size2 < endPos - startPos) 868 if (size2 >= endPos - startPos)
676 {
677 UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
678 Byte *buffer = m_OutStreamCurrent->GetStream();
679 for (UInt32 i = 0; i < numBytes; i++)
680 buffer[startBytePos + i] = buffer[startBytePos2 + i];
681 m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
682 m_NumCrcs = numCrcs;
683 m_CRCs[m_NumCrcs++] = crcVal;
684 }
685 else
686 { 869 {
687 m_OutStreamCurrent->SetPos(endPos); 870 m_OutStreamCurrent.SetPos(endPos);
688 m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte); 871 m_OutStreamCurrent.SetCurState((endPos & 7), endCurByte);
872 return;
689 } 873 }
874 const UInt32 numBytes = m_OutStreamCurrent.GetBytePos() - startBytePos2;
875 Byte * const buffer = m_OutStreamCurrent.GetStream();
876 memmove(buffer + startBytePos, buffer + startBytePos2, numBytes);
877 m_OutStreamCurrent.SetPos(startPos + size2);
878 // we don't call m_OutStreamCurrent.SetCurState() here because
879 // m_OutStreamCurrent._curByte is correct already
690 } 880 }
691 else 881 m_CRCs[numCrcs] = crcVal;
692 { 882 m_NumCrcs = numCrcs + 1;
693 m_NumCrcs = numCrcs;
694 m_CRCs[m_NumCrcs++] = crcVal;
695 }
696} 883}
697 884
885
698HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize) 886HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
699{ 887{
700 CMsbfEncoderTemp outStreamTemp; 888 CMsbfEncoderTemp &outStreamTemp = m_OutStreamCurrent;
701 outStreamTemp.SetStream(m_TempArray); 889 outStreamTemp.SetStream(m_TempArray);
702 outStreamTemp.Init(); 890 outStreamTemp.Init();
703 m_OutStreamCurrent = &outStreamTemp;
704
705 m_NumCrcs = 0; 891 m_NumCrcs = 0;
706 892
707 EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses); 893 EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
708 894
709 #ifndef Z7_ST 895#ifndef Z7_ST
710 if (Encoder->MtMode) 896 if (Encoder->MtMode)
711 Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); 897 Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
712 #endif 898#endif
899
713 for (UInt32 i = 0; i < m_NumCrcs; i++) 900 for (UInt32 i = 0; i < m_NumCrcs; i++)
714 Encoder->CombinedCrc.Update(m_CRCs[i]); 901 Encoder->CombinedCrc.Update(m_CRCs[i]);
715 Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); 902 Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetNonFlushedByteBits());
716 HRESULT res = S_OK; 903 HRESULT res = S_OK;
717 #ifndef Z7_ST 904
905#ifndef Z7_ST
718 if (Encoder->MtMode) 906 if (Encoder->MtMode)
719 { 907 {
720 UInt32 blockIndex = m_BlockIndex + 1; 908 UInt32 blockIndex = m_BlockIndex + 1;
721 if (blockIndex == Encoder->NumThreads) 909 if (blockIndex == Encoder->NumThreads)
722 blockIndex = 0; 910 blockIndex = 0;
723
724 if (Encoder->Progress) 911 if (Encoder->Progress)
725 { 912 {
726 const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); 913 const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
727 res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); 914 res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
728 } 915 }
729
730 Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); 916 Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
731 } 917 }
732 #endif 918#endif
733 return res; 919 return res;
734} 920}
735 921
736void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) 922void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits)
737{ 923{
738 UInt32 bytesSize = (sizeInBits >> 3); 924 m_OutStream.WriteBytes(data, sizeInBits >> 3);
739 for (UInt32 i = 0; i < bytesSize; i++) 925 sizeInBits &= 7;
740 m_OutStream.WriteBits(data[i], 8); 926 if (sizeInBits)
741 WriteBits(lastByte, (sizeInBits & 7)); 927 m_OutStream.WriteBits(lastByteBits, sizeInBits);
742} 928}
743 929
744 930
@@ -746,11 +932,12 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
746 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 932 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
747{ 933{
748 NumBlocks = 0; 934 NumBlocks = 0;
749 #ifndef Z7_ST 935#ifndef Z7_ST
750 Progress = progress; 936 Progress = progress;
937 ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup
751 RINOK(Create()) 938 RINOK(Create())
752 for (UInt32 t = 0; t < NumThreads; t++) 939 for (UInt32 t = 0; t < NumThreads; t++)
753 #endif 940#endif
754 { 941 {
755 #ifndef Z7_ST 942 #ifndef Z7_ST
756 CThreadInfo &ti = ThreadsInfo[t]; 943 CThreadInfo &ti = ThreadsInfo[t];
@@ -823,11 +1010,11 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
823 { 1010 {
824 CThreadInfo &ti = 1011 CThreadInfo &ti =
825 #ifndef Z7_ST 1012 #ifndef Z7_ST
826 ThreadsInfo[0]; 1013 ThreadsInfo[0];
827 #else 1014 #else
828 ThreadsInfo; 1015 ThreadsInfo;
829 #endif 1016 #endif
830 UInt32 blockSize = ReadRleBlock(ti.m_Block); 1017 const UInt32 blockSize = ReadRleBlock(ti.m_Block);
831 if (blockSize == 0) 1018 if (blockSize == 0)
832 break; 1019 break;
833 RINOK(ti.EncodeBlock3(blockSize)) 1020 RINOK(ti.EncodeBlock3(blockSize))
@@ -845,8 +1032,11 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
845 WriteByte(kFinSig3); 1032 WriteByte(kFinSig3);
846 WriteByte(kFinSig4); 1033 WriteByte(kFinSig4);
847 WriteByte(kFinSig5); 1034 WriteByte(kFinSig5);
848 1035 {
849 WriteCrc(CombinedCrc.GetDigest()); 1036 const UInt32 v = CombinedCrc.GetDigest();
1037 for (int i = 24; i >= 0; i -= 8)
1038 WriteByte((Byte)(v >> i));
1039 }
850 RINOK(Flush()) 1040 RINOK(Flush())
851 if (!m_InStream.WasFinished()) 1041 if (!m_InStream.WasFinished())
852 return E_FAIL; 1042 return E_FAIL;
@@ -869,14 +1059,21 @@ Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA
869 for (UInt32 i = 0; i < numProps; i++) 1059 for (UInt32 i = 0; i < numProps; i++)
870 { 1060 {
871 const PROPVARIANT &prop = coderProps[i]; 1061 const PROPVARIANT &prop = coderProps[i];
872 PROPID propID = propIDs[i]; 1062 const PROPID propID = propIDs[i];
873 1063
874 if (propID == NCoderPropID::kAffinity) 1064 if (propID == NCoderPropID::kAffinity)
875 { 1065 {
876 if (prop.vt == VT_UI8) 1066 if (prop.vt != VT_UI8)
877 props.Affinity = prop.uhVal.QuadPart; 1067 return E_INVALIDARG;
878 else 1068 props.Affinity = prop.uhVal.QuadPart;
1069 continue;
1070 }
1071
1072 if (propID == NCoderPropID::kNumThreadGroups)
1073 {
1074 if (prop.vt != VT_UI4)
879 return E_INVALIDARG; 1075 return E_INVALIDARG;
1076 props.NumThreadGroups = (UInt32)prop.ulVal;
880 continue; 1077 continue;
881 } 1078 }
882 1079
@@ -884,7 +1081,7 @@ Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA
884 continue; 1081 continue;
885 if (prop.vt != VT_UI4) 1082 if (prop.vt != VT_UI4)
886 return E_INVALIDARG; 1083 return E_INVALIDARG;
887 UInt32 v = (UInt32)prop.ulVal; 1084 const UInt32 v = (UInt32)prop.ulVal;
888 switch (propID) 1085 switch (propID)
889 { 1086 {
890 case NCoderPropID::kNumPasses: props.NumPasses = v; break; 1087 case NCoderPropID::kNumPasses: props.NumPasses = v; break;
diff --git a/CPP/7zip/Compress/BZip2Encoder.h b/CPP/7zip/Compress/BZip2Encoder.h
index 4a04fbd..bcb4025 100644
--- a/CPP/7zip/Compress/BZip2Encoder.h
+++ b/CPP/7zip/Compress/BZip2Encoder.h
@@ -3,7 +3,6 @@
3#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H 3#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
4#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H 4#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
5 5
6#include "../../Common/Defs.h"
7#include "../../Common/MyCom.h" 6#include "../../Common/MyCom.h"
8 7
9#ifndef Z7_ST 8#ifndef Z7_ST
@@ -23,80 +22,114 @@
23namespace NCompress { 22namespace NCompress {
24namespace NBZip2 { 23namespace NBZip2 {
25 24
26class CMsbfEncoderTemp 25const unsigned kNumPassesMax = 10;
26
27struct CMsbfEncoderTemp
27{ 28{
28 UInt32 _pos; 29 unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
29 unsigned _bitPos; 30 unsigned _curByte; // low (_bitPos) bits are zeros
30 Byte _curByte; 31 // high (8 - _bitPos) bits are filled
31 Byte *_buf; 32 Byte *_buf;
32public: 33 Byte *_buf_base;
33 void SetStream(Byte *buf) { _buf = buf; } 34 void SetStream(Byte *buf) { _buf_base = _buf = buf; }
34 Byte *GetStream() const { return _buf; } 35 Byte *GetStream() const { return _buf_base; }
35 36
36 void Init() 37 void Init()
37 { 38 {
38 _pos = 0;
39 _bitPos = 8; 39 _bitPos = 8;
40 _curByte = 0; 40 _curByte = 0;
41 _buf = _buf_base;
41 } 42 }
42 43
43 void Flush() 44 // required condition: (value >> numBits) == 0
44 { 45 // numBits == 0 is allowed
45 if (_bitPos < 8)
46 WriteBits(0, _bitPos);
47 }
48
49 void WriteBits(UInt32 value, unsigned numBits) 46 void WriteBits(UInt32 value, unsigned numBits)
50 { 47 {
51 while (numBits > 0) 48 do
52 { 49 {
53 unsigned numNewBits = MyMin(numBits, _bitPos); 50 unsigned bp = _bitPos;
54 numBits -= numNewBits; 51 unsigned curByte = _curByte;
55 52 if (numBits < bp)
56 _curByte = (Byte)(_curByte << numNewBits);
57 UInt32 newBits = value >> numBits;
58 _curByte |= Byte(newBits);
59 value -= (newBits << numBits);
60
61 _bitPos -= numNewBits;
62
63 if (_bitPos == 0)
64 { 53 {
65 _buf[_pos++] = _curByte; 54 bp -= numBits;
66 _bitPos = 8; 55 _curByte = curByte | (value << bp);
56 _bitPos = bp;
57 return;
67 } 58 }
59 numBits -= bp;
60 const UInt32 hi = value >> numBits;
61 value -= (hi << numBits);
62 Byte *buf = _buf;
63 _bitPos = 8;
64 _curByte = 0;
65 *buf++ = (Byte)(curByte | hi);
66 _buf = buf;
68 } 67 }
68 while (numBits);
69 } 69 }
70 70
71 UInt32 GetBytePos() const { return _pos ; } 71 void WriteBit(unsigned value)
72 UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); } 72 {
73 Byte GetCurByte() const { return _curByte; } 73 const unsigned bp = _bitPos - 1;
74 const unsigned curByte = _curByte | (value << bp);
75 _curByte = curByte;
76 _bitPos = bp;
77 if (bp == 0)
78 {
79 *_buf++ = (Byte)curByte;
80 _curByte = 0;
81 _bitPos = 8;
82 }
83 }
84
85 void WriteByte(unsigned b)
86 {
87 const unsigned bp = _bitPos;
88 const unsigned a = _curByte | (b >> (8 - bp));
89 _curByte = b << bp;
90 Byte *buf = _buf;
91 *buf++ = (Byte)a;
92 _buf = buf;
93 }
94
95 UInt32 GetBytePos() const { return (UInt32)(size_t)(_buf - _buf_base); }
96 UInt32 GetPos() const { return GetBytePos() * 8 + 8 - _bitPos; }
97 unsigned GetCurByte() const { return _curByte; }
98 unsigned GetNonFlushedByteBits() const { return _curByte >> _bitPos; }
74 void SetPos(UInt32 bitPos) 99 void SetPos(UInt32 bitPos)
75 { 100 {
76 _pos = bitPos >> 3; 101 _buf = _buf_base + (bitPos >> 3);
77 _bitPos = 8 - ((unsigned)bitPos & 7); 102 _bitPos = 8 - ((unsigned)bitPos & 7);
78 } 103 }
79 void SetCurState(unsigned bitPos, Byte curByte) 104 void SetCurState(unsigned bitPos, unsigned curByte)
80 { 105 {
81 _bitPos = 8 - bitPos; 106 _bitPos = 8 - bitPos;
82 _curByte = curByte; 107 _curByte = curByte;
83 } 108 }
84}; 109};
85 110
86class CEncoder;
87 111
88const unsigned kNumPassesMax = 10; 112class CEncoder;
89 113
90class CThreadInfo 114class CThreadInfo
91{ 115{
116private:
117 CMsbfEncoderTemp m_OutStreamCurrent;
92public: 118public:
119 CEncoder *Encoder;
93 Byte *m_Block; 120 Byte *m_Block;
94private: 121private:
95 Byte *m_MtfArray; 122 Byte *m_MtfArray;
96 Byte *m_TempArray; 123 Byte *m_TempArray;
97 UInt32 *m_BlockSorterIndex; 124 UInt32 *m_BlockSorterIndex;
98 125
99 CMsbfEncoderTemp *m_OutStreamCurrent; 126public:
127 bool m_OptimizeNumTables;
128 UInt32 m_NumCrcs;
129 UInt32 m_BlockIndex;
130 UInt64 m_UnpackSize;
131
132 Byte *m_Block_Base;
100 133
101 Byte Lens[kNumTablesMax][kMaxAlphaSize]; 134 Byte Lens[kNumTablesMax][kMaxAlphaSize];
102 UInt32 Freqs[kNumTablesMax][kMaxAlphaSize]; 135 UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
@@ -105,20 +138,16 @@ private:
105 Byte m_Selectors[kNumSelectorsMax]; 138 Byte m_Selectors[kNumSelectorsMax];
106 139
107 UInt32 m_CRCs[1 << kNumPassesMax]; 140 UInt32 m_CRCs[1 << kNumPassesMax];
108 UInt32 m_NumCrcs;
109 141
110 void WriteBits2(UInt32 value, unsigned numBits); 142 void WriteBits2(UInt32 value, unsigned numBits);
111 void WriteByte2(Byte b); 143 void WriteByte2(unsigned b) { WriteBits2(b, 8); }
112 void WriteBit2(Byte v); 144 void WriteBit2(unsigned v) { m_OutStreamCurrent.WriteBit(v); }
113 void WriteCrc2(UInt32 v);
114 145
115 void EncodeBlock(const Byte *block, UInt32 blockSize); 146 void EncodeBlock(const Byte *block, UInt32 blockSize);
116 UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize); 147 UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
117 void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses); 148 void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
118public: 149public:
119 bool m_OptimizeNumTables; 150#ifndef Z7_ST
120 CEncoder *Encoder;
121 #ifndef Z7_ST
122 NWindows::CThread Thread; 151 NWindows::CThread Thread;
123 152
124 NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; 153 NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
@@ -127,17 +156,14 @@ public:
127 // it's not member of this thread. We just need one event per thread 156 // it's not member of this thread. We just need one event per thread
128 NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; 157 NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
129 158
130private:
131 UInt32 m_BlockIndex;
132 UInt64 m_UnpackSize;
133public: 159public:
134 Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. 160 Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
135 HRESULT Create(); 161 HRESULT Create();
136 void FinishStream(bool needLeave); 162 void FinishStream(bool needLeave);
137 THREAD_FUNC_RET_TYPE ThreadFunc(); 163 THREAD_FUNC_RET_TYPE ThreadFunc();
138 #endif 164#endif
139 165
140 CThreadInfo(): m_Block(NULL), m_BlockSorterIndex(NULL) {} 166 CThreadInfo(): m_BlockSorterIndex(NULL), m_Block_Base(NULL) {}
141 ~CThreadInfo() { Free(); } 167 ~CThreadInfo() { Free(); }
142 bool Alloc(); 168 bool Alloc();
143 void Free(); 169 void Free();
@@ -145,16 +171,19 @@ public:
145 HRESULT EncodeBlock3(UInt32 blockSize); 171 HRESULT EncodeBlock3(UInt32 blockSize);
146}; 172};
147 173
174
148struct CEncProps 175struct CEncProps
149{ 176{
150 UInt32 BlockSizeMult; 177 UInt32 BlockSizeMult;
151 UInt32 NumPasses; 178 UInt32 NumPasses;
179 UInt32 NumThreadGroups;
152 UInt64 Affinity; 180 UInt64 Affinity;
153 181
154 CEncProps() 182 CEncProps()
155 { 183 {
156 BlockSizeMult = (UInt32)(Int32)-1; 184 BlockSizeMult = (UInt32)(Int32)-1;
157 NumPasses = (UInt32)(Int32)-1; 185 NumPasses = (UInt32)(Int32)-1;
186 NumThreadGroups = 0;
158 Affinity = 0; 187 Affinity = 0;
159 } 188 }
160 void Normalize(int level); 189 void Normalize(int level);
@@ -206,6 +235,7 @@ public:
206 bool CloseThreads; 235 bool CloseThreads;
207 bool StreamWasFinished; 236 bool StreamWasFinished;
208 NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; 237 NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
238 CThreadNextGroup ThreadNextGroup;
209 239
210 HRESULT Result; 240 HRESULT Result;
211 ICompressProgressInfo *Progress; 241 ICompressProgressInfo *Progress;
@@ -218,12 +248,8 @@ public:
218 UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); } 248 UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); }
219 249
220 UInt32 ReadRleBlock(Byte *buf); 250 UInt32 ReadRleBlock(Byte *buf);
221 void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); 251 void WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits);
222
223 void WriteBits(UInt32 value, unsigned numBits);
224 void WriteByte(Byte b); 252 void WriteByte(Byte b);
225 // void WriteBit(Byte v);
226 void WriteCrc(UInt32 v);
227 253
228 #ifndef Z7_ST 254 #ifndef Z7_ST
229 HRESULT Create(); 255 HRESULT Create();
diff --git a/CPP/7zip/Compress/BitlEncoder.h b/CPP/7zip/Compress/BitlEncoder.h
index 67b1428..364f84d 100644
--- a/CPP/7zip/Compress/BitlEncoder.h
+++ b/CPP/7zip/Compress/BitlEncoder.h
@@ -33,6 +33,7 @@ public:
33 _bitPos = 8; 33 _bitPos = 8;
34 _curByte = 0; 34 _curByte = 0;
35 } 35 }
36 Z7_FORCE_INLINE
36 void WriteBits(UInt32 value, unsigned numBits) 37 void WriteBits(UInt32 value, unsigned numBits)
37 { 38 {
38 while (numBits > 0) 39 while (numBits > 0)
diff --git a/CPP/7zip/Compress/BitmEncoder.h b/CPP/7zip/Compress/BitmEncoder.h
index 978ee1c..f7448cd 100644
--- a/CPP/7zip/Compress/BitmEncoder.h
+++ b/CPP/7zip/Compress/BitmEncoder.h
@@ -8,8 +8,9 @@
8template<class TOutByte> 8template<class TOutByte>
9class CBitmEncoder 9class CBitmEncoder
10{ 10{
11 unsigned _bitPos; 11 unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
12 Byte _curByte; 12 unsigned _curByte; // low (_bitPos) bits are zeros
13 // high (8 - _bitPos) bits are filled
13 TOutByte _stream; 14 TOutByte _stream;
14public: 15public:
15 bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); } 16 bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); }
@@ -24,25 +25,65 @@ public:
24 HRESULT Flush() 25 HRESULT Flush()
25 { 26 {
26 if (_bitPos < 8) 27 if (_bitPos < 8)
27 WriteBits(0, _bitPos); 28 {
29 _stream.WriteByte((Byte)_curByte);
30 _bitPos = 8;
31 _curByte = 0;
32 }
28 return _stream.Flush(); 33 return _stream.Flush();
29 } 34 }
35
36 // required condition: (value >> numBits) == 0
37 // numBits == 0 is allowed
30 void WriteBits(UInt32 value, unsigned numBits) 38 void WriteBits(UInt32 value, unsigned numBits)
31 { 39 {
32 while (numBits > 0) 40 do
33 { 41 {
34 if (numBits < _bitPos) 42 unsigned bp = _bitPos;
43 unsigned curByte = _curByte;
44 if (numBits < bp)
35 { 45 {
36 _curByte = (Byte)(_curByte | (value << (_bitPos -= numBits))); 46 bp -= numBits;
47 _curByte = curByte | (value << bp);
48 _bitPos = bp;
37 return; 49 return;
38 } 50 }
39 numBits -= _bitPos; 51 numBits -= bp;
40 UInt32 newBits = (value >> numBits); 52 const UInt32 hi = (value >> numBits);
41 value -= (newBits << numBits); 53 value -= (hi << numBits);
42 _stream.WriteByte((Byte)(_curByte | newBits)); 54 _stream.WriteByte((Byte)(curByte | hi));
43 _bitPos = 8; 55 _bitPos = 8;
44 _curByte = 0; 56 _curByte = 0;
45 } 57 }
58 while (numBits);
59 }
60 void WriteByte(unsigned b)
61 {
62 const unsigned bp = _bitPos;
63 const unsigned a = _curByte | (b >> (8 - bp));
64 _curByte = b << bp;
65 _stream.WriteByte((Byte)a);
66 }
67
68 void WriteBytes(const Byte *data, size_t num)
69 {
70 const unsigned bp = _bitPos;
71#if 1 // 1 for optional speed-optimized code branch
72 if (bp == 8)
73 {
74 _stream.WriteBytes(data, num);
75 return;
76 }
77#endif
78 unsigned c = _curByte;
79 const unsigned bp_rev = 8 - bp;
80 for (size_t i = 0; i < num; i++)
81 {
82 const unsigned b = data[i];
83 _stream.WriteByte((Byte)(c | (b >> bp_rev)));
84 c = b << bp;
85 }
86 _curByte = c;
46 } 87 }
47}; 88};
48 89
diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp
index 73895fe..7993176 100644
--- a/CPP/7zip/Compress/DeflateDecoder.cpp
+++ b/CPP/7zip/Compress/DeflateDecoder.cpp
@@ -117,15 +117,13 @@ bool CCoder::ReadTables(void)
117 if (_numDistLevels > kDistTableSize32) 117 if (_numDistLevels > kDistTableSize32)
118 return false; 118 return false;
119 119
120 Byte levelLevels[kLevelTableSize]; 120 const unsigned kLevelTableSize_aligned4 = kLevelTableSize + 1;
121 for (unsigned i = 0; i < kLevelTableSize; i++) 121 Byte levelLevels[kLevelTableSize_aligned4];
122 { 122 memset (levelLevels, 0, sizeof(levelLevels));
123 const unsigned position = kCodeLengthAlphabetOrder[i]; 123 unsigned i = 0;
124 if (i < numLevelCodes) 124 do
125 levelLevels[position] = (Byte)ReadBits(kLevelFieldSize); 125 levelLevels[kCodeLengthAlphabetOrder[i++]] = (Byte)ReadBits(kLevelFieldSize);
126 else 126 while (i != numLevelCodes);
127 levelLevels[position] = 0;
128 }
129 127
130 if (m_InBitStream.ExtraBitsWereRead()) 128 if (m_InBitStream.ExtraBitsWereRead())
131 return false; 129 return false;
diff --git a/CPP/7zip/Compress/DeflateEncoder.cpp b/CPP/7zip/Compress/DeflateEncoder.cpp
index 87b4f83..afc5f12 100644
--- a/CPP/7zip/Compress/DeflateEncoder.cpp
+++ b/CPP/7zip/Compress/DeflateEncoder.cpp
@@ -19,12 +19,16 @@
19#define NO_INLINE 19#define NO_INLINE
20#endif 20#endif
21 21
22#define MAX_HUF_LEN_12 12
23
22namespace NCompress { 24namespace NCompress {
23namespace NDeflate { 25namespace NDeflate {
24namespace NEncoder { 26namespace NEncoder {
25 27
28static const unsigned k_CodeValue_Len_Is_Literal_Flag = 1u << 15;
29
26static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio. 30static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio.
27static const UInt32 kNumTables = (1 << kNumDivPassesMax); 31static const unsigned kNumTables = 1u << kNumDivPassesMax;
28 32
29static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio. 33static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio.
30static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. 34static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
@@ -77,7 +81,7 @@ public:
77 81
78static CFastPosInit g_FastPosInit; 82static CFastPosInit g_FastPosInit;
79 83
80inline UInt32 GetPosSlot(UInt32 pos) 84inline unsigned GetPosSlot(UInt32 pos)
81{ 85{
82 /* 86 /*
83 if (pos < 0x200) 87 if (pos < 0x200)
@@ -162,13 +166,13 @@ HRESULT CCoder::Create()
162 // COM_TRY_BEGIN 166 // COM_TRY_BEGIN
163 if (!m_Values) 167 if (!m_Values)
164 { 168 {
165 m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue)); 169 m_Values = (CCodeValue *)MyAlloc(kMaxUncompressedBlockSize * sizeof(CCodeValue));
166 if (!m_Values) 170 if (!m_Values)
167 return E_OUTOFMEMORY; 171 return E_OUTOFMEMORY;
168 } 172 }
169 if (!m_Tables) 173 if (!m_Tables)
170 { 174 {
171 m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables)); 175 m_Tables = (CTables *)MyAlloc(kNumTables * sizeof(CTables));
172 if (!m_Tables) 176 if (!m_Tables)
173 return E_OUTOFMEMORY; 177 return E_OUTOFMEMORY;
174 } 178 }
@@ -268,19 +272,21 @@ NO_INLINE void CCoder::GetMatches()
268 272
269 UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; 273 UInt32 distanceTmp[kMatchMaxLen * 2 + 3];
270 274
271 const UInt32 numPairs = (UInt32)((_btMode ? 275 const size_t numPairs = (size_t)((_btMode ?
272 Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): 276 Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp):
273 Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp); 277 Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp);
274 278
275 *m_MatchDistances = (UInt16)numPairs; 279 UInt16 *matchDistances = m_MatchDistances;
280 *matchDistances++ = (UInt16)numPairs;
276 281
277 if (numPairs != 0) 282 if (numPairs != 0)
278 { 283 {
279 UInt32 i; 284 size_t i;
280 for (i = 0; i < numPairs; i += 2) 285 for (i = 0; i < numPairs; i += 2)
281 { 286 {
282 m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i]; 287 matchDistances[0] = (UInt16)distanceTmp[i];
283 m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1]; 288 matchDistances[1] = (UInt16)distanceTmp[(size_t)i + 1];
289 matchDistances += 2;
284 } 290 }
285 UInt32 len = distanceTmp[(size_t)numPairs - 2]; 291 UInt32 len = distanceTmp[(size_t)numPairs - 2];
286 if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen) 292 if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
@@ -291,11 +297,11 @@ NO_INLINE void CCoder::GetMatches()
291 if (numAvail > m_MatchMaxLen) 297 if (numAvail > m_MatchMaxLen)
292 numAvail = m_MatchMaxLen; 298 numAvail = m_MatchMaxLen;
293 for (; len < numAvail && pby[len] == pby2[len]; len++); 299 for (; len < numAvail && pby[len] == pby2[len]; len++);
294 m_MatchDistances[(size_t)i - 1] = (UInt16)len; 300 matchDistances[-2] = (UInt16)len;
295 } 301 }
296 } 302 }
297 if (m_IsMultiPass) 303 if (m_IsMultiPass)
298 m_Pos += numPairs + 1; 304 m_Pos += (UInt32)numPairs + 1;
299 if (!m_SecondPass) 305 if (!m_SecondPass)
300 m_AdditionalOffset++; 306 m_AdditionalOffset++;
301} 307}
@@ -535,6 +541,7 @@ NO_INLINE void CCoder::WriteBits(UInt32 value, unsigned numBits)
535} 541}
536 542
537#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i]) 543#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i])
544#define WRITE_HF2_NO_INLINE(codes, lens, i) WriteBits(codes[i], lens[i])
538#define WRITE_HF(i) WriteBits(codes[i], lens[i]) 545#define WRITE_HF(i) WriteBits(codes[i], lens[i])
539 546
540NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes) 547NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes)
@@ -619,17 +626,22 @@ static NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens,
619 return price; 626 return price;
620} 627}
621 628
622static NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase) 629static NO_INLINE UInt32 Huffman_GetPrice_Spec(
630 const UInt32 *freqs, const Byte *lens, UInt32 num,
631 const Byte *extraBits, UInt32 extraBase)
623{ 632{
624 return Huffman_GetPrice(freqs, lens, num) + 633 return
634 Huffman_GetPrice(freqs, lens, num) +
625 Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); 635 Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase);
626} 636}
627 637
628NO_INLINE UInt32 CCoder::GetLzBlockPrice() const 638NO_INLINE UInt32 CCoder::GetLzBlockPrice() const
629{ 639{
630 return 640 return
631 Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + 641 Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels,
632 Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0); 642 kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) +
643 Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels,
644 kDistTableSize64, kDistDirectBits, 0);
633} 645}
634 646
635NO_INLINE void CCoder::TryBlock() 647NO_INLINE void CCoder::TryBlock()
@@ -658,7 +670,7 @@ NO_INLINE void CCoder::TryBlock()
658 CCodeValue &codeValue = m_Values[m_ValueIndex++]; 670 CCodeValue &codeValue = m_Values[m_ValueIndex++];
659 if (len >= kMatchMinLen) 671 if (len >= kMatchMinLen)
660 { 672 {
661 UInt32 newLen = len - kMatchMinLen; 673 const UInt32 newLen = len - kMatchMinLen;
662 codeValue.Len = (UInt16)newLen; 674 codeValue.Len = (UInt16)newLen;
663 mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++; 675 mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++;
664 codeValue.Pos = (UInt16)pos; 676 codeValue.Pos = (UInt16)pos;
@@ -666,10 +678,10 @@ NO_INLINE void CCoder::TryBlock()
666 } 678 }
667 else 679 else
668 { 680 {
669 Byte b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset); 681 const unsigned b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset);
670 mainFreqs[b]++; 682 mainFreqs[b]++;
671 codeValue.SetAsLiteral(); 683 codeValue.Len = k_CodeValue_Len_Is_Literal_Flag;
672 codeValue.Pos = b; 684 codeValue.Pos = (UInt16)b;
673 } 685 }
674 m_AdditionalOffset -= len; 686 m_AdditionalOffset -= len;
675 BlockSizeRes += len; 687 BlockSizeRes += len;
@@ -704,16 +716,24 @@ NO_INLINE void CCoder::SetPrices(const CLevels &levels)
704 } 716 }
705} 717}
706 718
719#if MAX_HUF_LEN_12 > 12
720// Huffman_ReverseBits() now supports 12-bits values only.
721#error Stop_Compiling_Bad_MAX_HUF_LEN_12
722#endif
707static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num) 723static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num)
708{ 724{
709 for (UInt32 i = 0; i < num; i++) 725 const Byte * const lens_lim = lens + num;
726 do
710 { 727 {
711 UInt32 x = codes[i]; 728 // we should change constants, if lens[*] can be larger than 12.
712 x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1); 729 UInt32 x = *codes;
713 x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2); 730 x = ((x & (0x555 )) << 2) + (x & (0xAAA ));
714 x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4); 731 x = ((x & (0x333 << 1)) << 4) | (x & (0xCCC << 1));
715 codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]); 732 x = ((x & (0xF0F << 3)) << 8) | (x & (0x0F0 << 3));
733 // we can use (x) instead of (x & (0xFF << 7)), if we support garabage data after (*lens) bits.
734 *codes++ = (((x & (0xFF << 7)) << 16) | x) >> (*lens ^ 31);
716 } 735 }
736 while (++lens != lens_lim);
717} 737}
718 738
719NO_INLINE void CCoder::WriteBlock() 739NO_INLINE void CCoder::WriteBlock()
@@ -721,24 +741,28 @@ NO_INLINE void CCoder::WriteBlock()
721 Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize); 741 Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize);
722 Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64); 742 Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64);
723 743
724 for (UInt32 i = 0; i < m_ValueIndex; i++) 744 CCodeValue *values = m_Values;
745 const CCodeValue * const values_lim = values + m_ValueIndex;
746
747 if (values != values_lim)
748 do
725 { 749 {
726 const CCodeValue &codeValue = m_Values[i]; 750 const UInt32 len = values->Len;
727 if (codeValue.IsLiteral()) 751 const UInt32 dist = values->Pos;
728 WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos); 752 if (len == k_CodeValue_Len_Is_Literal_Flag)
753 WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, dist);
729 else 754 else
730 { 755 {
731 UInt32 len = codeValue.Len; 756 const unsigned lenSlot = g_LenSlots[len];
732 UInt32 lenSlot = g_LenSlots[len];
733 WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot); 757 WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot);
734 m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]); 758 m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]);
735 UInt32 dist = codeValue.Pos; 759 const unsigned posSlot = GetPosSlot(dist);
736 UInt32 posSlot = GetPosSlot(dist);
737 WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot); 760 WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot);
738 m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]); 761 m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]);
739 } 762 }
740 } 763 }
741 WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock); 764 while (++values != values_lim);
765 WRITE_HF2_NO_INLINE(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock);
742} 766}
743 767
744static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition) 768static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition)
@@ -787,10 +811,10 @@ NO_INLINE UInt32 CCoder::TryDynBlock(unsigned tableIndex, UInt32 numPasses)
787 { 811 {
788 m_Pos = posTemp; 812 m_Pos = posTemp;
789 TryBlock(); 813 TryBlock();
790 unsigned numHuffBits = 814 const unsigned numHuffBits =
791 (m_ValueIndex > 18000 ? 12 : 815 m_ValueIndex > 18000 ? MAX_HUF_LEN_12 :
792 (m_ValueIndex > 7000 ? 11 : 816 m_ValueIndex > 7000 ? 11 :
793 (m_ValueIndex > 2000 ? 10 : 9))); 817 m_ValueIndex > 2000 ? 10 : 9;
794 MakeTables(numHuffBits); 818 MakeTables(numHuffBits);
795 SetPrices(m_NewLevels); 819 SetPrices(m_NewLevels);
796 } 820 }
diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp
index 0dc7e23..ffe1152 100644
--- a/CPP/7zip/Compress/Lzma2Encoder.cpp
+++ b/CPP/7zip/Compress/Lzma2Encoder.cpp
@@ -52,7 +52,15 @@ HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzm
52 case NCoderPropID::kNumThreads: 52 case NCoderPropID::kNumThreads:
53 if (prop.vt != VT_UI4) 53 if (prop.vt != VT_UI4)
54 return E_INVALIDARG; 54 return E_INVALIDARG;
55 lzma2Props.numTotalThreads = (int)(prop.ulVal); 55 lzma2Props.numTotalThreads = (int)prop.ulVal;
56 break;
57 case NCoderPropID::kNumThreadGroups:
58 if (prop.vt != VT_UI4)
59 return E_INVALIDARG;
60 // 16-bit value supported by Windows
61 if (prop.ulVal >= (1u << 16))
62 return E_INVALIDARG;
63 lzma2Props.numThreadGroups = (unsigned)prop.ulVal;
56 break; 64 break;
57 default: 65 default:
58 RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)) 66 RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps))
diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp
index 08e3ba5..bca2eee 100644
--- a/CPP/7zip/Compress/LzmaEncoder.cpp
+++ b/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -101,6 +101,24 @@ HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
101 return S_OK; 101 return S_OK;
102 } 102 }
103 103
104 if (propID == NCoderPropID::kAffinityInGroup)
105 {
106 if (prop.vt == VT_UI8)
107 ep.affinityInGroup = prop.uhVal.QuadPart;
108 else
109 return E_INVALIDARG;
110 return S_OK;
111 }
112
113 if (propID == NCoderPropID::kThreadGroup)
114 {
115 if (prop.vt == VT_UI4)
116 ep.affinityGroup = (Int32)(UInt32)prop.ulVal;
117 else
118 return E_INVALIDARG;
119 return S_OK;
120 }
121
104 if (propID == NCoderPropID::kHashBits) 122 if (propID == NCoderPropID::kHashBits)
105 { 123 {
106 if (prop.vt == VT_UI4) 124 if (prop.vt == VT_UI4)
diff --git a/CPP/7zip/Compress/Mtf8.h b/CPP/7zip/Compress/Mtf8.h
index 1b44d00..5fce30e 100644
--- a/CPP/7zip/Compress/Mtf8.h
+++ b/CPP/7zip/Compress/Mtf8.h
@@ -13,6 +13,18 @@ struct CMtf8Encoder
13 13
14 unsigned FindAndMove(Byte v) throw() 14 unsigned FindAndMove(Byte v) throw()
15 { 15 {
16#if 1
17 Byte b = Buf[0];
18 if (v == b)
19 return 0;
20 Buf[0] = v;
21 for (unsigned pos = 0;;)
22 {
23 Byte a;
24 a = Buf[++pos]; Buf[pos] = b; if (v == a) return pos;
25 b = Buf[++pos]; Buf[pos] = a; if (v == b) return pos;
26 }
27#else
16 size_t pos; 28 size_t pos;
17 for (pos = 0; Buf[pos] != v; pos++); 29 for (pos = 0; Buf[pos] != v; pos++);
18 const unsigned resPos = (unsigned)pos; 30 const unsigned resPos = (unsigned)pos;
@@ -31,6 +43,7 @@ struct CMtf8Encoder
31 Buf[pos] = Buf[pos - 1]; 43 Buf[pos] = Buf[pos - 1];
32 Buf[0] = v; 44 Buf[0] = v;
33 return resPos; 45 return resPos;
46#endif
34 } 47 }
35}; 48};
36 49
diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp
index 8be24e2..7279b5a 100644
--- a/CPP/7zip/Compress/Rar5Decoder.cpp
+++ b/CPP/7zip/Compress/Rar5Decoder.cpp
@@ -936,31 +936,30 @@ HRESULT CDecoder::ExecuteFilter(const CFilter &f)
936HRESULT CDecoder::WriteBuf() 936HRESULT CDecoder::WriteBuf()
937{ 937{
938 DeleteUnusedFilters(); 938 DeleteUnusedFilters();
939
940 const UInt64 lzSize = _lzSize + _winPos; 939 const UInt64 lzSize = _lzSize + _winPos;
941 940
942 for (unsigned i = 0; i < _numFilters;) 941 for (unsigned i = 0; i < _numFilters;)
943 { 942 {
944 const CFilter &f = _filters[i];
945 const UInt64 blockStart = f.Start;
946 const size_t lzAvail = (size_t)(lzSize - _lzWritten); 943 const size_t lzAvail = (size_t)(lzSize - _lzWritten);
947 if (lzAvail == 0) 944 if (lzAvail == 0)
948 break; 945 break;
949 946 // (lzAvail != 0)
947 const CFilter &f = _filters[i];
948 const UInt64 blockStart = f.Start;
950 if (blockStart > _lzWritten) 949 if (blockStart > _lzWritten)
951 { 950 {
952 const UInt64 rem = blockStart - _lzWritten; 951 const UInt64 rem = blockStart - _lzWritten;
952 // (rem != 0)
953 size_t size = lzAvail; 953 size_t size = lzAvail;
954 if (size > rem) 954 if (size > rem)
955 size = (size_t)rem; 955 size = (size_t)rem;
956 if (size != 0) // is it true always ? 956 // (size != 0)
957 { 957 RINOK(WriteData(_window + _winPos - lzAvail, size))
958 RINOK(WriteData(_window + _winPos - lzAvail, size)) 958 _lzWritten += size;
959 _lzWritten += size;
960 }
961 continue; 959 continue;
962 } 960 }
963 961
962 // (blockStart <= _lzWritten)
964 const UInt32 blockSize = f.Size; 963 const UInt32 blockSize = f.Size;
965 size_t offset = (size_t)(_lzWritten - blockStart); 964 size_t offset = (size_t)(_lzWritten - blockStart);
966 if (offset == 0) 965 if (offset == 0)
@@ -987,10 +986,8 @@ HRESULT CDecoder::WriteBuf()
987 } 986 }
988 987
989 DeleteUnusedFilters(); 988 DeleteUnusedFilters();
990
991 if (_numFilters) 989 if (_numFilters)
992 return S_OK; 990 return S_OK;
993
994 const size_t lzAvail = (size_t)(lzSize - _lzWritten); 991 const size_t lzAvail = (size_t)(lzSize - _lzWritten);
995 RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)) 992 RINOK(WriteData(_window + _winPos - lzAvail, lzAvail))
996 _lzWritten += lzAvail; 993 _lzWritten += lzAvail;
@@ -1367,6 +1364,12 @@ enum enum_exit_type
1367 Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR }) 1364 Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR })
1368 1365
1369 1366
1367/*
1368 DecodeLZ2() will stop decoding if it reaches limit when (_winPos >= _limit)
1369 at return:
1370 (_winPos < _limit + kMaxMatchLen)
1371 also it can write up to (COPY_CHUNK_SIZE - 1) additional junk bytes after (_winPos).
1372*/
1370HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw() 1373HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw()
1371{ 1374{
1372#if 0 1375#if 0
@@ -1656,6 +1659,13 @@ decode_error:
1656 1659
1657 1660
1658 1661
1662/*
1663input conditions:
1664 _winPos < _winSize
1665return:
1666 _winPos < _winSize is expected, if (return_res == S_OK)
1667 _winPos >= _winSize is possible in (return_res != S_OK)
1668*/
1659HRESULT CDecoder::DecodeLZ() 1669HRESULT CDecoder::DecodeLZ()
1660{ 1670{
1661 CBitDecoder _bitStream; 1671 CBitDecoder _bitStream;
@@ -1679,6 +1689,8 @@ HRESULT CDecoder::DecodeLZ()
1679 if (winPos >= limit) 1689 if (winPos >= limit)
1680 { 1690 {
1681 _winPos = winPos < _winSize ? winPos : _winSize; 1691 _winPos = winPos < _winSize ? winPos : _winSize;
1692 // _winPos == min(winPos, _winSize)
1693 // we will not write data after _winSize
1682 RINOK(WriteBuf()) 1694 RINOK(WriteBuf())
1683 if (_unpackSize_Defined && _writtenFileSize > _unpackSize) 1695 if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
1684 break; // return S_FALSE; 1696 break; // return S_FALSE;
@@ -1854,7 +1866,15 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
1854 { 1866 {
1855 // if (_winPos > 100) _winPos -= 100; // for debug: corruption 1867 // if (_winPos > 100) _winPos -= 100; // for debug: corruption
1856 const UInt64 lzSize = _lzSize + _winPos; 1868 const UInt64 lzSize = _lzSize + _winPos;
1857 if (!_isSolid || !_wasInit 1869/*
1870 if previous file was decoded with error or for some another cases, then
1871 (lzSize > _lzEnd) is possible
1872 (_winPos > _winSize) is possible
1873 (_winPos < _winSize + kMaxMatchLen)
1874*/
1875 if (!_window
1876 || !_isSolid
1877 || !_wasInit
1858 || (lzSize < _lzEnd 1878 || (lzSize < _lzEnd
1859#if Z7_RAR_RECOVER_SOLID_LIMIT != 0 1879#if Z7_RAR_RECOVER_SOLID_LIMIT != 0
1860 && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd 1880 && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd
@@ -1863,9 +1883,9 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
1863 { 1883 {
1864 if (_isSolid) 1884 if (_isSolid)
1865 _lzError = LZ_ERROR_TYPE_HEADER; 1885 _lzError = LZ_ERROR_TYPE_HEADER;
1866 _lzEnd = 0;
1867 _lzSize = 0; 1886 _lzSize = 0;
1868 _lzWritten = 0; 1887 // _lzEnd = 0; // it will be set later
1888 // _lzWritten = 0; // it will be set later
1869 _winPos = 0; 1889 _winPos = 0;
1870 for (unsigned i = 0; i < kNumReps; i++) 1890 for (unsigned i = 0; i < kNumReps; i++)
1871 _reps[i] = (size_t)0 - 1; 1891 _reps[i] = (size_t)0 - 1;
@@ -1873,51 +1893,67 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
1873 _tableWasFilled = false; 1893 _tableWasFilled = false;
1874 _wasInit = true; 1894 _wasInit = true;
1875 } 1895 }
1876#if Z7_RAR_RECOVER_SOLID_LIMIT != 0 1896 else
1877 else if (lzSize < _lzEnd)
1878 { 1897 {
1898 const size_t ws = _winSize;
1899 if (_winPos >= ws)
1900 {
1901 // we must normalize (_winPos) and data in _window,
1902 _winPos -= ws;
1903 _lzSize += ws;
1904 // (_winPos < kMaxMatchLen < _winSize)
1905 // if (_window)
1906 memcpy(_window, _window + ws, _winPos); // memmove is not required here
1907 }
1908
1909#if Z7_RAR_RECOVER_SOLID_LIMIT != 0
1910 if (lzSize < _lzEnd)
1911 {
1879#if 0 1912#if 0
1880 return S_FALSE; 1913 return S_FALSE;
1881#else 1914#else
1882 // we can report that recovering was made: 1915 // we can report that recovering was made:
1883 // _lzError = LZ_ERROR_TYPE_HEADER; 1916 // _lzError = LZ_ERROR_TYPE_HEADER;
1884 // We write zeros to area after corruption: 1917 // We write zeros to area after corruption:
1885 if (_window) 1918 // if (_window)
1886 {
1887 UInt64 rem = _lzEnd - lzSize;
1888 const size_t ws = _winSize;
1889 if (rem >= ws)
1890 { 1919 {
1891 My_ZeroMemory(_window, ws); 1920 UInt64 rem = _lzEnd - lzSize;
1892 _lzSize = ws; 1921 if (rem >= ws)
1893 _winPos = 0;
1894 }
1895 else
1896 {
1897 const size_t cur = ws - _winPos;
1898 if (cur <= rem)
1899 { 1922 {
1900 rem -= cur; 1923 My_ZeroMemory(_window, ws);
1901 My_ZeroMemory(_window + _winPos, cur); 1924 _lzSize = ws;
1902 _lzSize += _winPos;
1903 _winPos = 0; 1925 _winPos = 0;
1904 } 1926 }
1905 My_ZeroMemory(_window + _winPos, (size_t)rem); 1927 else
1906 _winPos += (size_t)rem; 1928 {
1929 // rem < _winSize
1930 // _winPos <= ws
1931 const size_t cur = ws - _winPos;
1932 if (cur <= rem)
1933 {
1934 rem -= cur;
1935 My_ZeroMemory(_window + _winPos, cur);
1936 _lzSize = ws;
1937 _winPos = 0;
1938 }
1939 My_ZeroMemory(_window + _winPos, (size_t)rem);
1940 _winPos += (size_t)rem;
1941 }
1907 } 1942 }
1908 } 1943 // else return S_FALSE;
1909 // else return S_FALSE;
1910#endif 1944#endif
1945 }
1911 } 1946 }
1912#endif 1947#endif
1913 } 1948 }
1914 1949
1950 // _winPos < _winSize
1915 // we don't want _lzSize overflow 1951 // we don't want _lzSize overflow
1916 if (_lzSize >= DICT_SIZE_MAX) 1952 if (_lzSize >= DICT_SIZE_MAX)
1917 _lzSize = DICT_SIZE_MAX; 1953 _lzSize = DICT_SIZE_MAX;
1918 _lzEnd = _lzSize + _winPos; 1954 _lzEnd = _lzSize + _winPos;
1919 // _lzSize <= DICT_SIZE_MAX 1955 // _lzSize <= DICT_SIZE_MAX
1920 // _lzEnd <= DICT_SIZE_MAX * 2 1956 // _lzEnd < DICT_SIZE_MAX + _winSize
1921 1957
1922 size_t newSize = _dictSize; 1958 size_t newSize = _dictSize;
1923 if (newSize < kWinSize_Min) 1959 if (newSize < kWinSize_Min)
@@ -1941,10 +1977,11 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
1941 // If dictionary was increased in solid, we don't want grow. 1977 // If dictionary was increased in solid, we don't want grow.
1942 return S_FALSE; // E_OUTOFMEMORY 1978 return S_FALSE; // E_OUTOFMEMORY
1943 } 1979 }
1944 // (newSize <= _winSize) 1980 // (newSize <= _dictSize_forCheck)
1945 } 1981 }
1946 else 1982 else
1947 { 1983 {
1984 // !_isSolid || !_window
1948 _dictSize_forCheck = newSize; 1985 _dictSize_forCheck = newSize;
1949 { 1986 {
1950 size_t newSize_small = newSize; 1987 size_t newSize_small = newSize;
@@ -1964,7 +2001,7 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
1964 if (!_window || allocSize > _winSize_Allocated) 2001 if (!_window || allocSize > _winSize_Allocated)
1965 { 2002 {
1966 Z7_RAR_FREE_WINDOW 2003 Z7_RAR_FREE_WINDOW
1967 _window = NULL; 2004 _window = NULL;
1968 _winSize_Allocated = 0; 2005 _winSize_Allocated = 0;
1969 Byte *win = (Byte *)::BigAlloc(allocSize); 2006 Byte *win = (Byte *)::BigAlloc(allocSize);
1970 if (!win) 2007 if (!win)
diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp
index f84bca8..0ae0e16 100644
--- a/CPP/7zip/Crypto/MyAes.cpp
+++ b/CPP/7zip/Crypto/MyAes.cpp
@@ -153,7 +153,26 @@ Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size))
153#ifndef Z7_EXTRACT_ONLY 153#ifndef Z7_EXTRACT_ONLY
154 154
155#ifdef MY_CPU_X86_OR_AMD64 155#ifdef MY_CPU_X86_OR_AMD64
156 #define USE_HW_AES 156
157 #if defined(__INTEL_COMPILER)
158 #if (__INTEL_COMPILER >= 1110)
159 #define USE_HW_AES
160 #if (__INTEL_COMPILER >= 1900)
161 #define USE_HW_VAES
162 #endif
163 #endif
164 #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
165 || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400)
166 #define USE_HW_AES
167 #if defined(__clang__) && (__clang_major__ >= 8) \
168 || defined(__GNUC__) && (__GNUC__ >= 8)
169 #define USE_HW_VAES
170 #endif
171 #elif defined(_MSC_VER)
172 #define USE_HW_AES
173 #define USE_HW_VAES
174 #endif
175
157#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) 176#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
158 177
159 #if defined(__ARM_FEATURE_AES) \ 178 #if defined(__ARM_FEATURE_AES) \
@@ -186,15 +205,15 @@ Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size))
186 #define SET_AES_FUNC_2(f2) \ 205 #define SET_AES_FUNC_2(f2) \
187 if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \ 206 if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \
188 { f = f2; } 207 { f = f2; }
189 #ifdef MY_CPU_X86_OR_AMD64 208 #ifdef USE_HW_VAES
190 #define SET_AES_FUNC_23(f2, f3) \ 209 #define SET_AES_FUNC_23(f2, f3) \
191 SET_AES_FUNC_2(f2) \ 210 SET_AES_FUNC_2(f2) \
192 if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \ 211 if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \
193 { f = f3; } 212 { f = f3; }
194 #else // MY_CPU_X86_OR_AMD64 213 #else // USE_HW_VAES
195 #define SET_AES_FUNC_23(f2, f3) \ 214 #define SET_AES_FUNC_23(f2, f3) \
196 SET_AES_FUNC_2(f2) 215 SET_AES_FUNC_2(f2)
197 #endif // MY_CPU_X86_OR_AMD64 216 #endif // USE_HW_VAES
198#else // USE_HW_AES 217#else // USE_HW_AES
199 #define SET_AES_FUNC_23(f2, f3) 218 #define SET_AES_FUNC_23(f2, f3)
200#endif // USE_HW_AES 219#endif // USE_HW_AES
diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp
index 26c6100..34ea4ff 100644
--- a/CPP/7zip/Crypto/Rar5Aes.cpp
+++ b/CPP/7zip/Crypto/Rar5Aes.cpp
@@ -8,16 +8,17 @@
8#include "../../Windows/Synchronization.h" 8#include "../../Windows/Synchronization.h"
9#endif 9#endif
10 10
11#include "Rar5Aes.h"
12#include "HmacSha256.h" 11#include "HmacSha256.h"
12#include "Rar5Aes.h"
13
14#define MY_ALIGN_FOR_SHA256 MY_ALIGN(16)
13 15
14namespace NCrypto { 16namespace NCrypto {
15namespace NRar5 { 17namespace NRar5 {
16 18
17static const unsigned kNumIterationsLog_Max = 24; 19static const unsigned kNumIterationsLog_Max = 24;
18 20static const unsigned kPswCheckCsumSize32 = 1;
19static const unsigned kPswCheckCsumSize = 4; 21static const unsigned kCheckSize32 = kPswCheckSize32 + kPswCheckCsumSize32;
20static const unsigned kCheckSize = kPswCheckSize + kPswCheckCsumSize;
21 22
22CKey::CKey(): 23CKey::CKey():
23 _needCalc(true), 24 _needCalc(true),
@@ -27,15 +28,29 @@ CKey::CKey():
27 _salt[i] = 0; 28 _salt[i] = 0;
28} 29}
29 30
31CKey::~CKey()
32{
33 Wipe();
34}
35
36void CKey::Wipe()
37{
38 _password.Wipe();
39 Z7_memset_0_ARRAY(_salt);
40 // Z7_memset_0_ARRAY(_key32);
41 // Z7_memset_0_ARRAY(_check_Calced32);
42 // Z7_memset_0_ARRAY(_hashKey32);
43 CKeyBase::Wipe();
44}
45
30CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {} 46CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {}
31 47
32static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val) 48static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val)
33{ 49{
34 *val = 0; 50 *val = 0;
35
36 for (unsigned i = 0; i < maxSize && i < 10;) 51 for (unsigned i = 0; i < maxSize && i < 10;)
37 { 52 {
38 Byte b = p[i]; 53 const Byte b = p[i];
39 *val |= (UInt64)(b & 0x7F) << (7 * i); 54 *val |= (UInt64)(b & 0x7F) << (7 * i);
40 i++; 55 i++;
41 if ((b & 0x80) == 0) 56 if ((b & 0x80) == 0)
@@ -64,7 +79,7 @@ HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV,
64 size -= num; 79 size -= num;
65 80
66 bool isCheck = IsThereCheck(); 81 bool isCheck = IsThereCheck();
67 if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize : 0)) 82 if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize32 * 4 : 0))
68 return E_NOTIMPL; 83 return E_NOTIMPL;
69 84
70 if (_numIterationsLog != p[0]) 85 if (_numIterationsLog != p[0])
@@ -93,19 +108,21 @@ HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV,
93 108
94 if (isCheck) 109 if (isCheck)
95 { 110 {
96 memcpy(_check, p, kPswCheckSize); 111 memcpy(_check32, p, sizeof(_check32));
112 MY_ALIGN_FOR_SHA256
97 CSha256 sha; 113 CSha256 sha;
114 MY_ALIGN_FOR_SHA256
98 Byte digest[SHA256_DIGEST_SIZE]; 115 Byte digest[SHA256_DIGEST_SIZE];
99 Sha256_Init(&sha); 116 Sha256_Init(&sha);
100 Sha256_Update(&sha, _check, kPswCheckSize); 117 Sha256_Update(&sha, (const Byte *)_check32, sizeof(_check32));
101 Sha256_Final(&sha, digest); 118 Sha256_Final(&sha, digest);
102 _canCheck = (memcmp(digest, p + kPswCheckSize, kPswCheckCsumSize) == 0); 119 _canCheck = (memcmp(digest, p + sizeof(_check32), kPswCheckCsumSize32 * 4) == 0);
103 if (_canCheck && isService) 120 if (_canCheck && isService)
104 { 121 {
105 // There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros. 122 // There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros.
106 // so we disable password checking for such bad records. 123 // so we disable password checking for such bad records.
107 _canCheck = false; 124 _canCheck = false;
108 for (unsigned i = 0; i < kPswCheckSize; i++) 125 for (unsigned i = 0; i < kPswCheckSize32 * 4; i++)
109 if (p[i] != 0) 126 if (p[i] != 0)
110 { 127 {
111 _canCheck = true; 128 _canCheck = true;
@@ -132,7 +149,7 @@ void CDecoder::SetPassword(const Byte *data, size_t size)
132Z7_COM7F_IMF(CDecoder::Init()) 149Z7_COM7F_IMF(CDecoder::Init())
133{ 150{
134 CalcKey_and_CheckPassword(); 151 CalcKey_and_CheckPassword();
135 RINOK(SetKey(_key, kAesKeySize)) 152 RINOK(SetKey((const Byte *)_key32, kAesKeySize))
136 RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)) 153 RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
137 return CAesCoder::Init(); 154 return CAesCoder::Init();
138} 155}
@@ -140,27 +157,27 @@ Z7_COM7F_IMF(CDecoder::Init())
140 157
141UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const 158UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const
142{ 159{
143 MY_ALIGN (16) 160 MY_ALIGN_FOR_SHA256
144 NSha256::CHmac ctx; 161 NSha256::CHmac ctx;
145 ctx.SetKey(_hashKey, NSha256::kDigestSize); 162 ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize);
146 UInt32 v; 163 UInt32 v;
147 SetUi32(&v, crc) 164 SetUi32a(&v, crc)
148 ctx.Update((const Byte *)&v, 4); 165 ctx.Update((const Byte *)&v, 4);
149 MY_ALIGN (16) 166 MY_ALIGN_FOR_SHA256
150 UInt32 h[SHA256_NUM_DIGEST_WORDS]; 167 UInt32 h[SHA256_NUM_DIGEST_WORDS];
151 ctx.Final((Byte *)h); 168 ctx.Final((Byte *)h);
152 crc = 0; 169 crc = 0;
153 for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++) 170 for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++)
154 crc ^= (UInt32)GetUi32(h + i); 171 crc ^= (UInt32)GetUi32a(h + i);
155 return crc; 172 return crc;
156} 173}
157 174
158 175
159void CDecoder::Hmac_Convert_32Bytes(Byte *data) const 176void CDecoder::Hmac_Convert_32Bytes(Byte *data) const
160{ 177{
161 MY_ALIGN (16) 178 MY_ALIGN_FOR_SHA256
162 NSha256::CHmac ctx; 179 NSha256::CHmac ctx;
163 ctx.SetKey(_hashKey, NSha256::kDigestSize); 180 ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize);
164 ctx.Update(data, NSha256::kDigestSize); 181 ctx.Update(data, NSha256::kDigestSize);
165 ctx.Final(data); 182 ctx.Final(data);
166} 183}
@@ -190,30 +207,31 @@ bool CDecoder::CalcKey_and_CheckPassword()
190 207
191 if (_needCalc) 208 if (_needCalc)
192 { 209 {
193 Byte pswCheck[SHA256_DIGEST_SIZE]; 210 MY_ALIGN_FOR_SHA256
194 211 UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS];
195 { 212 {
196 // Pbkdf HMAC-SHA-256 213 // Pbkdf HMAC-SHA-256
197 214 MY_ALIGN_FOR_SHA256
198 MY_ALIGN (16)
199 NSha256::CHmac baseCtx; 215 NSha256::CHmac baseCtx;
200 baseCtx.SetKey(_password, _password.Size()); 216 baseCtx.SetKey(_password, _password.Size());
201 217 MY_ALIGN_FOR_SHA256
202 NSha256::CHmac ctx = baseCtx; 218 NSha256::CHmac ctx;
219 ctx = baseCtx;
203 ctx.Update(_salt, sizeof(_salt)); 220 ctx.Update(_salt, sizeof(_salt));
204 221
205 MY_ALIGN (16) 222 MY_ALIGN_FOR_SHA256
206 Byte u[NSha256::kDigestSize]; 223 UInt32 u[SHA256_NUM_DIGEST_WORDS];
207 MY_ALIGN (16) 224 MY_ALIGN_FOR_SHA256
208 Byte key[NSha256::kDigestSize]; 225 UInt32 key[SHA256_NUM_DIGEST_WORDS];
209 226
210 u[0] = 0; 227 // u[0] = 0;
211 u[1] = 0; 228 // u[1] = 0;
212 u[2] = 0; 229 // u[2] = 0;
213 u[3] = 1; 230 // u[3] = 1;
231 SetUi32a(u, 0x1000000)
214 232
215 ctx.Update(u, 4); 233 ctx.Update((const Byte *)(const void *)u, 4);
216 ctx.Final(u); 234 ctx.Final((Byte *)(void *)u);
217 235
218 memcpy(key, u, NSha256::kDigestSize); 236 memcpy(key, u, NSha256::kDigestSize);
219 237
@@ -221,35 +239,24 @@ bool CDecoder::CalcKey_and_CheckPassword()
221 239
222 for (unsigned i = 0; i < 3; i++) 240 for (unsigned i = 0; i < 3; i++)
223 { 241 {
224 UInt32 j = numIterations; 242 for (; numIterations != 0; numIterations--)
225
226 for (; j != 0; j--)
227 { 243 {
228 ctx = baseCtx; 244 ctx = baseCtx;
229 ctx.Update(u, NSha256::kDigestSize); 245 ctx.Update((const Byte *)(const void *)u, NSha256::kDigestSize);
230 ctx.Final(u); 246 ctx.Final((Byte *)(void *)u);
231 for (unsigned s = 0; s < NSha256::kDigestSize; s++) 247 for (unsigned s = 0; s < Z7_ARRAY_SIZE(u); s++)
232 key[s] ^= u[s]; 248 key[s] ^= u[s];
233 } 249 }
234 250
235 // RAR uses additional iterations for additional keys 251 // RAR uses additional iterations for additional keys
236 memcpy((i == 0 ? _key : (i == 1 ? _hashKey : pswCheck)), key, NSha256::kDigestSize); 252 memcpy(i == 0 ? _key32 : i == 1 ? _hashKey32 : pswCheck,
253 key, NSha256::kDigestSize);
237 numIterations = 16; 254 numIterations = 16;
238 } 255 }
239 } 256 }
240 257 _check_Calced32[0] = pswCheck[0] ^ pswCheck[2] ^ pswCheck[4] ^ pswCheck[6];
241 { 258 _check_Calced32[1] = pswCheck[1] ^ pswCheck[3] ^ pswCheck[5] ^ pswCheck[7];
242 unsigned i;
243
244 for (i = 0; i < kPswCheckSize; i++)
245 _check_Calced[i] = pswCheck[i];
246
247 for (i = kPswCheckSize; i < SHA256_DIGEST_SIZE; i++)
248 _check_Calced[i & (kPswCheckSize - 1)] ^= pswCheck[i];
249 }
250
251 _needCalc = false; 259 _needCalc = false;
252
253 { 260 {
254 MT_LOCK 261 MT_LOCK
255 g_Key = *this; 262 g_Key = *this;
@@ -258,7 +265,7 @@ bool CDecoder::CalcKey_and_CheckPassword()
258 } 265 }
259 266
260 if (IsThereCheck() && _canCheck) 267 if (IsThereCheck() && _canCheck)
261 return (memcmp(_check_Calced, _check, kPswCheckSize) == 0); 268 return memcmp(_check_Calced32, _check32, sizeof(_check32)) == 0;
262 return true; 269 return true;
263} 270}
264 271
diff --git a/CPP/7zip/Crypto/Rar5Aes.h b/CPP/7zip/Crypto/Rar5Aes.h
index 3cd7992..c6059aa 100644
--- a/CPP/7zip/Crypto/Rar5Aes.h
+++ b/CPP/7zip/Crypto/Rar5Aes.h
@@ -13,7 +13,7 @@ namespace NCrypto {
13namespace NRar5 { 13namespace NRar5 {
14 14
15const unsigned kSaltSize = 16; 15const unsigned kSaltSize = 16;
16const unsigned kPswCheckSize = 8; 16const unsigned kPswCheckSize32 = 2;
17const unsigned kAesKeySize = 32; 17const unsigned kAesKeySize = 32;
18 18
19namespace NCryptoFlags 19namespace NCryptoFlags
@@ -22,48 +22,47 @@ namespace NCryptoFlags
22 const unsigned kUseMAC = 1 << 1; 22 const unsigned kUseMAC = 1 << 1;
23} 23}
24 24
25struct CKey 25struct CKeyBase
26{ 26{
27 bool _needCalc; 27protected:
28 UInt32 _key32[kAesKeySize / 4];
29 UInt32 _hashKey32[SHA256_NUM_DIGEST_WORDS];
30 UInt32 _check_Calced32[kPswCheckSize32];
28 31
29 unsigned _numIterationsLog; 32 void Wipe()
30 Byte _salt[kSaltSize]; 33 {
31 CByteBuffer _password; 34 memset(this, 0, sizeof(*this));
35 }
32 36
33 Byte _key[kAesKeySize]; 37 void CopyCalcedKeysFrom(const CKeyBase &k)
34 Byte _check_Calced[kPswCheckSize];
35 Byte _hashKey[SHA256_DIGEST_SIZE];
36
37 void CopyCalcedKeysFrom(const CKey &k)
38 { 38 {
39 memcpy(_key, k._key, sizeof(_key)); 39 *this = k;
40 memcpy(_check_Calced, k._check_Calced, sizeof(_check_Calced));
41 memcpy(_hashKey, k._hashKey, sizeof(_hashKey));
42 } 40 }
41};
43 42
43struct CKey: public CKeyBase
44{
45 CByteBuffer _password;
46 bool _needCalc;
47 unsigned _numIterationsLog;
48 Byte _salt[kSaltSize];
49
44 bool IsKeyEqualTo(const CKey &key) 50 bool IsKeyEqualTo(const CKey &key)
45 { 51 {
46 return (_numIterationsLog == key._numIterationsLog 52 return _numIterationsLog == key._numIterationsLog
47 && memcmp(_salt, key._salt, sizeof(_salt)) == 0 53 && memcmp(_salt, key._salt, sizeof(_salt)) == 0
48 && _password == key._password); 54 && _password == key._password;
49 } 55 }
50
51 CKey();
52 56
53 void Wipe() 57 CKey();
54 { 58 ~CKey();
55 _password.Wipe(); 59
56 Z7_memset_0_ARRAY(_salt); 60 void Wipe();
57 Z7_memset_0_ARRAY(_key);
58 Z7_memset_0_ARRAY(_check_Calced);
59 Z7_memset_0_ARRAY(_hashKey);
60 }
61 61
62#ifdef Z7_CPP_IS_SUPPORTED_default 62#ifdef Z7_CPP_IS_SUPPORTED_default
63 // CKey(const CKey &) = default; 63 // CKey(const CKey &) = default;
64 CKey& operator =(const CKey &) = default; 64 CKey& operator =(const CKey &) = default;
65#endif 65#endif
66 ~CKey() { Wipe(); }
67}; 66};
68 67
69 68
@@ -71,11 +70,11 @@ class CDecoder Z7_final:
71 public CAesCbcDecoder, 70 public CAesCbcDecoder,
72 public CKey 71 public CKey
73{ 72{
74 Byte _check[kPswCheckSize]; 73 UInt32 _check32[kPswCheckSize32];
75 bool _canCheck; 74 bool _canCheck;
76 UInt64 Flags; 75 UInt64 Flags;
77 76
78 bool IsThereCheck() const { return ((Flags & NCryptoFlags::kPswCheck) != 0); } 77 bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
79public: 78public:
80 Byte _iv[AES_BLOCK_SIZE]; 79 Byte _iv[AES_BLOCK_SIZE];
81 80
diff --git a/CPP/7zip/Crypto/RarAes.cpp b/CPP/7zip/Crypto/RarAes.cpp
index 878ea3a..e63f82c 100644
--- a/CPP/7zip/Crypto/RarAes.cpp
+++ b/CPP/7zip/Crypto/RarAes.cpp
@@ -111,7 +111,8 @@ static void UpdatePswDataSha1(Byte *data)
111 111
112 for (i = 16; i < 80; i++) 112 for (i = 16; i < 80; i++)
113 { 113 {
114 WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1); 114 const UInt32 t = WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16);
115 WW(i) = rotlFixed(t, 1);
115 } 116 }
116 117
117 for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) 118 for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
@@ -128,6 +129,7 @@ void CDecoder::CalcKey()
128 129
129 const unsigned kSaltSize = 8; 130 const unsigned kSaltSize = 8;
130 131
132 MY_ALIGN (16)
131 Byte buf[kPasswordLen_Bytes_MAX + kSaltSize]; 133 Byte buf[kPasswordLen_Bytes_MAX + kSaltSize];
132 134
133 if (_password.Size() != 0) 135 if (_password.Size() != 0)
@@ -148,7 +150,7 @@ void CDecoder::CalcKey()
148 MY_ALIGN (16) 150 MY_ALIGN (16)
149 Byte digest[NSha1::kDigestSize]; 151 Byte digest[NSha1::kDigestSize];
150 // rar reverts hash for sha. 152 // rar reverts hash for sha.
151 const UInt32 kNumRounds = ((UInt32)1 << 18); 153 const UInt32 kNumRounds = (UInt32)1 << 18;
152 UInt32 pos = 0; 154 UInt32 pos = 0;
153 UInt32 i; 155 UInt32 i;
154 for (i = 0; i < kNumRounds; i++) 156 for (i = 0; i < kNumRounds; i++)
@@ -171,8 +173,14 @@ void CDecoder::CalcKey()
171 } 173 }
172 } 174 }
173 pos += (UInt32)rawSize; 175 pos += (UInt32)rawSize;
176#if 1
177 UInt32 pswNum;
178 SetUi32a(&pswNum, i)
179 sha.Update((const Byte *)&pswNum, 3);
180#else
174 Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) }; 181 Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
175 sha.Update(pswNum, 3); 182 sha.Update(pswNum, 3);
183#endif
176 pos += 3; 184 pos += 3;
177 if (i % (kNumRounds / 16) == 0) 185 if (i % (kNumRounds / 16) == 0)
178 { 186 {
diff --git a/CPP/7zip/Crypto/ZipStrong.cpp b/CPP/7zip/Crypto/ZipStrong.cpp
index 59698d8..c4e8311 100644
--- a/CPP/7zip/Crypto/ZipStrong.cpp
+++ b/CPP/7zip/Crypto/ZipStrong.cpp
@@ -24,30 +24,31 @@ static const UInt16 kAES128 = 0x660E;
24 if (method != AES && method != 3DES), probably we need another code. 24 if (method != AES && method != 3DES), probably we need another code.
25*/ 25*/
26 26
27static void DeriveKey2(const Byte *digest, Byte c, Byte *dest) 27static void DeriveKey2(const UInt32 *digest32, Byte c, UInt32 *dest32)
28{ 28{
29 const unsigned kBufSize = 64;
29 MY_ALIGN (16) 30 MY_ALIGN (16)
30 Byte buf[64]; 31 UInt32 buf32[kBufSize / 4];
31 memset(buf, c, 64); 32 memset(buf32, c, kBufSize);
32 for (unsigned i = 0; i < NSha1::kDigestSize; i++) 33 for (unsigned i = 0; i < NSha1::kNumDigestWords; i++)
33 buf[i] ^= digest[i]; 34 buf32[i] ^= digest32[i];
34 MY_ALIGN (16) 35 MY_ALIGN (16)
35 NSha1::CContext sha; 36 NSha1::CContext sha;
36 sha.Init(); 37 sha.Init();
37 sha.Update(buf, 64); 38 sha.Update((const Byte *)buf32, kBufSize);
38 sha.Final(dest); 39 sha.Final((Byte *)dest32);
39} 40}
40 41
41static void DeriveKey(NSha1::CContext &sha, Byte *key) 42static void DeriveKey(NSha1::CContext &sha, Byte *key)
42{ 43{
43 MY_ALIGN (16) 44 MY_ALIGN (16)
44 Byte digest[NSha1::kDigestSize]; 45 UInt32 digest32[NSha1::kNumDigestWords];
45 sha.Final(digest); 46 sha.Final((Byte *)digest32);
46 MY_ALIGN (16) 47 MY_ALIGN (16)
47 Byte temp[NSha1::kDigestSize * 2]; 48 UInt32 temp32[NSha1::kNumDigestWords * 2];
48 DeriveKey2(digest, 0x36, temp); 49 DeriveKey2(digest32, 0x36, temp32);
49 DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); 50 DeriveKey2(digest32, 0x5C, temp32 + NSha1::kNumDigestWords);
50 memcpy(key, temp, 32); 51 memcpy(key, temp32, 32);
51} 52}
52 53
53void CKeyInfo::SetPassword(const Byte *data, UInt32 size) 54void CKeyInfo::SetPassword(const Byte *data, UInt32 size)
@@ -122,24 +123,24 @@ HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK)
122 passwOK = false; 123 passwOK = false;
123 if (_remSize < 16) 124 if (_remSize < 16)
124 return E_NOTIMPL; 125 return E_NOTIMPL;
125 Byte *p = _bufAligned; 126 Byte * const p = _bufAligned;
126 const unsigned format = GetUi16(p); 127 const unsigned format = GetUi16a(p);
127 if (format != 3) 128 if (format != 3)
128 return E_NOTIMPL; 129 return E_NOTIMPL;
129 unsigned algId = GetUi16(p + 2); 130 unsigned algId = GetUi16a(p + 2);
130 if (algId < kAES128) 131 if (algId < kAES128)
131 return E_NOTIMPL; 132 return E_NOTIMPL;
132 algId -= kAES128; 133 algId -= kAES128;
133 if (algId > 2) 134 if (algId > 2)
134 return E_NOTIMPL; 135 return E_NOTIMPL;
135 const unsigned bitLen = GetUi16(p + 4); 136 const unsigned bitLen = GetUi16a(p + 4);
136 const unsigned flags = GetUi16(p + 6); 137 const unsigned flags = GetUi16a(p + 6);
137 if (algId * 64 + 128 != bitLen) 138 if (algId * 64 + 128 != bitLen)
138 return E_NOTIMPL; 139 return E_NOTIMPL;
139 _key.KeySize = 16 + algId * 8; 140 _key.KeySize = 16 + algId * 8;
140 const bool cert = ((flags & 2) != 0); 141 const bool cert = ((flags & 2) != 0);
141 142
142 if ((flags & 0x4000) != 0) 143 if (flags & 0x4000)
143 { 144 {
144 // Use 3DES for rd data 145 // Use 3DES for rd data
145 return E_NOTIMPL; 146 return E_NOTIMPL;
@@ -155,7 +156,7 @@ HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK)
155 return E_NOTIMPL; 156 return E_NOTIMPL;
156 } 157 }
157 158
158 UInt32 rdSize = GetUi16(p + 8); 159 UInt32 rdSize = GetUi16a(p + 8);
159 160
160 if (rdSize + 16 > _remSize) 161 if (rdSize + 16 > _remSize)
161 return E_NOTIMPL; 162 return E_NOTIMPL;
@@ -174,7 +175,7 @@ HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK)
174 // PKCS7 padding 175 // PKCS7 padding
175 if (rdSize < kPadSize) 176 if (rdSize < kPadSize)
176 return E_NOTIMPL; 177 return E_NOTIMPL;
177 if ((rdSize & (kPadSize - 1)) != 0) 178 if (rdSize & (kPadSize - 1))
178 return E_NOTIMPL; 179 return E_NOTIMPL;
179 } 180 }
180 181
diff --git a/CPP/7zip/GuiCommon.rc b/CPP/7zip/GuiCommon.rc
index 95654b6..bf8ad8b 100644
--- a/CPP/7zip/GuiCommon.rc
+++ b/CPP/7zip/GuiCommon.rc
@@ -115,5 +115,5 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
115 _x + _xSize, _y, 8, 12 // these values are unused 115 _x + _xSize, _y, 8, 12 // these values are unused
116 116
117 117
118#define OPTIONS_PAGE_XC_SIZE 280 118#define OPTIONS_PAGE_XC_SIZE 300
119#define OPTIONS_PAGE_YC_SIZE 280 119#define OPTIONS_PAGE_YC_SIZE 280
diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt
index abbaf20..fbae89c 100644
--- a/CPP/7zip/Guid.txt
+++ b/CPP/7zip/Guid.txt
@@ -20,6 +20,8 @@
20 10 IFolderArchiveUpdateCallback2 20 10 IFolderArchiveUpdateCallback2
21 11 IFolderScanProgress 21 11 IFolderScanProgress
22 12 IFolderSetZoneIdMode 22 12 IFolderSetZoneIdMode
23 13 IFolderSetZoneIdFile
24 14 IFolderArchiveUpdateCallback_MoveArc
23 25
24 20 IFileExtractCallback.h::IGetProp 26 20 IFileExtractCallback.h::IGetProp
25 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old) 27 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old)
diff --git a/CPP/7zip/ICoder.h b/CPP/7zip/ICoder.h
index aec2834..20d0ff7 100644
--- a/CPP/7zip/ICoder.h
+++ b/CPP/7zip/ICoder.h
@@ -136,6 +136,9 @@ namespace NCoderPropID
136 kAffinity, // VT_UI8 136 kAffinity, // VT_UI8
137 kBranchOffset, // VT_UI4 137 kBranchOffset, // VT_UI4
138 kHashBits, // VT_UI4 138 kHashBits, // VT_UI4
139 kNumThreadGroups, // VT_UI4
140 kThreadGroup, // VT_UI4
141 kAffinityInGroup, // VT_UI8
139 /* 142 /*
140 // kHash3Bits, // VT_UI4 143 // kHash3Bits, // VT_UI4
141 // kHash2Bits, // VT_UI4 144 // kHash2Bits, // VT_UI4
diff --git a/CPP/7zip/Sort.mak b/CPP/7zip/Sort.mak
new file mode 100644
index 0000000..ca0ff59
--- /dev/null
+++ b/CPP/7zip/Sort.mak
@@ -0,0 +1,6 @@
1!IF defined(USE_NO_ASM) || defined(USE_C_SORT) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
2C_OBJS = $(C_OBJS) \
3!ELSE
4ASM_OBJS = $(ASM_OBJS) \
5!ENDIF
6 $O\Sort.obj
diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp
index eb77f25..46b740a 100644
--- a/CPP/7zip/UI/Agent/Agent.cpp
+++ b/CPP/7zip/UI/Agent/Agent.cpp
@@ -1516,6 +1516,8 @@ Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices,
1516 if (_zoneMode != NExtract::NZoneIdMode::kNone) 1516 if (_zoneMode != NExtract::NZoneIdMode::kNone)
1517 { 1517 {
1518 ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf); 1518 ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf);
1519 if (_zoneBuf.Size() != 0)
1520 extractCallbackSpec->ZoneBuf = _zoneBuf;
1519 } 1521 }
1520 #endif 1522 #endif
1521 1523
diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h
index ea81aa8..a63e459 100644
--- a/CPP/7zip/UI/Agent/Agent.h
+++ b/CPP/7zip/UI/Agent/Agent.h
@@ -60,6 +60,7 @@ class CAgentFolder Z7_final:
60 public IArchiveFolderInternal, 60 public IArchiveFolderInternal,
61 public IInArchiveGetStream, 61 public IInArchiveGetStream,
62 public IFolderSetZoneIdMode, 62 public IFolderSetZoneIdMode,
63 public IFolderSetZoneIdFile,
63 public IFolderOperations, 64 public IFolderOperations,
64 public IFolderSetFlatMode, 65 public IFolderSetFlatMode,
65 public CMyUnknownImp 66 public CMyUnknownImp
@@ -75,6 +76,7 @@ class CAgentFolder Z7_final:
75 Z7_COM_QI_ENTRY(IArchiveFolderInternal) 76 Z7_COM_QI_ENTRY(IArchiveFolderInternal)
76 Z7_COM_QI_ENTRY(IInArchiveGetStream) 77 Z7_COM_QI_ENTRY(IInArchiveGetStream)
77 Z7_COM_QI_ENTRY(IFolderSetZoneIdMode) 78 Z7_COM_QI_ENTRY(IFolderSetZoneIdMode)
79 Z7_COM_QI_ENTRY(IFolderSetZoneIdFile)
78 Z7_COM_QI_ENTRY(IFolderOperations) 80 Z7_COM_QI_ENTRY(IFolderOperations)
79 Z7_COM_QI_ENTRY(IFolderSetFlatMode) 81 Z7_COM_QI_ENTRY(IFolderSetFlatMode)
80 Z7_COM_QI_END 82 Z7_COM_QI_END
@@ -91,6 +93,7 @@ class CAgentFolder Z7_final:
91 Z7_IFACE_COM7_IMP(IArchiveFolderInternal) 93 Z7_IFACE_COM7_IMP(IArchiveFolderInternal)
92 Z7_IFACE_COM7_IMP(IInArchiveGetStream) 94 Z7_IFACE_COM7_IMP(IInArchiveGetStream)
93 Z7_IFACE_COM7_IMP(IFolderSetZoneIdMode) 95 Z7_IFACE_COM7_IMP(IFolderSetZoneIdMode)
96 Z7_IFACE_COM7_IMP(IFolderSetZoneIdFile)
94 Z7_IFACE_COM7_IMP(IFolderOperations) 97 Z7_IFACE_COM7_IMP(IFolderOperations)
95 Z7_IFACE_COM7_IMP(IFolderSetFlatMode) 98 Z7_IFACE_COM7_IMP(IFolderSetFlatMode)
96 99
@@ -106,11 +109,11 @@ public:
106 int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); 109 int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw);
107 110
108 CAgentFolder(): 111 CAgentFolder():
109 _proxyDirIndex(0),
110 _isAltStreamFolder(false), 112 _isAltStreamFolder(false),
111 _flatMode(false), 113 _flatMode(false),
112 _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now 114 _loadAltStreams(false), // _loadAltStreams alt streams works in flat mode, but we don't use it now
113 , _zoneMode(NExtract::NZoneIdMode::kNone) 115 _proxyDirIndex(0),
116 _zoneMode(NExtract::NZoneIdMode::kNone)
114 /* , _replaceAltStreamCharsMode(0) */ 117 /* , _replaceAltStreamCharsMode(0) */
115 {} 118 {}
116 119
@@ -145,21 +148,23 @@ public:
145 UString GetFullPrefix(UInt32 index) const; // relative too root folder of archive 148 UString GetFullPrefix(UInt32 index) const; // relative too root folder of archive
146 149
147public: 150public:
151 bool _isAltStreamFolder;
152 bool _flatMode;
153 bool _loadAltStreams; // in Flat mode
148 const CProxyArc *_proxy; 154 const CProxyArc *_proxy;
149 const CProxyArc2 *_proxy2; 155 const CProxyArc2 *_proxy2;
150 unsigned _proxyDirIndex; 156 unsigned _proxyDirIndex;
151 bool _isAltStreamFolder; 157 NExtract::NZoneIdMode::EEnum _zoneMode;
158 CByteBuffer _zoneBuf;
159 // Int32 _replaceAltStreamCharsMode;
152 // CMyComPtr<IFolderFolder> _parentFolder; 160 // CMyComPtr<IFolderFolder> _parentFolder;
153 CMyComPtr<IInFolderArchive> _agent; 161 CMyComPtr<IInFolderArchive> _agent;
154 CAgent *_agentSpec; 162 CAgent *_agentSpec;
155
156 CRecordVector<CProxyItem> _items; 163 CRecordVector<CProxyItem> _items;
157 bool _flatMode;
158 bool _loadAltStreams; // in Flat mode
159 // Int32 _replaceAltStreamCharsMode;
160 NExtract::NZoneIdMode::EEnum _zoneMode;
161}; 164};
162 165
166
167
163class CAgent Z7_final: 168class CAgent Z7_final:
164 public IInFolderArchive, 169 public IInFolderArchive,
165 public IFolderArcProps, 170 public IFolderArcProps,
@@ -213,22 +218,22 @@ public:
213 CProxyArc2 *_proxy2; 218 CProxyArc2 *_proxy2;
214 CArchiveLink _archiveLink; 219 CArchiveLink _archiveLink;
215 220
216 bool ThereIsPathProp;
217 // bool ThereIsAltStreamProp;
218
219 UString ArchiveType; 221 UString ArchiveType;
220 222
221 FStringVector _names; 223 FStringVector _names;
222 FString _folderPrefix; // for new files from disk 224 FString _folderPrefix; // for new files from disk
223 225
224 bool _updatePathPrefix_is_AltFolder;
225 UString _updatePathPrefix; 226 UString _updatePathPrefix;
226 CAgentFolder *_agentFolder; 227 CAgentFolder *_agentFolder;
227 228
228 UString _archiveFilePath; 229 UString _archiveFilePath; // it can be path of non-existing file if file is virtual
230
229 DWORD _attrib; 231 DWORD _attrib;
232 bool _updatePathPrefix_is_AltFolder;
233 bool ThereIsPathProp;
230 bool _isDeviceFile; 234 bool _isDeviceFile;
231 bool _isHashHandler; 235 bool _isHashHandler;
236
232 FString _hashBaseFolderPrefix; 237 FString _hashBaseFolderPrefix;
233 238
234 #ifndef Z7_EXTRACT_ONLY 239 #ifndef Z7_EXTRACT_ONLY
diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp
index 176f39b..d04ddab 100644
--- a/CPP/7zip/UI/Agent/AgentProxy.cpp
+++ b/CPP/7zip/UI/Agent/AgentProxy.cpp
@@ -636,7 +636,7 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
636 file.Name = (const wchar_t *)p; 636 file.Name = (const wchar_t *)p;
637 file.NameLen = 0; 637 file.NameLen = 0;
638 if (size >= sizeof(wchar_t)) 638 if (size >= sizeof(wchar_t))
639 file.NameLen = size / sizeof(wchar_t) - 1; 639 file.NameLen = size / (unsigned)sizeof(wchar_t) - 1;
640 } 640 }
641 else 641 else
642 #endif 642 #endif
diff --git a/CPP/7zip/UI/Agent/ArchiveFolder.cpp b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
index 89b20dc..eea681c 100644
--- a/CPP/7zip/UI/Agent/ArchiveFolder.cpp
+++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
@@ -22,6 +22,12 @@ Z7_COM7F_IMF(CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode))
22 return S_OK; 22 return S_OK;
23} 23}
24 24
25Z7_COM7F_IMF(CAgentFolder::SetZoneIdFile(const Byte *data, UInt32 size))
26{
27 _zoneBuf.CopyFrom(data, size);
28 return S_OK;
29}
30
25 31
26Z7_COM7F_IMF(CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, 32Z7_COM7F_IMF(CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
27 Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, 33 Int32 includeAltStreams, Int32 replaceAltStreamCharsMode,
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
index 0189224..1da6601 100644
--- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
@@ -62,6 +62,33 @@ static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path)
62 return RemoveDir(path); 62 return RemoveDir(path);
63} 63}
64 64
65
66
67struct C_CopyFileProgress_to_FolderCallback_MoveArc Z7_final:
68 public ICopyFileProgress
69{
70 IFolderArchiveUpdateCallback_MoveArc *Callback;
71 HRESULT CallbackResult;
72
73 virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) Z7_override
74 {
75 HRESULT res = Callback->MoveArc_Progress(total, current);
76 CallbackResult = res;
77 // we can ignore E_ABORT here, because we update archive,
78 // and we want to get correct archive after updating
79 if (res == E_ABORT)
80 res = S_OK;
81 return res == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL;
82 }
83
84 C_CopyFileProgress_to_FolderCallback_MoveArc(
85 IFolderArchiveUpdateCallback_MoveArc *callback) :
86 Callback(callback),
87 CallbackResult(S_OK)
88 {}
89};
90
91
65HRESULT CAgentFolder::CommonUpdateOperation( 92HRESULT CAgentFolder::CommonUpdateOperation(
66 AGENT_OP operation, 93 AGENT_OP operation,
67 bool moveMode, 94 bool moveMode,
@@ -159,8 +186,51 @@ HRESULT CAgentFolder::CommonUpdateOperation(
159 // now: we reopen archive after close 186 // now: we reopen archive after close
160 187
161 // m_FolderItem = NULL; 188 // m_FolderItem = NULL;
189 _items.Clear();
190 _proxyDirIndex = k_Proxy_RootDirIndex;
191
192 CMyComPtr<IFolderArchiveUpdateCallback_MoveArc> updateCallback_MoveArc;
193 if (progress)
194 progress->QueryInterface(IID_IFolderArchiveUpdateCallback_MoveArc, (void **)&updateCallback_MoveArc);
162 195
163 const HRESULT res = tempFile.MoveToOriginal(true); 196 HRESULT res;
197 if (updateCallback_MoveArc)
198 {
199 const FString &tempFilePath = tempFile.Get_TempFilePath();
200 UInt64 totalSize = 0;
201 {
202 NFind::CFileInfo fi;
203 if (fi.Find(tempFilePath))
204 totalSize = fi.Size;
205 }
206 RINOK(updateCallback_MoveArc->MoveArc_Start(
207 fs2us(tempFilePath),
208 fs2us(tempFile.Get_OriginalFilePath()),
209 totalSize,
210 1)) // updateMode
211
212 C_CopyFileProgress_to_FolderCallback_MoveArc prox(updateCallback_MoveArc);
213 res = tempFile.MoveToOriginal(
214 true, // deleteOriginal
215 &prox);
216 if (res == S_OK)
217 {
218 res = updateCallback_MoveArc->MoveArc_Finish();
219 // we don't return after E_ABORT here, because
220 // we want to reopen new archive still.
221 }
222 else if (prox.CallbackResult != S_OK)
223 res = prox.CallbackResult;
224
225 // if updating callback returned E_ABORT,
226 // then openCallback still can return E_ABORT also.
227 // So ReOpen() will return with E_ABORT.
228 // But we want to open archive still.
229 // And Before_ArcReopen() call will clear user break status in that case.
230 RINOK(updateCallback_MoveArc->Before_ArcReopen())
231 }
232 else
233 res = tempFile.MoveToOriginal(true); // deleteOriginal
164 234
165 // RINOK(res); 235 // RINOK(res);
166 if (res == S_OK) 236 if (res == S_OK)
@@ -189,10 +259,10 @@ HRESULT CAgentFolder::CommonUpdateOperation(
189 } 259 }
190 260
191 // CAgent::ReOpen() deletes _proxy and _proxy2 261 // CAgent::ReOpen() deletes _proxy and _proxy2
192 _items.Clear(); 262 // _items.Clear();
193 _proxy = NULL; 263 _proxy = NULL;
194 _proxy2 = NULL; 264 _proxy2 = NULL;
195 _proxyDirIndex = k_Proxy_RootDirIndex; 265 // _proxyDirIndex = k_Proxy_RootDirIndex;
196 _isAltStreamFolder = false; 266 _isAltStreamFolder = false;
197 267
198 268
diff --git a/CPP/7zip/UI/Agent/IFolderArchive.h b/CPP/7zip/UI/Agent/IFolderArchive.h
index 55f1423..12b900f 100644
--- a/CPP/7zip/UI/Agent/IFolderArchive.h
+++ b/CPP/7zip/UI/Agent/IFolderArchive.h
@@ -103,5 +103,21 @@ Z7_IFACE_CONSTR_FOLDERARC(IFolderScanProgress, 0x11)
103 103
104Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdMode, 0x12) 104Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdMode, 0x12)
105 105
106#define Z7_IFACEM_IFolderSetZoneIdFile(x) \
107 x(SetZoneIdFile(const Byte *data, UInt32 size)) \
108
109Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdFile, 0x13)
110
111
112// if the caller calls Before_ArcReopen(), the callee must
113// clear user break status, because the caller want to open archive still.
114#define Z7_IFACEM_IFolderArchiveUpdateCallback_MoveArc(x) \
115 x(MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode)) \
116 x(MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)) \
117 x(MoveArc_Finish()) \
118 x(Before_ArcReopen()) \
119
120Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback_MoveArc, 0x14)
121
106Z7_PURE_INTERFACES_END 122Z7_PURE_INTERFACES_END
107#endif 123#endif
diff --git a/CPP/7zip/UI/Client7z/makefile.gcc b/CPP/7zip/UI/Client7z/makefile.gcc
index 3f97205..0f89cb0 100644
--- a/CPP/7zip/UI/Client7z/makefile.gcc
+++ b/CPP/7zip/UI/Client7z/makefile.gcc
@@ -24,7 +24,6 @@ else
24 24
25SYS_OBJS = \ 25SYS_OBJS = \
26 $O/MyWindows.o \ 26 $O/MyWindows.o \
27 $O/TimeUtils.o \
28 27
29endif 28endif
30 29
@@ -53,12 +52,16 @@ WIN_OBJS = \
53 $O/FileName.o \ 52 $O/FileName.o \
54 $O/PropVariant.o \ 53 $O/PropVariant.o \
55 $O/PropVariantConv.o \ 54 $O/PropVariantConv.o \
55 $O/TimeUtils.o \
56 56
577ZIP_COMMON_OBJS = \ 577ZIP_COMMON_OBJS = \
58 $O/FileStreams.o \ 58 $O/FileStreams.o \
59 59
60C_OBJS = \
61 $O/Alloc.o \
60 62
61OBJS = \ 63OBJS = \
64 $(C_OBJS) \
62 $(COMMON_OBJS) \ 65 $(COMMON_OBJS) \
63 $(WIN_OBJS) \ 66 $(WIN_OBJS) \
64 $(SYS_OBJS) \ 67 $(SYS_OBJS) \
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
index 556b25a..7fe18fb 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -63,17 +63,46 @@ EXTERN_C_END
63 63
64#else 64#else
65 65
66// #define MY_isatty_fileno(x) (isatty(fileno(x))) 66static bool MY_IS_TERMINAL(FILE *x)
67// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
68static inline bool MY_IS_TERMINAL(FILE *x)
69{ 67{
70 return ( 68#ifdef _WIN32
71 #if defined(_MSC_VER) && (_MSC_VER >= 1400) 69 /*
72 _isatty(_fileno(x)) 70crt/stdio.h:
73 #else 71typedef struct _iobuf FILE;
74 isatty(fileno(x)) 72#define stdin (&_iob[0])
75 #endif 73#define stdout (&_iob[1])
76 != 0); 74#define stderr (&_iob[2])
75*/
76 // fprintf(stderr, "\nMY_IS_TERMINAL = %p", x);
77 const int fd = _fileno(x);
78 /* (fd) is 0, 1 or 2 in console program.
79 docs: If stdout or stderr is not associated with
80 an output stream (for example, in a Windows application
81 without a console window), the file descriptor returned is -2.
82 In previous versions, the file descriptor returned was -1.
83 */
84 if (fd < 0) // is not associated with an output stream application (without a console window)
85 return false;
86 // fprintf(stderr, "\n\nstderr _fileno(%p) = %d", x, fd);
87 if (!_isatty(fd))
88 return false;
89 // fprintf(stderr, "\nisatty_val = true");
90 const HANDLE h = (HANDLE)_get_osfhandle(fd);
91 /* _get_osfhandle() returns intptr_t in new SDK, or long in MSVC6.
92 Also it can return (INVALID_HANDLE_VALUE).
93 docs: _get_osfhandle also returns the special value -2 when
94 the file descriptor is not associated with a stream
95 in old msvcrt.dll: it returns (-1) for incorrect value
96 */
97 // fprintf(stderr, "\n_get_osfhandle() = %p", (void *)h);
98 if (h == NULL || h == INVALID_HANDLE_VALUE)
99 return false;
100 DWORD st;
101 // fprintf(stderr, "\nGetConsoleMode() = %u", (unsigned)GetConsoleMode(h, &st));
102 return GetConsoleMode(h, &st) != 0;
103#else
104 return isatty(fileno(x)) != 0;
105#endif
77} 106}
78 107
79#endif 108#endif
@@ -312,7 +341,7 @@ static const CSwitchForm kSwitchForms[] =
312 { "spf", SWFRM_STRING_SINGL(0) }, 341 { "spf", SWFRM_STRING_SINGL(0) },
313 342
314 { "snh", SWFRM_MINUS }, 343 { "snh", SWFRM_MINUS },
315 { "snld", SWFRM_MINUS }, 344 { "snld", SWFRM_STRING },
316 { "snl", SWFRM_MINUS }, 345 { "snl", SWFRM_MINUS },
317 { "sni", SWFRM_SIMPLE }, 346 { "sni", SWFRM_SIMPLE },
318 347
@@ -1088,7 +1117,7 @@ void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
1088 const UString &s = parser[NKey::kLargePages].PostStrings[0]; 1117 const UString &s = parser[NKey::kLargePages].PostStrings[0];
1089 if (s.IsEmpty()) 1118 if (s.IsEmpty())
1090 slp = 1; 1119 slp = 1;
1091 else if (s != L"-") 1120 else if (!s.IsEqualTo("-"))
1092 { 1121 {
1093 if (!StringToUInt32(s, slp)) 1122 if (!StringToUInt32(s, slp))
1094 throw CArcCmdLineException("Unsupported switch postfix for -slp", s); 1123 throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
@@ -1338,7 +1367,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1338 const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; 1367 const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
1339 if (!s.IsEmpty()) 1368 if (!s.IsEmpty())
1340 { 1369 {
1341 if (s == L"2") 1370 if (s.IsEqualTo("2"))
1342 censorPathMode = NWildcard::k_FullPath; 1371 censorPathMode = NWildcard::k_FullPath;
1343 else 1372 else
1344 throw CArcCmdLineException("Unsupported -spf:", s); 1373 throw CArcCmdLineException("Unsupported -spf:", s);
@@ -1400,6 +1429,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1400 const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); 1429 const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
1401 const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; 1430 const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
1402 const bool isRename = options.Command.CommandType == NCommandType::kRename; 1431 const bool isRename = options.Command.CommandType == NCommandType::kRename;
1432 options.UpdateOptions.RenameMode = isRename;
1403 1433
1404 if ((isExtractOrList || isRename) && options.StdInMode) 1434 if ((isExtractOrList || isRename) && options.StdInMode)
1405 thereIsArchiveName = false; 1435 thereIsArchiveName = false;
@@ -1449,14 +1479,8 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1449 1479
1450 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); 1480 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
1451 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); 1481 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
1452
1453 CBoolPair symLinks_AllowDangerous;
1454 SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
1455
1456
1457 /* 1482 /*
1458 bool supportSymLink = options.SymLinks.Val; 1483 bool supportSymLink = options.SymLinks.Val;
1459
1460 if (!options.SymLinks.Def) 1484 if (!options.SymLinks.Def)
1461 { 1485 {
1462 if (isExtractOrList) 1486 if (isExtractOrList)
@@ -1464,7 +1488,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1464 else 1488 else
1465 supportSymLink = false; 1489 supportSymLink = false;
1466 } 1490 }
1467
1468 #ifdef ENV_HAVE_LSTAT 1491 #ifdef ENV_HAVE_LSTAT
1469 if (supportSymLink) 1492 if (supportSymLink)
1470 global_use_lstat = 1; 1493 global_use_lstat = 1;
@@ -1473,7 +1496,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1473 #endif 1496 #endif
1474 */ 1497 */
1475 1498
1476
1477 if (isExtractOrList) 1499 if (isExtractOrList)
1478 { 1500 {
1479 CExtractOptionsBase &eo = options.ExtractOptions; 1501 CExtractOptionsBase &eo = options.ExtractOptions;
@@ -1497,7 +1519,15 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1497 if (!options.SymLinks.Def) 1519 if (!options.SymLinks.Def)
1498 nt.SymLinks.Val = true; 1520 nt.SymLinks.Val = true;
1499 1521
1500 nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; 1522 if (parser[NKey::kSymLinks_AllowDangerous].ThereIs)
1523 {
1524 const UString &s = parser[NKey::kSymLinks_AllowDangerous].PostStrings[0];
1525 UInt32 v = 9; // default value for "-snld" instead of default = 5 without "-snld".
1526 if (!s.IsEmpty())
1527 if (!StringToUInt32(s, v))
1528 throw CArcCmdLineException("Unsupported switch postfix -snld", s);
1529 nt.SymLinks_DangerousLevel = (unsigned)v;
1530 }
1501 1531
1502 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; 1532 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
1503 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; 1533 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
@@ -1516,9 +1546,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1516 const UString &s = parser[NKey::kZoneFile].PostStrings[0]; 1546 const UString &s = parser[NKey::kZoneFile].PostStrings[0];
1517 if (!s.IsEmpty()) 1547 if (!s.IsEmpty())
1518 { 1548 {
1519 if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; 1549 if (s.IsEqualTo("0")) eo.ZoneMode = NExtract::NZoneIdMode::kNone;
1520 else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; 1550 else if (s.IsEqualTo("1")) eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1521 else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; 1551 else if (s.IsEqualTo("2")) eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
1522 else 1552 else
1523 throw CArcCmdLineException("Unsupported -snz:", s); 1553 throw CArcCmdLineException("Unsupported -snz:", s);
1524 } 1554 }
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index 2d32694..6631629 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -6,12 +6,10 @@
6#undef printf 6#undef printf
7 7
8// #include <stdio.h> 8// #include <stdio.h>
9// #include "../../../../C/CpuTicks.h"
10 9
11#include "../../../../C/Alloc.h" 10#include "../../../../C/Alloc.h"
12#include "../../../../C/CpuArch.h" 11#include "../../../../C/CpuArch.h"
13 12
14
15#include "../../../Common/ComTry.h" 13#include "../../../Common/ComTry.h"
16#include "../../../Common/IntToString.h" 14#include "../../../Common/IntToString.h"
17#include "../../../Common/StringConvert.h" 15#include "../../../Common/StringConvert.h"
@@ -33,6 +31,8 @@
33#include "../../Common/FilePathAutoRename.h" 31#include "../../Common/FilePathAutoRename.h"
34#include "../../Common/StreamUtils.h" 32#include "../../Common/StreamUtils.h"
35 33
34#include "../../Archive/Common/ItemNameUtils.h"
35
36#include "../Common/ExtractingFilePath.h" 36#include "../Common/ExtractingFilePath.h"
37#include "../Common/PropIDUtils.h" 37#include "../Common/PropIDUtils.h"
38 38
@@ -54,6 +54,23 @@ static const char * const kCantSetFileLen = "Cannot set length for output file";
54#ifdef SUPPORT_LINKS 54#ifdef SUPPORT_LINKS
55static const char * const kCantCreateHardLink = "Cannot create hard link"; 55static const char * const kCantCreateHardLink = "Cannot create hard link";
56static const char * const kCantCreateSymLink = "Cannot create symbolic link"; 56static const char * const kCantCreateSymLink = "Cannot create symbolic link";
57static const char * const k_HardLink_to_SymLink_Ignored = "Hard link to symbolic link was ignored";
58static const char * const k_CantDelete_File_for_SymLink = "Cannot delete file for symbolic link creation";
59static const char * const k_CantDelete_Dir_for_SymLink = "Cannot delete directory for symbolic link creation";
60#endif
61
62static const unsigned k_LinkDataSize_LIMIT = 1 << 12;
63
64#ifdef SUPPORT_LINKS
65#if WCHAR_PATH_SEPARATOR != L'/'
66 // we convert linux slashes to windows slashes for further processing.
67 // also we convert linux backslashes to BackslashReplacement character.
68 #define REPLACE_SLASHES_from_Linux_to_Sys(s) \
69 { NArchive::NItemName::ReplaceToWinSlashes(s, true); } // useBackslashReplacement
70 // { s.Replace(L'/', WCHAR_PATH_SEPARATOR); }
71#else
72 #define REPLACE_SLASHES_from_Linux_to_Sys(s)
73#endif
57#endif 74#endif
58 75
59#ifndef Z7_SFX 76#ifndef Z7_SFX
@@ -140,21 +157,25 @@ static bool FindExt2(const char *p, const UString &name)
140} 157}
141 158
142 159
143static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); 160static const char * const k_ZoneId_StreamName_With_Colon_Prefix = ":Zone.Identifier";
144 161
145void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf) 162bool Is_ZoneId_StreamName(const wchar_t *s)
146{ 163{
147 FString fileName (fileName2); 164 return StringsAreEqualNoCase_Ascii(s, k_ZoneId_StreamName_With_Colon_Prefix + 1);
148 fileName += k_ZoneId_StreamName; 165}
149 166
167void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf)
168{
150 buf.Free(); 169 buf.Free();
170 FString path (fileName);
171 path += k_ZoneId_StreamName_With_Colon_Prefix;
151 NIO::CInFile file; 172 NIO::CInFile file;
152 if (!file.Open(fileName)) 173 if (!file.Open(path))
153 return; 174 return;
154 UInt64 fileSize; 175 UInt64 fileSize;
155 if (!file.GetLength(fileSize)) 176 if (!file.GetLength(fileSize))
156 return; 177 return;
157 if (fileSize == 0 || fileSize >= ((UInt32)1 << 16)) 178 if (fileSize == 0 || fileSize >= (1u << 15))
158 return; 179 return;
159 buf.Alloc((size_t)fileSize); 180 buf.Alloc((size_t)fileSize);
160 size_t processed; 181 size_t processed;
@@ -166,7 +187,7 @@ void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf)
166bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf) 187bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf)
167{ 188{
168 FString path (fileName); 189 FString path (fileName);
169 path += k_ZoneId_StreamName; 190 path += k_ZoneId_StreamName_With_Colon_Prefix;
170 NIO::COutFile file; 191 NIO::COutFile file;
171 if (!file.Create_ALWAYS(path)) 192 if (!file.Create_ALWAYS(path))
172 return false; 193 return false;
@@ -213,7 +234,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
213 if (!_arc->Ask_INode) 234 if (!_arc->Ask_INode)
214 return S_OK; 235 return S_OK;
215 236
216 IInArchive *archive = _arc->Archive; 237 IInArchive * const archive = _arc->Archive;
217 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; 238 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;
218 239
219 { 240 {
@@ -275,16 +296,13 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
275 296
276 297
277CArchiveExtractCallback::CArchiveExtractCallback(): 298CArchiveExtractCallback::CArchiveExtractCallback():
278 _arc(NULL), 299 // Write_CTime(true),
279 Write_CTime(true), 300 // Write_ATime(true),
280 Write_ATime(true), 301 // Write_MTime(true),
281 Write_MTime(true),
282 Is_elimPrefix_Mode(false), 302 Is_elimPrefix_Mode(false),
303 _arc(NULL),
283 _multiArchives(false) 304 _multiArchives(false)
284{ 305{
285 LocalProgressSpec = new CLocalProgress();
286 _localProgress = LocalProgressSpec;
287
288 #ifdef Z7_USE_SECURITY_CODE 306 #ifdef Z7_USE_SECURITY_CODE
289 _saclEnabled = InitLocalPrivileges(); 307 _saclEnabled = InitLocalPrivileges();
290 #endif 308 #endif
@@ -293,9 +311,9 @@ CArchiveExtractCallback::CArchiveExtractCallback():
293 311
294void CArchiveExtractCallback::InitBeforeNewArchive() 312void CArchiveExtractCallback::InitBeforeNewArchive()
295{ 313{
296 #if defined(_WIN32) && !defined(UNDER_CE) 314#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
297 ZoneBuf.Free(); 315 ZoneBuf.Free();
298 #endif 316#endif
299} 317}
300 318
301void CArchiveExtractCallback::Init( 319void CArchiveExtractCallback::Init(
@@ -312,37 +330,31 @@ void CArchiveExtractCallback::Init(
312 _outFileStream.Release(); 330 _outFileStream.Release();
313 _bufPtrSeqOutStream.Release(); 331 _bufPtrSeqOutStream.Release();
314 332
315 #ifdef SUPPORT_LINKS 333#ifdef SUPPORT_LINKS
316 _hardLinks.Clear(); 334 _hardLinks.Clear();
317 #endif 335 _postLinks.Clear();
336#endif
318 337
319 #ifdef SUPPORT_ALT_STREAMS 338#ifdef SUPPORT_ALT_STREAMS
320 _renamedFiles.Clear(); 339 _renamedFiles.Clear();
321 #endif 340#endif
322 341
323 _ntOptions = ntOptions; 342 _ntOptions = ntOptions;
324 _wildcardCensor = wildcardCensor; 343 _wildcardCensor = wildcardCensor;
325
326 _stdOutMode = stdOutMode; 344 _stdOutMode = stdOutMode;
327 _testMode = testMode; 345 _testMode = testMode;
328
329 // _progressTotal = 0;
330 // _progressTotal_Defined = false;
331
332 _packTotal = packSize; 346 _packTotal = packSize;
333 _progressTotal = packSize; 347 _progressTotal = packSize;
334 _progressTotal_Defined = true; 348 // _progressTotal = 0;
335 349 // _progressTotal_Defined = false;
350 // _progressTotal_Defined = true;
336 _extractCallback2 = extractCallback2; 351 _extractCallback2 = extractCallback2;
337
338 /* 352 /*
339 _compressProgress.Release(); 353 _compressProgress.Release();
340 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); 354 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
341
342 _callbackMessage.Release(); 355 _callbackMessage.Release();
343 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage); 356 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage);
344 */ 357 */
345
346 _folderArchiveExtractCallback2.Release(); 358 _folderArchiveExtractCallback2.Release();
347 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); 359 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
348 360
@@ -390,7 +402,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size))
390{ 402{
391 COM_TRY_BEGIN 403 COM_TRY_BEGIN
392 _progressTotal = size; 404 _progressTotal = size;
393 _progressTotal_Defined = true; 405 // _progressTotal_Defined = true;
394 if (!_multiArchives && _extractCallback2) 406 if (!_multiArchives && _extractCallback2)
395 return _extractCallback2->SetTotal(size); 407 return _extractCallback2->SetTotal(size);
396 return S_OK; 408 return S_OK;
@@ -430,7 +442,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
430 if (_multiArchives) 442 if (_multiArchives)
431 { 443 {
432 packCur = LocalProgressSpec->InSize; 444 packCur = LocalProgressSpec->InSize;
433 if (completeValue && _progressTotal_Defined) 445 if (completeValue /* && _progressTotal_Defined */)
434 packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal); 446 packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal);
435 completeValue = &packCur; 447 completeValue = &packCur;
436 } 448 }
@@ -443,12 +455,13 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
443Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) 455Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
444{ 456{
445 COM_TRY_BEGIN 457 COM_TRY_BEGIN
446 return _localProgress->SetRatioInfo(inSize, outSize); 458 return LocalProgressSpec.Interface()->SetRatioInfo(inSize, outSize);
447 COM_TRY_END 459 COM_TRY_END
448} 460}
449 461
450 462
451void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) 463void CArchiveExtractCallback::CreateComplexDirectory(
464 const UStringVector &dirPathParts, bool isFinal, FString &fullPath)
452{ 465{
453 // we use (_item.IsDir) in this function 466 // we use (_item.IsDir) in this function
454 467
@@ -480,7 +493,7 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat
480 const UString &s = dirPathParts[i]; 493 const UString &s = dirPathParts[i];
481 fullPath += us2fs(s); 494 fullPath += us2fs(s);
482 495
483 const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir); 496 const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir);
484 497
485 if (fullPath.IsEmpty()) 498 if (fullPath.IsEmpty())
486 { 499 {
@@ -541,7 +554,7 @@ static void AddPathToMessage(UString &s, const FString &path)
541 s += fs2us(path); 554 s += fs2us(path);
542} 555}
543 556
544HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) 557HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) const
545{ 558{
546 UString s (message); 559 UString s (message);
547 AddPathToMessage(s, path); 560 AddPathToMessage(s, path);
@@ -549,7 +562,7 @@ HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FSt
549} 562}
550 563
551 564
552HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) 565HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const
553{ 566{
554 UString s (message); 567 UString s (message);
555 if (errorCode != S_OK) 568 if (errorCode != S_OK)
@@ -561,13 +574,13 @@ HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode,
561 return _extractCallback2->MessageError(s); 574 return _extractCallback2->MessageError(s);
562} 575}
563 576
564HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) 577HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) const
565{ 578{
566 const HRESULT errorCode = GetLastError_noZero_HRESULT(); 579 const HRESULT errorCode = GetLastError_noZero_HRESULT();
567 return SendMessageError_with_Error(errorCode, message, path); 580 return SendMessageError_with_Error(errorCode, message, path);
568} 581}
569 582
570HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) 583HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const
571{ 584{
572 UString s (message); 585 UString s (message);
573 if (errorCode != 0) 586 if (errorCode != 0)
@@ -580,15 +593,32 @@ HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char
580 return _extractCallback2->MessageError(s); 593 return _extractCallback2->MessageError(s);
581} 594}
582 595
596HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError(
597 const char *message, const FString &path1, const FString &path2) const
598{
599 const HRESULT errorCode = GetLastError_noZero_HRESULT();
600 return SendMessageError2(errorCode, message, path1, path2);
601}
602
583#ifndef Z7_SFX 603#ifndef Z7_SFX
584 604
605Z7_CLASS_IMP_COM_1(
606 CGetProp
607 , IGetProp
608)
609public:
610 UInt32 IndexInArc;
611 const CArc *Arc;
612 // UString BaseName; // relative path
613};
614
585Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) 615Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
586{ 616{
587 /* 617 /*
588 if (propID == kpidName) 618 if (propID == kpidBaseName)
589 { 619 {
590 COM_TRY_BEGIN 620 COM_TRY_BEGIN
591 NCOM::CPropVariant prop = Name; 621 NCOM::CPropVariant prop = BaseName;
592 prop.Detach(value); 622 prop.Detach(value);
593 return S_OK; 623 return S_OK;
594 COM_TRY_END 624 COM_TRY_END
@@ -600,38 +630,25 @@ Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
600#endif // Z7_SFX 630#endif // Z7_SFX
601 631
602 632
603#ifdef SUPPORT_LINKS
604
605static UString GetDirPrefixOf(const UString &src)
606{
607 UString s (src);
608 if (!s.IsEmpty())
609 {
610 if (IsPathSepar(s.Back()))
611 s.DeleteBack();
612 int pos = s.ReverseFind_PathSepar();
613 s.DeleteFrom((unsigned)(pos + 1));
614 }
615 return s;
616}
617
618#endif // SUPPORT_LINKS
619
620struct CLinkLevelsInfo 633struct CLinkLevelsInfo
621{ 634{
622 bool IsAbsolute; 635 bool IsAbsolute;
636 bool ParentDirDots_after_NonParent;
623 int LowLevel; 637 int LowLevel;
624 int FinalLevel; 638 int FinalLevel;
625 639
626 void Parse(const UString &path); 640 void Parse(const UString &path, bool isWSL);
627}; 641};
628 642
629void CLinkLevelsInfo::Parse(const UString &path) 643void CLinkLevelsInfo::Parse(const UString &path, bool isWSL)
630{ 644{
631 IsAbsolute = NName::IsAbsolutePath(path); 645 IsAbsolute = isWSL ?
632 646 IS_PATH_SEPAR(path[0]) :
647 NName::IsAbsolutePath(path);
633 LowLevel = 0; 648 LowLevel = 0;
634 FinalLevel = 0; 649 FinalLevel = 0;
650 ParentDirDots_after_NonParent = false;
651 bool nonParentDir = false;
635 652
636 UStringVector parts; 653 UStringVector parts;
637 SplitPathToParts(path, parts); 654 SplitPathToParts(path, parts);
@@ -646,32 +663,41 @@ void CLinkLevelsInfo::Parse(const UString &path)
646 IsAbsolute = true; 663 IsAbsolute = true;
647 continue; 664 continue;
648 } 665 }
649 if (s == L".") 666 if (s.IsEqualTo("."))
650 continue; 667 continue;
651 if (s == L"..") 668 if (s.IsEqualTo(".."))
652 { 669 {
670 if (IsAbsolute || nonParentDir)
671 ParentDirDots_after_NonParent = true;
653 level--; 672 level--;
654 if (LowLevel > level) 673 if (LowLevel > level)
655 LowLevel = level; 674 LowLevel = level;
656 } 675 }
657 else 676 else
677 {
678 nonParentDir = true;
658 level++; 679 level++;
680 }
659 } 681 }
660 682
661 FinalLevel = level; 683 FinalLevel = level;
662} 684}
663 685
664 686
665bool IsSafePath(const UString &path); 687static bool IsSafePath(const UString &path, bool isWSL)
666bool IsSafePath(const UString &path)
667{ 688{
668 CLinkLevelsInfo levelsInfo; 689 CLinkLevelsInfo levelsInfo;
669 levelsInfo.Parse(path); 690 levelsInfo.Parse(path, isWSL);
670 return !levelsInfo.IsAbsolute 691 return !levelsInfo.IsAbsolute
671 && levelsInfo.LowLevel >= 0 692 && levelsInfo.LowLevel >= 0
672 && levelsInfo.FinalLevel > 0; 693 && levelsInfo.FinalLevel > 0;
673} 694}
674 695
696bool IsSafePath(const UString &path);
697bool IsSafePath(const UString &path)
698{
699 return IsSafePath(path, false); // isWSL
700}
675 701
676bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); 702bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
677bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) 703bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
@@ -787,159 +813,113 @@ HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
787 813
788HRESULT CArchiveExtractCallback::ReadLink() 814HRESULT CArchiveExtractCallback::ReadLink()
789{ 815{
790 IInArchive *archive = _arc->Archive; 816 IInArchive * const archive = _arc->Archive;
791 const UInt32 index = _index; 817 const UInt32 index = _index;
792 _link.Clear(); 818 // _link.Clear(); // _link.Clear() was called already.
793
794 { 819 {
795 NCOM::CPropVariant prop; 820 NCOM::CPropVariant prop;
796 RINOK(archive->GetProperty(index, kpidHardLink, &prop)) 821 RINOK(archive->GetProperty(index, kpidHardLink, &prop))
797 if (prop.vt == VT_BSTR) 822 if (prop.vt == VT_BSTR)
798 { 823 {
799 _link.isHardLink = true; 824 _link.LinkType = k_LinkType_HardLink;
800 // _link.isCopyLink = false;
801 _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive 825 _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive
802 _link.linkPath.SetFromBstr(prop.bstrVal); 826 _link.LinkPath.SetFromBstr(prop.bstrVal);
827 // 7-Zip 24-: tar handler returned original path (with linux slash in most case)
828 // 7-Zip 24-: rar5 handler returned path with system slash.
829 // 7-Zip 25+: tar/rar5 handlers return linux path in most cases.
803 } 830 }
804 else if (prop.vt != VT_EMPTY) 831 else if (prop.vt != VT_EMPTY)
805 return E_FAIL; 832 return E_FAIL;
806 } 833 }
807
808 /* 834 /*
809 { 835 {
810 NCOM::CPropVariant prop; 836 NCOM::CPropVariant prop;
811 RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); 837 RINOK(archive->GetProperty(index, kpidCopyLink, &prop));
812 if (prop.vt == VT_BSTR) 838 if (prop.vt == VT_BSTR)
813 { 839 {
814 _link.isHardLink = false; 840 _link.LinkType = k_LinkType_CopyLink;
815 _link.isCopyLink = true;
816 _link.isRelative = false; // RAR5: copy links are from root folder of archive 841 _link.isRelative = false; // RAR5: copy links are from root folder of archive
817 _link.linkPath.SetFromBstr(prop.bstrVal); 842 _link.LinkPath.SetFromBstr(prop.bstrVal);
818 } 843 }
819 else if (prop.vt != VT_EMPTY) 844 else if (prop.vt != VT_EMPTY)
820 return E_FAIL; 845 return E_FAIL;
821 } 846 }
822 */ 847 */
823
824 { 848 {
825 NCOM::CPropVariant prop; 849 NCOM::CPropVariant prop;
826 RINOK(archive->GetProperty(index, kpidSymLink, &prop)) 850 RINOK(archive->GetProperty(index, kpidSymLink, &prop))
827 if (prop.vt == VT_BSTR) 851 if (prop.vt == VT_BSTR)
828 { 852 {
829 _link.isHardLink = false; 853 _link.LinkType = k_LinkType_PureSymLink;
830 // _link.isCopyLink = false; 854 _link.isRelative = true; // RAR5, TAR: symbolic links are relative by default
831 _link.isRelative = true; // RAR5, TAR: symbolic links can be relative 855 _link.LinkPath.SetFromBstr(prop.bstrVal);
832 _link.linkPath.SetFromBstr(prop.bstrVal); 856 // 7-Zip 24-: (tar, cpio, xar, ext, iso) handlers returned returned original path (with linux slash in most case)
857 // 7-Zip 24-: rar5 handler returned path with system slash.
858 // 7-Zip 25+: all handlers return linux path in most cases.
833 } 859 }
834 else if (prop.vt != VT_EMPTY) 860 else if (prop.vt != VT_EMPTY)
835 return E_FAIL; 861 return E_FAIL;
836 } 862 }
837 863
838 NtReparse_Data = NULL; 864 // linux path separator in (_link.LinkPath) is expected for most cases,
839 NtReparse_Size = 0; 865 // if new handler code is used, and if data in archive is correct.
840 866 // NtReparse_Data = NULL;
841 if (_link.linkPath.IsEmpty() && _arc->GetRawProps) 867 // NtReparse_Size = 0;
868 if (!_link.LinkPath.IsEmpty())
869 {
870 REPLACE_SLASHES_from_Linux_to_Sys(_link.LinkPath)
871 }
872 else if (_arc->GetRawProps)
842 { 873 {
843 const void *data; 874 const void *data;
844 UInt32 dataSize; 875 UInt32 dataSize, propType;
845 UInt32 propType; 876 if (_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType) == S_OK
846 877 // && dataSize == 1234567 // for debug: unpacking without reparse
847 _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); 878 && dataSize)
848
849 // if (dataSize == 1234567) // for debug: unpacking without reparse
850 if (dataSize != 0)
851 { 879 {
852 if (propType != NPropDataType::kRaw) 880 if (propType != NPropDataType::kRaw)
853 return E_FAIL; 881 return E_FAIL;
854
855 // 21.06: we need kpidNtReparse in linux for wim archives created in Windows 882 // 21.06: we need kpidNtReparse in linux for wim archives created in Windows
856 // #ifdef _WIN32 883 // NtReparse_Data = data;
857 884 // NtReparse_Size = dataSize;
858 NtReparse_Data = data; 885 // we ignore error code here, if there is failure of parsing:
859 NtReparse_Size = dataSize; 886 _link.Parse_from_WindowsReparseData((const Byte *)data, dataSize);
860
861 CReparseAttr reparse;
862 bool isOkReparse = reparse.Parse((const Byte *)data, dataSize);
863 if (isOkReparse)
864 {
865 _link.isHardLink = false;
866 // _link.isCopyLink = false;
867 _link.linkPath = reparse.GetPath();
868 _link.isJunction = reparse.IsMountPoint();
869
870 if (reparse.IsSymLink_WSL())
871 {
872 _link.isWSL = true;
873 _link.isRelative = reparse.IsRelative_WSL();
874 }
875 else
876 _link.isRelative = reparse.IsRelative_Win();
877
878 // const AString s = GetAnsiString(_link.linkPath);
879 // printf("\n_link.linkPath: %s\n", s.Ptr());
880
881 #ifndef _WIN32
882 _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
883 #endif
884 }
885 // #endif
886 } 887 }
887 } 888 }
888 889
889 if (_link.linkPath.IsEmpty()) 890 if (_link.LinkPath.IsEmpty())
890 return S_OK; 891 return S_OK;
891 892 // (_link.LinkPath) uses system path separator.
893 // windows: (_link.LinkPath) doesn't contain linux separator (slash).
892 { 894 {
893 #ifdef _WIN32 895 // _link.LinkPath = "\\??\\r:\\1\\2"; // for debug
894 _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); 896 // rar5+ returns kpidSymLink absolute link path with "\??\" prefix.
895 #endif 897 // we normalize such prefix:
896 898 if (_link.LinkPath.IsPrefixedBy(STRING_PATH_SEPARATOR "??" STRING_PATH_SEPARATOR))
897 // rar5 uses "\??\" prefix for absolute links
898 if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
899 {
900 _link.isRelative = false;
901 _link.linkPath.DeleteFrontal(4);
902 }
903
904 for (;;)
905 // while (NName::IsAbsolutePath(linkPath))
906 { 899 {
907 unsigned n = NName::GetRootPrefixSize(_link.linkPath);
908 if (n == 0)
909 break;
910 _link.isRelative = false; 900 _link.isRelative = false;
911 _link.linkPath.DeleteFrontal(n); 901 // we normalize prefix from "\??\" to "\\?\":
912 } 902 _link.LinkPath.ReplaceOneCharAtPos(1, WCHAR_PATH_SEPARATOR);
913 } 903 _link.isWindowsPath = true;
914 904 if (_link.LinkPath.IsPrefixedBy_Ascii_NoCase(
915 if (_link.linkPath.IsEmpty()) 905 STRING_PATH_SEPARATOR
916 return S_OK; 906 STRING_PATH_SEPARATOR "?"
917 907 STRING_PATH_SEPARATOR "UNC"
918 if (!_link.isRelative && _removePathParts.Size() != 0) 908 STRING_PATH_SEPARATOR))
919 {
920 UStringVector pathParts;
921 SplitPathToParts(_link.linkPath, pathParts);
922 bool badPrefix = false;
923 FOR_VECTOR (i, _removePathParts)
924 {
925 if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
926 { 909 {
927 badPrefix = true; 910 // we normalize prefix from "\\?\UNC\path" to "\\path":
928 break; 911 _link.LinkPath.DeleteFrontal(6);
912 _link.LinkPath.ReplaceOneCharAtPos(0, WCHAR_PATH_SEPARATOR);
913 }
914 else
915 {
916 const unsigned k_prefix_Size = 4;
917 if (NName::IsDrivePath(_link.LinkPath.Ptr(k_prefix_Size)))
918 _link.LinkPath.DeleteFrontal(k_prefix_Size);
929 } 919 }
930 } 920 }
931 if (!badPrefix)
932 pathParts.DeleteFrontal(_removePathParts.Size());
933 _link.linkPath = MakePathFromParts(pathParts);
934 }
935
936 /*
937 if (!_link.linkPath.IsEmpty())
938 {
939 printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr());
940 } 921 }
941 */ 922 _link.Normalize_to_RelativeSafe(_removePathParts);
942
943 return S_OK; 923 return S_OK;
944} 924}
945 925
@@ -949,7 +929,7 @@ HRESULT CArchiveExtractCallback::ReadLink()
949#ifndef _WIN32 929#ifndef _WIN32
950 930
951static HRESULT GetOwner(IInArchive *archive, 931static HRESULT GetOwner(IInArchive *archive,
952 UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) 932 UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res)
953{ 933{
954 { 934 {
955 NWindows::NCOM::CPropVariant prop; 935 NWindows::NCOM::CPropVariant prop;
@@ -957,7 +937,7 @@ static HRESULT GetOwner(IInArchive *archive,
957 if (prop.vt == VT_UI4) 937 if (prop.vt == VT_UI4)
958 { 938 {
959 res.Id_Defined = true; 939 res.Id_Defined = true;
960 res.Id = prop.ulVal; // for debug 940 res.Id = prop.ulVal;
961 // res.Id++; // for debug 941 // res.Id++; // for debug
962 // if (pidId == kpidGroupId) res.Id += 7; // for debug 942 // if (pidId == kpidGroupId) res.Id += 7; // for debug
963 // res.Id = 0; // for debug 943 // res.Id = 0; // for debug
@@ -989,7 +969,7 @@ static HRESULT GetOwner(IInArchive *archive,
989 969
990HRESULT CArchiveExtractCallback::Read_fi_Props() 970HRESULT CArchiveExtractCallback::Read_fi_Props()
991{ 971{
992 IInArchive *archive = _arc->Archive; 972 IInArchive * const archive = _arc->Archive;
993 const UInt32 index = _index; 973 const UInt32 index = _index;
994 974
995 _fi.Attrib_Defined = false; 975 _fi.Attrib_Defined = false;
@@ -1081,35 +1061,35 @@ void CArchiveExtractCallback::CorrectPathParts()
1081} 1061}
1082 1062
1083 1063
1084void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) 1064static void GetFiTimesCAM(const CProcessedFileInfo &fi, CFiTimesCAM &pt, const CArc &arc)
1085{ 1065{
1086 pt.CTime_Defined = false; 1066 pt.CTime_Defined = false;
1087 pt.ATime_Defined = false; 1067 pt.ATime_Defined = false;
1088 pt.MTime_Defined = false; 1068 pt.MTime_Defined = false;
1089 1069
1090 if (Write_MTime) 1070 // if (Write_MTime)
1091 { 1071 {
1092 if (_fi.MTime.Def) 1072 if (fi.MTime.Def)
1093 { 1073 {
1094 _fi.MTime.Write_To_FiTime(pt.MTime); 1074 fi.MTime.Write_To_FiTime(pt.MTime);
1095 pt.MTime_Defined = true; 1075 pt.MTime_Defined = true;
1096 } 1076 }
1097 else if (_arc->MTime.Def) 1077 else if (arc.MTime.Def)
1098 { 1078 {
1099 _arc->MTime.Write_To_FiTime(pt.MTime); 1079 arc.MTime.Write_To_FiTime(pt.MTime);
1100 pt.MTime_Defined = true; 1080 pt.MTime_Defined = true;
1101 } 1081 }
1102 } 1082 }
1103 1083
1104 if (Write_CTime && _fi.CTime.Def) 1084 if (/* Write_CTime && */ fi.CTime.Def)
1105 { 1085 {
1106 _fi.CTime.Write_To_FiTime(pt.CTime); 1086 fi.CTime.Write_To_FiTime(pt.CTime);
1107 pt.CTime_Defined = true; 1087 pt.CTime_Defined = true;
1108 } 1088 }
1109 1089
1110 if (Write_ATime && _fi.ATime.Def) 1090 if (/* Write_ATime && */ fi.ATime.Def)
1111 { 1091 {
1112 _fi.ATime.Write_To_FiTime(pt.ATime); 1092 fi.ATime.Write_To_FiTime(pt.ATime);
1113 pt.ATime_Defined = true; 1093 pt.ATime_Defined = true;
1114 } 1094 }
1115} 1095}
@@ -1120,6 +1100,7 @@ void CArchiveExtractCallback::CreateFolders()
1120 // 21.04 : we don't change original (_item.PathParts) here 1100 // 21.04 : we don't change original (_item.PathParts) here
1121 UStringVector pathParts = _item.PathParts; 1101 UStringVector pathParts = _item.PathParts;
1122 1102
1103 bool isFinal = true;
1123 // bool is_DirOp = false; 1104 // bool is_DirOp = false;
1124 if (!pathParts.IsEmpty()) 1105 if (!pathParts.IsEmpty())
1125 { 1106 {
@@ -1129,12 +1110,15 @@ void CArchiveExtractCallback::CreateFolders()
1129 but if we create dir item here, it's not problem. */ 1110 but if we create dir item here, it's not problem. */
1130 if (!_item.IsDir 1111 if (!_item.IsDir
1131 #ifdef SUPPORT_LINKS 1112 #ifdef SUPPORT_LINKS
1132 #ifndef WIN32 1113 // #ifndef WIN32
1133 || !_link.linkPath.IsEmpty() 1114 || !_link.LinkPath.IsEmpty()
1134 #endif 1115 // #endif
1135 #endif 1116 #endif
1136 ) 1117 )
1118 {
1137 pathParts.DeleteBack(); 1119 pathParts.DeleteBack();
1120 isFinal = false; // last path part was excluded
1121 }
1138 // else is_DirOp = true; 1122 // else is_DirOp = true;
1139 } 1123 }
1140 1124
@@ -1158,7 +1142,7 @@ void CArchiveExtractCallback::CreateFolders()
1158 */ 1142 */
1159 1143
1160 FString fullPathNew; 1144 FString fullPathNew;
1161 CreateComplexDirectory(pathParts, fullPathNew); 1145 CreateComplexDirectory(pathParts, isFinal, fullPathNew);
1162 1146
1163 /* 1147 /*
1164 if (is_DirOp) 1148 if (is_DirOp)
@@ -1179,12 +1163,12 @@ void CArchiveExtractCallback::CreateFolders()
1179 return; 1163 return;
1180 1164
1181 CDirPathTime pt; 1165 CDirPathTime pt;
1182 GetFiTimesCAM(pt); 1166 GetFiTimesCAM(_fi, pt, *_arc);
1183 1167
1184 if (pt.IsSomeTimeDefined()) 1168 if (pt.IsSomeTimeDefined())
1185 { 1169 {
1186 pt.Path = fullPathNew; 1170 pt.Path = fullPathNew;
1187 pt.SetDirTime(); 1171 pt.SetDirTime_to_FS_2();
1188 _extractedFolders.Add(pt); 1172 _extractedFolders.Add(pt);
1189 } 1173 }
1190} 1174}
@@ -1269,8 +1253,7 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1269 // MyMoveFile can rename folders. So it's OK to use it for folders too 1253 // MyMoveFile can rename folders. So it's OK to use it for folders too
1270 if (!MyMoveFile(fullProcessedPath, existPath)) 1254 if (!MyMoveFile(fullProcessedPath, existPath))
1271 { 1255 {
1272 HRESULT errorCode = GetLastError_noZero_HRESULT(); 1256 RINOK(SendMessageError2_with_LastError(kCantRenameFile, existPath, fullProcessedPath))
1273 RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath))
1274 return E_FAIL; 1257 return E_FAIL;
1275 } 1258 }
1276 } 1259 }
@@ -1302,7 +1285,7 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1302 { 1285 {
1303 #if defined(_WIN32) && !defined(UNDER_CE) 1286 #if defined(_WIN32) && !defined(UNDER_CE)
1304 // we need to clear READ-ONLY of parent before creating alt stream 1287 // we need to clear READ-ONLY of parent before creating alt stream
1305 int colonPos = NName::FindAltStreamColon(fullProcessedPath); 1288 const int colonPos = NName::FindAltStreamColon(fullProcessedPath);
1306 if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0) 1289 if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)
1307 { 1290 {
1308 FString parentFsPath (fullProcessedPath); 1291 FString parentFsPath (fullProcessedPath);
@@ -1311,7 +1294,11 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1311 if (parentFi.Find(parentFsPath)) 1294 if (parentFi.Find(parentFsPath))
1312 { 1295 {
1313 if (parentFi.IsReadOnly()) 1296 if (parentFi.IsReadOnly())
1297 {
1298 _altStream_NeedRestore_Attrib_for_parentFsPath = parentFsPath;
1299 _altStream_NeedRestore_AttribVal = parentFi.Attrib;
1314 SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY); 1300 SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY);
1301 }
1315 } 1302 }
1316 } 1303 }
1317 #endif // defined(_WIN32) && !defined(UNDER_CE) 1304 #endif // defined(_WIN32) && !defined(UNDER_CE)
@@ -1323,9 +1310,11 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1323 1310
1324 1311
1325 1312
1326 1313/*
1327 1314return:
1328 1315 needExit = false: caller will use (outStreamLoc) and _hashStreamSpec
1316 needExit = true : caller will not use (outStreamLoc) and _hashStreamSpec.
1317*/
1329HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit) 1318HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit)
1330{ 1319{
1331 needExit = true; 1320 needExit = true;
@@ -1333,7 +1322,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1333 RINOK(Read_fi_Props()) 1322 RINOK(Read_fi_Props())
1334 1323
1335 #ifdef SUPPORT_LINKS 1324 #ifdef SUPPORT_LINKS
1336 IInArchive *archive = _arc->Archive; 1325 IInArchive * const archive = _arc->Archive;
1337 #endif 1326 #endif
1338 1327
1339 const UInt32 index = _index; 1328 const UInt32 index = _index;
@@ -1379,7 +1368,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1379 if (isAnti) 1368 if (isAnti)
1380 RemoveDir(_diskFilePath); 1369 RemoveDir(_diskFilePath);
1381 #ifdef SUPPORT_LINKS 1370 #ifdef SUPPORT_LINKS
1382 if (_link.linkPath.IsEmpty()) 1371 if (_link.LinkPath.IsEmpty())
1383 #endif 1372 #endif
1384 { 1373 {
1385 if (!isAnti) 1374 if (!isAnti)
@@ -1408,18 +1397,21 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1408 1397
1409 #ifdef SUPPORT_LINKS 1398 #ifdef SUPPORT_LINKS
1410 1399
1411 if (!_link.linkPath.IsEmpty()) 1400 if (!_link.LinkPath.IsEmpty())
1412 { 1401 {
1413 #ifndef UNDER_CE 1402 #ifndef UNDER_CE
1414 { 1403 {
1415 bool linkWasSet = false; 1404 bool linkWasSet = false;
1416 RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet)) 1405 RINOK(SetLink(fullProcessedPath, _link, linkWasSet))
1406/*
1407 // we don't set attributes for placeholder.
1417 if (linkWasSet) 1408 if (linkWasSet)
1418 { 1409 {
1419 _isSymLinkCreated = _link.IsSymLink(); 1410 _isSymLinkCreated = _link.Is_AnySymLink();
1420 SetAttrib(); 1411 SetAttrib();
1421 // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); 1412 // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath));
1422 } 1413 }
1414*/
1423 } 1415 }
1424 #endif // UNDER_CE 1416 #endif // UNDER_CE
1425 1417
@@ -1445,16 +1437,17 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1445 hl = fullProcessedPath; 1437 hl = fullProcessedPath;
1446 else 1438 else
1447 { 1439 {
1448 if (!MyCreateHardLink(fullProcessedPath, hl)) 1440 bool link_was_Created = false;
1449 { 1441 RINOK(CreateHardLink2(fullProcessedPath, hl, link_was_Created))
1450 const HRESULT errorCode = GetLastError_noZero_HRESULT(); 1442 if (!link_was_Created)
1451 RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl))
1452 return S_OK; 1443 return S_OK;
1453 }
1454
1455 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); 1444 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
1456 // _needSetAttrib = true; // do we need to set attribute ? 1445 // _needSetAttrib = true; // do we need to set attribute ?
1457 SetAttrib(); 1446 SetAttrib();
1447 /* if we set (needExit = false) here, _hashStreamSpec will be used,
1448 and hash will be calulated for all hard links files (it's slower).
1449 But "Test" operation also calculates hashes.
1450 */
1458 needExit = false; 1451 needExit = false;
1459 return S_OK; 1452 return S_OK;
1460 } 1453 }
@@ -1483,7 +1476,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1483 1476
1484 bool is_SymLink_in_Data = false; 1477 bool is_SymLink_in_Data = false;
1485 1478
1486 if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12)) 1479 if (_curSize_Defined && _curSize && _curSize < k_LinkDataSize_LIMIT)
1487 { 1480 {
1488 if (_fi.IsLinuxSymLink()) 1481 if (_fi.IsLinuxSymLink())
1489 { 1482 {
@@ -1505,7 +1498,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1505 _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); 1498 _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size());
1506 outStreamLoc = _bufPtrSeqOutStream; 1499 outStreamLoc = _bufPtrSeqOutStream;
1507 } 1500 }
1508 else // not reprase 1501 else // not reparse
1509 { 1502 {
1510 if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) 1503 if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12))
1511 { 1504 {
@@ -1560,7 +1553,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1560 RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) 1553 RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL))
1561 } 1554 }
1562 outStreamLoc = outFileStream_Loc; 1555 outStreamLoc = outFileStream_Loc;
1563 } // if not reprase 1556 } // if not reparse
1564 1557
1565 _outFileStream = outFileStream_Loc; 1558 _outFileStream = outFileStream_Loc;
1566 1559
@@ -1607,37 +1600,36 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1607 _bufPtrSeqOutStream.Release(); 1600 _bufPtrSeqOutStream.Release();
1608 1601
1609 _encrypted = false; 1602 _encrypted = false;
1610 _position = 0;
1611 _isSplit = false; 1603 _isSplit = false;
1612
1613 _curSize = 0;
1614 _curSize_Defined = false; 1604 _curSize_Defined = false;
1615 _fileLength_WasSet = false; 1605 _fileLength_WasSet = false;
1616 _fileLength_that_WasSet = 0;
1617 _index = index;
1618
1619 _diskFilePath.Empty();
1620
1621 _isRenamed = false; 1606 _isRenamed = false;
1622
1623 // _fi.Clear(); 1607 // _fi.Clear();
1624 1608 _extractMode = false;
1625 // _is_SymLink_in_Data = false;
1626 _is_SymLink_in_Data_Linux = false; 1609 _is_SymLink_in_Data_Linux = false;
1627
1628 _needSetAttrib = false; 1610 _needSetAttrib = false;
1629 _isSymLinkCreated = false; 1611 _isSymLinkCreated = false;
1630 _itemFailure = false; 1612 _itemFailure = false;
1631
1632 _some_pathParts_wereRemoved = false; 1613 _some_pathParts_wereRemoved = false;
1633 // _op_WasReported = false; 1614 // _op_WasReported = false;
1634 1615
1616 _position = 0;
1617 _curSize = 0;
1618 _fileLength_that_WasSet = 0;
1619 _index = index;
1620
1621#if defined(_WIN32) && !defined(UNDER_CE)
1622 _altStream_NeedRestore_AttribVal = 0;
1623 _altStream_NeedRestore_Attrib_for_parentFsPath.Empty();
1624#endif
1625
1626 _diskFilePath.Empty();
1627
1635 #ifdef SUPPORT_LINKS 1628 #ifdef SUPPORT_LINKS
1636 // _copyFile_Path.Empty(); 1629 // _copyFile_Path.Empty();
1637 _link.Clear(); 1630 _link.Clear();
1638 #endif 1631 #endif
1639 1632
1640 _extractMode = false;
1641 1633
1642 switch (askExtractMode) 1634 switch (askExtractMode)
1643 { 1635 {
@@ -1653,7 +1645,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1653 } 1645 }
1654 1646
1655 1647
1656 IInArchive *archive = _arc->Archive; 1648 IInArchive * const archive = _arc->Archive;
1657 1649
1658 RINOK(GetItem(index)) 1650 RINOK(GetItem(index))
1659 1651
@@ -1669,10 +1661,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1669 } 1661 }
1670 } 1662 }
1671 1663
1672 #ifdef SUPPORT_LINKS 1664#ifdef SUPPORT_LINKS
1673 RINOK(ReadLink()) 1665 RINOK(ReadLink())
1674 #endif // SUPPORT_LINKS 1666#endif
1675
1676 1667
1677 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) 1668 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted))
1678 1669
@@ -1692,6 +1683,19 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1692 return S_OK; 1683 return S_OK;
1693 } 1684 }
1694 1685
1686#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
1687 if (askExtractMode == NArchive::NExtract::NAskMode::kExtract
1688 && !_testMode
1689 && _item.IsAltStream
1690 && ZoneBuf.Size() != 0
1691 && Is_ZoneId_StreamName(_item.AltStreamName))
1692 if (ZoneMode != NExtract::NZoneIdMode::kOffice
1693 || _item.PathParts.IsEmpty()
1694 || FindExt2(kOfficeExtensions, _item.PathParts.Back()))
1695 return S_OK;
1696#endif
1697
1698
1695 #ifndef Z7_SFX 1699 #ifndef Z7_SFX
1696 if (_use_baseParentFolder_mode) 1700 if (_use_baseParentFolder_mode)
1697 { 1701 {
@@ -1810,15 +1814,11 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1810 1814
1811 if (ExtractToStreamCallback) 1815 if (ExtractToStreamCallback)
1812 { 1816 {
1813 if (!GetProp) 1817 CMyComPtr2_Create<IGetProp, CGetProp> GetProp;
1814 { 1818 GetProp->Arc = _arc;
1815 GetProp_Spec = new CGetProp; 1819 GetProp->IndexInArc = index;
1816 GetProp = GetProp_Spec;
1817 }
1818 GetProp_Spec->Arc = _arc;
1819 GetProp_Spec->IndexInArc = index;
1820 UString name (MakePathFromParts(pathParts)); 1820 UString name (MakePathFromParts(pathParts));
1821 1821 // GetProp->BaseName = name;
1822 #ifdef SUPPORT_ALT_STREAMS 1822 #ifdef SUPPORT_ALT_STREAMS
1823 if (_item.IsAltStream) 1823 if (_item.IsAltStream)
1824 { 1824 {
@@ -1972,7 +1972,7 @@ HRESULT CArchiveExtractCallback::CloseFile()
1972 #endif 1972 #endif
1973 1973
1974 CFiTimesCAM t; 1974 CFiTimesCAM t;
1975 GetFiTimesCAM(t); 1975 GetFiTimesCAM(_fi, t, *_arc);
1976 1976
1977 // #ifdef _WIN32 1977 // #ifdef _WIN32
1978 if (t.IsSomeTimeDefined()) 1978 if (t.IsSomeTimeDefined())
@@ -1984,94 +1984,290 @@ HRESULT CArchiveExtractCallback::CloseFile()
1984 1984
1985 RINOK(_outFileStreamSpec->Close()) 1985 RINOK(_outFileStreamSpec->Close())
1986 _outFileStream.Release(); 1986 _outFileStream.Release();
1987
1988#if defined(_WIN32) && !defined(UNDER_CE)
1989 if (!_altStream_NeedRestore_Attrib_for_parentFsPath.IsEmpty())
1990 {
1991 SetFileAttrib(_altStream_NeedRestore_Attrib_for_parentFsPath, _altStream_NeedRestore_AttribVal);
1992 _altStream_NeedRestore_Attrib_for_parentFsPath.Empty();
1993 }
1994#endif
1995
1987 return hres; 1996 return hres;
1988} 1997}
1989 1998
1990 1999
1991#ifdef SUPPORT_LINKS 2000#ifdef SUPPORT_LINKS
1992 2001
2002static bool CheckLinkPath_in_FS_for_pathParts(const FString &path, const UStringVector &v)
2003{
2004 FString path2 = path;
2005 FOR_VECTOR (i, v)
2006 {
2007 // if (i == v.Size() - 1) path = path2; // we don't need last part in returned path
2008 path2 += us2fs(v[i]);
2009 NFind::CFileInfo fi;
2010 // printf("\nCheckLinkPath_in_FS_for_pathParts(): %s\n", GetOemString(path2).Ptr());
2011 if (fi.Find(path2) && fi.IsOsSymLink())
2012 return false;
2013 path2.Add_PathSepar();
2014 }
2015 return true;
2016}
2017
2018/*
2019link.isRelative / relative_item_PathPrefix
2020 false / empty
2021 true / item path without last part
2022*/
2023static bool CheckLinkPath_in_FS(
2024 const FString &pathPrefix_in_FS,
2025 const CPostLink &postLink,
2026 const UString &relative_item_PathPrefix)
2027{
2028 const CLinkInfo &link = postLink.LinkInfo;
2029 if (postLink.item_PathParts.IsEmpty() || link.LinkPath.IsEmpty())
2030 return false;
2031 FString path;
2032 {
2033 const UString &s = postLink.item_PathParts[0];
2034 if (!s.IsEmpty() && !NName::IsAbsolutePath(s))
2035 path = pathPrefix_in_FS; // item_PathParts is relative. So we use absolutre prefix
2036 }
2037 if (!CheckLinkPath_in_FS_for_pathParts(path, postLink.item_PathParts))
2038 return false;
2039 path += us2fs(relative_item_PathPrefix);
2040 UStringVector v;
2041 SplitPathToParts(link.LinkPath, v);
2042 // we check target paths:
2043 return CheckLinkPath_in_FS_for_pathParts(path, v);
2044}
1993 2045
1994HRESULT CArchiveExtractCallback::SetFromLinkPath( 2046static const unsigned k_DangLevel_MAX_for_Link_over_Link = 9;
1995 const FString &fullProcessedPath, 2047
1996 const CLinkInfo &linkInfo, 2048HRESULT CArchiveExtractCallback::CreateHardLink2(
1997 bool &linkWasSet) 2049 const FString &newFilePath, const FString &existFilePath, bool &link_was_Created) const
2050{
2051 link_was_Created = false;
2052 if (_ntOptions.SymLinks_DangerousLevel <= k_DangLevel_MAX_for_Link_over_Link)
2053 {
2054 NFind::CFileInfo fi;
2055 if (fi.Find(existFilePath) && fi.IsOsSymLink())
2056 return SendMessageError2(0, k_HardLink_to_SymLink_Ignored, newFilePath, existFilePath);
2057 }
2058 if (!MyCreateHardLink(newFilePath, existFilePath))
2059 return SendMessageError2_with_LastError(kCantCreateHardLink, newFilePath, existFilePath);
2060 link_was_Created = true;
2061 return S_OK;
2062}
2063
2064
2065
2066HRESULT CArchiveExtractCallback::SetLink(
2067 const FString &fullProcessedPath_from,
2068 const CLinkInfo &link,
2069 bool &linkWasSet) // placeholder was created
1998{ 2070{
1999 linkWasSet = false; 2071 linkWasSet = false;
2000 if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink) 2072 if (link.LinkPath.IsEmpty())
2073 return S_OK;
2074 if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink())
2001 return S_OK; 2075 return S_OK;
2076 CPostLink postLink;
2077 postLink.Index_in_Arc = _index;
2078 postLink.item_IsDir = _item.IsDir;
2079 postLink.item_Path = _item.Path;
2080 postLink.item_PathParts = _item.PathParts;
2081 postLink.item_FileInfo = _fi;
2082 postLink.fullProcessedPath_from = fullProcessedPath_from;
2083 postLink.LinkInfo = link;
2084 _postLinks.Add(postLink);
2085
2086 // file doesn't exist in most cases. So we don't check for error.
2087 DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, false); // checkThatFileIsEmpty = false
2002 2088
2003 UString relatPath; 2089 NIO::COutFile outFile;
2090 if (!outFile.Create_NEW(fullProcessedPath_from))
2091 return SendMessageError("Cannot create temporary link file", fullProcessedPath_from);
2092#if 0 // 1 for debug
2093 // here we can write link path to temporary link file placeholder,
2094 // but empty placeholder is better, because we don't want to get any non-eampty data instead of link file.
2095 AString s;
2096 ConvertUnicodeToUTF8(link.LinkPath, s);
2097 outFile.WriteFull(s, s.Len());
2098#endif
2099 linkWasSet = true;
2100 return S_OK;
2101}
2004 2102
2005 /* if (linkInfo.isRelative) 2103
2006 linkInfo.linkPath is final link path that must be stored to file link field 2104// if file/dir is symbolic link it will remove only link itself
2007 else 2105HRESULT CArchiveExtractCallback::DeleteLinkFileAlways_or_RemoveEmptyDir(
2008 linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath. 2106 const FString &path, bool checkThatFileIsEmpty) const
2009 */ 2107{
2010 2108 NFile::NFind::CFileInfo fi;
2011 if (linkInfo.isRelative) 2109 if (fi.Find(path)) // followLink = false
2012 relatPath = GetDirPrefixOf(_item.Path);
2013 relatPath += linkInfo.linkPath;
2014
2015 if (!IsSafePath(relatPath))
2016 { 2110 {
2017 return SendMessageError2( 2111 if (fi.IsDir())
2018 0, // errorCode 2112 {
2019 "Dangerous link path was ignored", 2113 if (RemoveDirAlways_if_Empty(path))
2020 us2fs(_item.Path), 2114 return S_OK;
2021 us2fs(linkInfo.linkPath)); // us2fs(relatPath) 2115 }
2116 else
2117 {
2118 // link file placeholder must be empty
2119 if (checkThatFileIsEmpty && !fi.IsOsSymLink() && fi.Size != 0)
2120 return SendMessageError("Temporary link file is not empty", path);
2121 if (DeleteFileAlways(path))
2122 return S_OK;
2123 }
2124 if (GetLastError() != ERROR_FILE_NOT_FOUND)
2125 return SendMessageError_with_LastError(
2126 fi.IsDir() ?
2127 k_CantDelete_Dir_for_SymLink:
2128 k_CantDelete_File_for_SymLink,
2129 path);
2022 } 2130 }
2131 return S_OK;
2132}
2133
2134
2135/*
2136in:
2137 link.LinkPath : must be relative (non-absolute) path in any case !!!
2138 link.isRelative / target path that must stored as created link:
2139 == false / _dirPathPrefix_Full + link.LinkPath
2140 == true / link.LinkPath
2141*/
2142static HRESULT SetLink2(const CArchiveExtractCallback &callback,
2143 const CPostLink &postLink, bool &linkWasSet)
2144{
2145 const CLinkInfo &link = postLink.LinkInfo;
2146 const FString &fullProcessedPath_from = postLink.fullProcessedPath_from; // full file path in FS (fullProcessedPath_from)
2023 2147
2024 FString existPath; 2148 const unsigned level = callback._ntOptions.SymLinks_DangerousLevel;
2025 if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative) 2149 if (level < 20)
2026 { 2150 {
2027 if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) 2151 /*
2152 We want to use additional check for links that can link to directory.
2153 - linux: all symbolic links are files.
2154 - windows: we can have file/directory symbolic link,
2155 but file symbolic link works like directory link in windows.
2156 So we use additional check for all relative links.
2157
2158 We don't allow decreasing of final level of link.
2159 So if some another extracted file will use this link,
2160 then number of real path parts (after link redirection) cannot be
2161 smaller than number of requested path parts from archive records.
2162
2163 here we check only (link.LinkPath) without (_item.PathParts).
2164 */
2165 CLinkLevelsInfo li;
2166 li.Parse(link.LinkPath, link.Is_WSL());
2167 bool isDang;
2168 UString relativePathPrefix;
2169 if (li.IsAbsolute // unexpected
2170 || li.ParentDirDots_after_NonParent
2171 || (level <= 5 && link.isRelative && li.FinalLevel < 1) // final level lower
2172 || (level <= 5 && link.isRelative && li.LowLevel < 0) // negative temporary levels
2173 )
2174 isDang = true;
2175 else // if (!isDang)
2028 { 2176 {
2029 RINOK(SendMessageError("Incorrect path", us2fs(relatPath))) 2177 UString path;
2030 } 2178 if (link.isRelative)
2179 {
2180 // item_PathParts : parts that will be created in output folder.
2181 // we want to get directory prefix of link item.
2182 // so we remove file name (last non-empty part) from PathParts:
2183 UStringVector v = postLink.item_PathParts;
2184 while (!v.IsEmpty())
2185 {
2186 const unsigned len = v.Back().Len();
2187 v.DeleteBack();
2188 if (len)
2189 break;
2190 }
2191 path = MakePathFromParts(v);
2192 NName::NormalizeDirPathPrefix(path);
2193 relativePathPrefix = path;
2194 }
2195 path += link.LinkPath;
2196 /*
2197 path is calculated virtual target path of link
2198 path is relative to root folder of extracted items
2199 if (!link.isRelative), then (path == link.LinkPath)
2200 */
2201 isDang = false;
2202 if (!IsSafePath(path, link.Is_WSL()))
2203 isDang = true;
2204 }
2205 const char *message = NULL;
2206 if (isDang)
2207 message = "Dangerous link path was ignored";
2208 else if (level <= k_DangLevel_MAX_for_Link_over_Link
2209 && !CheckLinkPath_in_FS(callback._dirPathPrefix_Full,
2210 postLink, relativePathPrefix))
2211 message = "Dangerous link via another link was ignored";
2212 if (message)
2213 return callback.SendMessageError2(0, // errorCode
2214 message, us2fs(postLink.item_Path), us2fs(link.LinkPath));
2215 }
2216
2217 FString target; // target path that will be stored to link field
2218 if (link.Is_HardLink() /* || link.IsCopyLink */ || !link.isRelative)
2219 {
2220 // isRelative == false
2221 // all hard links and absolute symbolic links
2222 // relatPath == link.LinkPath
2223 // we get absolute link path for target:
2224 if (!NName::GetFullPath(callback._dirPathPrefix_Full, us2fs(link.LinkPath), target))
2225 return callback.SendMessageError("Incorrect link path", us2fs(link.LinkPath));
2226 // (target) is (_dirPathPrefix_Full + relatPath)
2031 } 2227 }
2032 else 2228 else
2033 { 2229 {
2034 existPath = us2fs(linkInfo.linkPath); 2230 // link.isRelative == true
2035 // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr()); 2231 // relative symbolic links only
2232 target = us2fs(link.LinkPath);
2036 } 2233 }
2037 2234 if (target.IsEmpty())
2038 if (existPath.IsEmpty()) 2235 return callback.SendMessageError("Empty link", fullProcessedPath_from);
2039 return SendMessageError("Empty link", fullProcessedPath);
2040 2236
2041 if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */) 2237 if (link.Is_HardLink() /* || link.IsCopyLink */)
2042 { 2238 {
2043 // if (linkInfo.isHardLink) 2239 // if (link.isHardLink)
2044 { 2240 {
2045 if (!MyCreateHardLink(fullProcessedPath, existPath)) 2241 RINOK(callback.DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, true)) // checkThatFileIsEmpty
2046 { 2242 {
2047 const HRESULT errorCode = GetLastError_noZero_HRESULT(); 2243 // RINOK(SendMessageError_with_LastError(k_Cant_DeleteTempLinkFile, fullProcessedPath_from))
2048 RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath))
2049 } 2244 }
2245 return callback.CreateHardLink2(fullProcessedPath_from, target, linkWasSet);
2050 /* 2246 /*
2051 RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) 2247 RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract))
2052 _op_WasReported = true; 2248 _op_WasReported = true;
2053 RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK)) 2249 RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK))
2054 */
2055 linkWasSet = true; 2250 linkWasSet = true;
2056 return S_OK; 2251 return S_OK;
2252 */
2057 } 2253 }
2058 /* 2254 /*
2059 // IsCopyLink 2255 // IsCopyLink
2060 { 2256 {
2061 NFind::CFileInfo fi; 2257 NFind::CFileInfo fi;
2062 if (!fi.Find(existPath)) 2258 if (!fi.Find(target))
2063 { 2259 {
2064 RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath)); 2260 RINOK(SendMessageError2("Cannot find the file for copying", target, fullProcessedPath));
2065 } 2261 }
2066 else 2262 else
2067 { 2263 {
2068 if (_curSize_Defined && _curSize == fi.Size) 2264 if (_curSize_Defined && _curSize == fi.Size)
2069 _copyFile_Path = existPath; 2265 _copyFile_Path = target;
2070 else 2266 else
2071 { 2267 {
2072 RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); 2268 RINOK(SendMessageError2("File size collision for file copying", target, fullProcessedPath));
2073 } 2269 }
2074 // RINOK(MyCopyFile(existPath, fullProcessedPath)); 2270 // RINOK(MyCopyFile(target, fullProcessedPath));
2075 } 2271 }
2076 } 2272 }
2077 */ 2273 */
@@ -2085,127 +2281,227 @@ HRESULT CArchiveExtractCallback::SetFromLinkPath(
2085 // Windows before Vista doesn't support symbolic links. 2281 // Windows before Vista doesn't support symbolic links.
2086 // we could convert such symbolic links to Junction Points 2282 // we could convert such symbolic links to Junction Points
2087 // isJunction = true; 2283 // isJunction = true;
2088 // convertToAbs = true;
2089 } 2284 }
2090 */ 2285 */
2091 2286
2092 if (!_ntOptions.SymLinks_AllowDangerous.Val) 2287#ifdef _WIN32
2093 { 2288 const bool isDir = (postLink.item_IsDir || link.LinkType == k_LinkType_Junction);
2094 #ifdef _WIN32 2289#endif
2095 if (_item.IsDir)
2096 #endif
2097 if (linkInfo.isRelative)
2098 {
2099 CLinkLevelsInfo levelsInfo;
2100 levelsInfo.Parse(linkInfo.linkPath);
2101 if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute)
2102 {
2103 return SendMessageError2(
2104 0, // errorCode
2105 "Dangerous symbolic link path was ignored",
2106 us2fs(_item.Path),
2107 us2fs(linkInfo.linkPath));
2108 }
2109 }
2110 }
2111 2290
2112 2291
2113 #ifdef _WIN32 2292#ifdef _WIN32
2114
2115 CByteBuffer data; 2293 CByteBuffer data;
2116 // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr()); 2294 // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr());
2117 if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL)) 2295 if (link.Is_WSL())
2118 return SendMessageError("Cannot fill link data", us2fs(_item.Path));
2119
2120 /*
2121 if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
2122 { 2296 {
2123 SendMessageError("reconstructed Reparse is different", fs2us(existPath)); 2297 Convert_WinPath_to_WslLinuxPath(target, !link.isRelative);
2298 FillLinkData_WslLink(data, fs2us(target));
2124 } 2299 }
2300 else
2301 FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction);
2302 if (data.Size() == 0)
2303 return callback.SendMessageError("Cannot fill link data", us2fs(postLink.item_Path));
2304 /*
2305 if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
2306 SendMessageError("reconstructed Reparse is different", fs2us(target));
2125 */ 2307 */
2126
2127 CReparseAttr attr;
2128 if (!attr.Parse(data, data.Size()))
2129 { 2308 {
2130 RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))) 2309 // we check that reparse data is correct, but we ignore attr.MinorError.
2131 return S_OK; 2310 CReparseAttr attr;
2132 } 2311 if (!attr.Parse(data, data.Size()))
2133 if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) 2312 return callback.SendMessageError("Internal error for symbolic link file", us2fs(postLink.item_Path));
2134 {
2135 RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
2136 return S_OK;
2137 } 2313 }
2138 linkWasSet = true; 2314#endif
2139
2140 return S_OK;
2141
2142
2143 #else // ! _WIN32
2144 2315
2145 if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath)) 2316 RINOK(callback.DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, true)) // checkThatFileIsEmpty
2317#ifdef _WIN32
2318 if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size()))
2319#else // ! _WIN32
2320 if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target))
2321#endif // ! _WIN32
2146 { 2322 {
2147 RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) 2323 return callback.SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from);
2148 return S_OK;
2149 } 2324 }
2150 linkWasSet = true; 2325 linkWasSet = true;
2151
2152 return S_OK; 2326 return S_OK;
2153
2154 #endif // ! _WIN32
2155} 2327}
2156 2328
2157 2329
2158bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData)
2159{
2160 Clear();
2161 // this->isLinux = isLinuxData;
2162
2163 if (isLinuxData)
2164 {
2165 isJunction = false;
2166 isHardLink = false;
2167 AString utf;
2168 if (dataSize >= (1 << 12))
2169 return false;
2170 utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
2171 UString u;
2172 if (!ConvertUTF8ToUnicode(utf, u))
2173 return false;
2174 linkPath = u;
2175
2176 // in linux symbolic data: we expect that linux separator '/' is used
2177 // if windows link was created, then we also must use linux separator
2178 if (u.IsEmpty())
2179 return false;
2180 const wchar_t c = u[0];
2181 isRelative = !IS_PATH_SEPAR(c);
2182 return true;
2183 }
2184 2330
2331bool CLinkInfo::Parse_from_WindowsReparseData(const Byte *data, size_t dataSize)
2332{
2185 CReparseAttr reparse; 2333 CReparseAttr reparse;
2186 if (!reparse.Parse(data, dataSize)) 2334 if (!reparse.Parse(data, dataSize))
2187 return false; 2335 return false;
2188 isHardLink = false; 2336 // const AString s = GetAnsiString(LinkPath);
2189 // isCopyLink = false; 2337 // printf("\nlinkPath: %s\n", s.Ptr());
2190 linkPath = reparse.GetPath(); 2338 LinkPath = reparse.GetPath();
2191 isJunction = reparse.IsMountPoint();
2192
2193 if (reparse.IsSymLink_WSL()) 2339 if (reparse.IsSymLink_WSL())
2194 { 2340 {
2195 isWSL = true; 2341 LinkType = k_LinkType_WSL;
2196 isRelative = reparse.IsRelative_WSL(); 2342 isRelative = reparse.IsRelative_WSL(); // detected from LinkPath[0]
2343 // LinkPath is original raw name converted to UString from AString
2344 // Linux separator '/' is expected here.
2345 REPLACE_SLASHES_from_Linux_to_Sys(LinkPath)
2197 } 2346 }
2198 else 2347 else
2199 isRelative = reparse.IsRelative_Win(); 2348 {
2200 2349 LinkType = reparse.IsMountPoint() ? k_LinkType_Junction : k_LinkType_PureSymLink;
2201 // FIXME !!! 2350 isRelative = reparse.IsRelative_Win(); // detected by (Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE)
2202 #ifndef _WIN32 2351 isWindowsPath = true;
2203 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); 2352 // LinkPath is original windows link path from raparse data with \??\ prefix removed.
2204 #endif 2353 // windows '\\' separator is expected here.
2205 2354 // linux '/' separator is not expected here.
2355 // we translate both types of separators to system separator.
2356 LinkPath.Replace(
2357#if WCHAR_PATH_SEPARATOR == L'\\'
2358 L'/'
2359#else
2360 L'\\'
2361#endif
2362 , WCHAR_PATH_SEPARATOR);
2363 }
2364 // (LinkPath) uses system path separator.
2365 // windows: (LinkPath) doesn't contain linux separator (slash).
2366 return true;
2367}
2368
2369
2370bool CLinkInfo::Parse_from_LinuxData(const Byte *data, size_t dataSize)
2371{
2372 // Clear(); // *this object was cleared by constructor already.
2373 LinkType = k_LinkType_PureSymLink;
2374 AString utf;
2375 if (dataSize >= k_LinkDataSize_LIMIT)
2376 return false;
2377 utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
2378 UString u;
2379 if (!ConvertUTF8ToUnicode(utf, u))
2380 return false;
2381 if (u.IsEmpty())
2382 return false;
2383 const wchar_t c = u[0];
2384 isRelative = (c != L'/');
2385 // linux path separator is expected
2386 REPLACE_SLASHES_from_Linux_to_Sys(u)
2387 LinkPath = u;
2388 // (LinkPath) uses system path separator.
2389 // windows: (LinkPath) doesn't contain linux separator (slash).
2206 return true; 2390 return true;
2207} 2391}
2208 2392
2393
2394// in/out: (LinkPath) uses system path separator
2395// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
2396// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
2397// out: isRelative changed to false, if any prefix was removed.
2398// note: absolute windows links "c:\" to root will be reduced to empty string:
2399void CLinkInfo::Remove_AbsPathPrefixes()
2400{
2401 while (!LinkPath.IsEmpty())
2402 {
2403 unsigned n = 0;
2404 if (!Is_WSL())
2405 {
2406 n =
2407#ifndef _WIN32
2408 isWindowsPath ?
2409 NName::GetRootPrefixSize_WINDOWS(LinkPath) :
2410#endif
2411 NName::GetRootPrefixSize(LinkPath);
2412/*
2413 // "c:path" will be ignored later as "Dangerous absolute path"
2414 // so check is not required
2415 if (n == 0
2416#ifndef _WIN32
2417 && isWindowsPath
2418#endif
2419 && NName::IsDrivePath2(LinkPath))
2420 n = 2;
2421*/
2422 }
2423 if (n == 0)
2424 {
2425 if (!IS_PATH_SEPAR(LinkPath[0]))
2426 break;
2427 n = 1;
2428 }
2429 isRelative = false; // (LinkPath) will be treated as relative to root folder of archive
2430 LinkPath.DeleteFrontal(n);
2431 }
2432}
2433
2434
2435/*
2436 it removes redundant separators, if there are double separators,
2437 but it keeps double separators at start of string //name/.
2438 in/out: system path separator is used
2439 windows: slash character (linux separator) is not treated as separator
2440 windows: (path) doesn't contain linux separator (slash).
2441*/
2442static void RemoveRedundantPathSeparators(UString &path)
2443{
2444 wchar_t *dest = path.GetBuf();
2445 const wchar_t * const start = dest;
2446 const wchar_t *src = dest;
2447 for (;;)
2448 {
2449 wchar_t c = *src++;
2450 if (c == 0)
2451 break;
2452 // if (IS_PATH_SEPAR(c)) // for Windows: we can change (/) to (\).
2453 if (c == WCHAR_PATH_SEPARATOR)
2454 {
2455 if (dest - start >= 2 && dest[-1] == WCHAR_PATH_SEPARATOR)
2456 continue;
2457 // c = WCHAR_PATH_SEPARATOR; // for Windows: we can change (/) to (\).
2458 }
2459 *dest++ = c;
2460 }
2461 *dest = 0;
2462 path.ReleaseBuf_SetLen((unsigned)(dest - path.Ptr()));
2463}
2464
2465
2466// in/out: (LinkPath) uses system path separator
2467// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
2468// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
2469void CLinkInfo::Normalize_to_RelativeSafe(UStringVector &removePathParts)
2470{
2471 // We WILL NOT WRITE original absolute link path from archive to filesystem.
2472 // So here we remove all root prefixes from (LinkPath).
2473 // If we see any absolute root prefix, then we suppose that this prefix is virtual prefix
2474 // that shows that link is relative to root folder of archive
2475 RemoveRedundantPathSeparators(LinkPath);
2476 // LinkPath = "\\\\?\\r:test\\test2"; // for debug
2477 Remove_AbsPathPrefixes();
2478 // (LinkPath) now is relative:
2479 // if (isRelative == false), then (LinkPath) is relative to root folder of archive
2480 // if (isRelative == true ), then (LinkPath) is relative to current item
2481 if (LinkPath.IsEmpty() || isRelative || removePathParts.Size() == 0)
2482 return;
2483
2484 // if LinkPath is prefixed by _removePathParts, we remove these paths
2485 UStringVector pathParts;
2486 SplitPathToParts(LinkPath, pathParts);
2487 bool badPrefix = false;
2488 {
2489 FOR_VECTOR (i, removePathParts)
2490 {
2491 if (i >= pathParts.Size()
2492 || CompareFileNames(removePathParts[i], pathParts[i]) != 0)
2493 {
2494 badPrefix = true;
2495 break;
2496 }
2497 }
2498 }
2499 if (!badPrefix)
2500 pathParts.DeleteFrontal(removePathParts.Size());
2501 LinkPath = MakePathFromParts(pathParts);
2502 Remove_AbsPathPrefixes();
2503}
2504
2209#endif // SUPPORT_LINKS 2505#endif // SUPPORT_LINKS
2210 2506
2211 2507
@@ -2213,12 +2509,12 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2213{ 2509{
2214 HRESULT res = S_OK; 2510 HRESULT res = S_OK;
2215 2511
2216 #ifdef SUPPORT_LINKS 2512#ifdef SUPPORT_LINKS
2217 2513
2218 size_t reparseSize = 0; 2514 size_t reparseSize = 0;
2219 bool repraseMode = false; 2515 bool repraseMode = false;
2220 bool needSetReparse = false; 2516 bool needSetReparse = false;
2221 CLinkInfo linkInfo; 2517 CLinkInfo link;
2222 2518
2223 if (_bufPtrSeqOutStream) 2519 if (_bufPtrSeqOutStream)
2224 { 2520 {
@@ -2232,15 +2528,19 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2232 needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); 2528 needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
2233 if (needSetReparse) 2529 if (needSetReparse)
2234 { 2530 {
2235 UString linkPath = reparse.GetPath(); 2531 UString LinkPath = reparse.GetPath();
2236 #ifndef _WIN32 2532 #ifndef _WIN32
2237 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); 2533 LinkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
2238 #endif 2534 #endif
2239 } 2535 }
2240 */ 2536 */
2241 needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux); 2537 needSetReparse = _is_SymLink_in_Data_Linux ?
2538 link.Parse_from_LinuxData(_outMemBuf, reparseSize) :
2539 link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize);
2242 if (!needSetReparse) 2540 if (!needSetReparse)
2243 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); 2541 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
2542 // (link.LinkPath) uses system path separator.
2543 // windows: (link.LinkPath) doesn't contain linux separator (slash).
2244 } 2544 }
2245 else 2545 else
2246 { 2546 {
@@ -2255,25 +2555,21 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2255 _bufPtrSeqOutStream.Release(); 2555 _bufPtrSeqOutStream.Release();
2256 } 2556 }
2257 2557
2258 #endif // SUPPORT_LINKS 2558#endif // SUPPORT_LINKS
2259
2260 2559
2261 const HRESULT res2 = CloseFile(); 2560 const HRESULT res2 = CloseFile();
2262
2263 if (res == S_OK) 2561 if (res == S_OK)
2264 res = res2; 2562 res = res2;
2265
2266 RINOK(res) 2563 RINOK(res)
2267 2564
2268 #ifdef SUPPORT_LINKS 2565#ifdef SUPPORT_LINKS
2269 if (repraseMode) 2566 if (repraseMode)
2270 { 2567 {
2271 _curSize = reparseSize; 2568 _curSize = reparseSize;
2272 _curSize_Defined = true; 2569 _curSize_Defined = true;
2273
2274 #ifdef SUPPORT_LINKS
2275 if (needSetReparse) 2570 if (needSetReparse)
2276 { 2571 {
2572 // empty file was created so we must delete it.
2277 // in Linux : we must delete empty file before symbolic link creation 2573 // in Linux : we must delete empty file before symbolic link creation
2278 // in Windows : we can create symbolic link even without file deleting 2574 // in Windows : we can create symbolic link even without file deleting
2279 if (!DeleteFileAlways(_diskFilePath)) 2575 if (!DeleteFileAlways(_diskFilePath))
@@ -2281,42 +2577,57 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2281 RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) 2577 RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
2282 } 2578 }
2283 { 2579 {
2284 /*
2285 // for DEBUG ONLY: we can extract sym links as WSL links
2286 // to eliminate (non-admin) errors for sym links.
2287 #ifdef _WIN32
2288 if (!linkInfo.isHardLink && !linkInfo.isJunction)
2289 linkInfo.isWSL = true;
2290 #endif
2291 */
2292 bool linkWasSet = false; 2580 bool linkWasSet = false;
2293 RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet)) 2581 // link.LinkPath = "r:\\1\\2"; // for debug
2582 // link.isJunction = true; // for debug
2583 link.Normalize_to_RelativeSafe(_removePathParts);
2584 RINOK(SetLink(_diskFilePath, link, linkWasSet))
2585/*
2586 // we don't set attributes for placeholder.
2294 if (linkWasSet) 2587 if (linkWasSet)
2295 _isSymLinkCreated = linkInfo.IsSymLink(); 2588 _isSymLinkCreated = true; // link.IsSymLink();
2296 else 2589 else
2590*/
2297 _needSetAttrib = false; 2591 _needSetAttrib = false;
2298 } 2592 }
2299 /*
2300 if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
2301 {
2302 res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
2303 }
2304 */
2305 } 2593 }
2306 #endif
2307 } 2594 }
2308 #endif 2595#endif // SUPPORT_LINKS
2309 return res; 2596 return res;
2310} 2597}
2311 2598
2312 2599
2313void CArchiveExtractCallback::SetAttrib() 2600static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi,
2601 const CArchiveExtractCallback &callback)
2314{ 2602{
2315 #ifndef _WIN32 2603#ifndef _WIN32
2604 if (fi.Owner.Id_Defined &&
2605 fi.Group.Id_Defined)
2606 {
2607 if (my_chown(path, fi.Owner.Id, fi.Group.Id) != 0)
2608 callback.SendMessageError_with_LastError("Cannot set owner", path);
2609 }
2610#endif
2611
2612 if (fi.Attrib_Defined)
2613 {
2614 // const AString s = GetAnsiString(_diskFilePath);
2615 // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib);
2616 if (!SetFileAttrib_PosixHighDetect(path, fi.Attrib))
2617 {
2618 // do we need error message here in Windows and in posix?
2619 callback.SendMessageError_with_LastError("Cannot set file attribute", path);
2620 }
2621 }
2622}
2623
2624void CArchiveExtractCallback::SetAttrib() const
2625{
2626#ifndef _WIN32
2316 // Linux now doesn't support permissions for symlinks 2627 // Linux now doesn't support permissions for symlinks
2317 if (_isSymLinkCreated) 2628 if (_isSymLinkCreated)
2318 return; 2629 return;
2319 #endif 2630#endif
2320 2631
2321 if (_itemFailure 2632 if (_itemFailure
2322 || _diskFilePath.IsEmpty() 2633 || _diskFilePath.IsEmpty()
@@ -2324,29 +2635,39 @@ void CArchiveExtractCallback::SetAttrib()
2324 || !_extractMode) 2635 || !_extractMode)
2325 return; 2636 return;
2326 2637
2327 #ifndef _WIN32 2638 SetAttrib_Base(_diskFilePath, _fi, *this);
2328 if (_fi.Owner.Id_Defined && 2639}
2329 _fi.Group.Id_Defined)
2330 {
2331 if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0)
2332 {
2333 SendMessageError_with_LastError("Cannot set owner", _diskFilePath);
2334 }
2335 }
2336 #endif
2337 2640
2338 if (_fi.Attrib_Defined) 2641
2642#ifdef Z7_USE_SECURITY_CODE
2643HRESULT CArchiveExtractCallback::SetSecurityInfo(UInt32 indexInArc, const FString &path) const
2644{
2645 if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)
2339 { 2646 {
2340 // const AString s = GetAnsiString(_diskFilePath); 2647 const void *data;
2341 // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); 2648 UInt32 dataSize;
2342 bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib); 2649 UInt32 propType;
2343 if (!res) 2650 _arc->GetRawProps->GetRawProp(indexInArc, kpidNtSecure, &data, &dataSize, &propType);
2651 if (dataSize != 0)
2344 { 2652 {
2345 // do we need error message here in Windows and in posix? 2653 if (propType != NPropDataType::kRaw)
2346 SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath); 2654 return E_FAIL;
2655 if (CheckNtSecure((const Byte *)data, dataSize))
2656 {
2657 SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;
2658 if (_saclEnabled)
2659 securInfo |= SACL_SECURITY_INFORMATION;
2660 // if (!
2661 ::SetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data));
2662 {
2663 // RINOK(SendMessageError_with_LastError("SetFileSecurity FAILS", path))
2664 }
2665 }
2347 } 2666 }
2348 } 2667 }
2668 return S_OK;
2349} 2669}
2670#endif // Z7_USE_SECURITY_CODE
2350 2671
2351 2672
2352Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) 2673Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
@@ -2384,27 +2705,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
2384 2705
2385 RINOK(CloseReparseAndFile()) 2706 RINOK(CloseReparseAndFile())
2386 2707
2387 #ifdef Z7_USE_SECURITY_CODE 2708#ifdef Z7_USE_SECURITY_CODE
2388 if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) 2709 RINOK(SetSecurityInfo(_index, _diskFilePath))
2389 { 2710#endif
2390 const void *data;
2391 UInt32 dataSize;
2392 UInt32 propType;
2393 _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType);
2394 if (dataSize != 0)
2395 {
2396 if (propType != NPropDataType::kRaw)
2397 return E_FAIL;
2398 if (CheckNtSecure((const Byte *)data, dataSize))
2399 {
2400 SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;
2401 if (_saclEnabled)
2402 securInfo |= SACL_SECURITY_INFORMATION;
2403 ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data));
2404 }
2405 }
2406 }
2407 #endif // Z7_USE_SECURITY_CODE
2408 2711
2409 if (!_curSize_Defined) 2712 if (!_curSize_Defined)
2410 GetUnpackSize(); 2713 GetUnpackSize();
@@ -2648,15 +2951,58 @@ void CDirPathSortPair::SetNumSlashes(const FChar *s)
2648} 2951}
2649 2952
2650 2953
2651bool CDirPathTime::SetDirTime() const 2954bool CFiTimesCAM::SetDirTime_to_FS(CFSTR path) const
2652{ 2955{
2653 return NDir::SetDirTime(Path, 2956 // it's same function for dir and for file
2957 return NDir::SetDirTime(path,
2654 CTime_Defined ? &CTime : NULL, 2958 CTime_Defined ? &CTime : NULL,
2655 ATime_Defined ? &ATime : NULL, 2959 ATime_Defined ? &ATime : NULL,
2656 MTime_Defined ? &MTime : NULL); 2960 MTime_Defined ? &MTime : NULL);
2657} 2961}
2658 2962
2659 2963
2964#ifdef SUPPORT_LINKS
2965
2966bool CFiTimesCAM::SetLinkFileTime_to_FS(CFSTR path) const
2967{
2968 // it's same function for dir and for file
2969 return NDir::SetLinkFileTime(path,
2970 CTime_Defined ? &CTime : NULL,
2971 ATime_Defined ? &ATime : NULL,
2972 MTime_Defined ? &MTime : NULL);
2973}
2974
2975HRESULT CArchiveExtractCallback::SetPostLinks() const
2976{
2977 FOR_VECTOR (i, _postLinks)
2978 {
2979 const CPostLink &link = _postLinks[i];
2980 bool linkWasSet = false;
2981 RINOK(SetLink2(*this, link, linkWasSet))
2982 if (linkWasSet)
2983 {
2984#ifdef _WIN32
2985 // Linux now doesn't support permissions for symlinks
2986 SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this);
2987#endif
2988
2989 CFiTimesCAM pt;
2990 GetFiTimesCAM(link.item_FileInfo, pt, *_arc);
2991 if (pt.IsSomeTimeDefined())
2992 pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from);
2993
2994#ifdef Z7_USE_SECURITY_CODE
2995 // we set security information after timestamps setting
2996 RINOK(SetSecurityInfo(link.Index_in_Arc, link.fullProcessedPath_from))
2997#endif
2998 }
2999 }
3000 return S_OK;
3001}
3002
3003#endif
3004
3005
2660HRESULT CArchiveExtractCallback::SetDirsTimes() 3006HRESULT CArchiveExtractCallback::SetDirsTimes()
2661{ 3007{
2662 if (!_arc) 3008 if (!_arc)
@@ -2680,7 +3026,7 @@ HRESULT CArchiveExtractCallback::SetDirsTimes()
2680 for (i = 0; i < pairs.Size(); i++) 3026 for (i = 0; i < pairs.Size(); i++)
2681 { 3027 {
2682 const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; 3028 const CDirPathTime &dpt = _extractedFolders[pairs[i].Index];
2683 if (!dpt.SetDirTime()) 3029 if (!dpt.SetDirTime_to_FS_2())
2684 { 3030 {
2685 // result = E_FAIL; 3031 // result = E_FAIL;
2686 // do we need error message here in Windows and in posix? 3032 // do we need error message here in Windows and in posix?
@@ -2712,10 +3058,20 @@ HRESULT CArchiveExtractCallback::SetDirsTimes()
2712 3058
2713HRESULT CArchiveExtractCallback::CloseArc() 3059HRESULT CArchiveExtractCallback::CloseArc()
2714{ 3060{
3061 // we call CloseReparseAndFile() here because we can have non-closed file in some cases?
2715 HRESULT res = CloseReparseAndFile(); 3062 HRESULT res = CloseReparseAndFile();
2716 const HRESULT res2 = SetDirsTimes(); 3063#ifdef SUPPORT_LINKS
2717 if (res == S_OK) 3064 {
2718 res = res2; 3065 const HRESULT res2 = SetPostLinks();
3066 if (res == S_OK)
3067 res = res2;
3068 }
3069#endif
3070 {
3071 const HRESULT res2 = SetDirsTimes();
3072 if (res == S_OK)
3073 res = res2;
3074 }
2719 _arc = NULL; 3075 _arc = NULL;
2720 return res; 3076 return res;
2721} 3077}
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
index 7eb2f67..3c62763 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -52,7 +52,6 @@ struct CExtractNtOptions
52{ 52{
53 CBoolPair NtSecurity; 53 CBoolPair NtSecurity;
54 CBoolPair SymLinks; 54 CBoolPair SymLinks;
55 CBoolPair SymLinks_AllowDangerous;
56 CBoolPair HardLinks; 55 CBoolPair HardLinks;
57 CBoolPair AltStreams; 56 CBoolPair AltStreams;
58 bool ReplaceColonForAltStream; 57 bool ReplaceColonForAltStream;
@@ -66,6 +65,8 @@ struct CExtractNtOptions
66 bool PreserveATime; 65 bool PreserveATime;
67 bool OpenShareForWrite; 66 bool OpenShareForWrite;
68 67
68 unsigned SymLinks_DangerousLevel;
69
69 UInt64 MemLimit; 70 UInt64 MemLimit;
70 71
71 CExtractNtOptions(): 72 CExtractNtOptions():
@@ -74,10 +75,10 @@ struct CExtractNtOptions
74 ExtractOwner(false), 75 ExtractOwner(false),
75 PreserveATime(false), 76 PreserveATime(false),
76 OpenShareForWrite(false), 77 OpenShareForWrite(false),
78 SymLinks_DangerousLevel(5),
77 MemLimit((UInt64)(Int64)-1) 79 MemLimit((UInt64)(Int64)-1)
78 { 80 {
79 SymLinks.Val = true; 81 SymLinks.Val = true;
80 SymLinks_AllowDangerous.Val = false;
81 HardLinks.Val = true; 82 HardLinks.Val = true;
82 AltStreams.Val = true; 83 AltStreams.Val = true;
83 84
@@ -90,25 +91,10 @@ struct CExtractNtOptions
90 } 91 }
91}; 92};
92 93
93#ifndef Z7_SFX
94
95Z7_CLASS_IMP_COM_1(
96 CGetProp
97 , IGetProp
98)
99public:
100 UInt32 IndexInArc;
101 const CArc *Arc;
102 // UString Name; // relative path
103};
104
105#endif
106 94
107#ifndef Z7_SFX 95#ifndef Z7_SFX
108#ifndef UNDER_CE 96#ifndef UNDER_CE
109
110#define SUPPORT_LINKS 97#define SUPPORT_LINKS
111
112#endif 98#endif
113#endif 99#endif
114 100
@@ -181,53 +167,79 @@ struct CFiTimesCAM
181 ATime_Defined | 167 ATime_Defined |
182 MTime_Defined; 168 MTime_Defined;
183 } 169 }
170 bool SetDirTime_to_FS(CFSTR path) const;
171#ifdef SUPPORT_LINKS
172 bool SetLinkFileTime_to_FS(CFSTR path) const;
173#endif
184}; 174};
185 175
186struct CDirPathTime: public CFiTimesCAM 176struct CDirPathTime: public CFiTimesCAM
187{ 177{
188 FString Path; 178 FString Path;
189 179
190 bool SetDirTime() const; 180 bool SetDirTime_to_FS_2() const { return SetDirTime_to_FS(Path); }
191}; 181};
192 182
193 183
194#ifdef SUPPORT_LINKS 184#ifdef SUPPORT_LINKS
195 185
186enum ELinkType
187{
188 k_LinkType_HardLink,
189 k_LinkType_PureSymLink,
190 k_LinkType_Junction,
191 k_LinkType_WSL
192 // , k_LinkType_CopyLink;
193};
194
195
196struct CLinkInfo 196struct CLinkInfo
197{ 197{
198 // bool isCopyLink; 198 ELinkType LinkType;
199 bool isHardLink;
200 bool isJunction;
201 bool isRelative; 199 bool isRelative;
202 bool isWSL; 200 // if (isRelative == false), then (LinkPath) is relative to root folder of archive
203 UString linkPath; 201 // if (isRelative == true ), then (LinkPath) is relative to current item
202 bool isWindowsPath;
203 UString LinkPath;
204
205 bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; }
206 bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; }
204 207
205 bool IsSymLink() const { return !isHardLink; } 208 bool Is_WSL() const { return LinkType == k_LinkType_WSL; }
206 209
207 CLinkInfo(): 210 CLinkInfo():
208 // IsCopyLink(false), 211 LinkType(k_LinkType_PureSymLink),
209 isHardLink(false),
210 isJunction(false),
211 isRelative(false), 212 isRelative(false),
212 isWSL(false) 213 isWindowsPath(false)
213 {} 214 {}
214 215
215 void Clear() 216 void Clear()
216 { 217 {
217 // IsCopyLink = false; 218 LinkType = k_LinkType_PureSymLink;
218 isHardLink = false;
219 isJunction = false;
220 isRelative = false; 219 isRelative = false;
221 isWSL = false; 220 isWindowsPath = false;
222 linkPath.Empty(); 221 LinkPath.Empty();
223 } 222 }
224 223
225 bool Parse(const Byte *data, size_t dataSize, bool isLinuxData); 224 bool Parse_from_WindowsReparseData(const Byte *data, size_t dataSize);
225 bool Parse_from_LinuxData(const Byte *data, size_t dataSize);
226 void Normalize_to_RelativeSafe(UStringVector &removePathParts);
227private:
228 void Remove_AbsPathPrefixes();
226}; 229};
227 230
228#endif // SUPPORT_LINKS 231#endif // SUPPORT_LINKS
229 232
230 233
234
235struct CProcessedFileInfo
236{
237 CArcTime CTime;
238 CArcTime ATime;
239 CArcTime MTime;
240 UInt32 Attrib;
241 bool Attrib_Defined;
242
231#ifndef _WIN32 243#ifndef _WIN32
232 244
233struct COwnerInfo 245struct COwnerInfo
@@ -244,7 +256,75 @@ struct COwnerInfo
244 } 256 }
245}; 257};
246 258
259 COwnerInfo Owner;
260 COwnerInfo Group;
261#endif
262
263 void Clear()
264 {
265#ifndef _WIN32
266 Attrib_Defined = false;
267 Owner.Clear();
247#endif 268#endif
269 }
270
271 bool IsReparse() const
272 {
273 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
274 }
275
276 bool IsLinuxSymLink() const
277 {
278 return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
279 }
280
281 void SetFromPosixAttrib(UInt32 a)
282 {
283 // here we set only part of combined attribute required by SetFileAttrib() call
284 #ifdef _WIN32
285 // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
286 Attrib = MY_LIN_S_ISDIR(a) ?
287 FILE_ATTRIBUTE_DIRECTORY :
288 FILE_ATTRIBUTE_ARCHIVE;
289 if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
290 Attrib |= FILE_ATTRIBUTE_READONLY;
291 // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
292 a &= MY_LIN_S_IFMT;
293 if (a == MY_LIN_S_IFLNK)
294 Attrib |= (a << 16);
295 #else
296 Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
297 #endif
298 Attrib_Defined = true;
299 }
300};
301
302
303#ifdef SUPPORT_LINKS
304
305struct CPostLink
306{
307 UInt32 Index_in_Arc;
308 bool item_IsDir; // _item.IsDir
309 UString item_Path; // _item.Path;
310 UStringVector item_PathParts; // _item.PathParts;
311 CProcessedFileInfo item_FileInfo; // _fi
312 FString fullProcessedPath_from; // full file path in FS
313 CLinkInfo LinkInfo;
314};
315
316/*
317struct CPostLinks
318{
319 void Clear()
320 {
321 Links.Clear();
322 }
323};
324*/
325
326#endif // SUPPORT_LINKS
327
248 328
249 329
250class CArchiveExtractCallback Z7_final: 330class CArchiveExtractCallback Z7_final:
@@ -282,114 +362,78 @@ class CArchiveExtractCallback Z7_final:
282 Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) 362 Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback)
283#endif 363#endif
284 364
365 // bool Write_CTime;
366 // bool Write_ATime;
367 // bool Write_MTime;
368 bool _stdOutMode;
369 bool _testMode;
370 bool _removePartsForAltStreams;
371public:
372 bool Is_elimPrefix_Mode;
373private:
374
285 const CArc *_arc; 375 const CArc *_arc;
376public:
286 CExtractNtOptions _ntOptions; 377 CExtractNtOptions _ntOptions;
287 378private:
379 bool _encrypted;
288 bool _isSplit; 380 bool _isSplit;
381 bool _curSize_Defined;
382 bool _fileLength_WasSet;
289 383
384 bool _isRenamed;
290 bool _extractMode; 385 bool _extractMode;
291 386 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX.
292 bool Write_CTime; 387 // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file.
293 bool Write_ATime;
294 bool Write_MTime;
295 bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
296
297 bool _encrypted;
298
299 // bool _is_SymLink_in_Data;
300 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX
301
302 bool _needSetAttrib; 388 bool _needSetAttrib;
303 bool _isSymLinkCreated; 389 bool _isSymLinkCreated;
304 bool _itemFailure; 390 bool _itemFailure;
305
306 bool _some_pathParts_wereRemoved; 391 bool _some_pathParts_wereRemoved;
307public:
308 bool Is_elimPrefix_Mode;
309
310private:
311 bool _curSize_Defined;
312 bool _fileLength_WasSet;
313 392
314 bool _removePartsForAltStreams;
315
316 bool _stdOutMode;
317 bool _testMode;
318 bool _multiArchives; 393 bool _multiArchives;
394 bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
395#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
396 bool _saclEnabled;
397#endif
319 398
320 NExtract::NPathMode::EEnum _pathMode; 399 NExtract::NPathMode::EEnum _pathMode;
321 NExtract::NOverwriteMode::EEnum _overwriteMode; 400 NExtract::NOverwriteMode::EEnum _overwriteMode;
322 401
323 const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
324 CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2; 402 CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
403 const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
325 // CMyComPtr<ICompressProgressInfo> _compressProgress; 404 // CMyComPtr<ICompressProgressInfo> _compressProgress;
326 // CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage; 405 // CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage;
327 CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2; 406 CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
328 CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword; 407 CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
329 408
330 FString _dirPathPrefix; 409 FString _dirPathPrefix;
410public:
331 FString _dirPathPrefix_Full; 411 FString _dirPathPrefix_Full;
412private:
332 413
333 #ifndef Z7_SFX 414 #ifndef Z7_SFX
334 415
335 CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback; 416 CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
336 CGetProp *GetProp_Spec;
337 CMyComPtr<IGetProp> GetProp;
338 CMyComPtr<IArchiveRequestMemoryUseCallback> _requestMemoryUseCallback; 417 CMyComPtr<IArchiveRequestMemoryUseCallback> _requestMemoryUseCallback;
339 418
340 #endif 419 #endif
341 420
342 CReadArcItem _item; 421 CReadArcItem _item;
343 FString _diskFilePath; 422 FString _diskFilePath;
344 UInt64 _position;
345
346 struct CProcessedFileInfo
347 {
348 CArcTime CTime;
349 CArcTime ATime;
350 CArcTime MTime;
351 UInt32 Attrib;
352 bool Attrib_Defined;
353 423
354 #ifndef _WIN32 424 CProcessedFileInfo _fi;
355 COwnerInfo Owner;
356 COwnerInfo Group;
357 #endif
358
359 bool IsReparse() const
360 {
361 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
362 }
363
364 bool IsLinuxSymLink() const
365 {
366 return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
367 }
368 425
369 void SetFromPosixAttrib(UInt32 a) 426 UInt64 _position;
370 {
371 // here we set only part of combined attribute required by SetFileAttrib() call
372 #ifdef _WIN32
373 // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
374 Attrib = MY_LIN_S_ISDIR(a) ?
375 FILE_ATTRIBUTE_DIRECTORY :
376 FILE_ATTRIBUTE_ARCHIVE;
377 if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
378 Attrib |= FILE_ATTRIBUTE_READONLY;
379 // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
380 a &= MY_LIN_S_IFMT;
381 if (a == MY_LIN_S_IFLNK)
382 Attrib |= (a << 16);
383 #else
384 Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
385 #endif
386 Attrib_Defined = true;
387 }
388 } _fi;
389
390 UInt32 _index;
391 UInt64 _curSize; 427 UInt64 _curSize;
392 UInt64 _fileLength_that_WasSet; 428 UInt64 _fileLength_that_WasSet;
429 UInt32 _index;
430
431// #ifdef SUPPORT_ALT_STREAMS
432#if defined(_WIN32) && !defined(UNDER_CE)
433 DWORD _altStream_NeedRestore_AttribVal;
434 FString _altStream_NeedRestore_Attrib_for_parentFsPath;
435#endif
436// #endif
393 437
394 COutFileStream *_outFileStreamSpec; 438 COutFileStream *_outFileStreamSpec;
395 CMyComPtr<ISequentialOutStream> _outFileStream; 439 CMyComPtr<ISequentialOutStream> _outFileStream;
@@ -398,9 +442,7 @@ private:
398 CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec; 442 CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec;
399 CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream; 443 CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream;
400 444
401
402 #ifndef Z7_SFX 445 #ifndef Z7_SFX
403
404 COutStreamWithHash *_hashStreamSpec; 446 COutStreamWithHash *_hashStreamSpec;
405 CMyComPtr<ISequentialOutStream> _hashStream; 447 CMyComPtr<ISequentialOutStream> _hashStream;
406 bool _hashStreamWasUsed; 448 bool _hashStreamWasUsed;
@@ -411,11 +453,9 @@ private:
411 453
412 UStringVector _removePathParts; 454 UStringVector _removePathParts;
413 455
414 CMyComPtr<ICompressProgressInfo> _localProgress;
415 UInt64 _packTotal; 456 UInt64 _packTotal;
416
417 UInt64 _progressTotal; 457 UInt64 _progressTotal;
418 bool _progressTotal_Defined; 458 // bool _progressTotal_Defined;
419 459
420 CObjectVector<CDirPathTime> _extractedFolders; 460 CObjectVector<CDirPathTime> _extractedFolders;
421 461
@@ -423,31 +463,28 @@ private:
423 // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks; 463 // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
424 #endif 464 #endif
425 465
426 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) 466 void CreateComplexDirectory(
427 bool _saclEnabled; 467 const UStringVector &dirPathParts, bool isFinal, FString &fullPath);
428 #endif
429
430 void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
431 HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); 468 HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft);
432 HRESULT GetUnpackSize(); 469 HRESULT GetUnpackSize();
433 470
434 FString Hash_GetFullFilePath(); 471 FString Hash_GetFullFilePath();
435 472
436 void SetAttrib(); 473 void SetAttrib() const;
437 474
438public: 475public:
439 HRESULT SendMessageError(const char *message, const FString &path); 476 HRESULT SendMessageError(const char *message, const FString &path) const;
440 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); 477 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const;
441 HRESULT SendMessageError_with_LastError(const char *message, const FString &path); 478 HRESULT SendMessageError_with_LastError(const char *message, const FString &path) const;
442 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); 479 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const;
480 HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2) const;
443 481
444public: 482#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
445 #if defined(_WIN32) && !defined(UNDER_CE)
446 NExtract::NZoneIdMode::EEnum ZoneMode; 483 NExtract::NZoneIdMode::EEnum ZoneMode;
447 CByteBuffer ZoneBuf; 484 CByteBuffer ZoneBuf;
448 #endif 485#endif
449 486
450 CLocalProgress *LocalProgressSpec; 487 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> LocalProgressSpec;
451 488
452 UInt64 NumFolders; 489 UInt64 NumFolders;
453 UInt64 NumFiles; 490 UInt64 NumFiles;
@@ -468,11 +505,11 @@ public:
468 _multiArchives = multiArchives; 505 _multiArchives = multiArchives;
469 _pathMode = pathMode; 506 _pathMode = pathMode;
470 _overwriteMode = overwriteMode; 507 _overwriteMode = overwriteMode;
471 #if defined(_WIN32) && !defined(UNDER_CE) 508#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
472 ZoneMode = zoneMode; 509 ZoneMode = zoneMode;
473 #else 510#else
474 UNUSED_VAR(zoneMode) 511 UNUSED_VAR(zoneMode)
475 #endif 512#endif
476 _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes; 513 _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
477 NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; 514 NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
478 } 515 }
@@ -503,23 +540,32 @@ public:
503 UInt64 packSize); 540 UInt64 packSize);
504 541
505 542
506 #ifdef SUPPORT_LINKS 543#ifdef SUPPORT_LINKS
507 544
508private: 545private:
509 CHardLinks _hardLinks; 546 CHardLinks _hardLinks;
547 CObjectVector<CPostLink> _postLinks;
510 CLinkInfo _link; 548 CLinkInfo _link;
549 // const void *NtReparse_Data;
550 // UInt32 NtReparse_Size;
511 551
512 // FString _copyFile_Path; 552 // FString _copyFile_Path;
513 // HRESULT MyCopyFile(ISequentialOutStream *outStream); 553 // HRESULT MyCopyFile(ISequentialOutStream *outStream);
514 HRESULT Link(const FString &fullProcessedPath);
515 HRESULT ReadLink(); 554 HRESULT ReadLink();
555 HRESULT SetLink(
556 const FString &fullProcessedPath_from,
557 const CLinkInfo &linkInfo,
558 bool &linkWasSet);
559 HRESULT SetPostLinks() const;
516 560
517public: 561public:
518 // call PrepareHardLinks() after Init() 562 HRESULT CreateHardLink2(const FString &newFilePath,
563 const FString &existFilePath, bool &link_was_Created) const;
564 HRESULT DeleteLinkFileAlways_or_RemoveEmptyDir(const FString &path, bool checkThatFileIsEmpty) const;
519 HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items 565 HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
566#endif
520 567
521 #endif 568private:
522
523 569
524 #ifdef SUPPORT_ALT_STREAMS 570 #ifdef SUPPORT_ALT_STREAMS
525 CObjectVector<CIndexToPathPair> _renamedFiles; 571 CObjectVector<CIndexToPathPair> _renamedFiles;
@@ -527,6 +573,7 @@ public:
527 573
528 // call it after Init() 574 // call it after Init()
529 575
576public:
530 #ifndef Z7_SFX 577 #ifndef Z7_SFX
531 void SetBaseParentFolderIndex(UInt32 indexInArc) 578 void SetBaseParentFolderIndex(UInt32 indexInArc)
532 { 579 {
@@ -548,28 +595,16 @@ private:
548 595
549 HRESULT Read_fi_Props(); 596 HRESULT Read_fi_Props();
550 void CorrectPathParts(); 597 void CorrectPathParts();
551 void GetFiTimesCAM(CFiTimesCAM &pt);
552 void CreateFolders(); 598 void CreateFolders();
553 599
554 bool _isRenamed;
555 HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); 600 HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit);
556 HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit); 601 HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit);
557 HRESULT GetItem(UInt32 index); 602 HRESULT GetItem(UInt32 index);
558 603
559 HRESULT CloseFile(); 604 HRESULT CloseFile();
560 HRESULT CloseReparseAndFile(); 605 HRESULT CloseReparseAndFile();
561 HRESULT CloseReparseAndFile2();
562 HRESULT SetDirsTimes(); 606 HRESULT SetDirsTimes();
563 607 HRESULT SetSecurityInfo(UInt32 indexInArc, const FString &path) const;
564 const void *NtReparse_Data;
565 UInt32 NtReparse_Size;
566
567 #ifdef SUPPORT_LINKS
568 HRESULT SetFromLinkPath(
569 const FString &fullProcessedPath,
570 const CLinkInfo &linkInfo,
571 bool &linkWasSet);
572 #endif
573}; 608};
574 609
575 610
@@ -599,7 +634,8 @@ struct CArchiveExtractCallback_Closer
599 634
600bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); 635bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
601 636
602void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf); 637bool Is_ZoneId_StreamName(const wchar_t *s);
638void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf);
603bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf); 639bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf);
604 640
605#endif 641#endif
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp
index e1ca846..eb24e7f 100644
--- a/CPP/7zip/UI/Common/Bench.cpp
+++ b/CPP/7zip/UI/Common/Bench.cpp
@@ -871,14 +871,27 @@ struct CAffinityMode
871 unsigned NumCoreThreads; 871 unsigned NumCoreThreads;
872 unsigned NumCores; 872 unsigned NumCores;
873 // unsigned DivideNum; 873 // unsigned DivideNum;
874
875#ifdef _WIN32
876 unsigned NumGroups;
877#endif
878
874 UInt32 Sizes[NUM_CPU_LEVELS_MAX]; 879 UInt32 Sizes[NUM_CPU_LEVELS_MAX];
875 880
876 void SetLevels(unsigned numCores, unsigned numCoreThreads); 881 void SetLevels(unsigned numCores, unsigned numCoreThreads);
877 DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; 882 DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const;
878 bool NeedAffinity() const { return NumBundleThreads != 0; } 883 bool NeedAffinity() const { return NumBundleThreads != 0; }
879 884
885#ifdef _WIN32
886 bool NeedGroupsMode() const { return NumGroups > 1; }
887#endif
888
880 WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const 889 WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const
881 { 890 {
891#ifdef _WIN32
892 if (NeedGroupsMode()) // we need fix for bundleIndex usage
893 return thread.Create_With_Group(startAddress, parameter, bundleIndex % NumGroups);
894#endif
882 if (NeedAffinity()) 895 if (NeedAffinity())
883 { 896 {
884 CCpuSet cpuSet; 897 CCpuSet cpuSet;
@@ -892,6 +905,9 @@ struct CAffinityMode
892 NumBundleThreads(0), 905 NumBundleThreads(0),
893 NumLevels(0), 906 NumLevels(0),
894 NumCoreThreads(1) 907 NumCoreThreads(1)
908#ifdef _WIN32
909 , NumGroups(0)
910#endif
895 // DivideNum(1) 911 // DivideNum(1)
896 {} 912 {}
897}; 913};
@@ -1288,22 +1304,28 @@ HRESULT CEncoderInfo::Generate()
1288 if (scp) 1304 if (scp)
1289 { 1305 {
1290 const UInt64 reduceSize = kBufferSize; 1306 const UInt64 reduceSize = kBufferSize;
1291 1307 /* in posix : new thread uses same affinity as parent thread,
1292 /* in posix new thread uses same affinity as parent thread,
1293 so we don't need to send affinity to coder in posix */ 1308 so we don't need to send affinity to coder in posix */
1294 UInt64 affMask; 1309 UInt64 affMask = 0;
1295 #if !defined(Z7_ST) && defined(_WIN32) 1310 UInt32 affinityGroup = (UInt32)(Int32)-1;
1311 // UInt64 affinityInGroup = 0;
1312#if !defined(Z7_ST) && defined(_WIN32)
1296 { 1313 {
1297 CCpuSet cpuSet; 1314 CCpuSet cpuSet;
1298 affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); 1315 if (AffinityMode.NeedGroupsMode()) // we need fix for affinityInGroup also
1316 affinityGroup = EncoderIndex % AffinityMode.NumGroups;
1317 else
1318 affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet);
1299 } 1319 }
1300 #else 1320#endif
1301 affMask = 0; 1321 // affMask <<= 3; // debug line: to test no affinity in coder
1302 #endif 1322 // affMask = 0; // for debug
1303 // affMask <<= 3; // debug line: to test no affinity in coder; 1323 // affinityGroup = 0; // for debug
1304 // affMask = 0; 1324 // affinityInGroup = 1; // for debug
1305 1325 RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize,
1306 RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL))) 1326 affMask != 0 ? &affMask : NULL,
1327 affinityGroup != (UInt32)(Int32)-1 ? &affinityGroup : NULL,
1328 /* affinityInGroup != 0 ? &affinityInGroup : */ NULL))
1307 } 1329 }
1308 else 1330 else
1309 { 1331 {
@@ -2298,6 +2320,28 @@ HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size)
2298} 2320}
2299 2321
2300 2322
2323#if 1
2324#define HashUpdate(hf, data, size) hf->Update(data, size)
2325#else
2326// for debug:
2327static void HashUpdate(IHasher *hf, const void *data, UInt32 size)
2328{
2329 for (;;)
2330 {
2331 if (size == 0)
2332 return;
2333 UInt32 size2 = (size * 0x85EBCA87) % size / 8;
2334 // UInt32 size2 = size / 2;
2335 if (size2 == 0)
2336 size2 = 1;
2337 hf->Update(data, size2);
2338 data = (const void *)((const Byte *)data + size2);
2339 size -= size2;
2340 }
2341}
2342#endif
2343
2344
2301HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations, 2345HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations,
2302 const UInt32 *checkSum, IHasher *hf, 2346 const UInt32 *checkSum, IHasher *hf,
2303 IBenchPrintCallback *callback) 2347 IBenchPrintCallback *callback)
@@ -2328,7 +2372,7 @@ HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations,
2328 const size_t rem = size - pos; 2372 const size_t rem = size - pos;
2329 const UInt32 kStep = ((UInt32)1 << 31); 2373 const UInt32 kStep = ((UInt32)1 << 31);
2330 const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep; 2374 const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep;
2331 hf->Update(buf + pos, curSize); 2375 HashUpdate(hf, buf + pos, curSize);
2332 pos += curSize; 2376 pos += curSize;
2333 } 2377 }
2334 while (pos != size); 2378 while (pos != size);
@@ -2742,14 +2786,20 @@ static const CBenchHash g_Hash[] =
2742 { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" }, 2786 { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" },
2743 { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" }, 2787 { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" },
2744 { 10, 256, 0x41b901d1, "CRC64" }, 2788 { 10, 256, 0x41b901d1, "CRC64" },
2745 { 10, 64, 0x43eac94f, "XXH64" }, 2789 { 5, 64, 0x43eac94f, "XXH64" },
2746 2790 { 2, 2340, 0x3398a904, "MD5" },
2747 { 10, 5100, 0x7913ba03, "SHA256:1" }, 2791 { 10, 2340, 0xff769021, "SHA1:1" },
2748 { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" },
2749
2750 { 10, 2340, 0xff769021, "SHA1:1" },
2751 { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" }, 2792 { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" },
2752 2793 { 10, 5100, 0x7913ba03, "SHA256:1" },
2794 { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" },
2795 { 5, 3200, 0xe7aeb394, "SHA512:1" },
2796 { 2, CMPLX((40 * 4 + 1) * 4 + 4), 0xe7aeb394, "SHA512:2" },
2797 // { 10, 3428, 0x1cc99b18, "SHAKE128" },
2798 // { 10, 4235, 0x74eaddc3, "SHAKE256" },
2799 // { 10, 4000, 0xdf3e6863, "SHA3-224" },
2800 { 5, 4200, 0xcecac10d, "SHA3-256" },
2801 // { 10, 5538, 0x4e5d9163, "SHA3-384" },
2802 // { 10, 8000, 0x96a58289, "SHA3-512" },
2753 { 2, 4096, 0x85189d02, "BLAKE2sp:1" }, 2803 { 2, 4096, 0x85189d02, "BLAKE2sp:1" },
2754 { 2, 1024, 0x85189d02, "BLAKE2sp:2" }, // sse2-way4-fast 2804 { 2, 1024, 0x85189d02, "BLAKE2sp:2" }, // sse2-way4-fast
2755 { 2, 512, 0x85189d02, "BLAKE2sp:3" } // avx2-way8-fast 2805 { 2, 512, 0x85189d02, "BLAKE2sp:3" } // avx2-way8-fast
@@ -2934,7 +2984,7 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
2934{ 2984{
2935 AString s; 2985 AString s;
2936 // s.Add_UInt32(ti.numProcessThreads); 2986 // s.Add_UInt32(ti.numProcessThreads);
2937 unsigned numSysThreads = ti.GetNumSystemThreads(); 2987 const unsigned numSysThreads = ti.GetNumSystemThreads();
2938 if (ti.GetNumProcessThreads() != numSysThreads) 2988 if (ti.GetNumProcessThreads() != numSysThreads)
2939 { 2989 {
2940 // if (ti.numProcessThreads != ti.numSysThreads) 2990 // if (ti.numProcessThreads != ti.numSysThreads)
@@ -2964,6 +3014,35 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
2964 } 3014 }
2965 #endif 3015 #endif
2966 } 3016 }
3017#ifdef _WIN32
3018 if (ti.Groups.GroupSizes.Size() > 1 ||
3019 (ti.Groups.GroupSizes.Size() == 1
3020 && ti.Groups.NumThreadsTotal != numSysThreads))
3021 {
3022 s += " : ";
3023 s.Add_UInt32(ti.Groups.GroupSizes.Size());
3024 s += " groups : ";
3025 if (ti.Groups.NumThreadsTotal == numSysThreads)
3026 {
3027 s.Add_UInt32(ti.Groups.NumThreadsTotal);
3028 s += " c : ";
3029 }
3030 UInt32 minSize, maxSize;
3031 ti.Groups.Get_GroupSize_Min_Max(minSize, maxSize);
3032 if (minSize == maxSize)
3033 {
3034 s.Add_UInt32(ti.Groups.GroupSizes[0]);
3035 s += " c/g";
3036 }
3037 else
3038 FOR_VECTOR (i, ti.Groups.GroupSizes)
3039 {
3040 if (i != 0)
3041 s.Add_Char(' ');
3042 s.Add_UInt32(ti.Groups.GroupSizes[i]);
3043 }
3044 }
3045#endif
2967 return s; 3046 return s;
2968} 3047}
2969 3048
@@ -3687,7 +3766,7 @@ HRESULT Bench(
3687 return E_FAIL; 3766 return E_FAIL;
3688 3767
3689 UInt32 numCPUs = 1; 3768 UInt32 numCPUs = 1;
3690 UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29; 3769 size_t ramSize = (size_t)sizeof(size_t) << 29;
3691 3770
3692 NSystem::CProcessAffinity threadsInfo; 3771 NSystem::CProcessAffinity threadsInfo;
3693 threadsInfo.InitST(); 3772 threadsInfo.InitST();
@@ -3725,9 +3804,13 @@ HRESULT Bench(
3725 UInt64 complexInCommands = kComplexInCommands; 3804 UInt64 complexInCommands = kComplexInCommands;
3726 UInt32 numThreads_Start = 1; 3805 UInt32 numThreads_Start = 1;
3727 3806
3728 #ifndef Z7_ST 3807#ifndef Z7_ST
3729 CAffinityMode affinityMode; 3808 CAffinityMode affinityMode;
3730 #endif 3809#ifdef _WIN32
3810 if (threadsInfo.IsGroupMode && threadsInfo.Groups.GroupSizes.Size() > 1)
3811 affinityMode.NumGroups = threadsInfo.Groups.GroupSizes.Size();
3812#endif
3813#endif
3731 3814
3732 3815
3733 COneMethodInfo method; 3816 COneMethodInfo method;
@@ -4580,6 +4663,8 @@ HRESULT Bench(
4580 4663
4581 if (!dictIsDefined && !onlyHashBench) 4664 if (!dictIsDefined && !onlyHashBench)
4582 { 4665 {
4666 // we use dicSizeLog and dicSizeLog_Main for data size.
4667 // also we use it to reduce dictionary size of LZMA encoder via NCoderPropID::kReduceSize.
4583 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); 4668 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25);
4584 unsigned dicSizeLog = dicSizeLog_Main; 4669 unsigned dicSizeLog = dicSizeLog_Main;
4585 4670
@@ -4831,7 +4916,7 @@ HRESULT Bench(
4831 if (AreSameMethodNames(benchMethod, methodName)) 4916 if (AreSameMethodNames(benchMethod, methodName))
4832 { 4917 {
4833 if (benchProps.IsEmpty() 4918 if (benchProps.IsEmpty()
4834 || (benchProps == "x5" && method.PropsString.IsEmpty()) 4919 || (benchProps.IsEqualTo("x5") && method.PropsString.IsEmpty())
4835 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) 4920 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
4836 { 4921 {
4837 callback.BenchProps.EncComplex = h.EncComplex; 4922 callback.BenchProps.EncComplex = h.EncComplex;
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp
index 0758547..cada2e6 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -671,7 +671,7 @@ static HRESULT EnumerateForItem(
671 } 671 }
672 672
673 #if defined(_WIN32) 673 #if defined(_WIN32)
674 if (needAltStreams && dirItems.ScanAltStreams) 674 if (needAltStreams && dirItems.ScanAltStreams && !fi.IsAltStream)
675 { 675 {
676 RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, 676 RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
677 phyPrefix + fi.Name, // with (fi.Name) 677 phyPrefix + fi.Name, // with (fi.Name)
@@ -929,7 +929,7 @@ static HRESULT EnumerateDirItems(
929 } 929 }
930 930
931 #if defined(_WIN32) 931 #if defined(_WIN32)
932 if (needAltStreams && dirItems.ScanAltStreams) 932 if (needAltStreams && dirItems.ScanAltStreams && !fi.IsAltStream)
933 { 933 {
934 UStringVector pathParts; 934 UStringVector pathParts;
935 pathParts.Add(fs2us(fi.Name)); 935 pathParts.Add(fs2us(fi.Name));
@@ -1213,11 +1213,13 @@ HRESULT CDirItems::FillFixedReparse()
1213 // continue; // for debug 1213 // continue; // for debug
1214 if (!item.Has_Attrib_ReparsePoint()) 1214 if (!item.Has_Attrib_ReparsePoint())
1215 continue; 1215 continue;
1216 1216 /*
1217 We want to get properties of target file instead of properies of symbolic link.
1218 Probably this code is unused, because
1219 CFileInfo::Find(with followLink = true) called Fill_From_ByHandleFileInfo() already.
1220 */
1217 // if (item.IsDir()) continue; 1221 // if (item.IsDir()) continue;
1218
1219 const FString phyPath = GetPhyPath(i); 1222 const FString phyPath = GetPhyPath(i);
1220
1221 NFind::CFileInfo fi; 1223 NFind::CFileInfo fi;
1222 if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir() 1224 if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir()
1223 { 1225 {
@@ -1228,38 +1230,13 @@ HRESULT CDirItems::FillFixedReparse()
1228 item.Attrib = fi.Attrib; 1230 item.Attrib = fi.Attrib;
1229 continue; 1231 continue;
1230 } 1232 }
1231
1232 /*
1233 // we request properties of target file instead of properies of symbolic link
1234 // here we also can manually parse unsupported links (like WSL links)
1235 NIO::CInFile inFile;
1236 if (inFile.Open(phyPath))
1237 {
1238 BY_HANDLE_FILE_INFORMATION info;
1239 if (inFile.GetFileInformation(&info))
1240 {
1241 // Stat.FilesSize doesn't contain item.Size already
1242 // Stat.FilesSize -= item.Size;
1243 item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
1244 Stat.FilesSize += item.Size;
1245 item.CTime = info.ftCreationTime;
1246 item.ATime = info.ftLastAccessTime;
1247 item.MTime = info.ftLastWriteTime;
1248 item.Attrib = info.dwFileAttributes;
1249 continue;
1250 }
1251 }
1252 */
1253
1254 RINOK(AddError(phyPath)) 1233 RINOK(AddError(phyPath))
1255 continue; 1234 continue;
1256 } 1235 }
1257 1236
1258 // (SymLinks == true) here 1237 // (SymLinks == true)
1259
1260 if (item.ReparseData.Size() == 0) 1238 if (item.ReparseData.Size() == 0)
1261 continue; 1239 continue;
1262
1263 // if (item.Size == 0) 1240 // if (item.Size == 0)
1264 { 1241 {
1265 // 20.03: we use Reparse Data instead of real data 1242 // 20.03: we use Reparse Data instead of real data
@@ -1277,7 +1254,7 @@ HRESULT CDirItems::FillFixedReparse()
1277 /* imagex/WIM reduces absolute paths in links (raparse data), 1254 /* imagex/WIM reduces absolute paths in links (raparse data),
1278 if we archive non root folder. We do same thing here */ 1255 if we archive non root folder. We do same thing here */
1279 1256
1280 bool isWSL = false; 1257 // bool isWSL = false;
1281 if (attr.IsSymLink_WSL()) 1258 if (attr.IsSymLink_WSL())
1282 { 1259 {
1283 // isWSL = true; 1260 // isWSL = true;
@@ -1314,21 +1291,27 @@ HRESULT CDirItems::FillFixedReparse()
1314 continue; 1291 continue;
1315 if (rootPrefixSize == prefix.Len()) 1292 if (rootPrefixSize == prefix.Len())
1316 continue; // simple case: paths are from root 1293 continue; // simple case: paths are from root
1317
1318 if (link.Len() <= prefix.Len()) 1294 if (link.Len() <= prefix.Len())
1319 continue; 1295 continue;
1320
1321 if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) 1296 if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
1322 continue; 1297 continue;
1323 1298
1324 UString newLink = prefix.Left(rootPrefixSize); 1299 UString newLink = prefix.Left(rootPrefixSize);
1325 newLink += link.Ptr(prefix.Len()); 1300 newLink += link.Ptr(prefix.Len());
1326 1301
1327 CByteBuffer data; 1302 CByteBuffer &data = item.ReparseData2;
1328 bool isSymLink = !attr.IsMountPoint(); 1303/*
1329 if (!FillLinkData(data, newLink, isSymLink, isWSL)) 1304 if (isWSL)
1305 {
1306 Convert_WinPath_to_WslLinuxPath(newLink, true); // is absolute : change it
1307 FillLinkData_WslLink(data, newLink);
1308 }
1309 else
1310*/
1311 FillLinkData_WinLink(data, newLink, !attr.IsMountPoint());
1312 if (data.Size() == 0)
1330 continue; 1313 continue;
1331 item.ReparseData2 = data; 1314 // item.ReparseData2 = data;
1332 } 1315 }
1333 return S_OK; 1316 return S_OK;
1334} 1317}
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp
index 010b01c..0301976 100644
--- a/CPP/7zip/UI/Common/Extract.cpp
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -389,7 +389,7 @@ HRESULT Extract(
389 { 389 {
390 UString s = arcPath.Ptr(pos + 1); 390 UString s = arcPath.Ptr(pos + 1);
391 int index = codecs->FindFormatForExtension(s); 391 int index = codecs->FindFormatForExtension(s);
392 if (index >= 0 && s == L"001") 392 if (index >= 0 && s.IsEqualTo("001"))
393 { 393 {
394 s = arcPath.Left(pos); 394 s = arcPath.Left(pos);
395 pos = s.ReverseFind(L'.'); 395 pos = s.ReverseFind(L'.');
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
index 88da4ad..5ca5e66 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -208,7 +208,7 @@ void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UString
208 if (parts.Size() > 1 && parts[1].IsEmpty()) 208 if (parts.Size() > 1 && parts[1].IsEmpty())
209 { 209 {
210 i = 2; 210 i = 2;
211 if (parts.Size() > 2 && parts[2] == L"?") 211 if (parts.Size() > 2 && parts[2].IsEqualTo("?"))
212 { 212 {
213 i = 3; 213 i = 3;
214 if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) 214 if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp
index f3d65ef..f026f80 100644
--- a/CPP/7zip/UI/Common/HashCalc.cpp
+++ b/CPP/7zip/UI/Common/HashCalc.cpp
@@ -62,7 +62,7 @@ HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVecto
62 if (m.MethodName.IsEmpty()) 62 if (m.MethodName.IsEmpty())
63 m.MethodName = k_DefaultHashMethod; 63 m.MethodName = k_DefaultHashMethod;
64 64
65 if (m.MethodName == "*") 65 if (m.MethodName.IsEqualTo("*"))
66 { 66 {
67 CRecordVector<CMethodId> tempMethods; 67 CRecordVector<CMethodId> tempMethods;
68 GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); 68 GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
@@ -431,6 +431,19 @@ static void WriteLine(CDynLimBuf &hashFileString,
431} 431}
432 432
433 433
434static void Convert_TagName_to_MethodName(AString &method)
435{
436 // we need to convert at least SHA512/256 to SHA512-256, and SHA512/224 to SHA512-224
437 // but we convert any '/' to '-'.
438 method.Replace('/', '-');
439}
440
441static void Convert_MethodName_to_TagName(AString &method)
442{
443 if (method.IsPrefixedBy_Ascii_NoCase("SHA512-2"))
444 method.ReplaceOneCharAtPos(6, '/');
445}
446
434 447
435static void WriteLine(CDynLimBuf &hashFileString, 448static void WriteLine(CDynLimBuf &hashFileString,
436 const CHashOptionsLocal &options, 449 const CHashOptionsLocal &options,
@@ -440,8 +453,10 @@ static void WriteLine(CDynLimBuf &hashFileString,
440{ 453{
441 AString methodName; 454 AString methodName;
442 if (!hb.Hashers.IsEmpty()) 455 if (!hb.Hashers.IsEmpty())
456 {
443 methodName = hb.Hashers[0].Name; 457 methodName = hb.Hashers[0].Name;
444 458 Convert_MethodName_to_TagName(methodName);
459 }
445 AString hashesString; 460 AString hashesString;
446 AddHashResultLine(hashesString, hb.Hashers); 461 AddHashResultLine(hashesString, hb.Hashers);
447 WriteLine(hashFileString, options, path, isDir, methodName, hashesString); 462 WriteLine(hashFileString, options, path, isDir, methodName, hashesString);
@@ -752,7 +767,7 @@ bool CHashPair::ParseCksum(const char *s)
752 Name = end; 767 Name = end;
753 768
754 Hash.Alloc(4); 769 Hash.Alloc(4);
755 SetBe32(Hash, crc) 770 SetBe32a(Hash, crc)
756 771
757 Size_from_Arc = size; 772 Size_from_Arc = size;
758 Size_from_Arc_Defined = true; 773 Size_from_Arc_Defined = true;
@@ -773,48 +788,87 @@ static const char * const k_CsumMethodNames[] =
773{ 788{
774 "sha256" 789 "sha256"
775 , "sha224" 790 , "sha224"
776// , "sha512/224" 791 , "sha512-224"
777// , "sha512/256" 792 , "sha512-256"
778 , "sha512"
779 , "sha384" 793 , "sha384"
794 , "sha512"
795 , "sha3-224"
796 , "sha3-256"
797 , "sha3-384"
798 , "sha3-512"
799// , "shake128"
800// , "shake256"
780 , "sha1" 801 , "sha1"
802 , "sha2"
803 , "sha3"
804 , "sha"
781 , "md5" 805 , "md5"
806 , "blake2s"
782 , "blake2b" 807 , "blake2b"
783 , "crc64" 808 , "blake2sp"
809 , "xxh64"
784 , "crc32" 810 , "crc32"
811 , "crc64"
785 , "cksum" 812 , "cksum"
786}; 813};
787 814
788static UString GetMethod_from_FileName(const UString &name) 815
816// returns true, if (method) is known hash method or hash method group name.
817static bool GetMethod_from_FileName(const UString &name, AString &method)
789{ 818{
819 method.Empty();
790 AString s; 820 AString s;
791 ConvertUnicodeToUTF8(name, s); 821 ConvertUnicodeToUTF8(name, s);
792 const int dotPos = s.ReverseFind_Dot(); 822 const int dotPos = s.ReverseFind_Dot();
793 const char *src = s.Ptr();
794 bool isExtension = false;
795 if (dotPos >= 0) 823 if (dotPos >= 0)
796 { 824 {
797 isExtension = true; 825 method = s.Ptr(dotPos + 1);
798 src = s.Ptr(dotPos + 1); 826 if (method.IsEqualTo_Ascii_NoCase("txt") ||
827 method.IsEqualTo_Ascii_NoCase("asc"))
828 {
829 method.Empty();
830 const int dotPos2 = s.Find('.');
831 if (dotPos2 >= 0)
832 s.DeleteFrom(dotPos2);
833 }
799 } 834 }
800 const char *m = ""; 835 if (method.IsEmpty())
836 {
837 // we support file names with "sum" and "sums" postfixes: "sha256sum", "sha256sums"
838 unsigned size;
839 if (s.Len() > 4 && StringsAreEqualNoCase_Ascii(s.RightPtr(4), "sums"))
840 size = 4;
841 else if (s.Len() > 3 && StringsAreEqualNoCase_Ascii(s.RightPtr(3), "sum"))
842 size = 3;
843 else
844 return false;
845 method = s;
846 method.DeleteFrom(s.Len() - size);
847 }
848
801 unsigned i; 849 unsigned i;
802 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) 850 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
803 { 851 {
804 m = k_CsumMethodNames[i]; 852 const char *m = k_CsumMethodNames[i];
805 if (isExtension) 853 if (method.IsEqualTo_Ascii_NoCase(m))
806 { 854 {
807 if (StringsAreEqual_Ascii(src, m)) 855 // method = m; // we can get lowcase
808 break; 856 return true;
809 } 857 }
810 else if (IsString1PrefixedByString2_NoCase_Ascii(src, m))
811 if (StringsAreEqual_Ascii(src + strlen(m), "sums"))
812 break;
813 } 858 }
814 UString res; 859
815 if (i != Z7_ARRAY_SIZE(k_CsumMethodNames)) 860/*
816 res = m; 861 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
817 return res; 862 {
863 const char *m = k_CsumMethodNames[i];
864 if (method.IsPrefixedBy_Ascii_NoCase(m))
865 {
866 method = m; // we get lowcase
867 return true;
868 }
869 }
870*/
871 return false;
818} 872}
819 873
820 874
@@ -1039,7 +1093,7 @@ Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
1039 if (propID == kpidChecksum) 1093 if (propID == kpidChecksum)
1040 { 1094 {
1041 const CHashPair &hp = HashPairs[index]; 1095 const CHashPair &hp = HashPairs[index];
1042 if (hp.Hash.Size() > 0) 1096 if (hp.Hash.Size() != 0)
1043 { 1097 {
1044 *data = hp.Hash; 1098 *data = hp.Hash;
1045 *dataSize = (UInt32)hp.Hash.Size(); 1099 *dataSize = (UInt32)hp.Hash.Size();
@@ -1092,11 +1146,6 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1092 s.Add_UInt32(_hashSize * 8); 1146 s.Add_UInt32(_hashSize * 8);
1093 s += "-bit"; 1147 s += "-bit";
1094 } 1148 }
1095 if (!_nameExtenstion.IsEmpty())
1096 {
1097 s.Add_Space_if_NotEmpty();
1098 s += _nameExtenstion;
1099 }
1100 if (_is_PgpMethod) 1149 if (_is_PgpMethod)
1101 { 1150 {
1102 Add_OptSpace_String(s, "PGP"); 1151 Add_OptSpace_String(s, "PGP");
@@ -1112,6 +1161,18 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1112 Add_OptSpace_String(s, "TAG"); 1161 Add_OptSpace_String(s, "TAG");
1113 if (_are_there_Dirs) 1162 if (_are_there_Dirs)
1114 Add_OptSpace_String(s, "DIRS"); 1163 Add_OptSpace_String(s, "DIRS");
1164 if (!_method_from_FileName.IsEmpty())
1165 {
1166 Add_OptSpace_String(s, "filename_method:");
1167 s += _method_from_FileName;
1168 if (!_is_KnownMethod_in_FileName)
1169 s += ":UNKNOWN";
1170 }
1171 if (!_methods.IsEmpty())
1172 {
1173 Add_OptSpace_String(s, "cmd_method:");
1174 s += _methods[0];
1175 }
1115 prop = s; 1176 prop = s;
1116 break; 1177 break;
1117 } 1178 }
@@ -1220,6 +1281,15 @@ static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOp
1220} 1281}
1221 1282
1222 1283
1284static bool isThere_Zero_Byte(const Byte *data, size_t size)
1285{
1286 for (size_t i = 0; i < size; i++)
1287 if (data[i] == 0)
1288 return true;
1289 return false;
1290}
1291
1292
1223Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) 1293Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
1224{ 1294{
1225 COM_TRY_BEGIN 1295 COM_TRY_BEGIN
@@ -1231,17 +1301,9 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
1231 1301
1232 CObjectVector<CHashPair> &pairs = HashPairs; 1302 CObjectVector<CHashPair> &pairs = HashPairs;
1233 1303
1234 bool zeroMode = false; 1304 const bool zeroMode = isThere_Zero_Byte(buf, buf.Size());
1235 bool cr_lf_Mode = false;
1236 {
1237 for (size_t i = 0; i < buf.Size(); i++)
1238 if (buf.ConstData()[i] == 0)
1239 {
1240 zeroMode = true;
1241 break;
1242 }
1243 }
1244 _is_ZeroMode = zeroMode; 1305 _is_ZeroMode = zeroMode;
1306 bool cr_lf_Mode = false;
1245 if (!zeroMode) 1307 if (!zeroMode)
1246 cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); 1308 cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size());
1247 1309
@@ -1255,13 +1317,21 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
1255 NCOM::CPropVariant prop; 1317 NCOM::CPropVariant prop;
1256 RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) 1318 RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
1257 if (prop.vt == VT_BSTR) 1319 if (prop.vt == VT_BSTR)
1258 _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); 1320 _is_KnownMethod_in_FileName = GetMethod_from_FileName(prop.bstrVal, _method_from_FileName);
1259 } 1321 }
1260 } 1322 }
1261 1323
1262 bool cksumMode = false; 1324 if (!_methods.IsEmpty())
1263 if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) 1325 {
1264 cksumMode = true; 1326 ConvertUnicodeToUTF8(_methods[0], _method_for_Extraction);
1327 }
1328 if (_method_for_Extraction.IsEmpty())
1329 {
1330 // if (_is_KnownMethod_in_FileName)
1331 _method_for_Extraction = _method_from_FileName;
1332 }
1333
1334 const bool cksumMode = _method_for_Extraction.IsEqualTo_Ascii_NoCase("cksum");
1265 _is_CksumMode = cksumMode; 1335 _is_CksumMode = cksumMode;
1266 1336
1267 size_t pos = 0; 1337 size_t pos = 0;
@@ -1358,6 +1428,7 @@ void CHandler::ClearVars()
1358 _is_ZeroMode = false; 1428 _is_ZeroMode = false;
1359 _are_there_Tags = false; 1429 _are_there_Tags = false;
1360 _are_there_Dirs = false; 1430 _are_there_Dirs = false;
1431 _is_KnownMethod_in_FileName = false;
1361 _hashSize_Defined = false; 1432 _hashSize_Defined = false;
1362 _hashSize = 0; 1433 _hashSize = 0;
1363} 1434}
@@ -1366,7 +1437,8 @@ void CHandler::ClearVars()
1366Z7_COM7F_IMF(CHandler::Close()) 1437Z7_COM7F_IMF(CHandler::Close())
1367{ 1438{
1368 ClearVars(); 1439 ClearVars();
1369 _nameExtenstion.Empty(); 1440 _method_from_FileName.Empty();
1441 _method_for_Extraction.Empty();
1370 _pgpMethod.Empty(); 1442 _pgpMethod.Empty();
1371 HashPairs.Clear(); 1443 HashPairs.Clear();
1372 return S_OK; 1444 return S_OK;
@@ -1393,19 +1465,73 @@ static bool CheckDigests(const Byte *a, const Byte *b, size_t size)
1393} 1465}
1394 1466
1395 1467
1396static void AddDefaultMethod(UStringVector &methods, unsigned size) 1468static void AddDefaultMethod(UStringVector &methods,
1469 const char *name, unsigned size)
1397{ 1470{
1471 int shaVersion = -1;
1472 if (name)
1473 {
1474 if (StringsAreEqualNoCase_Ascii(name, "sha"))
1475 {
1476 shaVersion = 0;
1477 if (size == 0)
1478 size = 32;
1479 }
1480 else if (StringsAreEqualNoCase_Ascii(name, "sha1"))
1481 {
1482 shaVersion = 1;
1483 if (size == 0)
1484 size = 20;
1485 }
1486 else if (StringsAreEqualNoCase_Ascii(name, "sha2"))
1487 {
1488 shaVersion = 2;
1489 if (size == 0)
1490 size = 32;
1491 }
1492 else if (StringsAreEqualNoCase_Ascii(name, "sha3"))
1493 {
1494 if (size == 0 ||
1495 size == 32) name = "sha3-256";
1496 else if (size == 28) name = "sha3-224";
1497 else if (size == 48) name = "sha3-384";
1498 else if (size == 64) name = "sha3-512";
1499 }
1500 else if (StringsAreEqualNoCase_Ascii(name, "sha512"))
1501 {
1502 // we allow any sha512 derived hash inside .sha512 file:
1503 if (size == 48) name = "sha384";
1504 else if (size == 32) name = "sha512-256";
1505 else if (size == 28) name = "sha512-224";
1506 }
1507 if (shaVersion >= 0)
1508 name = NULL;
1509 }
1510
1398 const char *m = NULL; 1511 const char *m = NULL;
1399 if (size == 32) m = "sha256"; 1512 if (name)
1400 else if (size == 20) m = "sha1"; 1513 m = name;
1401 else if (size == 16) m = "md5";
1402 else if (size == 8) m = "crc64";
1403 else if (size == 4) m = "crc32";
1404 else 1514 else
1515 {
1516 if (size == 64) m = "sha512";
1517 else if (size == 48) m = "sha384";
1518 else if (size == 32) m = "sha256";
1519 else if (size == 28) m = "sha224";
1520 else if (size == 20) m = "sha1";
1521 else if (shaVersion < 0)
1522 {
1523 if (size == 16) m = "md5";
1524 else if (size == 8) m = "crc64";
1525 else if (size == 4) m = "crc32";
1526 }
1527 }
1528
1529 if (!m)
1405 return; 1530 return;
1406 #ifdef Z7_EXTERNAL_CODECS 1531
1532#ifdef Z7_EXTERNAL_CODECS
1407 const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; 1533 const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
1408 #endif 1534#endif
1409 CMethodId id; 1535 CMethodId id;
1410 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS 1536 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS
1411 AString(m), id)) 1537 AString(m), id))
@@ -1436,15 +1562,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1436 CHashBundle hb_Glob; 1562 CHashBundle hb_Glob;
1437 // UStringVector methods = options.Methods; 1563 // UStringVector methods = options.Methods;
1438 UStringVector methods; 1564 UStringVector methods;
1439 1565
1440 if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) 1566/*
1567 if (methods.IsEmpty() && !utf_nameExtenstion.IsEmpty() && !_hashSize_Defined)
1441 { 1568 {
1442 AString utf;
1443 ConvertUnicodeToUTF8(_nameExtenstion, utf);
1444 CMethodId id; 1569 CMethodId id;
1445 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) 1570 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf_nameExtenstion, id))
1446 methods.Add(_nameExtenstion); 1571 methods.Add(_nameExtenstion);
1447 } 1572 }
1573*/
1448 1574
1449 if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) 1575 if (methods.IsEmpty() && !_pgpMethod.IsEmpty())
1450 { 1576 {
@@ -1453,12 +1579,21 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1453 methods.Add(UString(_pgpMethod)); 1579 methods.Add(UString(_pgpMethod));
1454 } 1580 }
1455 1581
1582/*
1456 if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) 1583 if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined)
1457 AddDefaultMethod(methods, _hashSize); 1584 {
1585 AddDefaultMethod(methods,
1586 utf_nameExtenstion.IsEmpty() ? NULL : utf_nameExtenstion.Ptr(),
1587 _hashSize);
1588 }
1589*/
1458 1590
1459 RINOK(hb_Glob.SetMethods( 1591 if (!methods.IsEmpty())
1592 {
1593 RINOK(hb_Glob.SetMethods(
1460 EXTERNAL_CODECS_LOC_VARS 1594 EXTERNAL_CODECS_LOC_VARS
1461 methods)) 1595 methods))
1596 }
1462 1597
1463 Z7_DECL_CMyComPtr_QI_FROM( 1598 Z7_DECL_CMyComPtr_QI_FROM(
1464 IArchiveUpdateCallbackFile, 1599 IArchiveUpdateCallbackFile,
@@ -1553,9 +1688,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1553 { 1688 {
1554 hb_Use = &hb_Loc; 1689 hb_Use = &hb_Loc;
1555 CMethodId id; 1690 CMethodId id;
1556 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id)) 1691 AString methodName = hp.Method;
1692 Convert_TagName_to_MethodName(methodName);
1693 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, id))
1557 { 1694 {
1558 methods_loc.Add(UString(hp.Method)); 1695 methods_loc.Add(UString(methodName));
1559 RINOK(hb_Loc.SetMethods( 1696 RINOK(hb_Loc.SetMethods(
1560 EXTERNAL_CODECS_LOC_VARS 1697 EXTERNAL_CODECS_LOC_VARS
1561 methods_loc)) 1698 methods_loc))
@@ -1565,7 +1702,10 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1565 } 1702 }
1566 else if (methods.IsEmpty()) 1703 else if (methods.IsEmpty())
1567 { 1704 {
1568 AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size()); 1705 AddDefaultMethod(methods_loc,
1706 _method_for_Extraction.IsEmpty() ? NULL :
1707 _method_for_Extraction.Ptr(),
1708 (unsigned)hp.Hash.Size());
1569 if (!methods_loc.IsEmpty()) 1709 if (!methods_loc.IsEmpty())
1570 { 1710 {
1571 hb_Use = &hb_Loc; 1711 hb_Use = &hb_Loc;
@@ -1613,7 +1753,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1613 Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; 1753 Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod;
1614 if (isSupportedMode 1754 if (isSupportedMode
1615 && res_SetMethods != E_NOTIMPL 1755 && res_SetMethods != E_NOTIMPL
1616 && hb_Use->Hashers.Size() > 0 1756 && !hb_Use->Hashers.IsEmpty()
1617 ) 1757 )
1618 { 1758 {
1619 const CHasherState &hs = hb_Use->Hashers[0]; 1759 const CHasherState &hs = hb_Use->Hashers[0];
@@ -1766,10 +1906,6 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1766 methods.Add(_methods[k]); 1906 methods.Add(_methods[k]);
1767 } 1907 }
1768 } 1908 }
1769 else if (_crcSize_WasSet)
1770 {
1771 AddDefaultMethod(methods, _crcSize);
1772 }
1773 else 1909 else
1774 { 1910 {
1775 Z7_DECL_CMyComPtr_QI_FROM( 1911 Z7_DECL_CMyComPtr_QI_FROM(
@@ -1781,12 +1917,23 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1781 RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) 1917 RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop))
1782 if (prop.vt == VT_BSTR) 1918 if (prop.vt == VT_BSTR)
1783 { 1919 {
1784 const UString method = GetMethod_from_FileName(prop.bstrVal); 1920 AString method;
1921 /* const bool isKnownMethod = */ GetMethod_from_FileName(prop.bstrVal, method);
1785 if (!method.IsEmpty()) 1922 if (!method.IsEmpty())
1786 methods.Add(method); 1923 {
1924 AddDefaultMethod(methods, method, _crcSize_WasSet ? _crcSize : 0);
1925 if (methods.IsEmpty())
1926 return E_NOTIMPL;
1927 }
1787 } 1928 }
1788 } 1929 }
1789 } 1930 }
1931 if (methods.IsEmpty() && _crcSize_WasSet)
1932 {
1933 AddDefaultMethod(methods,
1934 NULL, // name
1935 _crcSize);
1936 }
1790 1937
1791 RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) 1938 RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods))
1792 1939
@@ -2030,6 +2177,15 @@ HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
2030} 2177}
2031 2178
2032 2179
2180void CHandler::InitProps()
2181{
2182 _supportWindowsBackslash = true;
2183 _crcSize_WasSet = false;
2184 _crcSize = 4;
2185 _methods.Clear();
2186 _options.Init_HashOptionsLocal();
2187}
2188
2033Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) 2189Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
2034{ 2190{
2035 COM_TRY_BEGIN 2191 COM_TRY_BEGIN
@@ -2076,11 +2232,32 @@ void Codecs_AddHashArcHandler(CCodecs *codecs)
2076 2232
2077 // ubuntu uses "SHA256SUMS" file 2233 // ubuntu uses "SHA256SUMS" file
2078 item.AddExts(UString ( 2234 item.AddExts(UString (
2079 "sha256 sha512 sha224 sha384 sha1 sha md5" 2235 "sha256"
2080 // "b2sum" 2236 " sha512"
2081 " crc32 crc64" 2237 " sha384"
2082 " asc" 2238 " sha224"
2239 " sha512-224"
2240 " sha512-256"
2241 " sha3-224"
2242 " sha3-256"
2243 " sha3-384"
2244 " sha3-512"
2245 // " shake128"
2246 // " shake256"
2247 " sha1"
2248 " sha2"
2249 " sha3"
2250 " sha"
2251 " md5"
2252 " blake2s"
2253 " blake2b"
2254 " blake2sp"
2255 " xxh64"
2256 " crc32"
2257 " crc64"
2083 " cksum" 2258 " cksum"
2259 " asc"
2260 // " b2sum"
2084 ), 2261 ),
2085 UString()); 2262 UString());
2086 2263
diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h
index 1e9dbf4..b8f867f 100644
--- a/CPP/7zip/UI/Common/HashCalc.h
+++ b/CPP/7zip/UI/Common/HashCalc.h
@@ -279,32 +279,25 @@ Z7_CLASS_IMP_CHandler_IInArchive_3(
279 bool _isArc; 279 bool _isArc;
280 bool _supportWindowsBackslash; 280 bool _supportWindowsBackslash;
281 bool _crcSize_WasSet; 281 bool _crcSize_WasSet;
282 UInt64 _phySize;
283 CObjectVector<CHashPair> HashPairs;
284 UString _nameExtenstion;
285 // UString _method_fromName;
286 AString _pgpMethod;
287 bool _is_CksumMode; 282 bool _is_CksumMode;
288 bool _is_PgpMethod; 283 bool _is_PgpMethod;
289 bool _is_ZeroMode; 284 bool _is_ZeroMode;
290 bool _are_there_Tags; 285 bool _are_there_Tags;
291 bool _are_there_Dirs; 286 bool _are_there_Dirs;
287 bool _is_KnownMethod_in_FileName;
292 bool _hashSize_Defined; 288 bool _hashSize_Defined;
293 unsigned _hashSize; 289 unsigned _hashSize;
294 UInt32 _crcSize; 290 UInt32 _crcSize;
291 UInt64 _phySize;
292 CObjectVector<CHashPair> HashPairs;
295 UStringVector _methods; 293 UStringVector _methods;
294 AString _method_from_FileName;
295 AString _pgpMethod;
296 AString _method_for_Extraction;
296 CHashOptionsLocal _options; 297 CHashOptionsLocal _options;
297 298
298 void ClearVars(); 299 void ClearVars();
299 300 void InitProps();
300 void InitProps()
301 {
302 _supportWindowsBackslash = true;
303 _crcSize_WasSet = false;
304 _crcSize = 4;
305 _methods.Clear();
306 _options.Init_HashOptionsLocal();
307 }
308 301
309 bool CanUpdate() const 302 bool CanUpdate() const
310 { 303 {
diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp
index 6bf53ea..943435a 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.cpp
+++ b/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -170,7 +170,7 @@ void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
170 if (i < addExts.Size()) 170 if (i < addExts.Size())
171 { 171 {
172 extInfo.AddExt = addExts[i]; 172 extInfo.AddExt = addExts[i];
173 if (extInfo.AddExt == L"*") 173 if (extInfo.AddExt.IsEqualTo("*"))
174 extInfo.AddExt.Empty(); 174 extInfo.AddExt.Empty();
175 } 175 }
176 Exts.Add(extInfo); 176 Exts.Add(extInfo);
@@ -931,8 +931,8 @@ bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &forma
931 const UString name = arcType.Mid(pos, (unsigned)pos2 - pos); 931 const UString name = arcType.Mid(pos, (unsigned)pos2 - pos);
932 if (name.IsEmpty()) 932 if (name.IsEmpty())
933 return false; 933 return false;
934 int index = FindFormatForArchiveType(name); 934 const int index = FindFormatForArchiveType(name);
935 if (index < 0 && name != L"*") 935 if (index < 0 && !name.IsEqualTo("*"))
936 { 936 {
937 formatIndices.Clear(); 937 formatIndices.Clear();
938 return false; 938 return false;
diff --git a/CPP/7zip/UI/Common/TempFiles.cpp b/CPP/7zip/UI/Common/TempFiles.cpp
index 2f86838..ad16e36 100644
--- a/CPP/7zip/UI/Common/TempFiles.cpp
+++ b/CPP/7zip/UI/Common/TempFiles.cpp
@@ -13,7 +13,8 @@ void CTempFiles::Clear()
13{ 13{
14 while (!Paths.IsEmpty()) 14 while (!Paths.IsEmpty())
15 { 15 {
16 NDir::DeleteFileAlways(Paths.Back()); 16 if (NeedDeleteFiles)
17 NDir::DeleteFileAlways(Paths.Back());
17 Paths.DeleteBack(); 18 Paths.DeleteBack();
18 } 19 }
19} 20}
diff --git a/CPP/7zip/UI/Common/TempFiles.h b/CPP/7zip/UI/Common/TempFiles.h
index dd4ac20..83c741f 100644
--- a/CPP/7zip/UI/Common/TempFiles.h
+++ b/CPP/7zip/UI/Common/TempFiles.h
@@ -10,6 +10,9 @@ class CTempFiles
10 void Clear(); 10 void Clear();
11public: 11public:
12 FStringVector Paths; 12 FStringVector Paths;
13 bool NeedDeleteFiles;
14
15 CTempFiles(): NeedDeleteFiles(true) {}
13 ~CTempFiles() { Clear(); } 16 ~CTempFiles() { Clear(); }
14}; 17};
15 18
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
index ed48605..1c2754e 100644
--- a/CPP/7zip/UI/Common/Update.cpp
+++ b/CPP/7zip/UI/Common/Update.cpp
@@ -474,7 +474,7 @@ static HRESULT Compress(
474 474
475 CArcToDoStat stat2; 475 CArcToDoStat stat2;
476 476
477 if (options.RenamePairs.Size() != 0) 477 if (options.RenameMode || options.RenamePairs.Size() != 0)
478 { 478 {
479 FOR_VECTOR (i, arcItems) 479 FOR_VECTOR (i, arcItems)
480 { 480 {
@@ -1096,6 +1096,30 @@ typedef Z7_WIN_MAPISENDMAILW FAR *Z7_WIN_LPMAPISENDMAILW;
1096#endif // _WIN32 1096#endif // _WIN32
1097 1097
1098 1098
1099struct C_CopyFileProgress_to_IUpdateCallbackUI2 Z7_final:
1100 public ICopyFileProgress
1101{
1102 IUpdateCallbackUI2 *Callback;
1103 HRESULT CallbackResult;
1104 // bool Disable_Break;
1105
1106 virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) Z7_override
1107 {
1108 const HRESULT res = Callback->MoveArc_Progress(total, current);
1109 CallbackResult = res;
1110 // if (Disable_Break && res == E_ABORT) res = S_OK;
1111 return res == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL;
1112 }
1113
1114 C_CopyFileProgress_to_IUpdateCallbackUI2(
1115 IUpdateCallbackUI2 *callback) :
1116 Callback(callback),
1117 CallbackResult(S_OK)
1118 // , Disable_Break(false)
1119 {}
1120};
1121
1122
1099HRESULT UpdateArchive( 1123HRESULT UpdateArchive(
1100 CCodecs *codecs, 1124 CCodecs *codecs,
1101 const CObjectVector<COpenType> &types, 1125 const CObjectVector<COpenType> &types,
@@ -1311,7 +1335,7 @@ HRESULT UpdateArchive(
1311 return E_NOTIMPL; 1335 return E_NOTIMPL;
1312 } 1336 }
1313 1337
1314 bool thereIsInArchive = arcLink.IsOpen; 1338 const bool thereIsInArchive = arcLink.IsOpen;
1315 if (!thereIsInArchive && renameMode) 1339 if (!thereIsInArchive && renameMode)
1316 return E_FAIL; 1340 return E_FAIL;
1317 1341
@@ -1588,7 +1612,14 @@ HRESULT UpdateArchive(
1588 multiStreams.DisableDeletion(); 1612 multiStreams.DisableDeletion();
1589 RINOK(multiStreams.Destruct()) 1613 RINOK(multiStreams.Destruct())
1590 1614
1591 tempFiles.Paths.Clear(); 1615 // here we disable deleting of temp archives.
1616 // note: archive moving can fail, or it can be interrupted,
1617 // if we move new temp update from another volume.
1618 // And we still want to keep temp archive in that case,
1619 // because we will have deleted original archive.
1620 tempFiles.NeedDeleteFiles = false;
1621 // tempFiles.Paths.Clear();
1622
1592 if (createTempFile) 1623 if (createTempFile)
1593 { 1624 {
1594 try 1625 try
@@ -1603,16 +1634,29 @@ HRESULT UpdateArchive(
1603 if (!DeleteFileAlways(us2fs(arcPath))) 1634 if (!DeleteFileAlways(us2fs(arcPath)))
1604 return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); 1635 return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath));
1605 } 1636 }
1606 1637
1607 if (!MyMoveFile(tempPath, us2fs(arcPath))) 1638 UInt64 totalArcSize = 0;
1639 {
1640 NFind::CFileInfo fi;
1641 if (fi.Find(tempPath))
1642 totalArcSize = fi.Size;
1643 }
1644 RINOK(callback->MoveArc_Start(fs2us(tempPath), arcPath,
1645 totalArcSize, BoolToInt(thereIsInArchive)))
1646
1647 C_CopyFileProgress_to_IUpdateCallbackUI2 prox(callback);
1648 // if we update archive, we have removed original archive.
1649 // So if we break archive moving, we will have only temporary archive.
1650 // We can disable breaking here:
1651 // prox.Disable_Break = thereIsInArchive;
1652
1653 if (!MyMoveFile_with_Progress(tempPath, us2fs(arcPath), &prox))
1608 { 1654 {
1609 errorInfo.SystemError = ::GetLastError(); 1655 errorInfo.SystemError = ::GetLastError();
1610 errorInfo.Message = "cannot move the file"; 1656 errorInfo.Message = "cannot move the file";
1611 if (errorInfo.SystemError == ERROR_INVALID_PARAMETER) 1657 if (errorInfo.SystemError == ERROR_INVALID_PARAMETER)
1612 { 1658 {
1613 NFind::CFileInfo fi; 1659 if (totalArcSize > (UInt32)(Int32)-1)
1614 if (fi.Find(tempPath) &&
1615 fi.Size > (UInt32)(Int32)-1)
1616 { 1660 {
1617 // bool isFsDetected = false; 1661 // bool isFsDetected = false;
1618 // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected) 1662 // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected)
@@ -1622,10 +1666,20 @@ HRESULT UpdateArchive(
1622 } 1666 }
1623 } 1667 }
1624 } 1668 }
1669 // if there was no input archive, and we have operation breaking.
1670 // then we can remove temporary archive, because we still have original uncompressed files.
1671 if (!thereIsInArchive
1672 && prox.CallbackResult == E_ABORT)
1673 tempFiles.NeedDeleteFiles = true;
1625 errorInfo.FileNames.Add(tempPath); 1674 errorInfo.FileNames.Add(tempPath);
1626 errorInfo.FileNames.Add(us2fs(arcPath)); 1675 errorInfo.FileNames.Add(us2fs(arcPath));
1676 RINOK(prox.CallbackResult)
1627 return errorInfo.Get_HRESULT_Error(); 1677 return errorInfo.Get_HRESULT_Error();
1628 } 1678 }
1679
1680 // MoveArc_Finish() can return delayed user break (E_ABORT) status,
1681 // if callback callee ignored interruption to finish archive creation operation.
1682 RINOK(callback->MoveArc_Finish())
1629 1683
1630 /* 1684 /*
1631 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) 1685 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
@@ -1866,7 +1920,7 @@ Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
1866 if (NFind::DoesDirExist(phyPath)) 1920 if (NFind::DoesDirExist(phyPath))
1867 { 1921 {
1868 RINOK(callback->DeletingAfterArchiving(phyPath, true)) 1922 RINOK(callback->DeletingAfterArchiving(phyPath, true))
1869 RemoveDir(phyPath); 1923 RemoveDirAlways_if_Empty(phyPath);
1870 } 1924 }
1871 } 1925 }
1872 1926
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h
index a9459ff..ae141e5 100644
--- a/CPP/7zip/UI/Common/Update.h
+++ b/CPP/7zip/UI/Common/Update.h
@@ -12,8 +12,6 @@
12#include "UpdateAction.h" 12#include "UpdateAction.h"
13#include "UpdateCallback.h" 13#include "UpdateCallback.h"
14 14
15#include "DirItem.h"
16
17enum EArcNameMode 15enum EArcNameMode
18{ 16{
19 k_ArcNameMode_Smart, 17 k_ArcNameMode_Smart,
@@ -96,6 +94,7 @@ struct CUpdateOptions
96 94
97 bool DeleteAfterCompressing; 95 bool DeleteAfterCompressing;
98 bool SetArcMTime; 96 bool SetArcMTime;
97 bool RenameMode;
99 98
100 CBoolPair NtSecurity; 99 CBoolPair NtSecurity;
101 CBoolPair AltStreams; 100 CBoolPair AltStreams;
@@ -141,6 +140,7 @@ struct CUpdateOptions
141 140
142 DeleteAfterCompressing(false), 141 DeleteAfterCompressing(false),
143 SetArcMTime(false), 142 SetArcMTime(false),
143 RenameMode(false),
144 144
145 ArcNameMode(k_ArcNameMode_Smart), 145 ArcNameMode(k_ArcNameMode_Smart),
146 PathMode(NWildcard::k_RelatPath) 146 PathMode(NWildcard::k_RelatPath)
@@ -195,6 +195,9 @@ Z7_PURE_INTERFACES_BEGIN
195 virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \ 195 virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \
196 virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \ 196 virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \
197 virtual HRESULT FinishDeletingAfterArchiving() x \ 197 virtual HRESULT FinishDeletingAfterArchiving() x \
198 virtual HRESULT MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode) x \
199 virtual HRESULT MoveArc_Progress(UInt64 total, UInt64 current) x \
200 virtual HRESULT MoveArc_Finish() x \
198 201
199DECLARE_INTERFACE(IUpdateCallbackUI2): 202DECLARE_INTERFACE(IUpdateCallbackUI2):
200 public IUpdateCallbackUI, 203 public IUpdateCallbackUI,
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
index d3ee639..e2f1866 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -32,6 +32,7 @@
32#include "../../../Windows/PropVariant.h" 32#include "../../../Windows/PropVariant.h"
33 33
34#include "../../Common/StreamObjects.h" 34#include "../../Common/StreamObjects.h"
35#include "../../Archive/Common/ItemNameUtils.h"
35 36
36#include "UpdateCallback.h" 37#include "UpdateCallback.h"
37 38
@@ -306,7 +307,7 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, con
306 307
307#if defined(_WIN32) && !defined(UNDER_CE) 308#if defined(_WIN32) && !defined(UNDER_CE)
308 309
309static UString GetRelativePath(const UString &to, const UString &from) 310static UString GetRelativePath(const UString &to, const UString &from, bool isWSL)
310{ 311{
311 UStringVector partsTo, partsFrom; 312 UStringVector partsTo, partsFrom;
312 SplitPathToParts(to, partsTo); 313 SplitPathToParts(to, partsTo);
@@ -324,11 +325,12 @@ static UString GetRelativePath(const UString &to, const UString &from)
324 325
325 if (i == 0) 326 if (i == 0)
326 { 327 {
327 #ifdef _WIN32 328#ifdef _WIN32
328 if (NName::IsDrivePath(to) || 329 if (isWSL ||
329 NName::IsDrivePath(from)) 330 (NName::IsDrivePath(to) ||
331 NName::IsDrivePath(from)))
330 return to; 332 return to;
331 #endif 333#endif
332 } 334 }
333 335
334 UString s; 336 UString s;
@@ -373,54 +375,87 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
373 return S_OK; 375 return S_OK;
374 } 376 }
375 377
376 #if !defined(UNDER_CE) 378#if !defined(UNDER_CE)
377
378 if (up.DirIndex >= 0) 379 if (up.DirIndex >= 0)
379 { 380 {
380 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; 381 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
381 382 if (di.ReparseData.Size())
382 #ifdef _WIN32
383 // if (di.IsDir())
384 { 383 {
384#ifdef _WIN32
385 CReparseAttr attr; 385 CReparseAttr attr;
386 if (attr.Parse(di.ReparseData, di.ReparseData.Size())) 386 if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
387 { 387 {
388 const UString simpleName = attr.GetPath(); 388 UString path = attr.GetPath();
389 if (!attr.IsSymLink_WSL() && attr.IsRelative_Win()) 389 if (!path.IsEmpty())
390 prop = simpleName;
391 else
392 { 390 {
393 const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); 391 bool isWSL = attr.IsSymLink_WSL();
394 FString fullPath; 392 if (isWSL)
395 if (NDir::MyGetFullPathName(phyPath, fullPath)) 393 NArchive::NItemName::ReplaceToWinSlashes(path, true); // useBackslashReplacement
394 // it's expected that (path) now uses windows slashes.
395 // CReparseAttr::IsRelative_Win() returns true if FLAG_RELATIVE is set
396 // CReparseAttr::IsRelative_Win() returns true for "\dir1\path"
397 // but we want to store real relative paths without "\" root prefix.
398 // so we parse path instead of IsRelative_Win() calling.
399 if (// attr.IsRelative_Win() ||
400 (isWSL ?
401 IS_PATH_SEPAR(path[0]) :
402 NName::IsAbsolutePath(path)))
396 { 403 {
397 prop = GetRelativePath(simpleName, fs2us(fullPath)); 404 // (path) is abolute path or relative to root: "\path"
405 // we try to convert (path) to relative path for writing to archive.
406 const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex);
407 FString fullPath;
408 if (NDir::MyGetFullPathName(phyPath, fullPath))
409 {
410 if (IS_PATH_SEPAR(path[0]) &&
411 !IS_PATH_SEPAR(path[1]))
412 {
413 // path is relative to root of (fullPath): "\path"
414 const unsigned prefixSize = NName::GetRootPrefixSize(fullPath);
415 if (prefixSize)
416 {
417 path.DeleteFrontal(1);
418 path.Insert(0, fs2us(fullPath.Left(prefixSize)));
419 // we have changed "\" prefix to drive prefix "c:\" in (path).
420 // (path) is Windows path now.
421 isWSL = false;
422 }
423 }
424 }
425 path = GetRelativePath(path, fs2us(fullPath), isWSL);
398 } 426 }
427#if WCHAR_PATH_SEPARATOR != L'/'
428 // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes.
429 // so we can return any slashes to TAR handler.
430 // or we can convert to linux slashes here,
431 // because input IInArchive handler uses linux slashes for kpidSymLink.
432 // path.Replace(WCHAR_PATH_SEPARATOR, L'/');
433#endif
434 if (!path.IsEmpty())
435 prop = path;
399 } 436 }
400 prop.Detach(value);
401 return S_OK;
402 } 437 }
403 } 438#else // ! _WIN32
404
405 #else // _WIN32
406
407 if (di.ReparseData.Size() != 0)
408 {
409 AString utf; 439 AString utf;
410 utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); 440 utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size());
411 441 #if 0 // 0 - for debug
442 // it's expected that link data uses system codepage.
443 // fs2us() ignores conversion errors. But we want correct path
444 UString us (fs2us(utf));
445 #else
412 UString us; 446 UString us;
413 if (ConvertUTF8ToUnicode(utf, us)) 447 if (ConvertUTF8ToUnicode(utf, us))
448 #endif
414 { 449 {
415 prop = us; 450 if (!us.IsEmpty())
416 prop.Detach(value); 451 prop = us;
417 return S_OK;
418 } 452 }
453#endif // ! _WIN32
419 } 454 }
420 455 prop.Detach(value);
421 #endif // _WIN32 456 return S_OK;
422 } 457 }
423 #endif // !defined(UNDER_CE) 458#endif // !defined(UNDER_CE)
424 } 459 }
425 else if (propID == kpidHardLink) 460 else if (propID == kpidHardLink)
426 { 461 {
@@ -428,7 +463,12 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
428 { 463 {
429 const CKeyKeyValPair &pair = _map[_hardIndex_To]; 464 const CKeyKeyValPair &pair = _map[_hardIndex_To];
430 const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; 465 const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
431 prop = DirItems->GetLogPath((unsigned)up2.DirIndex); 466 const UString path = DirItems->GetLogPath((unsigned)up2.DirIndex);
467#if WCHAR_PATH_SEPARATOR != L'/'
468 // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes.
469 // path.Replace(WCHAR_PATH_SEPARATOR, L'/');
470#endif
471 prop = path;
432 prop.Detach(value); 472 prop.Detach(value);
433 return S_OK; 473 return S_OK;
434 } 474 }
@@ -438,7 +478,7 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
438 return S_OK; 478 return S_OK;
439 } 479 }
440 } 480 }
441 } 481 } // if (up.NewData)
442 482
443 if (up.IsAnti 483 if (up.IsAnti
444 && propID != kpidIsDir 484 && propID != kpidIsDir
diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp
index cfec635..a492967 100644
--- a/CPP/7zip/UI/Common/WorkDir.cpp
+++ b/CPP/7zip/UI/Common/WorkDir.cpp
@@ -63,24 +63,22 @@ HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)
63 NWorkDir::CInfo workDirInfo; 63 NWorkDir::CInfo workDirInfo;
64 workDirInfo.Load(); 64 workDirInfo.Load();
65 FString namePart; 65 FString namePart;
66 const FString workDir = GetWorkDir(workDirInfo, originalPath, namePart); 66 FString path = GetWorkDir(workDirInfo, originalPath, namePart);
67 CreateComplexDir(workDir); 67 CreateComplexDir(path);
68 path += namePart;
68 _outStreamSpec = new COutFileStream; 69 _outStreamSpec = new COutFileStream;
69 OutStream = _outStreamSpec; 70 OutStream = _outStreamSpec;
70 if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File)) 71 if (!_tempFile.Create(path, &_outStreamSpec->File))
71 {
72 return GetLastError_noZero_HRESULT(); 72 return GetLastError_noZero_HRESULT();
73 }
74 _originalPath = originalPath; 73 _originalPath = originalPath;
75 return S_OK; 74 return S_OK;
76} 75}
77 76
78HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal) 77HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal,
78 NWindows::NFile::NDir::ICopyFileProgress *progress)
79{ 79{
80 OutStream.Release(); 80 OutStream.Release();
81 if (!_tempFile.MoveTo(_originalPath, deleteOriginal)) 81 if (!_tempFile.MoveTo(_originalPath, deleteOriginal, progress))
82 {
83 return GetLastError_noZero_HRESULT(); 82 return GetLastError_noZero_HRESULT();
84 }
85 return S_OK; 83 return S_OK;
86} 84}
diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h
index d32ab9d..fed8c4a 100644
--- a/CPP/7zip/UI/Common/WorkDir.h
+++ b/CPP/7zip/UI/Common/WorkDir.h
@@ -11,7 +11,7 @@
11 11
12FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName); 12FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName);
13 13
14class CWorkDirTempFile 14class CWorkDirTempFile MY_UNCOPYABLE
15{ 15{
16 FString _originalPath; 16 FString _originalPath;
17 NWindows::NFile::NDir::CTempFile _tempFile; 17 NWindows::NFile::NDir::CTempFile _tempFile;
@@ -19,8 +19,12 @@ class CWorkDirTempFile
19public: 19public:
20 CMyComPtr<IOutStream> OutStream; 20 CMyComPtr<IOutStream> OutStream;
21 21
22 const FString &Get_OriginalFilePath() const { return _originalPath; }
23 const FString &Get_TempFilePath() const { return _tempFile.GetPath(); }
24
22 HRESULT CreateTempFile(const FString &originalPath); 25 HRESULT CreateTempFile(const FString &originalPath);
23 HRESULT MoveToOriginal(bool deleteOriginal); 26 HRESULT MoveToOriginal(bool deleteOriginal,
27 NWindows::NFile::NDir::ICopyFileProgress *progress = NULL);
24}; 28};
25 29
26#endif 30#endif
diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp
index 73c56cf..936b888 100644
--- a/CPP/7zip/UI/Common/ZipRegistry.cpp
+++ b/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -45,8 +45,8 @@ static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value)
45 45
46static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value) 46static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value)
47{ 47{
48 if (key.QueryValue(name, value) != ERROR_SUCCESS) 48 value = (UInt32)(Int32)-1;
49 value = (UInt32)(Int32)-1; 49 key.GetValue_UInt32_IfOk(name, value);
50} 50}
51 51
52 52
@@ -59,7 +59,7 @@ static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b)
59static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val) 59static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val)
60{ 60{
61 bool oldVal = false; 61 bool oldVal = false;
62 if (key.GetValue_IfOk(name, oldVal) == ERROR_SUCCESS) 62 if (key.GetValue_bool_IfOk(name, oldVal) == ERROR_SUCCESS)
63 if (val == oldVal) 63 if (val == oldVal)
64 return; 64 return;
65 key.SetValue(name, val); 65 key.SetValue(name, val);
@@ -76,13 +76,13 @@ static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoo
76static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b) 76static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b)
77{ 77{
78 b.Val = false; 78 b.Val = false;
79 b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS); 79 b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS);
80} 80}
81 81
82static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b) 82static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b)
83{ 83{
84 b.Val = true; 84 b.Val = true;
85 b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS); 85 b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS);
86} 86}
87 87
88namespace NExtract 88namespace NExtract
@@ -155,12 +155,12 @@ void CInfo::Load()
155 155
156 key.GetValue_Strings(kPathHistory, Paths); 156 key.GetValue_Strings(kPathHistory, Paths);
157 UInt32 v; 157 UInt32 v;
158 if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths) 158 if (key.GetValue_UInt32_IfOk(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths)
159 { 159 {
160 PathMode = (NPathMode::EEnum)v; 160 PathMode = (NPathMode::EEnum)v;
161 PathMode_Force = true; 161 PathMode_Force = true;
162 } 162 }
163 if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting) 163 if (key.GetValue_UInt32_IfOk(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting)
164 { 164 {
165 OverwriteMode = (NOverwriteMode::EEnum)v; 165 OverwriteMode = (NOverwriteMode::EEnum)v;
166 OverwriteMode_Force = true; 166 OverwriteMode_Force = true;
@@ -181,7 +181,7 @@ bool Read_ShowPassword()
181 bool showPassword = false; 181 bool showPassword = false;
182 if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) 182 if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
183 return showPassword; 183 return showPassword;
184 key.GetValue_IfOk(kShowPassword, showPassword); 184 key.GetValue_bool_IfOk(kShowPassword, showPassword);
185 return showPassword; 185 return showPassword;
186} 186}
187 187
@@ -189,13 +189,10 @@ UInt32 Read_LimitGB()
189{ 189{
190 CS_LOCK 190 CS_LOCK
191 CKey key; 191 CKey key;
192 UInt32 v = (UInt32)(Int32)-1;
192 if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS) 193 if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS)
193 { 194 key.GetValue_UInt32_IfOk(kMemLimit, v);
194 UInt32 v; 195 return v;
195 if (key.QueryValue(kMemLimit, v) == ERROR_SUCCESS)
196 return v;
197 }
198 return (UInt32)(Int32)-1;
199} 196}
200 197
201} 198}
@@ -371,9 +368,9 @@ void CInfo::Load()
371 UString a; 368 UString a;
372 if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) 369 if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
373 ArcType = a; 370 ArcType = a;
374 key.GetValue_IfOk(kLevel, Level); 371 key.GetValue_UInt32_IfOk(kLevel, Level);
375 key.GetValue_IfOk(kShowPassword, ShowPassword); 372 key.GetValue_bool_IfOk(kShowPassword, ShowPassword);
376 key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders); 373 key.GetValue_bool_IfOk(kEncryptHeaders, EncryptHeaders);
377} 374}
378 375
379 376
@@ -517,7 +514,7 @@ void CInfo::Load()
517 return; 514 return;
518 515
519 UInt32 dirType; 516 UInt32 dirType;
520 if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS) 517 if (key.GetValue_UInt32_IfOk(kWorkDirType, dirType) != ERROR_SUCCESS)
521 return; 518 return;
522 switch (dirType) 519 switch (dirType)
523 { 520 {
@@ -535,7 +532,7 @@ void CInfo::Load()
535 if (Mode == NMode::kSpecified) 532 if (Mode == NMode::kSpecified)
536 Mode = NMode::kSystem; 533 Mode = NMode::kSystem;
537 } 534 }
538 key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly); 535 key.GetValue_bool_IfOk(kTempRemovableOnly, ForRemovableOnly);
539} 536}
540 537
541} 538}
@@ -598,5 +595,5 @@ void CContextMenuInfo::Load()
598 595
599 Key_Get_UInt32(key, kWriteZoneId, WriteZone); 596 Key_Get_UInt32(key, kWriteZoneId, WriteZone);
600 597
601 Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); 598 Flags_Def = (key.GetValue_UInt32_IfOk(kContextMenu, Flags) == ERROR_SUCCESS);
602} 599}
diff --git a/CPP/7zip/UI/Console/ConsoleClose.cpp b/CPP/7zip/UI/Console/ConsoleClose.cpp
index 9e4c040..a184ffb 100644
--- a/CPP/7zip/UI/Console/ConsoleClose.cpp
+++ b/CPP/7zip/UI/Console/ConsoleClose.cpp
@@ -16,7 +16,7 @@
16namespace NConsoleClose { 16namespace NConsoleClose {
17 17
18unsigned g_BreakCounter = 0; 18unsigned g_BreakCounter = 0;
19static const unsigned kBreakAbortThreshold = 2; 19static const unsigned kBreakAbortThreshold = 3;
20 20
21#ifdef _WIN32 21#ifdef _WIN32
22 22
@@ -28,8 +28,7 @@ static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
28 return TRUE; 28 return TRUE;
29 } 29 }
30 30
31 g_BreakCounter++; 31 if (++g_BreakCounter < kBreakAbortThreshold)
32 if (g_BreakCounter < kBreakAbortThreshold)
33 return TRUE; 32 return TRUE;
34 return FALSE; 33 return FALSE;
35 /* 34 /*
@@ -47,7 +46,7 @@ static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
47CCtrlHandlerSetter::CCtrlHandlerSetter() 46CCtrlHandlerSetter::CCtrlHandlerSetter()
48{ 47{
49 if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE)) 48 if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
50 throw "SetConsoleCtrlHandler fails"; 49 throw 1019; // "SetConsoleCtrlHandler fails";
51} 50}
52 51
53CCtrlHandlerSetter::~CCtrlHandlerSetter() 52CCtrlHandlerSetter::~CCtrlHandlerSetter()
@@ -63,8 +62,7 @@ CCtrlHandlerSetter::~CCtrlHandlerSetter()
63 62
64static void HandlerRoutine(int) 63static void HandlerRoutine(int)
65{ 64{
66 g_BreakCounter++; 65 if (++g_BreakCounter < kBreakAbortThreshold)
67 if (g_BreakCounter < kBreakAbortThreshold)
68 return; 66 return;
69 exit(EXIT_FAILURE); 67 exit(EXIT_FAILURE);
70} 68}
diff --git a/CPP/7zip/UI/Console/ConsoleClose.h b/CPP/7zip/UI/Console/ConsoleClose.h
index 25c5d0c..b0d99b4 100644
--- a/CPP/7zip/UI/Console/ConsoleClose.h
+++ b/CPP/7zip/UI/Console/ConsoleClose.h
@@ -5,7 +5,7 @@
5 5
6namespace NConsoleClose { 6namespace NConsoleClose {
7 7
8class CCtrlBreakException {}; 8// class CCtrlBreakException {};
9 9
10#ifdef UNDER_CE 10#ifdef UNDER_CE
11 11
diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
index f59d4c1..b127631 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -928,7 +928,7 @@ HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
928 if (result == E_ABORT 928 if (result == E_ABORT
929 || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)) 929 || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL))
930 return result; 930 return result;
931 NumArcsWithError++; 931 NumArcsWithError++;
932 932
933 if (_se) 933 if (_se)
934 { 934 {
diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp
index dabd696..90e00a4 100644
--- a/CPP/7zip/UI/Console/Main.cpp
+++ b/CPP/7zip/UI/Console/Main.cpp
@@ -908,9 +908,12 @@ int Main2(
908 908
909 if (options.EnableHeaders) 909 if (options.EnableHeaders)
910 { 910 {
911 ShowCopyrightAndHelp(g_StdStream, false); 911 if (g_StdStream)
912 if (!parser.Parse1Log.IsEmpty()) 912 {
913 *g_StdStream << parser.Parse1Log; 913 ShowCopyrightAndHelp(g_StdStream, false);
914 if (!parser.Parse1Log.IsEmpty())
915 *g_StdStream << parser.Parse1Log;
916 }
914 } 917 }
915 918
916 parser.Parse2(options); 919 parser.Parse2(options);
diff --git a/CPP/7zip/UI/Console/MainAr.cpp b/CPP/7zip/UI/Console/MainAr.cpp
index 602ab64..490950b 100644
--- a/CPP/7zip/UI/Console/MainAr.cpp
+++ b/CPP/7zip/UI/Console/MainAr.cpp
@@ -140,11 +140,13 @@ int Z7_CDECL main
140 PrintError(kMemoryExceptionMessage); 140 PrintError(kMemoryExceptionMessage);
141 return (NExitCode::kMemoryError); 141 return (NExitCode::kMemoryError);
142 } 142 }
143/*
143 catch(const NConsoleClose::CCtrlBreakException &) 144 catch(const NConsoleClose::CCtrlBreakException &)
144 { 145 {
145 PrintError(kUserBreakMessage); 146 PrintError(kUserBreakMessage);
146 return (NExitCode::kUserBreak); 147 return (NExitCode::kUserBreak);
147 } 148 }
149*/
148 catch(const CMessagePathException &e) 150 catch(const CMessagePathException &e)
149 { 151 {
150 PrintError(kException_CmdLine_Error_Message); 152 PrintError(kException_CmdLine_Error_Message);
diff --git a/CPP/7zip/UI/Console/PercentPrinter.h b/CPP/7zip/UI/Console/PercentPrinter.h
index 46988a5..379aa1b 100644
--- a/CPP/7zip/UI/Console/PercentPrinter.h
+++ b/CPP/7zip/UI/Console/PercentPrinter.h
@@ -26,6 +26,13 @@ struct CPercentPrinterState
26 26
27class CPercentPrinter: public CPercentPrinterState 27class CPercentPrinter: public CPercentPrinterState
28{ 28{
29public:
30 CStdOutStream *_so;
31 bool DisablePrint;
32 bool NeedFlush;
33 unsigned MaxLen;
34
35private:
29 UInt32 _tickStep; 36 UInt32 _tickStep;
30 DWORD _prevTick; 37 DWORD _prevTick;
31 38
@@ -41,18 +48,13 @@ class CPercentPrinter: public CPercentPrinterState
41 void GetPercents(); 48 void GetPercents();
42 49
43public: 50public:
44 CStdOutStream *_so;
45
46 bool DisablePrint;
47 bool NeedFlush;
48 unsigned MaxLen;
49 51
50 CPercentPrinter(UInt32 tickStep = 200): 52 CPercentPrinter(UInt32 tickStep = 200):
51 _tickStep(tickStep),
52 _prevTick(0),
53 DisablePrint(false), 53 DisablePrint(false),
54 NeedFlush(true), 54 NeedFlush(true),
55 MaxLen(80 - 1) 55 MaxLen(80 - 1),
56 _tickStep(tickStep),
57 _prevTick(0)
56 {} 58 {}
57 59
58 ~CPercentPrinter(); 60 ~CPercentPrinter();
diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
index 3e79645..5185d5c 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -361,6 +361,119 @@ HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size)
361} 361}
362 362
363 363
364
365HRESULT CUpdateCallbackConsole::MoveArc_UpdateStatus()
366{
367 if (NeedPercents())
368 {
369 AString &s = _percent.Command;
370 s = " : ";
371 s.Add_UInt64(_arcMoving_percents);
372 s.Add_Char('%');
373 const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1);
374 if (_arcMoving_current != 0 || totalDefined)
375 {
376 s += " : ";
377 s.Add_UInt64(_arcMoving_current >> 20);
378 s += " MiB";
379 }
380 if (totalDefined)
381 {
382 s += " / ";
383 s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20);
384 s += " MiB";
385 }
386 s += " : temporary archive moving ...";
387 _percent.Print();
388 }
389
390 // we ignore single Ctrl-C, if (_arcMoving_updateMode) mode
391 // because we want to get good final archive instead of temp archive.
392 if (NConsoleClose::g_BreakCounter == 1 && _arcMoving_updateMode)
393 return S_OK;
394 return CheckBreak();
395}
396
397
398HRESULT CUpdateCallbackConsole::MoveArc_Start(
399 const wchar_t *srcTempPath, const wchar_t *destFinalPath,
400 UInt64 size, Int32 updateMode)
401{
402#if 0 // 1 : for debug
403 if (LogLevel > 0 && _so)
404 {
405 ClosePercents_for_so();
406 *_so << "Temporary archive moving:" << endl;
407 _tempU = srcTempPath;
408 _so->Normalize_UString_Path(_tempU);
409 _so->PrintUString(_tempU, _tempA);
410 *_so << endl;
411 _tempU = destFinalPath;
412 _so->Normalize_UString_Path(_tempU);
413 _so->PrintUString(_tempU, _tempA);
414 *_so << endl;
415 }
416#else
417 UNUSED_VAR(srcTempPath)
418 UNUSED_VAR(destFinalPath)
419#endif
420
421 _arcMoving_updateMode = updateMode;
422 _arcMoving_total = size;
423 _arcMoving_current = 0;
424 _arcMoving_percents = 0;
425 return MoveArc_UpdateStatus();
426}
427
428
429HRESULT CUpdateCallbackConsole::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)
430{
431#if 0 // 1 : for debug
432 if (_so)
433 {
434 ClosePercents_for_so();
435 *_so << totalSize << " : " << currentSize << endl;
436 }
437#endif
438
439 UInt64 percents = 0;
440 if (totalSize != 0)
441 {
442 if (totalSize < ((UInt64)1 << 57))
443 percents = currentSize * 100 / totalSize;
444 else
445 percents = currentSize / (totalSize / 100);
446 }
447
448#ifdef _WIN32
449 // Sleep(300); // for debug
450#endif
451 // totalSize = (UInt64)(Int64)-1; // for debug
452
453 if (percents == _arcMoving_percents)
454 return CheckBreak();
455 _arcMoving_current = currentSize;
456 _arcMoving_total = totalSize;
457 _arcMoving_percents = percents;
458 return MoveArc_UpdateStatus();
459}
460
461
462HRESULT CUpdateCallbackConsole::MoveArc_Finish()
463{
464 // _arcMoving_percents = 0;
465 if (NeedPercents())
466 {
467 _percent.Command.Empty();
468 _percent.Print();
469 }
470 // it can return delayed user break (E_ABORT) status,
471 // if it ignored single CTRL+C in MoveArc_Progress().
472 return CheckBreak();
473}
474
475
476
364HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */) 477HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */)
365{ 478{
366 if (LogLevel > 0 && _so) 479 if (LogLevel > 0 && _so)
diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
index 276edba..a386371 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -29,30 +29,31 @@ struct CErrorPathCodes
29 29
30class CCallbackConsoleBase 30class CCallbackConsoleBase
31{ 31{
32protected: 32 void CommonError(const FString &path, DWORD systemError, bool isWarning);
33 CPercentPrinter _percent;
34 33
34protected:
35 CStdOutStream *_so; 35 CStdOutStream *_so;
36 CStdOutStream *_se; 36 CStdOutStream *_se;
37 37
38 void CommonError(const FString &path, DWORD systemError, bool isWarning);
39 // void CommonError(const char *message);
40
41 HRESULT ScanError_Base(const FString &path, DWORD systemError); 38 HRESULT ScanError_Base(const FString &path, DWORD systemError);
42 HRESULT OpenFileError_Base(const FString &name, DWORD systemError); 39 HRESULT OpenFileError_Base(const FString &name, DWORD systemError);
43 HRESULT ReadingFileError_Base(const FString &name, DWORD systemError); 40 HRESULT ReadingFileError_Base(const FString &name, DWORD systemError);
44 41
45public: 42public:
46 bool NeedPercents() const { return _percent._so != NULL; }
47
48 bool StdOutMode; 43 bool StdOutMode;
49
50 bool NeedFlush; 44 bool NeedFlush;
51 unsigned PercentsNameLevel; 45 unsigned PercentsNameLevel;
52 unsigned LogLevel; 46 unsigned LogLevel;
53 47
48protected:
54 AString _tempA; 49 AString _tempA;
55 UString _tempU; 50 UString _tempU;
51 CPercentPrinter _percent;
52
53public:
54 CErrorPathCodes FailedFiles;
55 CErrorPathCodes ScanErrors;
56 UInt64 NumNonOpenFiles;
56 57
57 CCallbackConsoleBase(): 58 CCallbackConsoleBase():
58 StdOutMode(false), 59 StdOutMode(false),
@@ -62,6 +63,7 @@ public:
62 NumNonOpenFiles(0) 63 NumNonOpenFiles(0)
63 {} 64 {}
64 65
66 bool NeedPercents() const { return _percent._so != NULL; }
65 void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } 67 void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
66 68
67 void Init( 69 void Init(
@@ -90,10 +92,6 @@ public:
90 _percent.ClosePrint(false); 92 _percent.ClosePrint(false);
91 } 93 }
92 94
93 CErrorPathCodes FailedFiles;
94 CErrorPathCodes ScanErrors;
95 UInt64 NumNonOpenFiles;
96
97 HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog); 95 HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog);
98 96
99 // void PrintInfoLine(const UString &s); 97 // void PrintInfoLine(const UString &s);
@@ -109,6 +107,14 @@ class CUpdateCallbackConsole Z7_final:
109 Z7_IFACE_IMP(IUpdateCallbackUI) 107 Z7_IFACE_IMP(IUpdateCallbackUI)
110 Z7_IFACE_IMP(IDirItemsCallback) 108 Z7_IFACE_IMP(IDirItemsCallback)
111 Z7_IFACE_IMP(IUpdateCallbackUI2) 109 Z7_IFACE_IMP(IUpdateCallbackUI2)
110
111 HRESULT MoveArc_UpdateStatus();
112
113 UInt64 _arcMoving_total;
114 UInt64 _arcMoving_current;
115 UInt64 _arcMoving_percents;
116 Int32 _arcMoving_updateMode;
117
112public: 118public:
113 bool DeleteMessageWasShown; 119 bool DeleteMessageWasShown;
114 120
@@ -119,7 +125,11 @@ public:
119 #endif 125 #endif
120 126
121 CUpdateCallbackConsole(): 127 CUpdateCallbackConsole():
122 DeleteMessageWasShown(false) 128 _arcMoving_total(0)
129 , _arcMoving_current(0)
130 , _arcMoving_percents(0)
131 , _arcMoving_updateMode(0)
132 , DeleteMessageWasShown(false)
123 #ifndef Z7_NO_CRYPTO 133 #ifndef Z7_NO_CRYPTO
124 , PasswordIsDefined(false) 134 , PasswordIsDefined(false)
125 , AskPassword(false) 135 , AskPassword(false)
diff --git a/CPP/7zip/UI/Console/makefile b/CPP/7zip/UI/Console/makefile
index a20b0cc..d449b38 100644
--- a/CPP/7zip/UI/Console/makefile
+++ b/CPP/7zip/UI/Console/makefile
@@ -59,10 +59,10 @@ COMPRESS_OBJS = \
59C_OBJS = $(C_OBJS) \ 59C_OBJS = $(C_OBJS) \
60 $O\Alloc.obj \ 60 $O\Alloc.obj \
61 $O\CpuArch.obj \ 61 $O\CpuArch.obj \
62 $O\Sort.obj \
63 $O\Threads.obj \ 62 $O\Threads.obj \
64 63
65!include "../../Crc.mak" 64!include "../../Crc.mak"
65!include "../../Sort.mak"
66!include "Console.mak" 66!include "Console.mak"
67 67
68!include "../../7zip.mak" 68!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp
index fab3493..0630d78 100644
--- a/CPP/7zip/UI/Explorer/ContextMenu.cpp
+++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp
@@ -295,9 +295,13 @@ static const CHashCommand g_HashCommands[] =
295{ 295{
296 { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" }, 296 { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" },
297 { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" }, 297 { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" },
298 { CZipContextMenu::kHash_XXH64, "XXH64", "XXH64" }, 298 { CZipContextMenu::kHash_XXH64, "XXH64", "XXH64" },
299 { CZipContextMenu::kHash_MD5, "MD5", "MD5" },
299 { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" }, 300 { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" },
300 { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" }, 301 { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" },
302 { CZipContextMenu::kHash_SHA384, "SHA-384", "SHA384" },
303 { CZipContextMenu::kHash_SHA512, "SHA-512", "SHA512" },
304 { CZipContextMenu::kHash_SHA3_256, "SHA3-256", "SHA3-256" },
301 { CZipContextMenu::kHash_BLAKE2SP, "BLAKE2sp", "BLAKE2sp" }, 305 { CZipContextMenu::kHash_BLAKE2SP, "BLAKE2sp", "BLAKE2sp" },
302 { CZipContextMenu::kHash_All, "*", "*" }, 306 { CZipContextMenu::kHash_All, "*", "*" },
303 { CZipContextMenu::kHash_Generate_SHA256, "SHA-256 -> file.sha256", "SHA256" }, 307 { CZipContextMenu::kHash_Generate_SHA256, "SHA-256 -> file.sha256", "SHA256" },
@@ -1338,8 +1342,12 @@ HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi)
1338 case kHash_CRC32: 1342 case kHash_CRC32:
1339 case kHash_CRC64: 1343 case kHash_CRC64:
1340 case kHash_XXH64: 1344 case kHash_XXH64:
1345 case kHash_MD5:
1341 case kHash_SHA1: 1346 case kHash_SHA1:
1342 case kHash_SHA256: 1347 case kHash_SHA256:
1348 case kHash_SHA384:
1349 case kHash_SHA512:
1350 case kHash_SHA3_256:
1343 case kHash_BLAKE2SP: 1351 case kHash_BLAKE2SP:
1344 case kHash_All: 1352 case kHash_All:
1345 case kHash_Generate_SHA256: 1353 case kHash_Generate_SHA256:
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.h b/CPP/7zip/UI/Explorer/ContextMenu.h
index a68ba9d..2759967 100644
--- a/CPP/7zip/UI/Explorer/ContextMenu.h
+++ b/CPP/7zip/UI/Explorer/ContextMenu.h
@@ -88,8 +88,12 @@ public:
88 kHash_CRC32, 88 kHash_CRC32,
89 kHash_CRC64, 89 kHash_CRC64,
90 kHash_XXH64, 90 kHash_XXH64,
91 kHash_MD5,
91 kHash_SHA1, 92 kHash_SHA1,
92 kHash_SHA256, 93 kHash_SHA256,
94 kHash_SHA384,
95 kHash_SHA512,
96 kHash_SHA3_256,
93 kHash_BLAKE2SP, 97 kHash_BLAKE2SP,
94 kHash_All, 98 kHash_All,
95 kHash_Generate_SHA256, 99 kHash_Generate_SHA256,
diff --git a/CPP/7zip/UI/Explorer/makefile b/CPP/7zip/UI/Explorer/makefile
index 3901d6b..311d70e 100644
--- a/CPP/7zip/UI/Explorer/makefile
+++ b/CPP/7zip/UI/Explorer/makefile
@@ -72,7 +72,7 @@ FM_OBJS = \
72 72
73C_OBJS = \ 73C_OBJS = \
74 $O\CpuArch.obj \ 74 $O\CpuArch.obj \
75 $O\Sort.obj \
76 $O\Threads.obj \ 75 $O\Threads.obj \
77 76
77!include "../../Sort.mak"
78!include "../../7zip.mak" 78!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/Far/Far.cpp b/CPP/7zip/UI/Far/Far.cpp
index 211dde8..962af97 100644
--- a/CPP/7zip/UI/Far/Far.cpp
+++ b/CPP/7zip/UI/Far/Far.cpp
@@ -116,15 +116,16 @@ Z7_CLASS_IMP_COM_3(
116 // DWORD m_StartTickValue; 116 // DWORD m_StartTickValue;
117 bool m_MessageBoxIsShown; 117 bool m_MessageBoxIsShown;
118 118
119 CProgressBox _progressBox;
120
121 bool _numFilesTotalDefined; 119 bool _numFilesTotalDefined;
122 bool _numBytesTotalDefined; 120 bool _numBytesTotalDefined;
123
124public: 121public:
125 bool PasswordIsDefined; 122 bool PasswordIsDefined;
126 UString Password; 123 UString Password;
127 124
125private:
126 CProgressBox _progressBox;
127public:
128
128 COpenArchiveCallback() 129 COpenArchiveCallback()
129 {} 130 {}
130 131
diff --git a/CPP/7zip/UI/Far/FarUtils.cpp b/CPP/7zip/UI/Far/FarUtils.cpp
index ed61ccc..3c33d8e 100644
--- a/CPP/7zip/UI/Far/FarUtils.cpp
+++ b/CPP/7zip/UI/Far/FarUtils.cpp
@@ -281,7 +281,7 @@ UInt32 CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName,
281 return valueDefault; 281 return valueDefault;
282 282
283 UInt32 value; 283 UInt32 value;
284 if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS) 284 if (regKey.GetValue_UInt32_IfOk(valueName, value) != ERROR_SUCCESS)
285 return valueDefault; 285 return valueDefault;
286 286
287 return value; 287 return value;
@@ -295,7 +295,7 @@ bool CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName,
295 return valueDefault; 295 return valueDefault;
296 296
297 bool value; 297 bool value;
298 if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS) 298 if (regKey.GetValue_bool_IfOk(valueName, value) != ERROR_SUCCESS)
299 return valueDefault; 299 return valueDefault;
300 300
301 return value; 301 return value;
diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp
index 2d31b8a..b7f91d6 100644
--- a/CPP/7zip/UI/Far/Plugin.cpp
+++ b/CPP/7zip/UI/Far/Plugin.cpp
@@ -61,7 +61,6 @@ static void MyGetFileTime(IFolderFolder *folder, UInt32 itemIndex,
61} 61}
62 62
63#define kDotsReplaceString "[[..]]" 63#define kDotsReplaceString "[[..]]"
64#define kDotsReplaceStringU L"[[..]]"
65 64
66static void CopyStrLimited(char *dest, const AString &src, unsigned len) 65static void CopyStrLimited(char *dest, const AString &src, unsigned len)
67{ 66{
@@ -84,7 +83,7 @@ void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex)
84 throw 272340; 83 throw 272340;
85 84
86 AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); 85 AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP));
87 if (oemString == "..") 86 if (oemString.IsEqualTo(".."))
88 oemString = kDotsReplaceString; 87 oemString = kDotsReplaceString;
89 88
90 COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString); 89 COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString);
@@ -193,7 +192,7 @@ void CPlugin::EnterToDirectory(const UString &dirName)
193{ 192{
194 CMyComPtr<IFolderFolder> newFolder; 193 CMyComPtr<IFolderFolder> newFolder;
195 UString s = dirName; 194 UString s = dirName;
196 if (dirName == kDotsReplaceStringU) 195 if (dirName.IsEqualTo(kDotsReplaceString))
197 s = ".."; 196 s = "..";
198 _folder->BindToFolder(s, &newFolder); 197 _folder->BindToFolder(s, &newFolder);
199 if (!newFolder) 198 if (!newFolder)
@@ -209,12 +208,12 @@ void CPlugin::EnterToDirectory(const UString &dirName)
209int CPlugin::SetDirectory(const char *aszDir, int /* opMode */) 208int CPlugin::SetDirectory(const char *aszDir, int /* opMode */)
210{ 209{
211 UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP); 210 UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP);
212 if (path == WSTRING_PATH_SEPARATOR) 211 if (path.IsEqualTo(STRING_PATH_SEPARATOR))
213 { 212 {
214 _folder.Release(); 213 _folder.Release();
215 m_ArchiveHandler->BindToRootFolder(&_folder); 214 m_ArchiveHandler->BindToRootFolder(&_folder);
216 } 215 }
217 else if (path == L"..") 216 else if (path.IsEqualTo(".."))
218 { 217 {
219 CMyComPtr<IFolderFolder> newFolder; 218 CMyComPtr<IFolderFolder> newFolder;
220 _folder->BindToParentFolder(&newFolder); 219 _folder->BindToParentFolder(&newFolder);
diff --git a/CPP/7zip/UI/Far/ProgressBox.h b/CPP/7zip/UI/Far/ProgressBox.h
index 6e8b487..f6b36c4 100644
--- a/CPP/7zip/UI/Far/ProgressBox.h
+++ b/CPP/7zip/UI/Far/ProgressBox.h
@@ -45,7 +45,12 @@ class CProgressBox: public CPercentPrinterState
45 DWORD _prevElapsedSec; 45 DWORD _prevElapsedSec;
46 46
47 bool _wasPrinted; 47 bool _wasPrinted;
48public:
49 bool UseBytesForPercents;
50 DWORD StartTick;
51 unsigned MaxLen;
48 52
53private:
49 UString _tempU; 54 UString _tempU;
50 UString _name1U; 55 UString _name1U;
51 UString _name2U; 56 UString _name2U;
@@ -64,15 +69,12 @@ class CProgressBox: public CPercentPrinterState
64 void ReduceString(const UString &src, AString &dest); 69 void ReduceString(const UString &src, AString &dest);
65 70
66public: 71public:
67 DWORD StartTick;
68 bool UseBytesForPercents;
69 unsigned MaxLen;
70 72
71 CProgressBox(UInt32 tickStep = 200): 73 CProgressBox(UInt32 tickStep = 200):
72 _tickStep(tickStep), 74 _tickStep(tickStep),
73 _prevTick(0), 75 _prevTick(0),
74 StartTick(0),
75 UseBytesForPercents(true), 76 UseBytesForPercents(true),
77 StartTick(0),
76 MaxLen(60) 78 MaxLen(60)
77 {} 79 {}
78 80
diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
index 94f0a47..16702d3 100644
--- a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
+++ b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
@@ -210,6 +210,96 @@ Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 op, const wchar
210} 210}
211 211
212 212
213HRESULT CUpdateCallback100Imp::MoveArc_UpdateStatus()
214{
215 MT_LOCK
216
217 if (_percent)
218 {
219 AString s;
220 s.Add_UInt64(_arcMoving_percents);
221 // status.Add_Space();
222 s.Add_Char('%');
223 const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1);
224 if (_arcMoving_current != 0 || totalDefined)
225 {
226 s += " : ";
227 s.Add_UInt64(_arcMoving_current >> 20);
228 s += " MiB";
229 }
230 if (totalDefined)
231 {
232 s += " / ";
233 s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20);
234 s += " MiB";
235 }
236 s += " : temporary archive moving ...";
237 _percent->Command = s;
238 _percent->Print();
239 }
240
241 return CheckBreak2();
242}
243
244
245Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Start(const wchar_t *srcTempPath, const wchar_t * /* destFinalPath */ , UInt64 size, Int32 /* updateMode */))
246{
247 MT_LOCK
248
249 _arcMoving_total = size;
250 _arcMoving_current = 0;
251 _arcMoving_percents = 0;
252 // _arcMoving_updateMode = updateMode;
253 // _name2 = fs2us(destFinalPath);
254 if (_percent)
255 _percent->FileName = srcTempPath;
256 return MoveArc_UpdateStatus();
257}
258
259Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize))
260{
261 UInt64 percents = 0;
262 if (totalSize != 0)
263 {
264 if (totalSize < ((UInt64)1 << 57))
265 percents = currentSize * 100 / totalSize;
266 else
267 percents = currentSize / (totalSize / 100);
268 }
269
270#ifdef _WIN32
271 // Sleep(300); // for debug
272#endif
273 if (percents == _arcMoving_percents)
274 return CheckBreak2();
275 _arcMoving_total = totalSize;
276 _arcMoving_current = currentSize;
277 _arcMoving_percents = percents;
278 // if (_arcMoving_percents > 100) return E_FAIL;
279 return MoveArc_UpdateStatus();
280}
281
282
283Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Finish())
284{
285 // _arcMoving_percents = 0;
286 if (_percent)
287 {
288 _percent->Command.Empty();
289 _percent->FileName.Empty();
290 _percent->Print();
291 }
292 return CheckBreak2();
293}
294
295
296Z7_COM7F_IMF(CUpdateCallback100Imp::Before_ArcReopen())
297{
298 // fixme: we can use Clear_Stop_Status() here
299 return CheckBreak2();
300}
301
302
213extern HRESULT GetPassword(UString &password); 303extern HRESULT GetPassword(UString &password);
214 304
215Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password)) 305Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password))
diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.h b/CPP/7zip/UI/Far/UpdateCallbackFar.h
index 4ec5eed..8d2c8b8 100644
--- a/CPP/7zip/UI/Far/UpdateCallbackFar.h
+++ b/CPP/7zip/UI/Far/UpdateCallbackFar.h
@@ -11,10 +11,11 @@
11 11
12#include "ProgressBox.h" 12#include "ProgressBox.h"
13 13
14Z7_CLASS_IMP_COM_6( 14Z7_CLASS_IMP_COM_7(
15 CUpdateCallback100Imp 15 CUpdateCallback100Imp
16 , IFolderArchiveUpdateCallback 16 , IFolderArchiveUpdateCallback
17 , IFolderArchiveUpdateCallback2 17 , IFolderArchiveUpdateCallback2
18 , IFolderArchiveUpdateCallback_MoveArc
18 , IFolderScanProgress 19 , IFolderScanProgress
19 , ICryptoGetTextPassword2 20 , ICryptoGetTextPassword2
20 , ICryptoGetTextPassword 21 , ICryptoGetTextPassword
@@ -25,6 +26,15 @@ Z7_CLASS_IMP_COM_6(
25 // CMyComPtr<IInFolderArchive> _archiveHandler; 26 // CMyComPtr<IInFolderArchive> _archiveHandler;
26 CProgressBox *_percent; 27 CProgressBox *_percent;
27 // UInt64 _total; 28 // UInt64 _total;
29
30 HRESULT MoveArc_UpdateStatus();
31
32private:
33 UInt64 _arcMoving_total;
34 UInt64 _arcMoving_current;
35 UInt64 _arcMoving_percents;
36 // Int32 _arcMoving_updateMode;
37
28public: 38public:
29 bool PasswordIsDefined; 39 bool PasswordIsDefined;
30 UString Password; 40 UString Password;
@@ -38,6 +48,10 @@ public:
38 _percent = progressBox; 48 _percent = progressBox;
39 PasswordIsDefined = false; 49 PasswordIsDefined = false;
40 Password.Empty(); 50 Password.Empty();
51 _arcMoving_total = 0;
52 _arcMoving_current = 0;
53 _arcMoving_percents = 0;
54 // _arcMoving_updateMode = 0;
41 } 55 }
42}; 56};
43 57
diff --git a/CPP/7zip/UI/Far/makefile b/CPP/7zip/UI/Far/makefile
index a66f9d7..7bc166b 100644
--- a/CPP/7zip/UI/Far/makefile
+++ b/CPP/7zip/UI/Far/makefile
@@ -99,9 +99,9 @@ COMPRESS_OBJS = \
99C_OBJS = \ 99C_OBJS = \
100 $O\Alloc.obj \ 100 $O\Alloc.obj \
101 $O\CpuArch.obj \ 101 $O\CpuArch.obj \
102 $O\Sort.obj \
103 $O\Threads.obj \ 102 $O\Threads.obj \
104 103
105!include "../../Crc.mak" 104!include "../../Crc.mak"
105!include "../../Sort.mak"
106 106
107!include "../../7zip.mak" 107!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/FileManager/App.cpp b/CPP/7zip/UI/FileManager/App.cpp
index 06c2e8b..5b7d616 100644
--- a/CPP/7zip/UI/FileManager/App.cpp
+++ b/CPP/7zip/UI/FileManager/App.cpp
@@ -402,11 +402,17 @@ void CApp::Save()
402 // Save_ShowDeleted(ShowDeletedFiles); 402 // Save_ShowDeleted(ShowDeletedFiles);
403} 403}
404 404
405void CApp::Release() 405void CApp::ReleaseApp()
406{ 406{
407 // 24.09: ReleasePanel() will stop panel timer processing.
408 // but we want to stop timer processing for all panels
409 // before ReleasePanel() calling.
410 unsigned i;
411 for (i = 0; i < kNumPanelsMax; i++)
412 Panels[i].Disable_Processing_Timer_Notify_StatusBar();
407 // It's for unloading COM dll's: don't change it. 413 // It's for unloading COM dll's: don't change it.
408 for (unsigned i = 0; i < kNumPanelsMax; i++) 414 for (i = 0; i < kNumPanelsMax; i++)
409 Panels[i].Release(); 415 Panels[i].ReleasePanel();
410} 416}
411 417
412// reduces path to part that exists on disk (or root prefix of path) 418// reduces path to part that exists on disk (or root prefix of path)
@@ -644,7 +650,7 @@ void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex)
644 destPath += correctName; 650 destPath += correctName;
645 651
646 #if defined(_WIN32) && !defined(UNDER_CE) 652 #if defined(_WIN32) && !defined(UNDER_CE)
647 if (destPath.Len() > 0 && destPath[0] == '\\') 653 if (destPath.Len() != 0 && destPath[0] == '\\')
648 if (destPath.Len() == 1 || destPath[1] != '\\') 654 if (destPath.Len() == 1 || destPath[1] != '\\')
649 { 655 {
650 srcPanel.MessageBox_Error_UnsupportOperation(); 656 srcPanel.MessageBox_Error_UnsupportOperation();
diff --git a/CPP/7zip/UI/FileManager/App.h b/CPP/7zip/UI/FileManager/App.h
index 1e20532..cf74d6a 100644
--- a/CPP/7zip/UI/FileManager/App.h
+++ b/CPP/7zip/UI/FileManager/App.h
@@ -109,7 +109,7 @@ public:
109 HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes); 109 HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes);
110 void Read(); 110 void Read();
111 void Save(); 111 void Save();
112 void Release(); 112 void ReleaseApp();
113 113
114 // void SetFocus(int panelIndex) { Panels[panelIndex].SetFocusToList(); } 114 // void SetFocus(int panelIndex) { Panels[panelIndex].SetFocusToList(); }
115 void SetFocusToLastItem() { Panels[LastFocusedPanel].SetFocusToLastRememberedItem(); } 115 void SetFocusToLastItem() { Panels[LastFocusedPanel].SetFocusToLastRememberedItem(); }
diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp
index 6ec6065..da25969 100644
--- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp
+++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp
@@ -2,7 +2,6 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5
6#include "../../../Common/ComTry.h" 5#include "../../../Common/ComTry.h"
7#include "../../../Common/IntToString.h" 6#include "../../../Common/IntToString.h"
8#include "../../../Common/Lang.h" 7#include "../../../Common/Lang.h"
@@ -27,11 +26,11 @@
27#include "ExtractCallback.h" 26#include "ExtractCallback.h"
28#include "FormatUtils.h" 27#include "FormatUtils.h"
29#include "LangUtils.h" 28#include "LangUtils.h"
29#include "MemDialog.h"
30#include "OverwriteDialog.h" 30#include "OverwriteDialog.h"
31#ifndef Z7_NO_CRYPTO 31#ifndef Z7_NO_CRYPTO
32#include "PasswordDialog.h" 32#include "PasswordDialog.h"
33#endif 33#endif
34#include "MemDialog.h"
35#include "PropertyName.h" 34#include "PropertyName.h"
36 35
37using namespace NWindows; 36using namespace NWindows;
@@ -44,9 +43,9 @@ CExtractCallbackImp::~CExtractCallbackImp() {}
44 43
45void CExtractCallbackImp::Init() 44void CExtractCallbackImp::Init()
46{ 45{
47 _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING); 46 LangString(IDS_PROGRESS_EXTRACTING, _lang_Extracting);
48 _lang_Testing = LangString(IDS_PROGRESS_TESTING); 47 LangString(IDS_PROGRESS_TESTING, _lang_Testing);
49 _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING); 48 LangString(IDS_PROGRESS_SKIPPING, _lang_Skipping);
50 _lang_Reading = "Reading"; 49 _lang_Reading = "Reading";
51 50
52 NumArchiveErrors = 0; 51 NumArchiveErrors = 0;
@@ -107,19 +106,19 @@ HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *by
107 { 106 {
108 if (files) 107 if (files)
109 { 108 {
110 _totalFilesDefined = true; 109 _totalFiles_Defined = true;
111 // res = ProgressDialog->Sync.Set_NumFilesTotal(*files); 110 // res = ProgressDialog->Sync.Set_NumFilesTotal(*files);
112 } 111 }
113 else 112 else
114 _totalFilesDefined = false; 113 _totalFiles_Defined = false;
115 114
116 if (bytes) 115 if (bytes)
117 { 116 {
118 _totalBytesDefined = true; 117 _totalBytes_Defined = true;
119 ProgressDialog->Sync.Set_NumBytesTotal(*bytes); 118 ProgressDialog->Sync.Set_NumBytesTotal(*bytes);
120 } 119 }
121 else 120 else
122 _totalBytesDefined = false; 121 _totalBytes_Defined = false;
123 } 122 }
124 123
125 return res; 124 return res;
@@ -217,7 +216,7 @@ Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite(
217 dialog.NewFileInfo.Is_FileSystemFile = Src_Is_IO_FS_Folder; 216 dialog.NewFileInfo.Is_FileSystemFile = Src_Is_IO_FS_Folder;
218 217
219 ProgressDialog->WaitCreating(); 218 ProgressDialog->WaitCreating();
220 INT_PTR writeAnswer = dialog.Create(*ProgressDialog); 219 const INT_PTR writeAnswer = dialog.Create(*ProgressDialog);
221 220
222 switch (writeAnswer) 221 switch (writeAnswer)
223 { 222 {
@@ -478,10 +477,10 @@ UString GetOpenArcErrorMessage(UInt32 errorFlags)
478 477
479 for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsIds); i++) 478 for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsIds); i++)
480 { 479 {
481 UInt32 f = ((UInt32)1 << i); 480 const UInt32 f = (UInt32)1 << i;
482 if ((errorFlags & f) == 0) 481 if ((errorFlags & f) == 0)
483 continue; 482 continue;
484 UInt32 id = k_ErrorFlagsIds[i]; 483 const UInt32 id = k_ErrorFlagsIds[i];
485 UString m = LangString(id); 484 UString m = LangString(id);
486 if (m.IsEmpty()) 485 if (m.IsEmpty())
487 continue; 486 continue;
@@ -512,8 +511,8 @@ UString GetOpenArcErrorMessage(UInt32 errorFlags)
512 511
513static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er) 512static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
514{ 513{
515 UInt32 errorFlags = er.GetErrorFlags(); 514 const UInt32 errorFlags = er.GetErrorFlags();
516 UInt32 warningFlags = er.GetWarningFlags(); 515 const UInt32 warningFlags = er.GetWarningFlags();
517 516
518 if (errorFlags != 0) 517 if (errorFlags != 0)
519 AddNewLineString(s, GetOpenArcErrorMessage(errorFlags)); 518 AddNewLineString(s, GetOpenArcErrorMessage(errorFlags));
@@ -524,7 +523,7 @@ static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
524 if (warningFlags != 0) 523 if (warningFlags != 0)
525 { 524 {
526 s += GetNameOfProperty(kpidWarningFlags, L"Warnings"); 525 s += GetNameOfProperty(kpidWarningFlags, L"Warnings");
527 s += ":"; 526 s.Add_Colon();
528 s.Add_LF(); 527 s.Add_LF();
529 AddNewLineString(s, GetOpenArcErrorMessage(warningFlags)); 528 AddNewLineString(s, GetOpenArcErrorMessage(warningFlags));
530 } 529 }
@@ -852,34 +851,35 @@ Z7_COM7F_IMF(CExtractCallbackImp::GetStream7(const wchar_t *name,
852 _newVirtFileWasAdded = false; 851 _newVirtFileWasAdded = false;
853 _hashStream_WasUsed = false; 852 _hashStream_WasUsed = false;
854 _needUpdateStat = false; 853 _needUpdateStat = false;
854 _isFolder = IntToBool(isDir);
855 _curSize_Defined = false;
856 _curSize = 0;
855 857
856 if (_hashStream) 858 if (_hashStream)
857 _hashStream->ReleaseStream(); 859 _hashStream->ReleaseStream();
858 860
859 GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
860
861 if (!ProcessAltStreams && _isAltStream)
862 return S_OK;
863
864 _filePath = name; 861 _filePath = name;
865 _isFolder = IntToBool(isDir);
866 _curSize = 0;
867 _curSize_Defined = false;
868 862
869 UInt64 size = 0; 863 UInt64 size = 0;
870 bool sizeDefined; 864 bool size_Defined;
871 { 865 {
872 NCOM::CPropVariant prop; 866 NCOM::CPropVariant prop;
873 RINOK(getProp->GetProp(kpidSize, &prop)) 867 RINOK(getProp->GetProp(kpidSize, &prop))
874 sizeDefined = ConvertPropVariantToUInt64(prop, size); 868 size_Defined = ConvertPropVariantToUInt64(prop, size);
875 } 869 }
876 870 if (size_Defined)
877 if (sizeDefined)
878 { 871 {
879 _curSize = size; 872 _curSize = size;
880 _curSize_Defined = true; 873 _curSize_Defined = true;
881 } 874 }
882 875
876 GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
877 if (!ProcessAltStreams && _isAltStream)
878 return S_OK;
879
880 if (isDir) // we don't support dir items extraction in this code
881 return S_OK;
882
883 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract && 883 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&
884 askExtractMode != NArchive::NExtract::NAskMode::kTest) 884 askExtractMode != NArchive::NExtract::NAskMode::kTest)
885 return S_OK; 885 return S_OK;
@@ -890,40 +890,64 @@ Z7_COM7F_IMF(CExtractCallbackImp::GetStream7(const wchar_t *name,
890 890
891 if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract) 891 if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract)
892 { 892 {
893 CVirtFile &file = VirtFileSystemSpec->AddNewFile(); 893 if (!VirtFileSystemSpec->Files.IsEmpty())
894 VirtFileSystemSpec->MaxTotalAllocSize -= VirtFileSystemSpec->Files.Back().Data.Size();
895 CVirtFile &file = VirtFileSystemSpec->Files.AddNew();
894 _newVirtFileWasAdded = true; 896 _newVirtFileWasAdded = true;
895 file.Name = name; 897 // file.IsDir = _isFolder;
896 file.IsDir = IntToBool(isDir);
897 file.IsAltStream = _isAltStream; 898 file.IsAltStream = _isAltStream;
898 file.Size = 0; 899 file.WrittenSize = 0;
900 file.ExpectedSize = 0;
901 if (size_Defined)
902 file.ExpectedSize = size;
899 903
900 RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined)) 904 if (VirtFileSystemSpec->Index_of_MainExtractedFile_in_Files < 0)
901 RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined)) 905 if (!file.IsAltStream || VirtFileSystemSpec->IsAltStreamFile)
902 RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined)) 906 VirtFileSystemSpec->Index_of_MainExtractedFile_in_Files =
907 (int)(VirtFileSystemSpec->Files.Size() - 1);
903 908
904 NCOM::CPropVariant prop; 909 /* if we open only AltStream, then (name) contains only name without "fileName:" prefix */
905 RINOK(getProp->GetProp(kpidAttrib, &prop)) 910 file.BaseName = name;
906 if (prop.vt == VT_UI4) 911
912 if (file.IsAltStream
913 && !VirtFileSystemSpec->IsAltStreamFile
914 && file.BaseName.IsPrefixedBy_NoCase(VirtFileSystemSpec->FileName))
907 { 915 {
908 file.Attrib = prop.ulVal; 916 const unsigned colonPos = VirtFileSystemSpec->FileName.Len();
909 file.AttribDefined = true; 917 if (file.BaseName[colonPos] == ':')
918 {
919 file.ColonWasUsed = true;
920 file.AltStreamName = name + (size_t)colonPos + 1;
921 file.BaseName.DeleteFrom(colonPos);
922 if (Is_ZoneId_StreamName(file.AltStreamName))
923 {
924 if (VirtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files < 0)
925 VirtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files =
926 (int)(VirtFileSystemSpec->Files.Size() - 1);
927 }
928 }
929 }
930 RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTime_Defined))
931 RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATime_Defined))
932 RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTime_Defined))
933 {
934 NCOM::CPropVariant prop;
935 RINOK(getProp->GetProp(kpidAttrib, &prop))
936 if (prop.vt == VT_UI4)
937 {
938 file.Attrib = prop.ulVal;
939 file.Attrib_Defined = true;
940 }
910 } 941 }
911 // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY;
912
913 file.ExpectedSize = 0;
914 if (sizeDefined)
915 file.ExpectedSize = size;
916 outStreamLoc = VirtFileSystem; 942 outStreamLoc = VirtFileSystem;
917 } 943 }
918 944
919 if (_hashStream) 945 if (_hashStream)
920 { 946 {
921 { 947 _hashStream->SetStream(outStreamLoc);
922 _hashStream->SetStream(outStreamLoc); 948 outStreamLoc = _hashStream;
923 outStreamLoc = _hashStream; 949 _hashStream->Init(true);
924 _hashStream->Init(true); 950 _hashStream_WasUsed = true;
925 _hashStream_WasUsed = true;
926 }
927 } 951 }
928 952
929 if (outStreamLoc) 953 if (outStreamLoc)
@@ -1077,10 +1101,10 @@ Z7_COM7F_IMF(CExtractCallbackImp::RequestMemoryUse(
1077 // if (indexType == NArchive::NEventIndexType::kNoIndex) 1101 // if (indexType == NArchive::NEventIndexType::kNoIndex)
1078 if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) || 1102 if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) ||
1079 (flags & NRequestMemoryUseFlags::k_Report_SkipArc)) 1103 (flags & NRequestMemoryUseFlags::k_Report_SkipArc))
1080 s += LangString(IDS_MSG_ARC_UNPACKING_WAS_SKIPPED); 1104 AddLangString(s, IDS_MSG_ARC_UNPACKING_WAS_SKIPPED);
1081/* 1105/*
1082 else 1106 else
1083 s += LangString(IDS_MSG_ARC_FILES_UNPACKING_WAS_SKIPPED); 1107 AddLangString(, IDS_MSG_ARC_FILES_UNPACKING_WAS_SKIPPED);
1084*/ 1108*/
1085 AddError_Message_ShowArcPath(s); 1109 AddError_Message_ShowArcPath(s);
1086 } 1110 }
@@ -1093,88 +1117,154 @@ Z7_COM7F_IMF(CExtractCallbackImp::RequestMemoryUse(
1093} 1117}
1094 1118
1095 1119
1096
1097// static const UInt32 kBlockSize = ((UInt32)1 << 31);
1098
1099Z7_COM7F_IMF(CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)) 1120Z7_COM7F_IMF(CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize))
1100{ 1121{
1101 if (processedSize) 1122 if (processedSize)
1102 *processedSize = 0; 1123 *processedSize = 0;
1103 if (size == 0) 1124 if (size == 0)
1104 return S_OK; 1125 return S_OK;
1105 if (!_fileMode) 1126 if (!_wasSwitchedToFsMode)
1106 { 1127 {
1107 CVirtFile &file = Files.Back(); 1128 CVirtFile &file = Files.Back();
1108 size_t rem = file.Data.Size() - (size_t)file.Size; 1129 const size_t rem = file.Data.Size() - file.WrittenSize;
1109 bool useMem = true; 1130 bool useMem = true;
1110 if (rem < size) 1131 if (rem < size)
1111 { 1132 {
1112 UInt64 b = 0; 1133 UInt64 b = 0;
1113 if (file.Data.Size() == 0) 1134 if (file.Data.Size() == 0)
1114 b = file.ExpectedSize; 1135 b = file.ExpectedSize;
1115 UInt64 a = file.Size + size; 1136 UInt64 a = (UInt64)file.WrittenSize + size;
1116 if (b < a) 1137 if (b < a)
1117 b = a; 1138 b = a;
1118 a = (UInt64)file.Data.Size() * 2; 1139 a = (UInt64)file.Data.Size() * 2;
1119 if (b < a) 1140 if (b < a)
1120 b = a; 1141 b = a;
1121 useMem = false; 1142 useMem = false;
1122 const size_t b_sizet = (size_t)b; 1143 if (b <= MaxTotalAllocSize)
1123 if (b == b_sizet && b <= MaxTotalAllocSize) 1144 useMem = file.Data.ReAlloc_KeepData((size_t)b, file.WrittenSize);
1124 useMem = file.Data.ReAlloc_KeepData(b_sizet, (size_t)file.Size);
1125 } 1145 }
1146
1147#if 0 // 1 for debug : FLUSHING TO FS
1148 useMem = false;
1149#endif
1150
1126 if (useMem) 1151 if (useMem)
1127 { 1152 {
1128 memcpy(file.Data + file.Size, data, size); 1153 memcpy(file.Data + file.WrittenSize, data, size);
1129 file.Size += size; 1154 file.WrittenSize += size;
1130 if (processedSize) 1155 if (processedSize)
1131 *processedSize = (UInt32)size; 1156 *processedSize = (UInt32)size;
1132 return S_OK; 1157 return S_OK;
1133 } 1158 }
1134 _fileMode = true; 1159 _wasSwitchedToFsMode = true;
1160 }
1161
1162 if (!_newVirtFileStream_IsReadyToWrite) // we check for _newVirtFileStream_IsReadyToWrite to optimize execution
1163 {
1164 RINOK(FlushToDisk(false))
1135 } 1165 }
1136 RINOK(FlushToDisk(false)) 1166
1137 return _outFileStream.Interface()->Write(data, size, processedSize); 1167 if (_needWriteToRealFile)
1168 return _outFileStream.Interface()->Write(data, size, processedSize);
1169 if (processedSize)
1170 *processedSize = size;
1171 return S_OK;
1138} 1172}
1139 1173
1140 1174
1141HRESULT CVirtFileSystem::FlushToDisk(bool closeLast) 1175HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
1142{ 1176{
1143 _outFileStream.Create_if_Empty();
1144 while (_numFlushed < Files.Size()) 1177 while (_numFlushed < Files.Size())
1145 { 1178 {
1146 const CVirtFile &file = Files[_numFlushed]; 1179 CVirtFile &file = Files[_numFlushed];
1147 const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name)); 1180 const FString basePath = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.BaseName));
1148 if (!_fileIsOpen) 1181 FString path = basePath;
1182
1183 if (file.ColonWasUsed)
1149 { 1184 {
1150 if (!_outFileStream->Create_NEW(path)) 1185 if (ZoneBuf.Size() != 0
1186 && Is_ZoneId_StreamName(file.AltStreamName))
1151 { 1187 {
1152 // do we need to release stream here? 1188 // it's expected that
1153 // _outFileStream.Release(); 1189 // CArchiveExtractCallback::GetStream() have excluded
1154 return E_FAIL; 1190 // ZoneId alt stream from extraction already.
1155 // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath)); 1191 // But we exclude alt stream extraction here too.
1192 _numFlushed++;
1193 continue;
1156 } 1194 }
1157 _fileIsOpen = true; 1195 path.Add_Colon();
1158 RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size)) 1196 path += us2fs(Get_Correct_FsFile_Name(file.AltStreamName));
1159 } 1197 }
1198
1199 if (!_newVirtFileStream_IsReadyToWrite)
1200 {
1201 if (file.ColonWasUsed)
1202 {
1203 NFind::CFileInfo parentFi;
1204 if (parentFi.Find(basePath)
1205 && parentFi.IsReadOnly())
1206 {
1207 _altStream_NeedRestore_Attrib_bool = true;
1208 _altStream_NeedRestore_AttribVal = parentFi.Attrib;
1209 NDir::SetFileAttrib(basePath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY);
1210 }
1211 }
1212 _outFileStream.Create_if_Empty();
1213 _needWriteToRealFile = _outFileStream->Create_NEW(path);
1214 if (!_needWriteToRealFile)
1215 {
1216 if (!file.ColonWasUsed)
1217 return GetLastError_noZero_HRESULT(); // it's main file and we can't ignore such error.
1218 // (file.ColonWasUsed == true)
1219 // So it's additional alt stream.
1220 // And we ignore file creation error for additional alt stream.
1221 // ShowErrorMessage(UString("Can't create file ") + fs2us(path));
1222 }
1223 _newVirtFileStream_IsReadyToWrite = true;
1224 // _openFilePath = path;
1225 HRESULT hres = S_OK;
1226 if (_needWriteToRealFile)
1227 hres = WriteStream(_outFileStream, file.Data, file.WrittenSize);
1228 // we free allocated memory buffer after data flushing:
1229 file.WrittenSize = 0;
1230 file.Data.Free();
1231 RINOK(hres)
1232 }
1233
1160 if (_numFlushed == Files.Size() - 1 && !closeLast) 1234 if (_numFlushed == Files.Size() - 1 && !closeLast)
1161 break; 1235 break;
1162 if (file.CTimeDefined || 1236
1163 file.ATimeDefined || 1237 if (_needWriteToRealFile)
1164 file.MTimeDefined) 1238 {
1165 _outFileStream->SetTime( 1239 if (file.CTime_Defined ||
1166 file.CTimeDefined ? &file.CTime : NULL, 1240 file.ATime_Defined ||
1167 file.ATimeDefined ? &file.ATime : NULL, 1241 file.MTime_Defined)
1168 file.MTimeDefined ? &file.MTime : NULL); 1242 _outFileStream->SetTime(
1169 _outFileStream->Close(); 1243 file.CTime_Defined ? &file.CTime : NULL,
1244 file.ATime_Defined ? &file.ATime : NULL,
1245 file.MTime_Defined ? &file.MTime : NULL);
1246 _outFileStream->Close();
1247 }
1248
1170 _numFlushed++; 1249 _numFlushed++;
1171 _fileIsOpen = false; 1250 _newVirtFileStream_IsReadyToWrite = false;
1172 1251
1173 if (ZoneBuf.Size() != 0) 1252 if (_needWriteToRealFile)
1174 WriteZoneFile_To_BaseFile(path, ZoneBuf); 1253 {
1175 1254 if (!file.ColonWasUsed
1176 if (file.AttribDefined) 1255 && ZoneBuf.Size() != 0)
1177 NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib); 1256 WriteZoneFile_To_BaseFile(path, ZoneBuf);
1257 if (file.Attrib_Defined)
1258 NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib);
1259 // _openFilePath.Empty();
1260 _needWriteToRealFile = false;
1261 }
1262
1263 if (_altStream_NeedRestore_Attrib_bool)
1264 {
1265 _altStream_NeedRestore_Attrib_bool = false;
1266 NDir::SetFileAttrib(basePath, _altStream_NeedRestore_AttribVal);
1267 }
1178 } 1268 }
1179 return S_OK; 1269 return S_OK;
1180} 1270}
diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h
index 5c459aa..8b4dcb3 100644
--- a/CPP/7zip/UI/FileManager/ExtractCallback.h
+++ b/CPP/7zip/UI/FileManager/ExtractCallback.h
@@ -25,10 +25,6 @@
25 25
26#include "ProgressDialog2.h" 26#include "ProgressDialog2.h"
27 27
28#ifdef Z7_LANG
29// #include "LangUtils.h"
30#endif
31
32#ifndef Z7_SFX 28#ifndef Z7_SFX
33 29
34class CGrowBuf 30class CGrowBuf
@@ -39,12 +35,24 @@ class CGrowBuf
39 Z7_CLASS_NO_COPY(CGrowBuf) 35 Z7_CLASS_NO_COPY(CGrowBuf)
40 36
41public: 37public:
38 void Free()
39 {
40 MyFree(_items);
41 _items = NULL;
42 _size = 0;
43 }
44
45 // newSize >= keepSize
42 bool ReAlloc_KeepData(size_t newSize, size_t keepSize) 46 bool ReAlloc_KeepData(size_t newSize, size_t keepSize)
43 { 47 {
44 void *buf = MyAlloc(newSize); 48 void *buf = NULL;
45 if (!buf) 49 if (newSize)
46 return false; 50 {
47 if (keepSize != 0) 51 buf = MyAlloc(newSize);
52 if (!buf)
53 return false;
54 }
55 if (keepSize)
48 memcpy(buf, _items, keepSize); 56 memcpy(buf, _items, keepSize);
49 MyFree(_items); 57 MyFree(_items);
50 _items = (Byte *)buf; 58 _items = (Byte *)buf;
@@ -60,23 +68,27 @@ public:
60 size_t Size() const { return _size; } 68 size_t Size() const { return _size; }
61}; 69};
62 70
71
63struct CVirtFile 72struct CVirtFile
64{ 73{
65 CGrowBuf Data; 74 CGrowBuf Data;
66 75
67 UInt64 Size; // real size 76 UInt64 ExpectedSize; // size from props request. 0 if unknown
68 UInt64 ExpectedSize; // the size from props request. 0 if unknown 77 size_t WrittenSize; // size of written data in (Data) buffer
69 78 // use (WrittenSize) only if (CVirtFileSystem::_newVirtFileStream_IsReadyToWrite == false)
70 UString Name; 79 UString BaseName; // original name of file inside archive,
71 80 // It's not path. So any path separators
72 bool CTimeDefined; 81 // should be treated as part of name (or as incorrect chars)
73 bool ATimeDefined; 82 UString AltStreamName;
74 bool MTimeDefined; 83
75 bool AttribDefined; 84 bool CTime_Defined;
85 bool ATime_Defined;
86 bool MTime_Defined;
87 bool Attrib_Defined;
76 88
77 bool IsDir; 89 // bool IsDir;
78 bool IsAltStream; 90 bool IsAltStream;
79 91 bool ColonWasUsed;
80 DWORD Attrib; 92 DWORD Attrib;
81 93
82 FILETIME CTime; 94 FILETIME CTime;
@@ -84,82 +96,82 @@ struct CVirtFile
84 FILETIME MTime; 96 FILETIME MTime;
85 97
86 CVirtFile(): 98 CVirtFile():
87 CTimeDefined(false), 99 CTime_Defined(false),
88 ATimeDefined(false), 100 ATime_Defined(false),
89 MTimeDefined(false), 101 MTime_Defined(false),
90 AttribDefined(false), 102 Attrib_Defined(false),
91 IsDir(false), 103 // IsDir(false),
92 IsAltStream(false) {} 104 IsAltStream(false),
105 ColonWasUsed(false)
106 {}
93}; 107};
94 108
95 109
110/*
111 We use CVirtFileSystem only for single file extraction:
112 It supports the following cases and names:
113 - "fileName" : single file
114 - "fileName" item (main base file) and additional "fileName:altStream" items
115 - "altStream" : single item without "fileName:" prefix.
116 If file is flushed to disk, it uses Get_Correct_FsFile_Name(name).
117*/
118
96Z7_CLASS_IMP_NOQIB_1( 119Z7_CLASS_IMP_NOQIB_1(
97 CVirtFileSystem, 120 CVirtFileSystem,
98 ISequentialOutStream 121 ISequentialOutStream
99) 122)
100 UInt64 _totalAllocSize;
101
102 size_t _pos;
103 unsigned _numFlushed; 123 unsigned _numFlushed;
104 bool _fileIsOpen; 124public:
105 bool _fileMode; 125 bool IsAltStreamFile; // in:
126 // = true, if extracting file is alt stream without "fileName:" prefix.
127 // = false, if extracting file is normal file, but additional
128 // alt streams "fileName:altStream" items are possible.
129private:
130 bool _newVirtFileStream_IsReadyToWrite; // it can non real file (if can't open alt stream)
131 bool _needWriteToRealFile; // we need real writing to open file.
132 bool _wasSwitchedToFsMode;
133 bool _altStream_NeedRestore_Attrib_bool;
134 DWORD _altStream_NeedRestore_AttribVal;
135
106 CMyComPtr2<ISequentialOutStream, COutFileStream> _outFileStream; 136 CMyComPtr2<ISequentialOutStream, COutFileStream> _outFileStream;
107public: 137public:
108 CObjectVector<CVirtFile> Files; 138 CObjectVector<CVirtFile> Files;
109 UInt64 MaxTotalAllocSize; 139 size_t MaxTotalAllocSize; // remain size, including Files.Back()
110 FString DirPrefix; 140 FString DirPrefix; // files will be flushed to this FS directory.
141 UString FileName; // name of file that will be extracted.
142 // it can be name of alt stream without "fileName:" prefix, if (IsAltStreamFile == trye).
143 // we use that name to detect altStream part in "FileName:altStream".
111 CByteBuffer ZoneBuf; 144 CByteBuffer ZoneBuf;
145 int Index_of_MainExtractedFile_in_Files; // out: index in Files. == -1, if expected file was not extracted
146 int Index_of_ZoneBuf_AltStream_in_Files; // out: index in Files. == -1, if no zonbuf alt stream
147
112 148
113 149 CVirtFileSystem()
114 CVirtFile &AddNewFile()
115 { 150 {
116 if (!Files.IsEmpty()) 151 _numFlushed = 0;
117 { 152 IsAltStreamFile = false;
118 MaxTotalAllocSize -= Files.Back().Data.Size(); 153 _newVirtFileStream_IsReadyToWrite = false;
119 } 154 _needWriteToRealFile = false;
120 return Files.AddNew(); 155 _wasSwitchedToFsMode = false;
156 _altStream_NeedRestore_Attrib_bool = false;
157 MaxTotalAllocSize = (size_t)0 - 1;
158 Index_of_MainExtractedFile_in_Files = -1;
159 Index_of_ZoneBuf_AltStream_in_Files = -1;
121 } 160 }
161
162 bool WasStreamFlushedToFS() const { return _wasSwitchedToFsMode; }
163
122 HRESULT CloseMemFile() 164 HRESULT CloseMemFile()
123 { 165 {
124 if (_fileMode) 166 if (_wasSwitchedToFsMode)
125 { 167 return FlushToDisk(true); // closeLast
126 return FlushToDisk(true);
127 }
128 CVirtFile &file = Files.Back(); 168 CVirtFile &file = Files.Back();
129 if (file.Data.Size() != file.Size) 169 if (file.Data.Size() != file.WrittenSize)
130 { 170 file.Data.ReAlloc_KeepData(file.WrittenSize, file.WrittenSize);
131 file.Data.ReAlloc_KeepData((size_t)file.Size, (size_t)file.Size);
132 }
133 return S_OK; 171 return S_OK;
134 } 172 }
135 173
136 bool IsStreamInMem() const
137 {
138 if (_fileMode)
139 return false;
140 if (Files.Size() < 1 || /* Files[0].IsAltStream || */ Files[0].IsDir)
141 return false;
142 return true;
143 }
144
145 size_t GetMemStreamWrittenSize() const { return _pos; }
146
147 CVirtFileSystem():
148 MaxTotalAllocSize((UInt64)0 - 1)
149 {}
150
151 void Init()
152 {
153 _totalAllocSize = 0;
154 _fileMode = false;
155 _pos = 0;
156 _numFlushed = 0;
157 _fileIsOpen = false;
158 }
159
160 HRESULT CloseFile(const FString &path);
161 HRESULT FlushToDisk(bool closeLast); 174 HRESULT FlushToDisk(bool closeLast);
162 size_t GetPos() const { return _pos; }
163}; 175};
164 176
165#endif 177#endif
@@ -217,12 +229,12 @@ class CExtractCallbackImp Z7_final:
217 229
218 bool _needWriteArchivePath; 230 bool _needWriteArchivePath;
219 bool _isFolder; 231 bool _isFolder;
220 bool _totalFilesDefined; 232 bool _totalFiles_Defined;
221 bool _totalBytesDefined; 233 bool _totalBytes_Defined;
222public: 234public:
223 bool MultiArcMode; 235 bool MultiArcMode;
224 bool ProcessAltStreams; 236 bool ProcessAltStreams;
225 bool StreamMode; 237 bool StreamMode; // set to true, if you want the callee to call GetStream7()
226 bool ThereAreMessageErrors; 238 bool ThereAreMessageErrors;
227 bool Src_Is_IO_FS_Folder; 239 bool Src_Is_IO_FS_Folder;
228 240
@@ -246,9 +258,17 @@ private:
246 bool _skipArc; 258 bool _skipArc;
247#endif 259#endif
248 260
261public:
262 bool YesToAll;
263 bool TestMode;
264
265 UInt32 NumArchiveErrors;
266 NExtract::NOverwriteMode::EEnum OverwriteMode;
267
268private:
249 UString _currentArchivePath; 269 UString _currentArchivePath;
250 UString _currentFilePath; 270 UString _currentFilePath;
251 UString _filePath; 271 UString _filePath; // virtual path than will be sent via IFolderExtractToStreamCallback
252 272
253#ifndef Z7_SFX 273#ifndef Z7_SFX
254 UInt64 _curSize; 274 UInt64 _curSize;
@@ -266,12 +286,6 @@ public:
266 UInt64 NumFiles; 286 UInt64 NumFiles;
267#endif 287#endif
268 288
269 UInt32 NumArchiveErrors;
270 NExtract::NOverwriteMode::EEnum OverwriteMode;
271
272 bool YesToAll;
273 bool TestMode;
274
275#ifndef Z7_NO_CRYPTO 289#ifndef Z7_NO_CRYPTO
276 UString Password; 290 UString Password;
277#endif 291#endif
@@ -283,8 +297,8 @@ public:
283 UString _lang_Empty; 297 UString _lang_Empty;
284 298
285 CExtractCallbackImp(): 299 CExtractCallbackImp():
286 _totalFilesDefined(false) 300 _totalFiles_Defined(false)
287 , _totalBytesDefined(false) 301 , _totalBytes_Defined(false)
288 , MultiArcMode(false) 302 , MultiArcMode(false)
289 , ProcessAltStreams(true) 303 , ProcessAltStreams(true)
290 , StreamMode(false) 304 , StreamMode(false)
@@ -297,11 +311,13 @@ public:
297#ifndef Z7_SFX 311#ifndef Z7_SFX
298 , _remember(false) 312 , _remember(false)
299 , _skipArc(false) 313 , _skipArc(false)
300 , _hashCalc(NULL)
301#endif 314#endif
302 , OverwriteMode(NExtract::NOverwriteMode::kAsk)
303 , YesToAll(false) 315 , YesToAll(false)
304 , TestMode(false) 316 , TestMode(false)
317 , OverwriteMode(NExtract::NOverwriteMode::kAsk)
318#ifndef Z7_SFX
319 , _hashCalc(NULL)
320#endif
305 {} 321 {}
306 322
307 ~CExtractCallbackImp(); 323 ~CExtractCallbackImp();
diff --git a/CPP/7zip/UI/FileManager/FM.cpp b/CPP/7zip/UI/FileManager/FM.cpp
index fe4f2bd..b2f4c2b 100644
--- a/CPP/7zip/UI/FileManager/FM.cpp
+++ b/CPP/7zip/UI/FileManager/FM.cpp
@@ -63,8 +63,8 @@ bool g_LargePagesMode = false;
63static bool g_Maximized = false; 63static bool g_Maximized = false;
64 64
65extern 65extern
66UInt64 g_RAM_Size; 66size_t g_RAM_Size;
67UInt64 g_RAM_Size; 67size_t g_RAM_Size;
68 68
69#ifdef _WIN32 69#ifdef _WIN32
70extern 70extern
@@ -651,7 +651,7 @@ static int WINAPI WinMain2(int nCmdShow)
651 SplitStringToTwoStrings(commandsString, paramString, tailString); 651 SplitStringToTwoStrings(commandsString, paramString, tailString);
652 paramString.Trim(); 652 paramString.Trim();
653 tailString.Trim(); 653 tailString.Trim();
654 if (tailString.IsPrefixedBy(L"-t")) 654 if (tailString.IsPrefixedBy("-t"))
655 g_ArcFormat = tailString.Ptr(2); 655 g_ArcFormat = tailString.Ptr(2);
656 656
657 /* 657 /*
@@ -1025,8 +1025,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1025 break; 1025 break;
1026 } 1026 }
1027 1027
1028 case WM_DESTROY: 1028 case WM_CLOSE:
1029 { 1029 {
1030 // why do we use WA_INACTIVE here ?
1031 SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd);
1032 g_ExitEventLauncher.Exit(false);
1030 // ::DragAcceptFiles(hWnd, FALSE); 1033 // ::DragAcceptFiles(hWnd, FALSE);
1031 RevokeDragDrop(hWnd); 1034 RevokeDragDrop(hWnd);
1032 g_App._dropTarget.Release(); 1035 g_App._dropTarget.Release();
@@ -1034,12 +1037,18 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1034 if (g_WindowWasCreated) 1037 if (g_WindowWasCreated)
1035 g_App.Save(); 1038 g_App.Save();
1036 1039
1037 g_App.Release(); 1040 g_App.ReleaseApp();
1038 1041
1039 if (g_WindowWasCreated) 1042 if (g_WindowWasCreated)
1040 SaveWindowInfo(hWnd); 1043 SaveWindowInfo(hWnd);
1041 1044
1042 g_ExitEventLauncher.Exit(true); 1045 g_ExitEventLauncher.Exit(true);
1046 // default DefWindowProc will call DestroyWindow / WM_DESTROY
1047 break;
1048 }
1049
1050 case WM_DESTROY:
1051 {
1043 PostQuitMessage(0); 1052 PostQuitMessage(0);
1044 break; 1053 break;
1045 } 1054 }
diff --git a/CPP/7zip/UI/FileManager/LangUtils.cpp b/CPP/7zip/UI/FileManager/LangUtils.cpp
index 8fcb507..4712192 100644
--- a/CPP/7zip/UI/FileManager/LangUtils.cpp
+++ b/CPP/7zip/UI/FileManager/LangUtils.cpp
@@ -309,15 +309,13 @@ void ReloadLang()
309{ 309{
310 g_Lang.Clear(); 310 g_Lang.Clear();
311 ReadRegLang(g_LangID); 311 ReadRegLang(g_LangID);
312 #ifndef _UNICODE 312 if (g_LangID.IsEmpty())
313 if (g_IsNT)
314 #endif
315 { 313 {
316 if (g_LangID.IsEmpty()) 314#ifndef _UNICODE
317 { 315 if (g_IsNT)
316#endif
318 OpenDefaultLang(); 317 OpenDefaultLang();
319 return; 318 return;
320 }
321 } 319 }
322 if (g_LangID.Len() > 1 || g_LangID[0] != L'-') 320 if (g_LangID.Len() > 1 || g_LangID[0] != L'-')
323 { 321 {
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp
index 0f24761..a92ee4d 100644
--- a/CPP/7zip/UI/FileManager/LinkDialog.cpp
+++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp
@@ -45,28 +45,24 @@ static bool GetSymLink(CFSTR path, CReparseAttr &attr, UString &errorMessage)
45 CByteBuffer buf; 45 CByteBuffer buf;
46 if (!NIO::GetReparseData(path, buf, NULL)) 46 if (!NIO::GetReparseData(path, buf, NULL))
47 return false; 47 return false;
48
49 if (!attr.Parse(buf, buf.Size())) 48 if (!attr.Parse(buf, buf.Size()))
50 { 49 {
51 SetLastError(attr.ErrorCode); 50 SetLastError(attr.ErrorCode);
52 return false; 51 return false;
53 } 52 }
54
55 CByteBuffer data2; 53 CByteBuffer data2;
56 if (!FillLinkData(data2, attr.GetPath(), 54 FillLinkData(data2, attr.GetPath(),
57 !attr.IsMountPoint(), attr.IsSymLink_WSL())) 55 !attr.IsMountPoint(), attr.IsSymLink_WSL());
56 if (data2.Size() == 0)
58 { 57 {
59 errorMessage = "Cannot reproduce reparse point"; 58 errorMessage = "Cannot reproduce reparse point";
60 return false; 59 return false;
61 } 60 }
62 61 if (data2 != buf)
63 if (data2.Size() != buf.Size() ||
64 memcmp(data2, buf, buf.Size()) != 0)
65 { 62 {
66 errorMessage = "mismatch for reproduced reparse point"; 63 errorMessage = "mismatch for reproduced reparse point";
67 return false; 64 return false;
68 } 65 }
69
70 return true; 66 return true;
71} 67}
72 68
@@ -113,8 +109,8 @@ bool CLinkDialog::OnInit()
113 const bool res = GetSymLink(us2fs(FilePath), attr, error); 109 const bool res = GetSymLink(us2fs(FilePath), attr, error);
114 if (!res && error.IsEmpty()) 110 if (!res && error.IsEmpty())
115 { 111 {
116 DWORD lastError = GetLastError(); 112 const DWORD lastError = GetLastError();
117 if (lastError != 0) 113 if (lastError)
118 error = NError::MyFormatMessage(lastError); 114 error = NError::MyFormatMessage(lastError);
119 } 115 }
120 116
@@ -319,10 +315,10 @@ void CLinkDialog::OnButton_Link()
319 return; 315 return;
320 } 316 }
321 317
322 const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION);
323
324 CByteBuffer data; 318 CByteBuffer data;
325 if (!FillLinkData(data, to, isSymLink, isWSL)) 319 const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION);
320 FillLinkData(data, to, isSymLink, isWSL);
321 if (data.Size() == 0)
326 { 322 {
327 ShowError(L"Incorrect link"); 323 ShowError(L"Incorrect link");
328 return; 324 return;
@@ -386,6 +382,9 @@ void CApp::Link()
386 path = destPanel.GetFsPath(); 382 path = destPanel.GetFsPath();
387 } 383 }
388 384
385 CSelectedState srcSelState;
386 srcPanel.SaveSelectedState(srcSelState);
387
389 CLinkDialog dlg; 388 CLinkDialog dlg;
390 dlg.CurDirPrefix = fsPrefix; 389 dlg.CurDirPrefix = fsPrefix;
391 dlg.FilePath = srcPath + itemName; 390 dlg.FilePath = srcPath + itemName;
@@ -394,7 +393,10 @@ void CApp::Link()
394 if (dlg.Create(srcPanel.GetParent()) != IDOK) 393 if (dlg.Create(srcPanel.GetParent()) != IDOK)
395 return; 394 return;
396 395
397 // fix it: we should refresh panel with changed link 396 // we refresh srcPanel to show changes in "Link" (kpidNtReparse) column.
397 // maybe we should refresh another panel also?
398 if (srcPanel._visibleColumns.FindItem_for_PropID(kpidNtReparse) >= 0)
399 srcPanel.RefreshListCtrl(srcSelState);
398 400
399 RefreshTitleAlways(); 401 RefreshTitleAlways();
400} 402}
diff --git a/CPP/7zip/UI/FileManager/MemDialog.cpp b/CPP/7zip/UI/FileManager/MemDialog.cpp
index 1ba717e..5d26d3a 100644
--- a/CPP/7zip/UI/FileManager/MemDialog.cpp
+++ b/CPP/7zip/UI/FileManager/MemDialog.cpp
@@ -55,13 +55,13 @@ static void AddSize_GB(UString &s, UInt32 size_GB, UInt32 id)
55 AddLangString(s, id); 55 AddLangString(s, id);
56} 56}
57 57
58void CMemDialog::AddInfoMessage_To_String(UString &s, UInt64 *ramSize_GB) 58void CMemDialog::AddInfoMessage_To_String(UString &s, const UInt32 *ramSize_GB)
59{ 59{
60 AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM); 60 AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM);
61 AddSize_GB(s, Required_GB, IDS_MEM_REQUIRED_MEM_SIZE); 61 AddSize_GB(s, Required_GB, IDS_MEM_REQUIRED_MEM_SIZE);
62 AddSize_GB(s, Limit_GB, IDS_MEM_CURRENT_MEM_LIMIT); 62 AddSize_GB(s, Limit_GB, IDS_MEM_CURRENT_MEM_LIMIT);
63 if (ramSize_GB) 63 if (ramSize_GB)
64 AddSize_GB(s, (UInt32)*ramSize_GB, IDS_MEM_RAM_SIZE); 64 AddSize_GB(s, *ramSize_GB, IDS_MEM_RAM_SIZE);
65 if (!FilePath.IsEmpty()) 65 if (!FilePath.IsEmpty())
66 { 66 {
67 s.Add_LF(); 67 s.Add_LF();
@@ -88,11 +88,11 @@ bool CMemDialog::OnInit()
88 88
89 // m_Action.Attach(GetItem(IDC_MEM_ACTION)); 89 // m_Action.Attach(GetItem(IDC_MEM_ACTION));
90 90
91 UInt64 ramSize = (UInt64)sizeof(size_t) << 29; 91 size_t ramSize = (size_t)sizeof(size_t) << 29;
92 const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize); 92 const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize);
93 // ramSize *= 10; // for debug 93 // ramSize *= 10; // for debug
94 94
95 UInt64 ramSize_GB = (ramSize + (1u << 29)) >> 30; 95 UInt32 ramSize_GB = (UInt32)(((UInt64)ramSize + (1u << 29)) >> 30);
96 if (ramSize_GB == 0) 96 if (ramSize_GB == 0)
97 ramSize_GB = 1; 97 ramSize_GB = 1;
98 98
@@ -121,7 +121,7 @@ bool CMemDialog::OnInit()
121 if (ramSize_defined) 121 if (ramSize_defined)
122 { 122 {
123 s += " / "; 123 s += " / ";
124 s.Add_UInt64(ramSize_GB); 124 s.Add_UInt32(ramSize_GB);
125 s += " GB (RAM)"; 125 s += " GB (RAM)";
126 } 126 }
127 SetItemText(IDT_MEM_GB, s); 127 SetItemText(IDT_MEM_GB, s);
diff --git a/CPP/7zip/UI/FileManager/MemDialog.h b/CPP/7zip/UI/FileManager/MemDialog.h
index 79de658..67f6b33 100644
--- a/CPP/7zip/UI/FileManager/MemDialog.h
+++ b/CPP/7zip/UI/FileManager/MemDialog.h
@@ -30,7 +30,7 @@ public:
30 UString ArcPath; 30 UString ArcPath;
31 UString FilePath; 31 UString FilePath;
32 32
33 void AddInfoMessage_To_String(UString &s, UInt64 *ramSize_GB = NULL); 33 void AddInfoMessage_To_String(UString &s, const UInt32 *ramSize_GB = NULL);
34 34
35 CMemDialog(): 35 CMemDialog():
36 NeedSave(false), 36 NeedSave(false),
diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
index 51b8648..f190929 100644
--- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
+++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
@@ -764,8 +764,12 @@ bool ExecuteFileCommand(unsigned id)
764 case IDM_CRC32: g_App.CalculateCrc("CRC32"); break; 764 case IDM_CRC32: g_App.CalculateCrc("CRC32"); break;
765 case IDM_CRC64: g_App.CalculateCrc("CRC64"); break; 765 case IDM_CRC64: g_App.CalculateCrc("CRC64"); break;
766 case IDM_XXH64: g_App.CalculateCrc("XXH64"); break; 766 case IDM_XXH64: g_App.CalculateCrc("XXH64"); break;
767 case IDM_MD5: g_App.CalculateCrc("MD5"); break;
767 case IDM_SHA1: g_App.CalculateCrc("SHA1"); break; 768 case IDM_SHA1: g_App.CalculateCrc("SHA1"); break;
768 case IDM_SHA256: g_App.CalculateCrc("SHA256"); break; 769 case IDM_SHA256: g_App.CalculateCrc("SHA256"); break;
770 case IDM_SHA384: g_App.CalculateCrc("SHA384"); break;
771 case IDM_SHA512: g_App.CalculateCrc("SHA512"); break;
772 case IDM_SHA3_256: g_App.CalculateCrc("SHA3-256"); break;
769 case IDM_BLAKE2SP: g_App.CalculateCrc("BLAKE2sp"); break; 773 case IDM_BLAKE2SP: g_App.CalculateCrc("BLAKE2sp"); break;
770 774
771 case IDM_DIFF: g_App.DiffFiles(); break; 775 case IDM_DIFF: g_App.DiffFiles(); break;
@@ -807,8 +811,8 @@ bool OnMenuCommand(HWND hWnd, unsigned id)
807 { 811 {
808 // File 812 // File
809 case IDCLOSE: 813 case IDCLOSE:
810 SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd); 814 // SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd);
811 g_ExitEventLauncher.Exit(false); 815 // g_ExitEventLauncher.Exit(false);
812 SendMessage(hWnd, WM_CLOSE, 0, 0); 816 SendMessage(hWnd, WM_CLOSE, 0, 0);
813 break; 817 break;
814 818
diff --git a/CPP/7zip/UI/FileManager/OpenCallback.cpp b/CPP/7zip/UI/FileManager/OpenCallback.cpp
index 5b6df50..e3cb2ec 100644
--- a/CPP/7zip/UI/FileManager/OpenCallback.cpp
+++ b/CPP/7zip/UI/FileManager/OpenCallback.cpp
@@ -27,7 +27,7 @@ HRESULT COpenArchiveCallback::Open_SetTotal(const UInt64 *numFiles, const UInt64
27 ProgressDialog.Sync.Set_NumFilesTotal(numFiles ? *numFiles : (UInt64)(Int64)-1); 27 ProgressDialog.Sync.Set_NumFilesTotal(numFiles ? *numFiles : (UInt64)(Int64)-1);
28 // if (numFiles) 28 // if (numFiles)
29 { 29 {
30 ProgressDialog.Sync.Set_BytesProgressMode(numFiles == NULL); 30 ProgressDialog.Sync.Set_FilesProgressMode(numFiles != NULL);
31 } 31 }
32 if (numBytes) 32 if (numBytes)
33 ProgressDialog.Sync.Set_NumBytesTotal(*numBytes); 33 ProgressDialog.Sync.Set_NumBytesTotal(*numBytes);
diff --git a/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp
index f3fb38e..84bd88c 100644
--- a/CPP/7zip/UI/FileManager/Panel.cpp
+++ b/CPP/7zip/UI/FileManager/Panel.cpp
@@ -7,8 +7,8 @@
7#include "../../../Common/IntToString.h" 7#include "../../../Common/IntToString.h"
8#include "../../../Common/StringConvert.h" 8#include "../../../Common/StringConvert.h"
9 9
10#include "../../../Windows/FileName.h"
11#include "../../../Windows/ErrorMsg.h" 10#include "../../../Windows/ErrorMsg.h"
11#include "../../../Windows/FileName.h"
12#include "../../../Windows/PropVariant.h" 12#include "../../../Windows/PropVariant.h"
13#include "../../../Windows/Thread.h" 13#include "../../../Windows/Thread.h"
14 14
@@ -49,8 +49,9 @@ static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };
49 49
50extern HINSTANCE g_hInstance; 50extern HINSTANCE g_hInstance;
51 51
52void CPanel::Release() 52void CPanel::ReleasePanel()
53{ 53{
54 Disable_Processing_Timer_Notify_StatusBar();
54 // It's for unloading COM dll's: don't change it. 55 // It's for unloading COM dll's: don't change it.
55 CloseOpenFolders(); 56 CloseOpenFolders();
56 _sevenZipContextMenu.Release(); 57 _sevenZipContextMenu.Release();
@@ -893,7 +894,7 @@ void CPanel::SetListViewMode(UInt32 index)
893void CPanel::ChangeFlatMode() 894void CPanel::ChangeFlatMode()
894{ 895{
895 _flatMode = !_flatMode; 896 _flatMode = !_flatMode;
896 if (_parentFolders.Size() > 0) 897 if (!_parentFolders.IsEmpty())
897 _flatModeForArc = _flatMode; 898 _flatModeForArc = _flatMode;
898 else 899 else
899 _flatModeForDisk = _flatMode; 900 _flatModeForDisk = _flatMode;
@@ -904,7 +905,7 @@ void CPanel::ChangeFlatMode()
904void CPanel::Change_ShowNtfsStrems_Mode() 905void CPanel::Change_ShowNtfsStrems_Mode()
905{ 906{
906 _showNtfsStrems_Mode = !_showNtfsStrems_Mode; 907 _showNtfsStrems_Mode = !_showNtfsStrems_Mode;
907 if (_parentFolders.Size() > 0) 908 if (!_parentFolders.IsEmpty())
908 _showNtfsStrems_ModeForArc = _showNtfsStrems_Mode; 909 _showNtfsStrems_ModeForArc = _showNtfsStrems_Mode;
909 else 910 else
910 _showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode; 911 _showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode;
@@ -1006,7 +1007,7 @@ void CPanel::GetFilePaths(const CRecordVector<UInt32> &operatedIndices, UStringV
1006 1007
1007void CPanel::ExtractArchives() 1008void CPanel::ExtractArchives()
1008{ 1009{
1009 if (_parentFolders.Size() > 0) 1010 if (!_parentFolders.IsEmpty())
1010 { 1011 {
1011 _panelCallback->OnCopy(false, false); 1012 _panelCallback->OnCopy(false, false);
1012 return; 1013 return;
diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h
index 1b708f7..9ef0926 100644
--- a/CPP/7zip/UI/FileManager/Panel.h
+++ b/CPP/7zip/UI/FileManager/Panel.h
@@ -162,32 +162,39 @@ struct CTempFileInfo
162 NWindows::NFile::NDir::RemoveDir(FolderPath); 162 NWindows::NFile::NDir::RemoveDir(FolderPath);
163 } 163 }
164 } 164 }
165 bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const 165 bool WasChanged_from_TempFileInfo(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const
166 { 166 {
167 return newFileInfo.Size != FileInfo.Size || 167 return newFileInfo.Size != FileInfo.Size ||
168 CompareFileTime(&newFileInfo.MTime, &FileInfo.MTime) != 0; 168 CompareFileTime(&newFileInfo.MTime, &FileInfo.MTime) != 0;
169 } 169 }
170}; 170};
171 171
172
172struct CFolderLink: public CTempFileInfo 173struct CFolderLink: public CTempFileInfo
173{ 174{
174 bool IsVirtual; 175 bool IsVirtual; // == true (if archive was open via IInStream):
176 // archive was open from another archive,
177 // archive size meets the size conditions derived from g_RAM_Size.
178 // VirtFileSystem was used
179 // archive was fully extracted to memory.
175 bool UsePassword; 180 bool UsePassword;
176 NWindows::NDLL::CLibrary Library; 181 NWindows::NDLL::CLibrary Library;
177 CMyComPtr<IFolderFolder> ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0]) 182 CMyComPtr<IFolderFolder> ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0])
178 UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level) 183 UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level)
179 UString Password; 184 UString Password;
180
181 UString VirtualPath; // without tail slash 185 UString VirtualPath; // without tail slash
182 CFolderLink(): IsVirtual(false), UsePassword(false) {} 186 CByteBuffer ZoneBuf; // ZoneBuf for virtaul stream (IsVirtual)
183 187
184 bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const 188 CFolderLink(): IsVirtual(false), UsePassword(false) {}
189 bool WasChanged_from_FolderLink(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const
185 { 190 {
186 return IsVirtual || CTempFileInfo::WasChanged(newFileInfo); 191 // we call it, if we have two real files.
192 // if archive was virtual, it means that we have updated that virtual to real file.
193 return IsVirtual || CTempFileInfo::WasChanged_from_TempFileInfo(newFileInfo);
187 } 194 }
188
189}; 195};
190 196
197
191enum MyMessages 198enum MyMessages
192{ 199{
193 // we can use WM_USER, since we have defined new window class. 200 // we can use WM_USER, since we have defined new window class.
@@ -268,13 +275,14 @@ struct CCopyToOptions
268 275
269 bool NeedRegistryZone; 276 bool NeedRegistryZone;
270 NExtract::NZoneIdMode::EEnum ZoneIdMode; 277 NExtract::NZoneIdMode::EEnum ZoneIdMode;
278 CByteBuffer ZoneBuf;
271 279
272 UString folder; 280 UString folder;
273 281
274 UStringVector hashMethods; 282 UStringVector hashMethods;
275 283
276 CVirtFileSystem *VirtFileSystemSpec; 284 CVirtFileSystem *VirtFileSystemSpec;
277 ISequentialOutStream *VirtFileSystem; 285 // ISequentialOutStream *VirtFileSystem;
278 286
279 CCopyToOptions(): 287 CCopyToOptions():
280 streamMode(false), 288 streamMode(false),
@@ -285,8 +293,8 @@ struct CCopyToOptions
285 showErrorMessages(false), 293 showErrorMessages(false),
286 NeedRegistryZone(true), 294 NeedRegistryZone(true),
287 ZoneIdMode(NExtract::NZoneIdMode::kNone), 295 ZoneIdMode(NExtract::NZoneIdMode::kNone),
288 VirtFileSystemSpec(NULL), 296 VirtFileSystemSpec(NULL)
289 VirtFileSystem(NULL) 297 // , VirtFileSystem(NULL)
290 {} 298 {}
291}; 299};
292 300
@@ -310,11 +318,60 @@ struct COpenResult
310 318
311class CPanel Z7_final: public NWindows::NControl::CWindow2 319class CPanel Z7_final: public NWindows::NControl::CWindow2
312{ 320{
321 bool _thereAre_ListView_Items;
322 // bool _virtualMode;
323 bool _enableItemChangeNotify;
324 bool _thereAreDeletedItems;
325 bool _markDeletedItems;
326 bool _dontShowMode;
327 bool _needSaveInfo;
328
329public:
330 bool PanelCreated;
331 bool _mySelectMode;
332 bool _showDots;
333 bool _showRealFileIcons;
334 bool _flatMode;
335 bool _flatModeForArc;
336 bool _flatModeForDisk;
337 bool _selectionIsDefined;
338 // bool _showNtfsStrems_Mode;
339 // bool _showNtfsStrems_ModeForDisk;
340 // bool _showNtfsStrems_ModeForArc;
341
342 bool _selectMark;
343 bool _lastFocusedIsList;
344
345 bool _processTimer;
346 bool _processNotify;
347 bool _processStatusBar;
348
349public:
350 bool _ascending;
351 PROPID _sortID;
352 // int _sortIndex;
353 Int32 _isRawSortProp;
354
355 CMyListView _listView;
356 CPanelCallback *_panelCallback;
357
358private:
359
313 // CExtToIconMap _extToIconMap; 360 // CExtToIconMap _extToIconMap;
314 UINT _baseID; 361 UINT _baseID;
315 unsigned _comboBoxID; 362 unsigned _comboBoxID;
316 UINT _statusBarID; 363 UINT _statusBarID;
317 364
365public:
366 DWORD _exStyle;
367 // CUIntVector _realIndices;
368 int _timestampLevel;
369 UInt32 _listViewMode;
370 int _xSize;
371private:
372 int _startGroupSelect;
373 int _prevFocusedItem;
374
318 CAppState *_appState; 375 CAppState *_appState;
319 376
320 virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) Z7_override; 377 virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) Z7_override;
@@ -351,22 +408,7 @@ class CPanel Z7_final: public NWindows::NControl::CWindow2
351 bool OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result); 408 bool OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result);
352 409
353 410
354public:
355 HWND _mainWindow;
356 CPanelCallback *_panelCallback;
357
358 // void SysIconsWereChanged() { _extToIconMap.Clear(); }
359
360 void DeleteItems(bool toRecycleBin);
361 void CreateFolder();
362 void CreateFile();
363 bool CorrectFsPath(const UString &path, UString &result);
364 // bool IsPathForPlugin(const UString &path);
365
366private:
367
368 void ChangeWindowSize(int xSize, int ySize); 411 void ChangeWindowSize(int xSize, int ySize);
369
370 HRESULT InitColumns(); 412 HRESULT InitColumns();
371 void DeleteColumn(unsigned index); 413 void DeleteColumn(unsigned index);
372 void AddColumn(const CPropColumn &prop); 414 void AddColumn(const CPropColumn &prop);
@@ -379,20 +421,13 @@ private:
379 void OnInsert(); 421 void OnInsert();
380 // void OnUpWithShift(); 422 // void OnUpWithShift();
381 // void OnDownWithShift(); 423 // void OnDownWithShift();
382public:
383 void UpdateSelection();
384 void SelectSpec(bool selectMode);
385 void SelectByType(bool selectMode);
386 void SelectAll(bool selectMode);
387 void InvertSelection();
388private:
389
390 // UString GetFileType(UInt32 index); 424 // UString GetFileType(UInt32 index);
391 LRESULT SetItemText(LVITEMW &item); 425 LRESULT SetItemText(LVITEMW &item);
392
393 // CRecordVector<PROPID> m_ColumnsPropIDs; 426 // CRecordVector<PROPID> m_ColumnsPropIDs;
394 427
395public: 428public:
429 HWND _mainWindow;
430
396 NWindows::NControl::CReBar _headerReBar; 431 NWindows::NControl::CReBar _headerReBar;
397 NWindows::NControl::CToolBar _headerToolBar; 432 NWindows::NControl::CToolBar _headerToolBar;
398 NWindows::NControl:: 433 NWindows::NControl::
@@ -405,42 +440,57 @@ public:
405 UStringVector ComboBoxPaths; 440 UStringVector ComboBoxPaths;
406 // CMyComboBox _headerComboBox; 441 // CMyComboBox _headerComboBox;
407 CMyComboBoxEdit _comboBoxEdit; 442 CMyComboBoxEdit _comboBoxEdit;
408 CMyListView _listView;
409 bool _thereAre_ListView_Items;
410 NWindows::NControl::CStatusBar _statusBar; 443 NWindows::NControl::CStatusBar _statusBar;
411 bool _lastFocusedIsList;
412 // NWindows::NControl::CStatusBar _statusBar2; 444 // NWindows::NControl::CStatusBar _statusBar2;
413 445
414 DWORD _exStyle; 446 CBoolVector _selectedStatusVector;
415 bool _showDots; 447 CSelectedState _selectedState;
416 bool _showRealFileIcons;
417 // bool _virtualMode;
418 // CUIntVector _realIndices;
419 bool _enableItemChangeNotify;
420 bool _mySelectMode;
421 448
422 int _timestampLevel; 449 UString _currentFolderPrefix;
450
451 CObjectVector<CFolderLink> _parentFolders;
452 NWindows::NDLL::CLibrary _library;
453
454 CMyComPtr<IFolderFolder> _folder;
455 CBoolVector _isDirVector;
456 CMyComPtr<IFolderCompare> _folderCompare;
457 CMyComPtr<IFolderGetItemName> _folderGetItemName;
458 CMyComPtr<IArchiveGetRawProps> _folderRawProps;
459 CMyComPtr<IFolderAltStreams> _folderAltStreams;
460 CMyComPtr<IFolderOperations> _folderOperations;
423 461
462 // for drag and drop highliting
463 int m_DropHighlighted_SelectionIndex;
464 // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item)
465 UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder)
466
467 // CMyComPtr<IFolderGetSystemIconIndex> _folderGetSystemIconIndex;
468 UStringVector _fastFolders;
469
470 UString _typeIDString;
471 CListViewInfo _listViewInfo;
472
473 CPropColumns _columns;
474 CPropColumns _visibleColumns;
475
476 CMyComPtr<IContextMenu> _sevenZipContextMenu;
477 CMyComPtr<IContextMenu> _systemContextMenu;
478
479 void UpdateSelection();
480 void SelectSpec(bool selectMode);
481 void SelectByType(bool selectMode);
482 void SelectAll(bool selectMode);
483 void InvertSelection();
424 484
425 void RedrawListItems() 485 void RedrawListItems()
426 { 486 {
427 _listView.RedrawAllItems(); 487 _listView.RedrawAllItems();
428 } 488 }
429
430
431 CBoolVector _selectedStatusVector;
432
433 CSelectedState _selectedState;
434 bool _thereAreDeletedItems;
435 bool _markDeletedItems;
436
437 bool PanelCreated;
438
439 void DeleteListItems() 489 void DeleteListItems()
440 { 490 {
441 if (_thereAre_ListView_Items) 491 if (_thereAre_ListView_Items)
442 { 492 {
443 bool b = _enableItemChangeNotify; 493 const bool b = _enableItemChangeNotify;
444 _enableItemChangeNotify = false; 494 _enableItemChangeNotify = false;
445 _listView.DeleteAllItems(); 495 _listView.DeleteAllItems();
446 _thereAre_ListView_Items = false; 496 _thereAre_ListView_Items = false;
@@ -448,6 +498,15 @@ public:
448 } 498 }
449 } 499 }
450 500
501 // void SysIconsWereChanged() { _extToIconMap.Clear(); }
502
503 void DeleteItems(bool toRecycleBin);
504 void CreateFolder();
505 void CreateFile();
506 bool CorrectFsPath(const UString &path, UString &result);
507 // bool IsPathForPlugin(const UString &path);
508
509
451 HWND GetParent() const; 510 HWND GetParent() const;
452 511
453 UInt32 GetRealIndex(const LVITEMW &item) const 512 UInt32 GetRealIndex(const LVITEMW &item) const
@@ -471,46 +530,8 @@ public:
471 return (unsigned)param; 530 return (unsigned)param;
472 } 531 }
473 532
474 UInt32 _listViewMode;
475 int _xSize;
476
477 bool _flatMode;
478 bool _flatModeForDisk;
479 bool _flatModeForArc;
480
481 // bool _showNtfsStrems_Mode;
482 // bool _showNtfsStrems_ModeForDisk;
483 // bool _showNtfsStrems_ModeForArc;
484
485 bool _dontShowMode;
486
487
488 UString _currentFolderPrefix;
489
490 CObjectVector<CFolderLink> _parentFolders;
491 NWindows::NDLL::CLibrary _library;
492
493 CMyComPtr<IFolderFolder> _folder;
494 CBoolVector _isDirVector;
495 CMyComPtr<IFolderCompare> _folderCompare;
496 CMyComPtr<IFolderGetItemName> _folderGetItemName;
497 CMyComPtr<IArchiveGetRawProps> _folderRawProps;
498 CMyComPtr<IFolderAltStreams> _folderAltStreams;
499 CMyComPtr<IFolderOperations> _folderOperations;
500
501
502 // for drag and drop highliting
503 int m_DropHighlighted_SelectionIndex;
504 // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item)
505 UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder)
506
507 void ReleaseFolder(); 533 void ReleaseFolder();
508 void SetNewFolder(IFolderFolder *newFolder); 534 void SetNewFolder(IFolderFolder *newFolder);
509
510 // CMyComPtr<IFolderGetSystemIconIndex> _folderGetSystemIconIndex;
511
512 UStringVector _fastFolders;
513
514 void GetSelectedNames(UStringVector &selectedNames); 535 void GetSelectedNames(UStringVector &selectedNames);
515 void SaveSelectedState(CSelectedState &s); 536 void SaveSelectedState(CSelectedState &s);
516 HRESULT RefreshListCtrl(const CSelectedState &s); 537 HRESULT RefreshListCtrl(const CSelectedState &s);
@@ -575,61 +596,44 @@ public:
575 596
576 CPanel() : 597 CPanel() :
577 _thereAre_ListView_Items(false), 598 _thereAre_ListView_Items(false),
578 _exStyle(0), 599 // _virtualMode(false),
579 _showDots(false),
580 _showRealFileIcons(false),
581 // _virtualMode(flase),
582 _enableItemChangeNotify(true), 600 _enableItemChangeNotify(true),
583 _mySelectMode(false),
584 _timestampLevel(kTimestampPrintLevel_MIN),
585
586 _thereAreDeletedItems(false), 601 _thereAreDeletedItems(false),
587 _markDeletedItems(true), 602 _markDeletedItems(true),
588 PanelCreated(false), 603 _dontShowMode(false),
589 604 _needSaveInfo(false),
590 _listViewMode(3),
591 _xSize(300),
592 605
606 PanelCreated(false),
607 _mySelectMode(false),
608 _showDots(false),
609 _showRealFileIcons(false),
593 _flatMode(false), 610 _flatMode(false),
594 _flatModeForDisk(false),
595 _flatModeForArc(false), 611 _flatModeForArc(false),
596 612 _flatModeForDisk(false),
613 _selectionIsDefined(false),
597 // _showNtfsStrems_Mode(false), 614 // _showNtfsStrems_Mode(false),
598 // _showNtfsStrems_ModeForDisk(false), 615 // _showNtfsStrems_ModeForDisk(false),
599 // _showNtfsStrems_ModeForArc(false), 616 // _showNtfsStrems_ModeForArc(false),
600 617
601 _dontShowMode(false), 618 _exStyle(0),
602 619 _timestampLevel(kTimestampPrintLevel_MIN),
603 m_DropHighlighted_SelectionIndex(-1), 620 _listViewMode(3),
604 621 _xSize(300),
605 _needSaveInfo(false),
606 _startGroupSelect(0), 622 _startGroupSelect(0),
607 _selectionIsDefined(false) 623 m_DropHighlighted_SelectionIndex(-1)
608 {} 624 {}
609 625
626 ~CPanel() Z7_DESTRUCTOR_override;
627
628 void ReleasePanel();
629
610 void SetExtendedStyle() 630 void SetExtendedStyle()
611 { 631 {
612 if (_listView) 632 if (_listView)
613 _listView.SetExtendedListViewStyle(_exStyle); 633 _listView.SetExtendedListViewStyle(_exStyle);
614 } 634 }
615 635
616
617 bool _needSaveInfo;
618 UString _typeIDString;
619 CListViewInfo _listViewInfo;
620
621 CPropColumns _columns;
622 CPropColumns _visibleColumns;
623
624 PROPID _sortID;
625 // int _sortIndex;
626 bool _ascending;
627 Int32 _isRawSortProp;
628
629 void SetSortRawStatus(); 636 void SetSortRawStatus();
630
631 void Release();
632 ~CPanel() Z7_DESTRUCTOR_override;
633 void OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate); 637 void OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate);
634 bool OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result); 638 bool OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result);
635 void ShowColumnsContextMenu(int x, int y); 639 void ShowColumnsContextMenu(int x, int y);
@@ -638,9 +642,6 @@ public:
638 void OnReload(bool onTimer = false); 642 void OnReload(bool onTimer = false);
639 bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos); 643 bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos);
640 644
641 CMyComPtr<IContextMenu> _sevenZipContextMenu;
642 CMyComPtr<IContextMenu> _systemContextMenu;
643
644 HRESULT CreateShellContextMenu( 645 HRESULT CreateShellContextMenu(
645 const CRecordVector<UInt32> &operatedIndices, 646 const CRecordVector<UInt32> &operatedIndices,
646 CMyComPtr<IContextMenu> &systemContextMenu); 647 CMyComPtr<IContextMenu> &systemContextMenu);
@@ -672,12 +673,6 @@ public:
672 void EditCopy(); 673 void EditCopy();
673 void EditPaste(); 674 void EditPaste();
674 675
675 int _startGroupSelect;
676
677 bool _selectionIsDefined;
678 bool _selectMark;
679 int _prevFocusedItem;
680
681 676
682 // void SortItems(int index); 677 // void SortItems(int index);
683 void SortItemsWithPropID(PROPID propID); 678 void SortItemsWithPropID(PROPID propID);
@@ -716,8 +711,8 @@ public:
716 } 711 }
717 712
718 // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); } 713 // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); }
719 bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; } 714 bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\.\\"); }
720 bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; } 715 bool IsSuperDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\?\\"); }
721 716
722 /* 717 /*
723 c:\Dir 718 c:\Dir
@@ -751,9 +746,12 @@ public:
751 bool IsThereReadOnlyFolder() const; 746 bool IsThereReadOnlyFolder() const;
752 bool CheckBeforeUpdate(UINT resourceID); 747 bool CheckBeforeUpdate(UINT resourceID);
753 748
754 bool _processTimer; 749 void Disable_Processing_Timer_Notify_StatusBar()
755 bool _processNotify; 750 {
756 bool _processStatusBar; 751 _processTimer = false;
752 _processNotify = false;
753 _processStatusBar = false;
754 }
757 755
758 class CDisableTimerProcessing 756 class CDisableTimerProcessing
759 { 757 {
@@ -926,6 +924,7 @@ public:
926 void ExtractArchives(); 924 void ExtractArchives();
927 void TestArchives(); 925 void TestArchives();
928 926
927 void Get_ZoneId_Stream_from_ParentFolders(CByteBuffer &buf);
929 928
930 HRESULT CopyTo(CCopyToOptions &options, 929 HRESULT CopyTo(CCopyToOptions &options,
931 const CRecordVector<UInt32> &indices, 930 const CRecordVector<UInt32> &indices,
@@ -939,7 +938,7 @@ public:
939 { 938 {
940 bool usePassword = false; 939 bool usePassword = false;
941 UString password; 940 UString password;
942 if (_parentFolders.Size() > 0) 941 if (!_parentFolders.IsEmpty())
943 { 942 {
944 const CFolderLink &fl = _parentFolders.Back(); 943 const CFolderLink &fl = _parentFolders.Back();
945 usePassword = fl.UsePassword; 944 usePassword = fl.UsePassword;
@@ -978,6 +977,7 @@ public:
978 UString GetItemsInfoString(const CRecordVector<UInt32> &indices); 977 UString GetItemsInfoString(const CRecordVector<UInt32> &indices);
979}; 978};
980 979
980
981class CMyBuffer 981class CMyBuffer
982{ 982{
983 void *_data; 983 void *_data;
@@ -994,13 +994,12 @@ public:
994 ~CMyBuffer() { ::MidFree(_data); } 994 ~CMyBuffer() { ::MidFree(_data); }
995}; 995};
996 996
997class CExitEventLauncher 997struct CExitEventLauncher
998{ 998{
999public:
1000 NWindows::NSynchronization::CManualResetEvent _exitEvent; 999 NWindows::NSynchronization::CManualResetEvent _exitEvent;
1001 bool _needExit; 1000 bool _needExit;
1002 CRecordVector< ::CThread > _threads;
1003 unsigned _numActiveThreads; 1001 unsigned _numActiveThreads;
1002 CRecordVector< ::CThread > _threads;
1004 1003
1005 CExitEventLauncher() 1004 CExitEventLauncher()
1006 { 1005 {
diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp
index 36a0f6d..f070be9 100644
--- a/CPP/7zip/UI/FileManager/PanelCopy.cpp
+++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp
@@ -75,11 +75,21 @@ HRESULT CPanelCopyThread::ProcessVirt()
75 75
76 if (FolderOperations) 76 if (FolderOperations)
77 { 77 {
78 CMyComPtr<IFolderSetZoneIdMode> setZoneMode;
79 FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode);
80 if (setZoneMode)
81 { 78 {
82 RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode)) 79 CMyComPtr<IFolderSetZoneIdMode> setZoneMode;
80 FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode);
81 if (setZoneMode)
82 {
83 RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode))
84 }
85 }
86 {
87 CMyComPtr<IFolderSetZoneIdFile> setZoneFile;
88 FolderOperations.QueryInterface(IID_IFolderSetZoneIdFile, &setZoneFile);
89 if (setZoneFile)
90 {
91 RINOK(setZoneFile->SetZoneIdFile(options->ZoneBuf, (UInt32)options->ZoneBuf.Size()))
92 }
83 } 93 }
84 } 94 }
85 95
@@ -143,6 +153,32 @@ static void ThrowException_if_Error(HRESULT res)
143#endif 153#endif
144*/ 154*/
145 155
156void CPanel::Get_ZoneId_Stream_from_ParentFolders(CByteBuffer &buf)
157{
158 // we suppose that ZoneId of top parent has priority over ZoneId from childs.
159 FOR_VECTOR (i, _parentFolders)
160 {
161 // _parentFolders[0] = is top level archive
162 // _parentFolders[1 ... ].isVirtual == true is possible
163 // if extracted size meets size conditions derived from g_RAM_Size.
164 const CFolderLink &fl = _parentFolders[i];
165 if (fl.IsVirtual)
166 {
167 if (fl.ZoneBuf.Size() != 0)
168 {
169 buf = fl.ZoneBuf;
170 return;
171 }
172 }
173 else if (!fl.FilePath.IsEmpty())
174 {
175 ReadZoneFile_Of_BaseFile(fl.FilePath, buf);
176 if (buf.Size() != 0)
177 return;
178 }
179 }
180}
181
146HRESULT CPanel::CopyTo(CCopyToOptions &options, 182HRESULT CPanel::CopyTo(CCopyToOptions &options,
147 const CRecordVector<UInt32> &indices, 183 const CRecordVector<UInt32> &indices,
148 UStringVector *messages, 184 UStringVector *messages,
@@ -157,6 +193,10 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options,
157 options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone; 193 options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone;
158 } 194 }
159 195
196 if (options.ZoneBuf.Size() == 0
197 && options.ZoneIdMode != NExtract::NZoneIdMode::kNone)
198 Get_ZoneId_Stream_from_ParentFolders(options.ZoneBuf);
199
160 if (IsHashFolder()) 200 if (IsHashFolder())
161 { 201 {
162 if (!options.testMode) 202 if (!options.testMode)
@@ -205,9 +245,9 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options,
205 extracter.Hash.MainName = extracter.Hash.FirstFileName; 245 extracter.Hash.MainName = extracter.Hash.FirstFileName;
206 } 246 }
207 247
208 if (options.VirtFileSystem) 248 if (options.VirtFileSystemSpec)
209 { 249 {
210 extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystem; 250 extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystemSpec;
211 extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec; 251 extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec;
212 } 252 }
213 extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams; 253 extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams;
@@ -244,7 +284,7 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options,
244 if (options.hashMethods.Size() == 1) 284 if (options.hashMethods.Size() == 1)
245 { 285 {
246 const UString &s = options.hashMethods[0]; 286 const UString &s = options.hashMethods[0];
247 if (s != L"*") 287 if (!s.IsEqualTo("*"))
248 title = s; 288 title = s;
249 } 289 }
250 } 290 }
diff --git a/CPP/7zip/UI/FileManager/PanelDrag.cpp b/CPP/7zip/UI/FileManager/PanelDrag.cpp
index 040444c..f9b0a6c 100644
--- a/CPP/7zip/UI/FileManager/PanelDrag.cpp
+++ b/CPP/7zip/UI/FileManager/PanelDrag.cpp
@@ -2614,11 +2614,11 @@ Z7_COMWF_B CDropTarget::Drop(IDataObject *dataObject, DWORD keyState,
2614 UString s = LangString(cmdEffect == DROPEFFECT_MOVE ? 2614 UString s = LangString(cmdEffect == DROPEFFECT_MOVE ?
2615 IDS_MOVE_TO : IDS_COPY_TO); 2615 IDS_MOVE_TO : IDS_COPY_TO);
2616 s.Add_LF(); 2616 s.Add_LF();
2617 s += "\'"; 2617 // s += "\'";
2618 s += m_Panel->_currentFolderPrefix; 2618 s += m_Panel->_currentFolderPrefix;
2619 s += "\'"; 2619 // s += "\'";
2620 s.Add_LF(); 2620 s.Add_LF();
2621 s += LangString(IDS_WANT_TO_COPY_FILES); 2621 AddLangString(s, IDS_WANT_TO_COPY_FILES);
2622 s += " ?"; 2622 s += " ?";
2623 const int res = ::MessageBoxW(*m_Panel, s, title, MB_YESNOCANCEL | MB_ICONQUESTION); 2623 const int res = ::MessageBoxW(*m_Panel, s, title, MB_YESNOCANCEL | MB_ICONQUESTION);
2624 if (res != IDYES) 2624 if (res != IDYES)
@@ -2954,7 +2954,7 @@ static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags)
2954 name = MyFormatNew(name, destPath); 2954 name = MyFormatNew(name, destPath);
2955 */ 2955 */
2956 name.Add_Space(); 2956 name.Add_Space();
2957 name += LangString(IDS_CONTEXT_ARCHIVE); 2957 AddLangString(name, IDS_CONTEXT_ARCHIVE);
2958 } 2958 }
2959 if (cmdId == NDragMenu::k_Cancel) 2959 if (cmdId == NDragMenu::k_Cancel)
2960 menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); 2960 menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL);
diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
index c34cb74..b0fb53e 100644
--- a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
+++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
@@ -428,7 +428,7 @@ void CPanel::LoadFullPathAndShow()
428 UString name_Computer = RootFolder_GetName_Computer(iconIndex); 428 UString name_Computer = RootFolder_GetName_Computer(iconIndex);
429 name_Computer.Add_PathSepar(); 429 name_Computer.Add_PathSepar();
430 if (path == name_Computer 430 if (path == name_Computer
431 || path == L"\\\\?\\") 431 || path.IsEqualTo("\\\\?\\"))
432 item.iImage = iconIndex; 432 item.iImage = iconIndex;
433 else 433 else
434 { 434 {
@@ -639,7 +639,7 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
639 unsigned indent = 0; 639 unsigned indent = 0;
640 { 640 {
641 UString path = _currentFolderPrefix; 641 UString path = _currentFolderPrefix;
642 // path = L"\\\\.\\y:\\"; // for debug 642 // path = "\\\\.\\y:\\"; // for debug
643 UString prefix0; 643 UString prefix0;
644 if (path.IsPrefixedBy_Ascii_NoCase("\\\\")) 644 if (path.IsPrefixedBy_Ascii_NoCase("\\\\"))
645 { 645 {
@@ -702,7 +702,7 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
702 int iconIndex_Computer; 702 int iconIndex_Computer;
703 const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer); 703 const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer);
704 704
705 // const bool is_devicePrefix = (sumPath == L"\\\\.\\"); 705 // const bool is_devicePrefix = (sumPath.IsEqualTo("\\\\.\\"));
706 706
707 if (pathParts.Size() > 1) 707 if (pathParts.Size() > 1)
708 if (!sumPath.IsEmpty() 708 if (!sumPath.IsEmpty()
@@ -901,8 +901,8 @@ UString CPanel::GetParentDirPrefix() const
901 { 901 {
902 s = _currentFolderPrefix; 902 s = _currentFolderPrefix;
903 s.DeleteBack(); 903 s.DeleteBack();
904 if (s != L"\\\\." && 904 if (!s.IsEqualTo("\\\\.") &&
905 s != L"\\\\?") 905 !s.IsEqualTo("\\\\?"))
906 { 906 {
907 int pos = s.ReverseFind_PathSepar(); 907 int pos = s.ReverseFind_PathSepar();
908 if (pos >= 0) 908 if (pos >= 0)
@@ -935,8 +935,8 @@ void CPanel::OpenParentFolder()
935 } 935 }
936 else 936 else
937 */ 937 */
938 if (focusedName != L"\\\\." && 938 if (!focusedName.IsEqualTo("\\\\.") &&
939 focusedName != L"\\\\?") 939 !focusedName.IsEqualTo("\\\\?"))
940 { 940 {
941 const int pos = focusedName.ReverseFind_PathSepar(); 941 const int pos = focusedName.ReverseFind_PathSepar();
942 if (pos >= 0) 942 if (pos >= 0)
diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
index 244a962..aa56ef5 100644
--- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
@@ -39,7 +39,7 @@ using namespace NFile;
39using namespace NDir; 39using namespace NDir;
40 40
41extern bool g_RAM_Size_Defined; 41extern bool g_RAM_Size_Defined;
42extern UInt64 g_RAM_Size; 42extern size_t g_RAM_Size;
43 43
44#ifndef _UNICODE 44#ifndef _UNICODE
45extern bool g_IsNT; 45extern bool g_IsNT;
@@ -606,9 +606,9 @@ HRESULT CPanel::OpenParentArchiveFolder()
606 NFind::CFileInfo newFileInfo; 606 NFind::CFileInfo newFileInfo;
607 if (newFileInfo.Find(folderLink.FilePath)) 607 if (newFileInfo.Find(folderLink.FilePath))
608 { 608 {
609 if (folderLink.WasChanged(newFileInfo)) 609 if (folderLink.WasChanged_from_FolderLink(newFileInfo))
610 { 610 {
611 UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath); 611 const UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath);
612 if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) == IDYES) 612 if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) == IDYES)
613 { 613 {
614 if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath), 614 if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath),
@@ -1083,13 +1083,11 @@ void CExitEventLauncher::Exit(bool hardExit)
1083 FOR_VECTOR (i, _threads) 1083 FOR_VECTOR (i, _threads)
1084 { 1084 {
1085 ::CThread &th = _threads[i]; 1085 ::CThread &th = _threads[i];
1086 DWORD wait = (hardExit ? 100 : INFINITE);
1087 if (Thread_WasCreated(&th)) 1086 if (Thread_WasCreated(&th))
1088 { 1087 {
1089 DWORD waitResult = WaitForSingleObject(th, wait); 1088 const DWORD waitResult = WaitForSingleObject(th, hardExit ? 100 : INFINITE);
1090 // Thread_Wait(&th); 1089 // Thread_Wait(&th);
1091 if (waitResult == WAIT_TIMEOUT) 1090 // if (waitResult == WAIT_TIMEOUT) wait = 1;
1092 wait = 1;
1093 if (!hardExit && waitResult != WAIT_OBJECT_0) 1091 if (!hardExit && waitResult != WAIT_OBJECT_0)
1094 continue; 1092 continue;
1095 Thread_Close(&th); 1093 Thread_Close(&th);
@@ -1107,7 +1105,7 @@ static THREAD_FUNC_DECL MyThreadFunction(void *param)
1107 CMyUniquePtr<CTmpProcessInfo> tpi((CTmpProcessInfo *)param); 1105 CMyUniquePtr<CTmpProcessInfo> tpi((CTmpProcessInfo *)param);
1108 CChildProcesses &processes = tpi->Processes; 1106 CChildProcesses &processes = tpi->Processes;
1109 1107
1110 bool mainProcessWasSet = !processes.Handles.IsEmpty(); 1108 const bool mainProcessWasSet = !processes.Handles.IsEmpty();
1111 1109
1112 bool isComplexMode = true; 1110 bool isComplexMode = true;
1113 1111
@@ -1195,7 +1193,7 @@ static THREAD_FUNC_DECL MyThreadFunction(void *param)
1195 { 1193 {
1196 NFind::CFileInfo newFileInfo; 1194 NFind::CFileInfo newFileInfo;
1197 if (newFileInfo.Find(tpi->FilePath)) 1195 if (newFileInfo.Find(tpi->FilePath))
1198 if (tpi->WasChanged(newFileInfo)) 1196 if (tpi->WasChanged_from_TempFileInfo(newFileInfo))
1199 needFindProcessByPath = false; 1197 needFindProcessByPath = false;
1200 } 1198 }
1201 1199
@@ -1235,7 +1233,7 @@ static THREAD_FUNC_DECL MyThreadFunction(void *param)
1235 1233
1236 if (mainProcessWasSet) 1234 if (mainProcessWasSet)
1237 { 1235 {
1238 if (tpi->WasChanged(newFileInfo)) 1236 if (tpi->WasChanged_from_TempFileInfo(newFileInfo))
1239 { 1237 {
1240 UString m = MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(tpi->FilePath)); 1238 UString m = MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(tpi->FilePath));
1241 if (tpi->ReadOnly) 1239 if (tpi->ReadOnly)
@@ -1279,10 +1277,10 @@ static THREAD_FUNC_DECL MyThreadFunction(void *param)
1279 1277
1280 { 1278 {
1281 NFind::CFileInfo newFileInfo; 1279 NFind::CFileInfo newFileInfo;
1282 1280 const bool finded = newFileInfo.Find(tpi->FilePath);
1283 bool finded = newFileInfo.Find(tpi->FilePath); 1281 if (!needCheckTimestamp
1284 1282 || !finded
1285 if (!needCheckTimestamp || !finded || !tpi->WasChanged(newFileInfo)) 1283 || !tpi->WasChanged_from_TempFileInfo(newFileInfo))
1286 { 1284 {
1287 DEBUG_PRINT("Delete Temp file"); 1285 DEBUG_PRINT("Delete Temp file");
1288 tpi->DeleteDirAndFile(); 1286 tpi->DeleteDirAndFile();
@@ -1534,7 +1532,7 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1534 1532
1535 bool usePassword = false; 1533 bool usePassword = false;
1536 UString password; 1534 UString password;
1537 if (_parentFolders.Size() > 0) 1535 if (!_parentFolders.IsEmpty())
1538 { 1536 {
1539 const CFolderLink &fl = _parentFolders.Back(); 1537 const CFolderLink &fl = _parentFolders.Back();
1540 usePassword = fl.UsePassword; 1538 usePassword = fl.UsePassword;
@@ -1547,7 +1545,7 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1547 #ifndef _UNICODE 1545 #ifndef _UNICODE
1548 if (g_IsNT) 1546 if (g_IsNT)
1549 #endif 1547 #endif
1550 if (_parentFolders.Size() > 0) 1548 if (!_parentFolders.IsEmpty())
1551 { 1549 {
1552 const CFolderLink &fl = _parentFolders.Front(); 1550 const CFolderLink &fl = _parentFolders.Front();
1553 if (!fl.IsVirtual && !fl.FilePath.IsEmpty()) 1551 if (!fl.IsVirtual && !fl.FilePath.IsEmpty())
@@ -1576,39 +1574,42 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1576 1574
1577 if (tryAsArchive) 1575 if (tryAsArchive)
1578 { 1576 {
1577 // actually we want to get sum: size of main file plus sizes of altStreams.
1578 // but now there is no interface to get altStreams sizes.
1579 NCOM::CPropVariant prop; 1579 NCOM::CPropVariant prop;
1580 _folder->GetProperty(index, kpidSize, &prop); 1580 _folder->GetProperty(index, kpidSize, &prop);
1581 UInt64 fileLimit = 1 << 22; 1581 const size_t fileLimit = g_RAM_Size_Defined ?
1582 if (g_RAM_Size_Defined) 1582 g_RAM_Size >> MyMax(_parentFolders.Size() + 1, 8u):
1583 fileLimit = g_RAM_Size / 4; 1583 1u << 22;
1584
1585 UInt64 fileSize = 0; 1584 UInt64 fileSize = 0;
1586 if (!ConvertPropVariantToUInt64(prop, fileSize)) 1585 if (!ConvertPropVariantToUInt64(prop, fileSize))
1587 fileSize = fileLimit; 1586 fileSize = fileLimit;
1588 if (fileSize <= fileLimit && fileSize > 0) 1587#if 0 // 1 : for debug
1588 fileLimit = 1;
1589#endif
1590
1591 if (fileSize <= fileLimit)
1589 { 1592 {
1590 options.streamMode = true; 1593 options.streamMode = true;
1591 virtFileSystemSpec = new CVirtFileSystem; 1594 virtFileSystemSpec = new CVirtFileSystem;
1592 virtFileSystem = virtFileSystemSpec; 1595 virtFileSystem = virtFileSystemSpec;
1596 virtFileSystemSpec->FileName = name;
1597 virtFileSystemSpec->IsAltStreamFile = isAltStream;
1593 1598
1594#if defined(_WIN32) && !defined(UNDER_CE) 1599#if defined(_WIN32) && !defined(UNDER_CE)
1595#ifndef _UNICODE 1600#ifndef _UNICODE
1596 if (g_IsNT) 1601 if (g_IsNT)
1597#endif 1602#endif
1598 if (_parentFolders.Size() > 0)
1599 { 1603 {
1600 const CFolderLink &fl = _parentFolders.Front(); 1604 Get_ZoneId_Stream_from_ParentFolders(virtFileSystemSpec->ZoneBuf);
1601 if (!fl.IsVirtual && !fl.FilePath.IsEmpty()) 1605 options.ZoneBuf = virtFileSystemSpec->ZoneBuf;
1602 ReadZoneFile_Of_BaseFile(fl.FilePath, virtFileSystemSpec->ZoneBuf);
1603 } 1606 }
1604#endif 1607#endif
1605 1608
1606 // we allow additional total size for small alt streams; 1609 virtFileSystemSpec->MaxTotalAllocSize = (size_t)fileSize
1607 virtFileSystemSpec->MaxTotalAllocSize = fileSize + (1 << 10); 1610 + (1 << 16); // we allow additional total size for small alt streams.
1608
1609 virtFileSystemSpec->DirPrefix = tempDirNorm; 1611 virtFileSystemSpec->DirPrefix = tempDirNorm;
1610 virtFileSystemSpec->Init(); 1612 // options.VirtFileSystem = virtFileSystem;
1611 options.VirtFileSystem = virtFileSystem;
1612 options.VirtFileSystemSpec = virtFileSystemSpec; 1613 options.VirtFileSystemSpec = virtFileSystemSpec;
1613 } 1614 }
1614 } 1615 }
@@ -1618,7 +1619,7 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1618 1619
1619 const HRESULT result = CopyTo(options, indices, &messages, usePassword, password); 1620 const HRESULT result = CopyTo(options, indices, &messages, usePassword, password);
1620 1621
1621 if (_parentFolders.Size() > 0) 1622 if (!_parentFolders.IsEmpty())
1622 { 1623 {
1623 CFolderLink &fl = _parentFolders.Back(); 1624 CFolderLink &fl = _parentFolders.Back();
1624 fl.UsePassword = usePassword; 1625 fl.UsePassword = usePassword;
@@ -1634,34 +1635,46 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1634 return; 1635 return;
1635 } 1636 }
1636 1637
1637 if (options.VirtFileSystem) 1638 if (virtFileSystemSpec && !virtFileSystemSpec->WasStreamFlushedToFS())
1638 { 1639 {
1639 if (virtFileSystemSpec->IsStreamInMem()) 1640 int index_in_Files = virtFileSystemSpec->Index_of_MainExtractedFile_in_Files;
1641 if (index_in_Files < 0)
1640 { 1642 {
1641 const CVirtFile &file = virtFileSystemSpec->Files[0]; 1643 if (virtFileSystemSpec->Files.Size() != 1)
1642 1644 {
1643 size_t streamSize = (size_t)file.Size; 1645 MessageBox_Error_HRESULT(E_FAIL);
1644 CBufInStream *bufInStreamSpec = new CBufInStream; 1646 return;
1645 CMyComPtr<IInStream> bufInStream = bufInStreamSpec; 1647 }
1646 bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem); 1648 // it's not expected case that index was not set, but we support that case
1647 1649 index_in_Files = 0;
1648 HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"" 1650 }
1651 {
1652 const CVirtFile &file = virtFileSystemSpec->Files[index_in_Files];
1653 CMyComPtr2_Create<IInStream, CBufInStream> bufInStream;
1654 bufInStream->Init(file.Data, file.WrittenSize, virtFileSystem);
1655 const HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo,
1656 fullVirtPath, type ? type : L""
1649 // , encrypted 1657 // , encrypted
1650 // , true // showErrorMessage 1658 // , true // showErrorMessage
1651 ); 1659 );
1652
1653 if (res == S_OK) 1660 if (res == S_OK)
1654 { 1661 {
1662 if (virtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files >= 0
1663 && !_parentFolders.IsEmpty())
1664 {
1665 const CVirtFile &fileZone = virtFileSystemSpec->Files[
1666 virtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files];
1667 _parentFolders.Back().ZoneBuf.CopyFrom(fileZone.Data, fileZone.WrittenSize);
1668 }
1669
1655 tempDirectory.DisableDeleting(); 1670 tempDirectory.DisableDeleting();
1656 RefreshListCtrl(); 1671 RefreshListCtrl();
1657 return; 1672 return;
1658 } 1673 }
1659
1660 if (res == E_ABORT || res != S_FALSE) 1674 if (res == E_ABORT || res != S_FALSE)
1661 return; 1675 return;
1662 if (!tryExternal) 1676 if (!tryExternal)
1663 return; 1677 return;
1664
1665 tryAsArchive = false; 1678 tryAsArchive = false;
1666 if (virtFileSystemSpec->FlushToDisk(true) != S_OK) 1679 if (virtFileSystemSpec->FlushToDisk(true) != S_OK)
1667 return; 1680 return;
@@ -1684,7 +1697,7 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1684 1697
1685 if (tryAsArchive) 1698 if (tryAsArchive)
1686 { 1699 {
1687 HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L"" 1700 const HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L""
1688 // , encrypted 1701 // , encrypted
1689 // , true // showErrorMessage 1702 // , true // showErrorMessage
1690 ); 1703 );
@@ -1732,7 +1745,7 @@ void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExterna
1732 return; 1745 return;
1733 } 1746 }
1734 1747
1735 tpi->Window = (HWND)(*this); 1748 tpi->Window = (HWND)*this;
1736 tpi->FullPathFolderPrefix = _currentFolderPrefix; 1749 tpi->FullPathFolderPrefix = _currentFolderPrefix;
1737 tpi->FileIndex = index; 1750 tpi->FileIndex = index;
1738 tpi->RelPath = relPath; 1751 tpi->RelPath = relPath;
diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp
index 544e9bf..868ad22 100644
--- a/CPP/7zip/UI/FileManager/PanelItems.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItems.cpp
@@ -1438,13 +1438,16 @@ void CPanel::OnTimer()
1438 return; 1438 return;
1439 if (!AutoRefresh_Mode) 1439 if (!AutoRefresh_Mode)
1440 return; 1440 return;
1441 CMyComPtr<IFolderWasChanged> folderWasChanged; 1441 if (!_folder) // it's unexpected case, but we use it as additional protection.
1442 if (_folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged) != S_OK)
1443 return;
1444 Int32 wasChanged;
1445 if (folderWasChanged->WasChanged(&wasChanged) != S_OK)
1446 return;
1447 if (wasChanged == 0)
1448 return; 1442 return;
1443 {
1444 CMyComPtr<IFolderWasChanged> folderWasChanged;
1445 _folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged);
1446 if (!folderWasChanged)
1447 return;
1448 Int32 wasChanged;
1449 if (folderWasChanged->WasChanged(&wasChanged) != S_OK || wasChanged == 0)
1450 return;
1451 }
1449 OnReload(true); // onTimer 1452 OnReload(true); // onTimer
1450} 1453}
diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp
index 4dbd9f6..05ab36b 100644
--- a/CPP/7zip/UI/FileManager/PanelListNotify.cpp
+++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp
@@ -785,7 +785,7 @@ void CPanel::Refresh_StatusBar()
785 wchar_t selectSizeString[32]; 785 wchar_t selectSizeString[32];
786 selectSizeString[0] = 0; 786 selectSizeString[0] = 0;
787 787
788 if (indices.Size() > 0) 788 if (!indices.IsEmpty())
789 { 789 {
790 // for (unsigned ttt = 0; ttt < 1000; ttt++) { 790 // for (unsigned ttt = 0; ttt < 1000; ttt++) {
791 UInt64 totalSize = 0; 791 UInt64 totalSize = 0;
diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp
index af313ff..427464b 100644
--- a/CPP/7zip/UI/FileManager/PanelOperations.cpp
+++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp
@@ -80,7 +80,7 @@ HRESULT CThreadFolderOperations::DoOperation(CPanel &panel, const UString &progr
80 80
81 UpdateCallbackSpec->Init(); 81 UpdateCallbackSpec->Init();
82 82
83 if (panel._parentFolders.Size() > 0) 83 if (!panel._parentFolders.IsEmpty())
84 { 84 {
85 const CFolderLink &fl = panel._parentFolders.Back(); 85 const CFolderLink &fl = panel._parentFolders.Back();
86 UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword; 86 UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword;
@@ -275,8 +275,8 @@ static bool IsCorrectFsName(const UString &name)
275{ 275{
276 const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1)); 276 const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1));
277 return 277 return
278 lastPart != L"." && 278 !lastPart.IsEqualTo(".") &&
279 lastPart != L".."; 279 !lastPart.IsEqualTo("..");
280} 280}
281 281
282bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); 282bool CorrectFsPath(const UString &relBase, const UString &path, UString &result);
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
index 690ebec..a070a0a 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
@@ -78,8 +78,9 @@ static const UInt32 kLangIDs_Colon[] =
78#define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL) 78#define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL)
79 79
80CProgressSync::CProgressSync(): 80CProgressSync::CProgressSync():
81 _stopped(false), _paused(false), 81 _stopped(false),
82 _bytesProgressMode(true), 82 _paused(false),
83 _filesProgressMode(false),
83 _isDir(false), 84 _isDir(false),
84 _totalBytes(UNDEFINED_VAL), _completedBytes(0), 85 _totalBytes(UNDEFINED_VAL), _completedBytes(0),
85 _totalFiles(UNDEFINED_VAL), _curFiles(0), 86 _totalFiles(UNDEFINED_VAL), _curFiles(0),
@@ -108,6 +109,13 @@ HRESULT CProgressSync::CheckStop()
108 } 109 }
109} 110}
110 111
112void CProgressSync::Clear_Stop_Status()
113{
114 CRITICAL_LOCK
115 if (_stopped)
116 _stopped = false;
117}
118
111HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir) 119HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir)
112{ 120{
113 { 121 {
@@ -242,27 +250,27 @@ void CProgressSync::AddError_Code_Name(HRESULT systemError, const wchar_t *name)
242} 250}
243 251
244CProgressDialog::CProgressDialog(): 252CProgressDialog::CProgressDialog():
245 _timer(0), 253 _isDir(false),
246 CompressingMode(true), 254 _wasCreated(false),
247 MainWindow(NULL) 255 _needClose(false),
256 _errorsWereDisplayed(false),
257 _waitCloseByCancelButton(false),
258 _cancelWasPressed(false),
259 _inCancelMessageBox(false),
260 _externalCloseMessageWasReceived(false),
261 _background(false),
262 WaitMode(false),
263 MessagesDisplayed(false),
264 CompressingMode(true),
265 ShowCompressionInfo(true),
266 _numPostedMessages(0),
267 _numAutoSizeMessages(0),
268 _numMessages(0),
269 _timer(0),
270 IconID(-1),
271 MainWindow(NULL)
248{ 272{
249 _isDir = false; 273
250
251 _numMessages = 0;
252 IconID = -1;
253 MessagesDisplayed = false;
254 _wasCreated = false;
255 _needClose = false;
256 _inCancelMessageBox = false;
257 _externalCloseMessageWasReceived = false;
258
259 _numPostedMessages = 0;
260 _numAutoSizeMessages = 0;
261 _errorsWereDisplayed = false;
262 _waitCloseByCancelButton = false;
263 _cancelWasPressed = false;
264 ShowCompressionInfo = true;
265 WaitMode = false;
266 if (_dialogCreatedEvent.Create() != S_OK) 274 if (_dialogCreatedEvent.Create() != S_OK)
267 throw 1334987; 275 throw 1334987;
268 if (_createDialogEvent.Create() != S_OK) 276 if (_createDialogEvent.Create() != S_OK)
@@ -357,8 +365,6 @@ bool CProgressDialog::OnInit()
357 _filesStr_Prev.Empty(); 365 _filesStr_Prev.Empty();
358 _filesTotStr_Prev.Empty(); 366 _filesTotStr_Prev.Empty();
359 367
360 _foreground = true;
361
362 m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); 368 m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
363 _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES)); 369 _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES));
364 _messageList.SetUnicodeFormat(); 370 _messageList.SetUnicodeFormat();
@@ -388,9 +394,8 @@ bool CProgressDialog::OnInit()
388 SetPauseText(); 394 SetPauseText();
389 SetPriorityText(); 395 SetPriorityText();
390 396
391 _messageList.InsertColumn(0, L"", 30); 397 _messageList.InsertColumn(0, L"", 40);
392 _messageList.InsertColumn(1, L"", 600); 398 _messageList.InsertColumn(1, L"", 460);
393
394 _messageList.SetColumnWidthAuto(0); 399 _messageList.SetColumnWidthAuto(0);
395 _messageList.SetColumnWidthAuto(1); 400 _messageList.SetColumnWidthAuto(1);
396 401
@@ -690,7 +695,7 @@ static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
690void CProgressDialog::UpdateStatInfo(bool showAll) 695void CProgressDialog::UpdateStatInfo(bool showAll)
691{ 696{
692 UInt64 total, completed, totalFiles, completedFiles, inSize, outSize; 697 UInt64 total, completed, totalFiles, completedFiles, inSize, outSize;
693 bool bytesProgressMode; 698 bool filesProgressMode;
694 699
695 bool titleFileName_Changed; 700 bool titleFileName_Changed;
696 bool curFilePath_Changed; 701 bool curFilePath_Changed;
@@ -704,7 +709,7 @@ void CProgressDialog::UpdateStatInfo(bool showAll)
704 completedFiles = Sync._curFiles; 709 completedFiles = Sync._curFiles;
705 inSize = Sync._inSize; 710 inSize = Sync._inSize;
706 outSize = Sync._outSize; 711 outSize = Sync._outSize;
707 bytesProgressMode = Sync._bytesProgressMode; 712 filesProgressMode = Sync._filesProgressMode;
708 713
709 GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed); 714 GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed);
710 GetChangedString(Sync._filePath, _filePath, curFilePath_Changed); 715 GetChangedString(Sync._filePath, _filePath, curFilePath_Changed);
@@ -719,8 +724,8 @@ void CProgressDialog::UpdateStatInfo(bool showAll)
719 724
720 UInt32 curTime = ::GetTickCount(); 725 UInt32 curTime = ::GetTickCount();
721 726
722 const UInt64 progressTotal = bytesProgressMode ? total : totalFiles; 727 const UInt64 progressTotal = filesProgressMode ? totalFiles : total;
723 const UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles; 728 const UInt64 progressCompleted = filesProgressMode ? completedFiles : completed;
724 { 729 {
725 if (IS_UNDEFINED_VAL(progressTotal)) 730 if (IS_UNDEFINED_VAL(progressTotal))
726 { 731 {
@@ -900,7 +905,7 @@ void CProgressDialog::UpdateStatInfo(bool showAll)
900 { 905 {
901 UString s = _status; 906 UString s = _status;
902 ReduceString(s, _numReduceSymbols); 907 ReduceString(s, _numReduceSymbols);
903 SetItemText(IDT_PROGRESS_STATUS, _status); 908 SetItemText(IDT_PROGRESS_STATUS, s);
904 } 909 }
905 910
906 if (curFilePath_Changed) 911 if (curFilePath_Changed)
@@ -1086,12 +1091,10 @@ void CProgressDialog::SetTitleText()
1086 } 1091 }
1087 if (IS_DEFINED_VAL(_prevPercentValue)) 1092 if (IS_DEFINED_VAL(_prevPercentValue))
1088 { 1093 {
1089 char temp[32]; 1094 s.Add_UInt64(_prevPercentValue);
1090 ConvertUInt64ToString(_prevPercentValue, temp);
1091 s += temp;
1092 s.Add_Char('%'); 1095 s.Add_Char('%');
1093 } 1096 }
1094 if (!_foreground) 1097 if (_background)
1095 { 1098 {
1096 s.Add_Space(); 1099 s.Add_Space();
1097 s += _backgrounded_String; 1100 s += _backgrounded_String;
@@ -1138,17 +1141,17 @@ void CProgressDialog::OnPauseButton()
1138 1141
1139void CProgressDialog::SetPriorityText() 1142void CProgressDialog::SetPriorityText()
1140{ 1143{
1141 SetItemText(IDB_PROGRESS_BACKGROUND, _foreground ? 1144 SetItemText(IDB_PROGRESS_BACKGROUND, _background ?
1142 _background_String : 1145 _foreground_String :
1143 _foreground_String); 1146 _background_String);
1144 SetTitleText(); 1147 SetTitleText();
1145} 1148}
1146 1149
1147void CProgressDialog::OnPriorityButton() 1150void CProgressDialog::OnPriorityButton()
1148{ 1151{
1149 _foreground = !_foreground; 1152 _background = !_background;
1150 #ifndef UNDER_CE 1153 #ifndef UNDER_CE
1151 SetPriorityClass(GetCurrentProcess(), _foreground ? NORMAL_PRIORITY_CLASS: IDLE_PRIORITY_CLASS); 1154 SetPriorityClass(GetCurrentProcess(), _background ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS);
1152 #endif 1155 #endif
1153 SetPriorityText(); 1156 SetPriorityText();
1154} 1157}
@@ -1184,12 +1187,16 @@ void CProgressDialog::AddMessage(LPCWSTR message)
1184 _numMessages++; 1187 _numMessages++;
1185} 1188}
1186 1189
1187static unsigned GetNumDigits(UInt32 val) 1190static unsigned GetNumDigits(unsigned val)
1188{ 1191{
1189 unsigned i; 1192 unsigned i = 0;
1190 for (i = 0; val >= 10; i++) 1193 for (;;)
1194 {
1195 i++;
1191 val /= 10; 1196 val /= 10;
1192 return i; 1197 if (val == 0)
1198 return i;
1199 }
1193} 1200}
1194 1201
1195void CProgressDialog::UpdateMessagesDialog() 1202void CProgressDialog::UpdateMessagesDialog()
@@ -1197,7 +1204,7 @@ void CProgressDialog::UpdateMessagesDialog()
1197 UStringVector messages; 1204 UStringVector messages;
1198 { 1205 {
1199 NSynchronization::CCriticalSectionLock lock(Sync._cs); 1206 NSynchronization::CCriticalSectionLock lock(Sync._cs);
1200 unsigned num = Sync.Messages.Size(); 1207 const unsigned num = Sync.Messages.Size();
1201 if (num > _numPostedMessages) 1208 if (num > _numPostedMessages)
1202 { 1209 {
1203 messages.ClearAndReserve(num - _numPostedMessages); 1210 messages.ClearAndReserve(num - _numPostedMessages);
@@ -1210,7 +1217,11 @@ void CProgressDialog::UpdateMessagesDialog()
1210 { 1217 {
1211 FOR_VECTOR (i, messages) 1218 FOR_VECTOR (i, messages)
1212 AddMessage(messages[i]); 1219 AddMessage(messages[i]);
1213 if (_numAutoSizeMessages < 256 || GetNumDigits(_numPostedMessages) > GetNumDigits(_numAutoSizeMessages)) 1220 // SetColumnWidthAuto() can be slow for big number of files.
1221 if (_numPostedMessages < 1000000 || _numAutoSizeMessages < 100)
1222 if (_numAutoSizeMessages < 100 ||
1223 GetNumDigits(_numPostedMessages) >
1224 GetNumDigits(_numAutoSizeMessages))
1214 { 1225 {
1215 _messageList.SetColumnWidthAuto(0); 1226 _messageList.SetColumnWidthAuto(0);
1216 _messageList.SetColumnWidthAuto(1); 1227 _messageList.SetColumnWidthAuto(1);
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.h b/CPP/7zip/UI/FileManager/ProgressDialog2.h
index 4ca9be7..60a5ca6 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.h
@@ -33,9 +33,8 @@ class CProgressSync
33{ 33{
34 bool _stopped; 34 bool _stopped;
35 bool _paused; 35 bool _paused;
36
37public: 36public:
38 bool _bytesProgressMode; 37 bool _filesProgressMode;
39 bool _isDir; 38 bool _isDir;
40 UInt64 _totalBytes; 39 UInt64 _totalBytes;
41 UInt64 _completedBytes; 40 UInt64 _completedBytes;
@@ -73,13 +72,14 @@ public:
73 _paused = val; 72 _paused = val;
74 } 73 }
75 74
76 void Set_BytesProgressMode(bool bytesProgressMode) 75 void Set_FilesProgressMode(bool filesProgressMode)
77 { 76 {
78 NWindows::NSynchronization::CCriticalSectionLock lock(_cs); 77 NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
79 _bytesProgressMode = bytesProgressMode; 78 _filesProgressMode = filesProgressMode;
80 } 79 }
81 80
82 HRESULT CheckStop(); 81 HRESULT CheckStop();
82 void Clear_Stop_Status();
83 HRESULT ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir = false); 83 HRESULT ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir = false);
84 84
85 HRESULT Set_NumFilesTotal(UInt64 val); 85 HRESULT Set_NumFilesTotal(UInt64 val);
@@ -102,12 +102,32 @@ public:
102 bool ThereIsMessage() const { return !Messages.IsEmpty() || FinalMessage.ThereIsMessage(); } 102 bool ThereIsMessage() const { return !Messages.IsEmpty() || FinalMessage.ThereIsMessage(); }
103}; 103};
104 104
105
105class CProgressDialog: public NWindows::NControl::CModalDialog 106class CProgressDialog: public NWindows::NControl::CModalDialog
106{ 107{
108 bool _isDir;
109 bool _wasCreated;
110 bool _needClose;
111 bool _errorsWereDisplayed;
112 bool _waitCloseByCancelButton;
113 bool _cancelWasPressed;
114 bool _inCancelMessageBox;
115 bool _externalCloseMessageWasReceived;
116 bool _background;
117public:
118 bool WaitMode;
119 bool MessagesDisplayed; // = true if user pressed OK on all messages or there are no messages.
120 bool CompressingMode;
121 bool ShowCompressionInfo;
122
123private:
124 unsigned _numPostedMessages;
125 unsigned _numAutoSizeMessages;
126 unsigned _numMessages;
127
107 UString _titleFileName; 128 UString _titleFileName;
108 UString _filePath; 129 UString _filePath;
109 UString _status; 130 UString _status;
110 bool _isDir;
111 131
112 UString _background_String; 132 UString _background_String;
113 UString _backgrounded_String; 133 UString _backgrounded_String;
@@ -152,7 +172,6 @@ class CProgressDialog: public NWindows::NControl::CModalDialog
152 NWindows::NControl::CProgressBar m_ProgressBar; 172 NWindows::NControl::CProgressBar m_ProgressBar;
153 NWindows::NControl::CListView _messageList; 173 NWindows::NControl::CListView _messageList;
154 174
155 unsigned _numMessages;
156 UStringVector _messageStrings; 175 UStringVector _messageStrings;
157 176
158 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ 177 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
@@ -175,28 +194,10 @@ class CProgressDialog: public NWindows::NControl::CModalDialog
175 UString _filesStr_Prev; 194 UString _filesStr_Prev;
176 UString _filesTotStr_Prev; 195 UString _filesTotStr_Prev;
177 196
197 unsigned _numReduceSymbols;
178 unsigned _prevSpeed_MoveBits; 198 unsigned _prevSpeed_MoveBits;
179 UInt64 _prevSpeed; 199 UInt64 _prevSpeed;
180 200
181 bool _foreground;
182
183 unsigned _numReduceSymbols;
184
185 bool _wasCreated;
186 bool _needClose;
187
188 unsigned _numPostedMessages;
189 UInt32 _numAutoSizeMessages;
190
191 bool _errorsWereDisplayed;
192
193 bool _waitCloseByCancelButton;
194 bool _cancelWasPressed;
195
196 bool _inCancelMessageBox;
197 bool _externalCloseMessageWasReceived;
198
199
200 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ 201 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
201 void SetTaskbarProgressState(TBPFLAG tbpFlags) 202 void SetTaskbarProgressState(TBPFLAG tbpFlags)
202 { 203 {
@@ -244,14 +245,10 @@ class CProgressDialog: public NWindows::NControl::CModalDialog
244 void ShowAfterMessages(HWND wndParent); 245 void ShowAfterMessages(HWND wndParent);
245 246
246 void CheckNeedClose(); 247 void CheckNeedClose();
248
247public: 249public:
248 CProgressSync Sync; 250 CProgressSync Sync;
249 bool CompressingMode;
250 bool WaitMode;
251 bool ShowCompressionInfo;
252 bool MessagesDisplayed; // = true if user pressed OK on all messages or there are no messages.
253 int IconID; 251 int IconID;
254
255 HWND MainWindow; 252 HWND MainWindow;
256 #ifndef Z7_SFX 253 #ifndef Z7_SFX
257 UString MainTitle; 254 UString MainTitle;
diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.cpp b/CPP/7zip/UI/FileManager/RegistryUtils.cpp
index 7e61998..0284591 100644
--- a/CPP/7zip/UI/FileManager/RegistryUtils.cpp
+++ b/CPP/7zip/UI/FileManager/RegistryUtils.cpp
@@ -86,17 +86,15 @@ static bool Read7ZipOption(LPCTSTR value, bool defaultValue)
86 if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS) 86 if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS)
87 { 87 {
88 bool enabled; 88 bool enabled;
89 if (key.QueryValue(value, enabled) == ERROR_SUCCESS) 89 if (key.GetValue_bool_IfOk(value, enabled) == ERROR_SUCCESS)
90 return enabled; 90 return enabled;
91 } 91 }
92 return defaultValue; 92 return defaultValue;
93} 93}
94 94
95static void ReadOption(CKey &key, LPCTSTR value, bool &dest) 95static void ReadOption(CKey &key, LPCTSTR name, bool &dest)
96{ 96{
97 bool enabled = false; 97 key.GetValue_bool_IfOk(name, dest);
98 if (key.QueryValue(value, enabled) == ERROR_SUCCESS)
99 dest = enabled;
100} 98}
101 99
102/* 100/*
diff --git a/CPP/7zip/UI/FileManager/RootFolder.cpp b/CPP/7zip/UI/FileManager/RootFolder.cpp
index 192f660..b512f3b 100644
--- a/CPP/7zip/UI/FileManager/RootFolder.cpp
+++ b/CPP/7zip/UI/FileManager/RootFolder.cpp
@@ -249,7 +249,7 @@ Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resu
249 AreEqualNames(name2, L"Documents")) 249 AreEqualNames(name2, L"Documents"))
250 return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder); 250 return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder);
251 #else 251 #else
252 if (name2 == WSTRING_PATH_SEPARATOR) 252 if (name2.IsEqualTo(STRING_PATH_SEPARATOR))
253 return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); 253 return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
254 #endif 254 #endif
255 255
@@ -257,7 +257,7 @@ Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resu
257 AreEqualNames(name2, L"Computer")) 257 AreEqualNames(name2, L"Computer"))
258 return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); 258 return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
259 259
260 if (name2 == WSTRING_PATH_SEPARATOR) 260 if (name2.IsEqualTo(STRING_PATH_SEPARATOR))
261 { 261 {
262 CMyComPtr<IFolderFolder> subFolder = this; 262 CMyComPtr<IFolderFolder> subFolder = this;
263 *resultFolder = subFolder.Detach(); 263 *resultFolder = subFolder.Detach();
diff --git a/CPP/7zip/UI/FileManager/SettingsPage.cpp b/CPP/7zip/UI/FileManager/SettingsPage.cpp
index a5117be..8b5983a 100644
--- a/CPP/7zip/UI/FileManager/SettingsPage.cpp
+++ b/CPP/7zip/UI/FileManager/SettingsPage.cpp
@@ -161,7 +161,7 @@ bool CSettingsPage::OnInit()
161 needSetCur = false; 161 needSetCur = false;
162 } 162 }
163 { 163 {
164 _ramSize = (UInt64)(sizeof(size_t)) << 29; 164 _ramSize = (size_t)sizeof(size_t) << 29;
165 _ramSize_Defined = NSystem::GetRamSize(_ramSize); 165 _ramSize_Defined = NSystem::GetRamSize(_ramSize);
166 UString s; 166 UString s;
167 if (_ramSize_Defined) 167 if (_ramSize_Defined)
@@ -198,10 +198,10 @@ bool CSettingsPage::OnInit()
198 198
199 199
200 { 200 {
201 UInt64 ramSize = (UInt64)sizeof(size_t) << 29; 201 size_t ramSize = (size_t)sizeof(size_t) << 29;
202 const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize); 202 const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize);
203 // ramSize *= 10; // for debug 203 // ramSize *= 10; // for debug
204 UInt64 ramSize_GB = (ramSize + (1u << 29)) >> 30; 204 UInt32 ramSize_GB = (UInt32)(((UInt64)ramSize + (1u << 29)) >> 30);
205 if (ramSize_GB == 0) 205 if (ramSize_GB == 0)
206 ramSize_GB = 1; 206 ramSize_GB = 1;
207 UString s ("GB"); 207 UString s ("GB");
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
index 406c9e1..72fe5e7 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
@@ -109,7 +109,7 @@ DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(
109 iconIndex = shFileInfo.iIcon; 109 iconIndex = shFileInfo.iIcon;
110 // we use SHGFI_USEFILEATTRIBUTES, and 110 // we use SHGFI_USEFILEATTRIBUTES, and
111 // (res != 0) is expected for main cases, even if there are no such file. 111 // (res != 0) is expected for main cases, even if there are no such file.
112 // (res == 0) for path with kSuperPrefix \\?\ 112 // (res == 0) for path with kSuperPrefix "\\?\"
113 // Also SHGFI_USEFILEATTRIBUTES still returns icon inside exe. 113 // Also SHGFI_USEFILEATTRIBUTES still returns icon inside exe.
114 // So we can use SHGFI_USEFILEATTRIBUTES for any case. 114 // So we can use SHGFI_USEFILEATTRIBUTES for any case.
115 // UString temp = fs2us(path); // for debug 115 // UString temp = fs2us(path); // for debug
diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.cpp b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp
index 71ad710..0796eba 100644
--- a/CPP/7zip/UI/FileManager/UpdateCallback100.cpp
+++ b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp
@@ -113,6 +113,29 @@ Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, con
113 return ProgressDialog->Sync.CheckStop(); 113 return ProgressDialog->Sync.CheckStop();
114} 114}
115 115
116
117Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode))
118{
119 return MoveArc_Start_Base(srcTempPath, destFinalPath, size, updateMode);
120}
121
122Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize))
123{
124 return MoveArc_Progress_Base(totalSize, currentSize);
125}
126
127Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Finish())
128{
129 return MoveArc_Finish_Base();
130}
131
132Z7_COM7F_IMF(CUpdateCallback100Imp::Before_ArcReopen())
133{
134 ProgressDialog->Sync.Clear_Stop_Status();
135 return S_OK;
136}
137
138
116Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password)) 139Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password))
117{ 140{
118 *password = NULL; 141 *password = NULL;
diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.h b/CPP/7zip/UI/FileManager/UpdateCallback100.h
index 5d56dfb..adae94f 100644
--- a/CPP/7zip/UI/FileManager/UpdateCallback100.h
+++ b/CPP/7zip/UI/FileManager/UpdateCallback100.h
@@ -16,6 +16,7 @@
16class CUpdateCallback100Imp Z7_final: 16class CUpdateCallback100Imp Z7_final:
17 public IFolderArchiveUpdateCallback, 17 public IFolderArchiveUpdateCallback,
18 public IFolderArchiveUpdateCallback2, 18 public IFolderArchiveUpdateCallback2,
19 public IFolderArchiveUpdateCallback_MoveArc,
19 public IFolderScanProgress, 20 public IFolderScanProgress,
20 public ICryptoGetTextPassword2, 21 public ICryptoGetTextPassword2,
21 public ICryptoGetTextPassword, 22 public ICryptoGetTextPassword,
@@ -24,9 +25,10 @@ class CUpdateCallback100Imp Z7_final:
24 public CUpdateCallbackGUI2, 25 public CUpdateCallbackGUI2,
25 public CMyUnknownImp 26 public CMyUnknownImp
26{ 27{
27 Z7_COM_UNKNOWN_IMP_7( 28 Z7_COM_UNKNOWN_IMP_8(
28 IFolderArchiveUpdateCallback, 29 IFolderArchiveUpdateCallback,
29 IFolderArchiveUpdateCallback2, 30 IFolderArchiveUpdateCallback2,
31 IFolderArchiveUpdateCallback_MoveArc,
30 IFolderScanProgress, 32 IFolderScanProgress,
31 ICryptoGetTextPassword2, 33 ICryptoGetTextPassword2,
32 ICryptoGetTextPassword, 34 ICryptoGetTextPassword,
@@ -36,6 +38,7 @@ class CUpdateCallback100Imp Z7_final:
36 Z7_IFACE_COM7_IMP(IProgress) 38 Z7_IFACE_COM7_IMP(IProgress)
37 Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback) 39 Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback)
38 Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback2) 40 Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback2)
41 Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback_MoveArc)
39 Z7_IFACE_COM7_IMP(IFolderScanProgress) 42 Z7_IFACE_COM7_IMP(IFolderScanProgress)
40 Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2) 43 Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2)
41 Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) 44 Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
diff --git a/CPP/7zip/UI/FileManager/ViewSettings.cpp b/CPP/7zip/UI/FileManager/ViewSettings.cpp
index 3d64602..4a8f58d 100644
--- a/CPP/7zip/UI/FileManager/ViewSettings.cpp
+++ b/CPP/7zip/UI/FileManager/ViewSettings.cpp
@@ -81,15 +81,15 @@ void CListViewInfo::Read(const UString &id)
81{ 81{
82 Clear(); 82 Clear();
83 CByteBuffer buf; 83 CByteBuffer buf;
84 UInt32 size;
85 { 84 {
86 NSynchronization::CCriticalSectionLock lock(g_CS); 85 NSynchronization::CCriticalSectionLock lock(g_CS);
87 CKey key; 86 CKey key;
88 if (key.Open(HKEY_CURRENT_USER, kCulumnsKeyName, KEY_READ) != ERROR_SUCCESS) 87 if (key.Open(HKEY_CURRENT_USER, kCulumnsKeyName, KEY_READ) != ERROR_SUCCESS)
89 return; 88 return;
90 if (key.QueryValue(GetSystemString(id), buf, size) != ERROR_SUCCESS) 89 if (key.QueryValue_Binary(GetSystemString(id), buf) != ERROR_SUCCESS)
91 return; 90 return;
92 } 91 }
92 unsigned size = (unsigned)buf.Size();
93 if (size < kListViewHeaderSize) 93 if (size < kListViewHeaderSize)
94 return; 94 return;
95 UInt32 version; 95 UInt32 version;
@@ -104,7 +104,9 @@ void CListViewInfo::Read(const UString &id)
104 size -= kListViewHeaderSize; 104 size -= kListViewHeaderSize;
105 if (size % kColumnInfoSize != 0) 105 if (size % kColumnInfoSize != 0)
106 return; 106 return;
107 unsigned numItems = size / kColumnInfoSize; 107 if (size > 1000 * kColumnInfoSize)
108 return;
109 const unsigned numItems = size / kColumnInfoSize;
108 Columns.ClearAndReserve(numItems); 110 Columns.ClearAndReserve(numItems);
109 for (unsigned i = 0; i < numItems; i++) 111 for (unsigned i = 0; i < numItems; i++)
110 { 112 {
@@ -161,8 +163,7 @@ void CWindowInfo::Save() const
161 163
162static bool QueryBuf(CKey &key, LPCTSTR name, CByteBuffer &buf, UInt32 dataSize) 164static bool QueryBuf(CKey &key, LPCTSTR name, CByteBuffer &buf, UInt32 dataSize)
163{ 165{
164 UInt32 size; 166 return key.QueryValue_Binary(name, buf) == ERROR_SUCCESS && buf.Size() == dataSize;
165 return key.QueryValue(name, buf, size) == ERROR_SUCCESS && size == dataSize;
166} 167}
167 168
168void CWindowInfo::Read(bool &windowPosDefined, bool &panelInfoDefined) 169void CWindowInfo::Read(bool &windowPosDefined, bool &panelInfoDefined)
@@ -206,7 +207,7 @@ static bool ReadUi32Val(const TCHAR *name, UInt32 &value)
206 CKey key; 207 CKey key;
207 if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) 208 if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS)
208 return false; 209 return false;
209 return key.QueryValue(name, value) == ERROR_SUCCESS; 210 return key.GetValue_UInt32_IfOk(name, value) == ERROR_SUCCESS;
210} 211}
211 212
212void SaveToolbarsMask(UInt32 toolbarMask) 213void SaveToolbarsMask(UInt32 toolbarMask)
@@ -229,7 +230,7 @@ void CListMode::Save() const
229{ 230{
230 UInt32 t = 0; 231 UInt32 t = 0;
231 for (int i = 0; i < 2; i++) 232 for (int i = 0; i < 2; i++)
232 t |= ((Panels[i]) & 0xFF) << (i * 8); 233 t |= (Panels[i] & 0xFF) << (i * 8);
233 SaveUi32Val(kListMode, t); 234 SaveUi32Val(kListMode, t);
234} 235}
235 236
@@ -241,7 +242,7 @@ void CListMode::Read()
241 return; 242 return;
242 for (int i = 0; i < 2; i++) 243 for (int i = 0; i < 2; i++)
243 { 244 {
244 Panels[i] = (t & 0xFF); 245 Panels[i] = t & 0xFF;
245 t >>= 8; 246 t >>= 8;
246 } 247 }
247} 248}
diff --git a/CPP/7zip/UI/FileManager/makefile b/CPP/7zip/UI/FileManager/makefile
index 0ca5caa..24dc4ca 100644
--- a/CPP/7zip/UI/FileManager/makefile
+++ b/CPP/7zip/UI/FileManager/makefile
@@ -104,7 +104,7 @@ AR_COMMON_OBJS = \
104C_OBJS = $(C_OBJS) \ 104C_OBJS = $(C_OBJS) \
105 $O\Alloc.obj \ 105 $O\Alloc.obj \
106 $O\CpuArch.obj \ 106 $O\CpuArch.obj \
107 $O\Sort.obj \
108 $O\Threads.obj \ 107 $O\Threads.obj \
109 108
109!include "../../Sort.mak"
110!include "../../7zip.mak" 110!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/FileManager/resource.h b/CPP/7zip/UI/FileManager/resource.h
index 4e22230..36c4b53 100644
--- a/CPP/7zip/UI/FileManager/resource.h
+++ b/CPP/7zip/UI/FileManager/resource.h
@@ -25,9 +25,12 @@
25#define IDM_CRC64 103 25#define IDM_CRC64 103
26#define IDM_SHA1 104 26#define IDM_SHA1 104
27#define IDM_SHA256 105 27#define IDM_SHA256 105
28#define IDM_XXH64 106 28#define IDM_SHA384 106
29#define IDM_BLAKE2SP 107 29#define IDM_SHA512 107
30 30#define IDM_SHA3_256 108
31#define IDM_XXH64 120
32#define IDM_BLAKE2SP 121
33#define IDM_MD5 122
31 34
32#define IDM_FILE 500 35#define IDM_FILE 500
33#define IDM_EDIT 501 36#define IDM_EDIT 501
@@ -134,7 +137,7 @@
134#define IDS_COPY_TO 6002 137#define IDS_COPY_TO 6002
135#define IDS_MOVE_TO 6003 138#define IDS_MOVE_TO 6003
136#define IDS_COPYING 6004 139#define IDS_COPYING 6004
137#define IDS_MOVING 6005 140// #define IDS_MOVING 6005
138#define IDS_RENAMING 6006 141#define IDS_RENAMING 6006
139 142
140#define IDS_OPERATION_IS_NOT_SUPPORTED 6008 143#define IDS_OPERATION_IS_NOT_SUPPORTED 6008
diff --git a/CPP/7zip/UI/FileManager/resource.rc b/CPP/7zip/UI/FileManager/resource.rc
index feeeaf5..d9fc6f2 100644
--- a/CPP/7zip/UI/FileManager/resource.rc
+++ b/CPP/7zip/UI/FileManager/resource.rc
@@ -58,8 +58,12 @@ BEGIN
58 MENUITEM "CRC-32", IDM_CRC32 58 MENUITEM "CRC-32", IDM_CRC32
59 MENUITEM "CRC-64", IDM_CRC64 59 MENUITEM "CRC-64", IDM_CRC64
60 MENUITEM "XXH64", IDM_XXH64 60 MENUITEM "XXH64", IDM_XXH64
61 MENUITEM "MD5", IDM_MD5
61 MENUITEM "SHA-1", IDM_SHA1 62 MENUITEM "SHA-1", IDM_SHA1
62 MENUITEM "SHA-256", IDM_SHA256 63 MENUITEM "SHA-256", IDM_SHA256
64 MENUITEM "SHA-384", IDM_SHA384
65 MENUITEM "SHA-512", IDM_SHA512
66 MENUITEM "SHA3-256", IDM_SHA3_256
63 MENUITEM "BLAKE2sp", IDM_BLAKE2SP 67 MENUITEM "BLAKE2sp", IDM_BLAKE2SP
64 MENUITEM "*", IDM_HASH_ALL 68 MENUITEM "*", IDM_HASH_ALL
65 END 69 END
@@ -202,7 +206,7 @@ BEGIN
202 IDS_COPY_TO "Copy to:" 206 IDS_COPY_TO "Copy to:"
203 IDS_MOVE_TO "Move to:" 207 IDS_MOVE_TO "Move to:"
204 IDS_COPYING "Copying..." 208 IDS_COPYING "Copying..."
205 IDS_MOVING "Moving..." 209// IDS_MOVING "Moving..."
206 IDS_RENAMING "Renaming..." 210 IDS_RENAMING "Renaming..."
207 211
208 IDS_OPERATION_IS_NOT_SUPPORTED "Operation is not supported." 212 IDS_OPERATION_IS_NOT_SUPPORTED "Operation is not supported."
diff --git a/CPP/7zip/UI/FileManager/resourceGui.h b/CPP/7zip/UI/FileManager/resourceGui.h
index 848b36f..2e1bab3 100644
--- a/CPP/7zip/UI/FileManager/resourceGui.h
+++ b/CPP/7zip/UI/FileManager/resourceGui.h
@@ -6,6 +6,8 @@
6#define IDS_OPENNING 3303 6#define IDS_OPENNING 3303
7#define IDS_SCANNING 3304 7#define IDS_SCANNING 3304
8 8
9#define IDS_MOVING 6005
10
9#define IDS_CHECKSUM_CALCULATING 7500 11#define IDS_CHECKSUM_CALCULATING 7500
10#define IDS_CHECKSUM_INFORMATION 7501 12#define IDS_CHECKSUM_INFORMATION 7501
11#define IDS_CHECKSUM_CRC_DATA 7502 13#define IDS_CHECKSUM_CRC_DATA 7502
diff --git a/CPP/7zip/UI/FileManager/resourceGui.rc b/CPP/7zip/UI/FileManager/resourceGui.rc
index 143e9f6..ad0d1f4 100644
--- a/CPP/7zip/UI/FileManager/resourceGui.rc
+++ b/CPP/7zip/UI/FileManager/resourceGui.rc
@@ -6,6 +6,8 @@ BEGIN
6 6
7 IDS_PROGRESS_TESTING "Testing" 7 IDS_PROGRESS_TESTING "Testing"
8 8
9 IDS_MOVING "Moving..."
10
9 IDS_CHECKSUM_CALCULATING "Checksum calculating..." 11 IDS_CHECKSUM_CALCULATING "Checksum calculating..."
10 IDS_CHECKSUM_INFORMATION "Checksum information" 12 IDS_CHECKSUM_INFORMATION "Checksum information"
11 IDS_CHECKSUM_CRC_DATA "CRC checksum for data:" 13 IDS_CHECKSUM_CRC_DATA "CRC checksum for data:"
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
index 7f2edfa..1686c69 100644
--- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
@@ -61,9 +61,9 @@ struct CBenchPassResult
61{ 61{
62 CTotalBenchRes Enc; 62 CTotalBenchRes Enc;
63 CTotalBenchRes Dec; 63 CTotalBenchRes Dec;
64 #ifdef PRINT_ITER_TIME 64#ifdef PRINT_ITER_TIME
65 DWORD Ticks; 65 DWORD Ticks;
66 #endif 66#endif
67 // CBenchInfo EncInfo; // for debug 67 // CBenchInfo EncInfo; // for debug
68 // CBenchPassResult() {}; 68 // CBenchPassResult() {};
69}; 69};
@@ -97,21 +97,9 @@ struct CTotalBenchRes2: public CTotalBenchRes
97struct CSyncData 97struct CSyncData
98{ 98{
99 UInt32 NumPasses_Finished; 99 UInt32 NumPasses_Finished;
100 100#ifdef PRINT_ITER_TIME
101 // UInt64 NumEncProgress; // for debug
102 // UInt64 NumDecProgress; // for debug
103 // CBenchInfo EncInfo; // for debug
104
105 CTotalBenchRes2 Enc_BenchRes_1;
106 CTotalBenchRes2 Enc_BenchRes;
107
108 CTotalBenchRes2 Dec_BenchRes_1;
109 CTotalBenchRes2 Dec_BenchRes;
110
111 #ifdef PRINT_ITER_TIME
112 DWORD TotalTicks; 101 DWORD TotalTicks;
113 #endif 102#endif
114
115 int RatingVector_DeletedIndex; 103 int RatingVector_DeletedIndex;
116 // UInt64 RatingVector_NumDeleted; 104 // UInt64 RatingVector_NumDeleted;
117 105
@@ -124,6 +112,16 @@ struct CSyncData
124 bool NeedPrint_Dec; 112 bool NeedPrint_Dec;
125 bool NeedPrint_Tot; // intermediate Total was updated after current pass 113 bool NeedPrint_Tot; // intermediate Total was updated after current pass
126 114
115 // UInt64 NumEncProgress; // for debug
116 // UInt64 NumDecProgress; // for debug
117 // CBenchInfo EncInfo; // for debug
118
119 CTotalBenchRes2 Enc_BenchRes_1;
120 CTotalBenchRes2 Enc_BenchRes;
121
122 CTotalBenchRes2 Dec_BenchRes_1;
123 CTotalBenchRes2 Dec_BenchRes;
124
127 void Init(); 125 void Init();
128}; 126};
129 127
@@ -161,24 +159,18 @@ void CSyncData::Init()
161struct CBenchProgressSync 159struct CBenchProgressSync
162{ 160{
163 bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable 161 bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable
162 bool TextWasChanged;
163
164 UInt32 NumThreads; 164 UInt32 NumThreads;
165 UInt64 DictSize; 165 UInt64 DictSize;
166 UInt32 NumPasses_Limit; 166 UInt32 NumPasses_Limit;
167 int Level; 167 int Level;
168
169 // must be written by benchmark thread, read by GUI thread */
170 CSyncData sd;
171 CRecordVector<CBenchPassResult> RatingVector;
172
173 NWindows::NSynchronization::CCriticalSection CS;
174 168
175 AString Text; 169 AString Text;
176 bool TextWasChanged;
177 170
178 /* BenchFinish_Task_HRESULT - for result from benchmark code 171 /* BenchFinish_Task_HRESULT - for result from benchmark code
179 BenchFinish_Thread_HRESULT - for Exceptions and service errors 172 BenchFinish_Thread_HRESULT - for Exceptions and service errors
180 these arreos must be shown even if user escapes benchmark */ 173 these arreos must be shown even if user escapes benchmark */
181
182 HRESULT BenchFinish_Task_HRESULT; 174 HRESULT BenchFinish_Task_HRESULT;
183 HRESULT BenchFinish_Thread_HRESULT; 175 HRESULT BenchFinish_Thread_HRESULT;
184 176
@@ -186,6 +178,12 @@ struct CBenchProgressSync
186 UString FreqString_Sync; 178 UString FreqString_Sync;
187 UString FreqString_GUI; 179 UString FreqString_GUI;
188 180
181 // must be written by benchmark thread, read by GUI thread */
182 CRecordVector<CBenchPassResult> RatingVector;
183 CSyncData sd;
184
185 NWindows::NSynchronization::CCriticalSection CS;
186
189 CBenchProgressSync() 187 CBenchProgressSync()
190 { 188 {
191 NumPasses_Limit = 1; 189 NumPasses_Limit = 1;
@@ -258,6 +256,19 @@ struct CThreadBenchmark
258class CBenchmarkDialog: 256class CBenchmarkDialog:
259 public NWindows::NControl::CModalDialog 257 public NWindows::NControl::CModalDialog
260{ 258{
259 bool _finishTime_WasSet;
260
261 bool WasStopped_in_GUI;
262 bool ExitWasAsked_in_GUI;
263 bool NeedRestart;
264
265 bool RamSize_Defined;
266
267public:
268 bool TotalMode;
269
270private:
271
261 NWindows::NControl::CComboBox m_Dictionary; 272 NWindows::NControl::CComboBox m_Dictionary;
262 NWindows::NControl::CComboBox m_NumThreads; 273 NWindows::NControl::CComboBox m_NumThreads;
263 NWindows::NControl::CComboBox m_NumPasses; 274 NWindows::NControl::CComboBox m_NumPasses;
@@ -266,17 +277,11 @@ class CBenchmarkDialog:
266 277
267 UInt32 _startTime; 278 UInt32 _startTime;
268 UInt32 _finishTime; 279 UInt32 _finishTime;
269 bool _finishTime_WasSet;
270
271 bool WasStopped_in_GUI;
272 bool ExitWasAsked_in_GUI;
273 bool NeedRestart;
274 280
275 CMyFont _font; 281 CMyFont _font;
276 282
277 UInt64 RamSize; 283 size_t RamSize;
278 UInt64 RamSize_Limit; 284 size_t RamSize_Limit;
279 bool RamSize_Defined;
280 285
281 UInt32 NumPasses_Finished_Prev; 286 UInt32 NumPasses_Finished_Prev;
282 287
@@ -330,7 +335,6 @@ class CBenchmarkDialog:
330public: 335public:
331 CBenchProgressSync Sync; 336 CBenchProgressSync Sync;
332 337
333 bool TotalMode;
334 CObjectVector<CProperty> Props; 338 CObjectVector<CProperty> Props;
335 339
336 CSysString Bench2Text; 340 CSysString Bench2Text;
@@ -339,11 +343,11 @@ public:
339 CThreadBenchmark _threadBenchmark; 343 CThreadBenchmark _threadBenchmark;
340 344
341 CBenchmarkDialog(): 345 CBenchmarkDialog():
342 _timer(0),
343 WasStopped_in_GUI(false), 346 WasStopped_in_GUI(false),
344 ExitWasAsked_in_GUI(false), 347 ExitWasAsked_in_GUI(false),
345 NeedRestart(false), 348 NeedRestart(false),
346 TotalMode(false) 349 TotalMode(false),
350 _timer(0)
347 {} 351 {}
348 352
349 ~CBenchmarkDialog() Z7_DESTRUCTOR_override; 353 ~CBenchmarkDialog() Z7_DESTRUCTOR_override;
@@ -504,7 +508,8 @@ bool CBenchmarkDialog::OnInit()
504 SetItemTextA(IDT_BENCH_SYS2, s2); 508 SetItemTextA(IDT_BENCH_SYS2, s2);
505 } 509 }
506 { 510 {
507 GetCpuName_MultiLine(s); 511 AString registers;
512 GetCpuName_MultiLine(s, registers);
508 SetItemTextA(IDT_BENCH_CPU, s); 513 SetItemTextA(IDT_BENCH_CPU, s);
509 } 514 }
510 { 515 {
@@ -1851,7 +1856,7 @@ HRESULT Benchmark(
1851 const CProperty &prop = props[i]; 1856 const CProperty &prop = props[i];
1852 UString name = prop.Name; 1857 UString name = prop.Name;
1853 name.MakeLower_Ascii(); 1858 name.MakeLower_Ascii();
1854 if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*") 1859 if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value.IsEqualTo("*"))
1855 { 1860 {
1856 bd.TotalMode = true; 1861 bd.TotalMode = true;
1857 continue; 1862 continue;
@@ -1860,7 +1865,7 @@ HRESULT Benchmark(
1860 NCOM::CPropVariant propVariant; 1865 NCOM::CPropVariant propVariant;
1861 if (!prop.Value.IsEmpty()) 1866 if (!prop.Value.IsEmpty())
1862 ParseNumberString(prop.Value, propVariant); 1867 ParseNumberString(prop.Value, propVariant);
1863 if (name.IsPrefixedBy(L"mt")) 1868 if (name.IsPrefixedBy("mt"))
1864 { 1869 {
1865 #ifndef Z7_ST 1870 #ifndef Z7_ST
1866 RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)) 1871 RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads))
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.rc b/CPP/7zip/UI/GUI/BenchmarkDialog.rc
index 3e73e46..5df7ff2 100644
--- a/CPP/7zip/UI/GUI/BenchmarkDialog.rc
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.rc
@@ -81,7 +81,7 @@ BEGIN
81 81
82 LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8 82 LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8
83 COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO 83 COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO
84 LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, MY_TEXT_NOPREFIX 84 LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, 24, SS_NOPREFIX
85 85
86 RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX 86 RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX
87 RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX 87 RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp
index fd53062..85d7186 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.cpp
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -211,11 +211,13 @@ static const EMethodID g_ZstdMethods[] =
211}; 211};
212*/ 212*/
213 213
214/*
214static const EMethodID g_SwfcMethods[] = 215static const EMethodID g_SwfcMethods[] =
215{ 216{
216 kDeflate 217 kDeflate
217 // kLZMA 218 // kLZMA
218}; 219};
220*/
219 221
220static const EMethodID g_TarMethods[] = 222static const EMethodID g_TarMethods[] =
221{ 223{
@@ -278,7 +280,8 @@ static const CFormatInfo g_Formats[] =
278 }, 280 },
279 { 281 {
280 "7z", 282 "7z",
281 (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), 283 // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
284 (1 << 10) - 1,
282 METHODS_PAIR(g_7zMethods), 285 METHODS_PAIR(g_7zMethods),
283 kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt | 286 kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt |
284 kFF_EncryptFileNames | kFF_MemUse | kFF_SFX 287 kFF_EncryptFileNames | kFF_MemUse | kFF_SFX
@@ -306,7 +309,8 @@ static const CFormatInfo g_Formats[] =
306 }, 309 },
307 { 310 {
308 "xz", 311 "xz",
309 (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), 312 // (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
313 (1 << 10) - 1 - (1 << 0), // store (1 << 0) is not supported
310 METHODS_PAIR(g_XzMethods), 314 METHODS_PAIR(g_XzMethods),
311 kFF_Solid | kFF_MultiThread | kFF_MemUse 315 kFF_Solid | kFF_MultiThread | kFF_MemUse
312 }, 316 },
@@ -321,12 +325,14 @@ static const CFormatInfo g_Formats[] =
321 | kFF_MemUse 325 | kFF_MemUse
322 }, 326 },
323 */ 327 */
328/*
324 { 329 {
325 "Swfc", 330 "Swfc",
326 (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), 331 (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
327 METHODS_PAIR(g_SwfcMethods), 332 METHODS_PAIR(g_SwfcMethods),
328 0 333 0
329 }, 334 },
335*/
330 { 336 {
331 "Tar", 337 "Tar",
332 (1 << 0), 338 (1 << 0),
@@ -429,22 +435,23 @@ bool CCompressDialog::OnInit()
429 #endif 435 #endif
430 436
431 { 437 {
432 UInt64 size = (UInt64)(sizeof(size_t)) << 29; 438 size_t size = (size_t)sizeof(size_t) << 29;
433 _ramSize_Defined = NSystem::GetRamSize(size); 439 _ramSize_Defined = NSystem::GetRamSize(size);
434 // size = (UInt64)3 << 62; // for debug only; 440 // size = (UInt64)3 << 62; // for debug only;
435 _ramSize = size;
436 const UInt64 kMinUseSize = (1 << 26);
437 if (size < kMinUseSize)
438 size = kMinUseSize;
439
440 unsigned bits = sizeof(size_t) * 8;
441 if (bits == 32)
442 { 441 {
443 const UInt32 limit2 = (UInt32)7 << 28; 442 // we use reduced limit for 32-bit version:
444 if (size > limit2) 443 unsigned bits = sizeof(size_t) * 8;
445 size = limit2; 444 if (bits == 32)
445 {
446 const UInt32 limit2 = (UInt32)7 << 28;
447 if (size > limit2)
448 size = limit2;
449 }
446 } 450 }
447 451 _ramSize = size;
452 const size_t kMinUseSize = 1 << 26;
453 if (size < kMinUseSize)
454 size = kMinUseSize;
448 _ramSize_Reduced = size; 455 _ramSize_Reduced = size;
449 456
450 // 80% - is auto usage limit in handlers 457 // 80% - is auto usage limit in handlers
@@ -1580,24 +1587,26 @@ void CCompressDialog::SetLevel2()
1580 1587
1581 for (unsigned i = 0; i < sizeof(UInt32) * 8; i++) 1588 for (unsigned i = 0; i < sizeof(UInt32) * 8; i++)
1582 { 1589 {
1583 const UInt32 mask = (UInt32)1 << i; 1590 const UInt32 mask = fi.LevelsMask >> i;
1584 if ((fi.LevelsMask & mask) != 0) 1591 // if (mask == 0) break;
1592 if (mask & 1)
1585 { 1593 {
1586 const UInt32 langID = g_Levels[i];
1587 UString s; 1594 UString s;
1588 s.Add_UInt32(i); 1595 s.Add_UInt32(i);
1589 // if (fi.LevelsMask < (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1) 1596 if (i < Z7_ARRAY_SIZE(g_Levels))
1590 if (langID)
1591 if (i != 0 || !isZstd)
1592 { 1597 {
1593 s += " - "; 1598 const UInt32 langID = g_Levels[i];
1594 s += LangString(langID); 1599 // if (fi.LevelsMask < (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1)
1600 if (langID)
1601 if (i != 0 || !isZstd)
1602 {
1603 s += " - ";
1604 AddLangString(s, langID);
1605 }
1595 } 1606 }
1596 const int index = (int)m_Level.AddString(s); 1607 const int index = (int)m_Level.AddString(s);
1597 m_Level.SetItemData(index, (LPARAM)i); 1608 m_Level.SetItemData(index, (LPARAM)i);
1598 } 1609 }
1599 if (fi.LevelsMask <= mask)
1600 break;
1601 } 1610 }
1602 SetNearestSelectComboBox(m_Level, level); 1611 SetNearestSelectComboBox(m_Level, level);
1603} 1612}
@@ -1931,11 +1940,11 @@ void CCompressDialog::SetDictionary2()
1931 case kLZMA2: 1940 case kLZMA2:
1932 { 1941 {
1933 { 1942 {
1934 _auto_Dict = 1943 _auto_Dict = level <= 4 ?
1935 ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : 1944 (UInt32)1 << (level * 2 + 16) :
1936 ( level <= 6 ? ((UInt32)1 << (level + 19)) : 1945 level <= sizeof(size_t) / 2 + 4 ?
1937 ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) 1946 (UInt32)1 << (level + 20) :
1938 ))); 1947 (UInt32)1 << (sizeof(size_t) / 2 + 24);
1939 } 1948 }
1940 1949
1941 // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize. 1950 // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize.
@@ -2591,11 +2600,17 @@ void CCompressDialog::SetNumThreads2()
2591 UInt32 numAlgoThreadsMax = numHardwareThreads * 2; 2600 UInt32 numAlgoThreadsMax = numHardwareThreads * 2;
2592 const int methodID = GetMethodID(); 2601 const int methodID = GetMethodID();
2593 2602
2594 switch (methodID) 2603 const bool isZip = IsZipFormat();
2604 if (isZip)
2605 numAlgoThreadsMax =
2606 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit
2607 else if (IsXzFormat())
2608 numAlgoThreadsMax = 256 * 2;
2609 else switch (methodID)
2595 { 2610 {
2596 case kLZMA: numAlgoThreadsMax = 2; break; 2611 case kLZMA: numAlgoThreadsMax = 2; break;
2597 case kLZMA2: numAlgoThreadsMax = 256; break; 2612 case kLZMA2: numAlgoThreadsMax = 256; break;
2598 case kBZip2: numAlgoThreadsMax = 32; break; 2613 case kBZip2: numAlgoThreadsMax = 64; break;
2599 // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; 2614 // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break;
2600 case kCopy: 2615 case kCopy:
2601 case kPPMd: 2616 case kPPMd:
@@ -2604,17 +2619,6 @@ void CCompressDialog::SetNumThreads2()
2604 case kPPMdZip: 2619 case kPPMdZip:
2605 numAlgoThreadsMax = 1; 2620 numAlgoThreadsMax = 1;
2606 } 2621 }
2607 const bool isZip = IsZipFormat();
2608 if (isZip)
2609 {
2610 numAlgoThreadsMax =
2611 #ifdef _WIN32
2612 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
2613 #else
2614 128;
2615 #endif
2616 }
2617
2618 UInt32 autoThreads = numHardwareThreads; 2622 UInt32 autoThreads = numHardwareThreads;
2619 if (autoThreads > numAlgoThreadsMax) 2623 if (autoThreads > numAlgoThreadsMax)
2620 autoThreads = numAlgoThreadsMax; 2624 autoThreads = numAlgoThreadsMax;
@@ -2999,7 +3003,7 @@ UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads,
2999 else 3003 else
3000 { 3004 {
3001 size += numBlockThreads * (size1 + chunkSize); 3005 size += numBlockThreads * (size1 + chunkSize);
3002 UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; 3006 const UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
3003 if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; 3007 if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++;
3004 if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; 3008 if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++;
3005 if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; 3009 if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++;
diff --git a/CPP/7zip/UI/GUI/CompressDialog.h b/CPP/7zip/UI/GUI/CompressDialog.h
index c2d2699..e0f3aa5 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.h
+++ b/CPP/7zip/UI/GUI/CompressDialog.h
@@ -141,6 +141,15 @@ struct CBool1
141 141
142class CCompressDialog: public NWindows::NControl::CModalDialog 142class CCompressDialog: public NWindows::NControl::CModalDialog
143{ 143{
144public:
145 CBool1 SymLinks;
146 CBool1 HardLinks;
147 CBool1 AltStreams;
148 CBool1 NtSecurity;
149 CBool1 PreserveATime;
150private:
151 bool _ramSize_Defined;
152
144 NWindows::NControl::CComboBox m_ArchivePath; 153 NWindows::NControl::CComboBox m_ArchivePath;
145 NWindows::NControl::CComboBox m_Format; 154 NWindows::NControl::CComboBox m_Format;
146 NWindows::NControl::CComboBox m_Level; 155 NWindows::NControl::CComboBox m_Level;
@@ -179,20 +188,13 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
179 UString DirPrefix; 188 UString DirPrefix;
180 UString StartDirPrefix; 189 UString StartDirPrefix;
181 190
182 bool _ramSize_Defined; 191 size_t _ramSize; // full RAM size avail
183 UInt64 _ramSize; // full RAM size avail 192 size_t _ramSize_Reduced; // full for 64-bit and reduced for 32-bit
184 UInt64 _ramSize_Reduced; // full for 64-bit and reduced for 32-bit
185 UInt64 _ramUsage_Auto; 193 UInt64 _ramUsage_Auto;
186 194
187public: 195public:
188 NCompression::CInfo m_RegistryInfo; 196 NCompression::CInfo m_RegistryInfo;
189 197
190 CBool1 SymLinks;
191 CBool1 HardLinks;
192 CBool1 AltStreams;
193 CBool1 NtSecurity;
194 CBool1 PreserveATime;
195
196 void SetArchiveName(const UString &name); 198 void SetArchiveName(const UString &name);
197 int FindRegistryFormat(const UString &name); 199 int FindRegistryFormat(const UString &name);
198 unsigned FindRegistryFormat_Always(const UString &name); 200 unsigned FindRegistryFormat_Always(const UString &name);
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
index 26057a7..424c6e4 100644
--- a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
@@ -252,6 +252,21 @@ HRESULT CUpdateCallbackGUI::DeletingAfterArchiving(const FString &path, bool isD
252 return ProgressDialog->Sync.Set_Status2(_lang_Removing, fs2us(path), isDir); 252 return ProgressDialog->Sync.Set_Status2(_lang_Removing, fs2us(path), isDir);
253} 253}
254 254
255
256HRESULT CUpdateCallbackGUI::MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 totalSize, Int32 updateMode)
257{
258 return MoveArc_Start_Base(srcTempPath, destFinalPath, totalSize, updateMode);
259}
260HRESULT CUpdateCallbackGUI::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)
261{
262 return MoveArc_Progress_Base(totalSize, currentSize);
263}
264HRESULT CUpdateCallbackGUI::MoveArc_Finish()
265{
266 return MoveArc_Finish_Base();
267}
268
269
255HRESULT CUpdateCallbackGUI::StartOpenArchive(const wchar_t * /* name */) 270HRESULT CUpdateCallbackGUI::StartOpenArchive(const wchar_t * /* name */)
256{ 271{
257 return S_OK; 272 return S_OK;
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
index 966f57e..53fed91 100644
--- a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
@@ -8,6 +8,7 @@
8#include "resource2.h" 8#include "resource2.h"
9#include "resource3.h" 9#include "resource3.h"
10#include "ExtractRes.h" 10#include "ExtractRes.h"
11#include "../FileManager/resourceGui.h"
11 12
12#include "UpdateCallbackGUI.h" 13#include "UpdateCallbackGUI.h"
13 14
@@ -29,7 +30,8 @@ void CUpdateCallbackGUI2::Init()
29{ 30{
30 NumFiles = 0; 31 NumFiles = 0;
31 32
32 _lang_Removing = LangString(IDS_PROGRESS_REMOVE); 33 LangString(IDS_PROGRESS_REMOVE, _lang_Removing);
34 LangString(IDS_MOVING, _lang_Moving);
33 _lang_Ops.Clear(); 35 _lang_Ops.Clear();
34 for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_UpdNotifyLangs); i++) 36 for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_UpdNotifyLangs); i++)
35 _lang_Ops.Add(LangString(k_UpdNotifyLangs[i])); 37 _lang_Ops.Add(LangString(k_UpdNotifyLangs[i]));
@@ -57,3 +59,72 @@ HRESULT CUpdateCallbackGUI2::ShowAskPasswordDialog()
57 PasswordIsDefined = true; 59 PasswordIsDefined = true;
58 return S_OK; 60 return S_OK;
59} 61}
62
63
64HRESULT CUpdateCallbackGUI2::MoveArc_UpdateStatus()
65{
66 UString s;
67 s.Add_UInt64(_arcMoving_percents);
68 s.Add_Char('%');
69
70 const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1);
71 if (totalDefined || _arcMoving_current != 0)
72 {
73 s += " : ";
74 s.Add_UInt64(_arcMoving_current >> 20);
75 s += " MiB";
76 }
77 if (totalDefined)
78 {
79 s += " / ";
80 s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20);
81 s += " MiB";
82 }
83
84 s += " : ";
85 s += _lang_Moving;
86 s += " : ";
87 // s.Add_Char('\"');
88 s += _arcMoving_name1;
89 // s.Add_Char('\"');
90 return ProgressDialog->Sync.Set_Status2(s, _arcMoving_name2,
91 false); // isDir
92}
93
94
95HRESULT CUpdateCallbackGUI2::MoveArc_Start_Base(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 totalSize, Int32 updateMode)
96{
97 _arcMoving_percents = 0;
98 _arcMoving_total = totalSize;
99 _arcMoving_current = 0;
100 _arcMoving_updateMode = updateMode;
101 _arcMoving_name1 = srcTempPath;
102 _arcMoving_name2 = destFinalPath;
103 return MoveArc_UpdateStatus();
104}
105
106
107HRESULT CUpdateCallbackGUI2::MoveArc_Progress_Base(UInt64 totalSize, UInt64 currentSize)
108{
109 _arcMoving_total = totalSize;
110 _arcMoving_current = currentSize;
111 UInt64 percents = 0;
112 if (totalSize != 0)
113 {
114 if (totalSize < ((UInt64)1 << 57))
115 percents = currentSize * 100 / totalSize;
116 else
117 percents = currentSize / (totalSize / 100);
118 }
119 if (percents == _arcMoving_percents)
120 return ProgressDialog->Sync.CheckStop();
121 // Sleep(300); // for debug
122 _arcMoving_percents = percents;
123 return MoveArc_UpdateStatus();
124}
125
126
127HRESULT CUpdateCallbackGUI2::MoveArc_Finish_Base()
128{
129 return ProgressDialog->Sync.Set_Status2(L"", L"", false);
130}
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
index e32b602..56747ff 100644
--- a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
@@ -7,17 +7,38 @@
7 7
8class CUpdateCallbackGUI2 8class CUpdateCallbackGUI2
9{ 9{
10 UStringVector _lang_Ops;
11 UString _emptyString;
12public: 10public:
13 UString Password; 11 CProgressDialog *ProgressDialog;
12protected:
13 UString _arcMoving_name1;
14 UString _arcMoving_name2;
15 UInt64 _arcMoving_percents;
16 UInt64 _arcMoving_total;
17 UInt64 _arcMoving_current;
18 Int32 _arcMoving_updateMode;
19public:
14 bool PasswordIsDefined; 20 bool PasswordIsDefined;
15 bool PasswordWasAsked; 21 bool PasswordWasAsked;
16 UInt64 NumFiles; 22 UInt64 NumFiles;
17 23 UString Password;
24protected:
25 UStringVector _lang_Ops;
18 UString _lang_Removing; 26 UString _lang_Removing;
27 UString _lang_Moving;
28 UString _emptyString;
29
30 HRESULT MoveArc_UpdateStatus();
31 HRESULT MoveArc_Start_Base(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 /* totalSize */, Int32 updateMode);
32 HRESULT MoveArc_Progress_Base(UInt64 totalSize, UInt64 currentSize);
33 HRESULT MoveArc_Finish_Base();
34
35public:
19 36
20 CUpdateCallbackGUI2(): 37 CUpdateCallbackGUI2():
38 _arcMoving_percents(0),
39 _arcMoving_total(0),
40 _arcMoving_current(0),
41 _arcMoving_updateMode(0),
21 PasswordIsDefined(false), 42 PasswordIsDefined(false),
22 PasswordWasAsked(false), 43 PasswordWasAsked(false),
23 NumFiles(0) 44 NumFiles(0)
@@ -25,8 +46,6 @@ public:
25 46
26 void Init(); 47 void Init();
27 48
28 CProgressDialog *ProgressDialog;
29
30 HRESULT SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir); 49 HRESULT SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir);
31 HRESULT ShowAskPasswordDialog(); 50 HRESULT ShowAskPasswordDialog();
32}; 51};
diff --git a/CPP/7zip/UI/GUI/makefile b/CPP/7zip/UI/GUI/makefile
index 22ae095..b879a5d 100644
--- a/CPP/7zip/UI/GUI/makefile
+++ b/CPP/7zip/UI/GUI/makefile
@@ -141,10 +141,9 @@ C_OBJS = \
141 $O\Alloc.obj \ 141 $O\Alloc.obj \
142 $O\CpuArch.obj \ 142 $O\CpuArch.obj \
143 $O\DllSecur.obj \ 143 $O\DllSecur.obj \
144 $O\Sort.obj \
145 $O\Threads.obj \ 144 $O\Threads.obj \
146 145
147!include "../../Crc.mak" 146!include "../../Crc.mak"
148 147!include "../../Sort.mak"
149 148
150!include "../../7zip.mak" 149!include "../../7zip.mak"
diff --git a/CPP/7zip/warn_gcc.mak b/CPP/7zip/warn_gcc.mak
index b6ed9c3..6152ab1 100644
--- a/CPP/7zip/warn_gcc.mak
+++ b/CPP/7zip/warn_gcc.mak
@@ -11,16 +11,16 @@ CFLAGS_WARN_GCC_4_8 = \
11 -Wunused \ 11 -Wunused \
12 -Wunused-macros \ 12 -Wunused-macros \
13 13
14CFLAGS_WARN_GCC_6 = $(CFLAGS_WARN_GCC_4_8)\ 14CFLAGS_WARN_GCC_5 = $(CFLAGS_WARN_GCC_4_8)\
15 -Wbool-compare \ 15 -Wbool-compare \
16
17CFLAGS_WARN_GCC_6 = $(CFLAGS_WARN_GCC_5)\
16 -Wduplicated-cond \ 18 -Wduplicated-cond \
17 19
18# -Wno-strict-aliasing 20# -Wno-strict-aliasing
19 21
20CFLAGS_WARN_GCC_9 = $(CFLAGS_WARN_GCC_6)\ 22CFLAGS_WARN_GCC_7 = $(CFLAGS_WARN_GCC_6)\
21 -Waddress-of-packed-member \
22 -Wbool-operation \ 23 -Wbool-operation \
23 -Wcast-align=strict \
24 -Wconversion \ 24 -Wconversion \
25 -Wdangling-else \ 25 -Wdangling-else \
26 -Wduplicated-branches \ 26 -Wduplicated-branches \
@@ -28,8 +28,14 @@ CFLAGS_WARN_GCC_9 = $(CFLAGS_WARN_GCC_6)\
28 -Wint-in-bool-context \ 28 -Wint-in-bool-context \
29 -Wmaybe-uninitialized \ 29 -Wmaybe-uninitialized \
30 -Wmisleading-indentation \ 30 -Wmisleading-indentation \
31
32CFLAGS_WARN_GCC_8 = $(CFLAGS_WARN_GCC_7)\
33 -Wcast-align=strict \
31 -Wmissing-attributes 34 -Wmissing-attributes
32 35
36CFLAGS_WARN_GCC_9 = $(CFLAGS_WARN_GCC_8)\
37 -Waddress-of-packed-member \
38
33# In C: -Wsign-conversion enabled also by -Wconversion 39# In C: -Wsign-conversion enabled also by -Wconversion
34# -Wno-sign-conversion \ 40# -Wno-sign-conversion \
35 41
@@ -39,7 +45,10 @@ CFLAGS_WARN_GCC_PPMD_UNALIGNED = \
39 45
40 46
41CFLAGS_WARN = $(CFLAGS_WARN_GCC_4_8) 47CFLAGS_WARN = $(CFLAGS_WARN_GCC_4_8)
48CFLAGS_WARN = $(CFLAGS_WARN_GCC_5)
42CFLAGS_WARN = $(CFLAGS_WARN_GCC_6) 49CFLAGS_WARN = $(CFLAGS_WARN_GCC_6)
50CFLAGS_WARN = $(CFLAGS_WARN_GCC_7)
51CFLAGS_WARN = $(CFLAGS_WARN_GCC_8)
43CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) 52CFLAGS_WARN = $(CFLAGS_WARN_GCC_9)
44 53
45# CXX_STD_FLAGS = -std=c++11 54# CXX_STD_FLAGS = -std=c++11
diff --git a/CPP/Build.mak b/CPP/Build.mak
index afb7ae8..86cc2af 100644
--- a/CPP/Build.mak
+++ b/CPP/Build.mak
@@ -111,7 +111,13 @@ CFLAGS = $(CFLAGS) -Zc:forScope
111 111
112!IFNDEF UNDER_CE 112!IFNDEF UNDER_CE
113!IF "$(CC)" != "clang-cl" 113!IF "$(CC)" != "clang-cl"
114CFLAGS = $(CFLAGS) -MP4 114MP_NPROC = 16
115!IFDEF NUMBER_OF_PROCESSORS
116!IF $(NUMBER_OF_PROCESSORS) < $(MP_NPROC)
117MP_NPROC = $(NUMBER_OF_PROCESSORS)
118!ENDIF
119!ENDIF
120CFLAGS = $(CFLAGS) -MP$(MP_NPROC)
115!ENDIF 121!ENDIF
116!IFNDEF PLATFORM 122!IFNDEF PLATFORM
117# CFLAGS = $(CFLAGS) -arch:IA32 123# CFLAGS = $(CFLAGS) -arch:IA32
diff --git a/CPP/Common/Md5Reg.cpp b/CPP/Common/Md5Reg.cpp
new file mode 100644
index 0000000..026fd41
--- /dev/null
+++ b/CPP/Common/Md5Reg.cpp
@@ -0,0 +1,44 @@
1// Md5Reg.cpp
2
3#include "StdAfx.h"
4
5#include "../../C/Md5.h"
6
7#include "../Common/MyBuffer2.h"
8#include "../Common/MyCom.h"
9
10#include "../7zip/Common/RegisterCodec.h"
11
12Z7_CLASS_IMP_COM_1(
13 CMd5Hasher
14 , IHasher
15)
16 CAlignedBuffer1 _buf;
17public:
18 Byte _mtDummy[1 << 7];
19
20 CMd5 *Md5() { return (CMd5 *)(void *)(Byte *)_buf; }
21public:
22 CMd5Hasher():
23 _buf(sizeof(CMd5))
24 {
25 Md5_Init(Md5());
26 }
27};
28
29Z7_COM7F_IMF2(void, CMd5Hasher::Init())
30{
31 Md5_Init(Md5());
32}
33
34Z7_COM7F_IMF2(void, CMd5Hasher::Update(const void *data, UInt32 size))
35{
36 Md5_Update(Md5(), (const Byte *)data, size);
37}
38
39Z7_COM7F_IMF2(void, CMd5Hasher::Final(Byte *digest))
40{
41 Md5_Final(Md5(), digest);
42}
43
44REGISTER_HASHER(CMd5Hasher, 0x208, "MD5", MD5_DIGEST_SIZE)
diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h
index a3cc3c8..7dc21ba 100644
--- a/CPP/Common/MyCom.h
+++ b/CPP/Common/MyCom.h
@@ -468,6 +468,19 @@ EXTERN_C_END
468 Z7_COM_QI_ENTRY(i7) \ 468 Z7_COM_QI_ENTRY(i7) \
469 ) 469 )
470 470
471#define Z7_COM_UNKNOWN_IMP_8(i1, i2, i3, i4, i5, i6, i7, i8) \
472 Z7_COM_UNKNOWN_IMP_SPEC( \
473 Z7_COM_QI_ENTRY_UNKNOWN(i1) \
474 Z7_COM_QI_ENTRY(i1) \
475 Z7_COM_QI_ENTRY(i2) \
476 Z7_COM_QI_ENTRY(i3) \
477 Z7_COM_QI_ENTRY(i4) \
478 Z7_COM_QI_ENTRY(i5) \
479 Z7_COM_QI_ENTRY(i6) \
480 Z7_COM_QI_ENTRY(i7) \
481 Z7_COM_QI_ENTRY(i8) \
482 )
483
471 484
472#define Z7_IFACES_IMP_UNK_1(i1) \ 485#define Z7_IFACES_IMP_UNK_1(i1) \
473 Z7_COM_UNKNOWN_IMP_1(i1) \ 486 Z7_COM_UNKNOWN_IMP_1(i1) \
@@ -508,6 +521,16 @@ EXTERN_C_END
508 Z7_IFACE_COM7_IMP(i5) \ 521 Z7_IFACE_COM7_IMP(i5) \
509 Z7_IFACE_COM7_IMP(i6) \ 522 Z7_IFACE_COM7_IMP(i6) \
510 523
524#define Z7_IFACES_IMP_UNK_7(i1, i2, i3, i4, i5, i6, i7) \
525 Z7_COM_UNKNOWN_IMP_7(i1, i2, i3, i4, i5, i6, i7) \
526 Z7_IFACE_COM7_IMP(i1) \
527 Z7_IFACE_COM7_IMP(i2) \
528 Z7_IFACE_COM7_IMP(i3) \
529 Z7_IFACE_COM7_IMP(i4) \
530 Z7_IFACE_COM7_IMP(i5) \
531 Z7_IFACE_COM7_IMP(i6) \
532 Z7_IFACE_COM7_IMP(i7) \
533
511 534
512#define Z7_CLASS_IMP_COM_0(c) \ 535#define Z7_CLASS_IMP_COM_0(c) \
513 Z7_class_final(c) : \ 536 Z7_class_final(c) : \
@@ -574,6 +597,20 @@ EXTERN_C_END
574 private: 597 private:
575 598
576 599
600#define Z7_CLASS_IMP_COM_7(c, i1, i2, i3, i4, i5, i6, i7) \
601 Z7_class_final(c) : \
602 public i1, \
603 public i2, \
604 public i3, \
605 public i4, \
606 public i5, \
607 public i6, \
608 public i7, \
609 public CMyUnknownImp { \
610 Z7_IFACES_IMP_UNK_7(i1, i2, i3, i4, i5, i6, i7) \
611 private:
612
613
577/* 614/*
578#define Z7_CLASS_IMP_NOQIB_0(c) \ 615#define Z7_CLASS_IMP_NOQIB_0(c) \
579 Z7_class_final(c) : \ 616 Z7_class_final(c) : \
diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp
index b5f7e52..10e2331 100644
--- a/CPP/Common/MyString.cpp
+++ b/CPP/Common/MyString.cpp
@@ -208,35 +208,6 @@ bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
208 208
209// ---------- ASCII ---------- 209// ---------- ASCII ----------
210 210
211bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
212{
213 const char *s1 = _chars;
214 for (;;)
215 {
216 const char c2 = *s++;
217 if (c2 == 0)
218 return true;
219 const char c1 = *s1++;
220 if (MyCharLower_Ascii(c1) !=
221 MyCharLower_Ascii(c2))
222 return false;
223 }
224}
225
226bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
227{
228 const wchar_t *s1 = _chars;
229 for (;;)
230 {
231 const char c2 = *s++;
232 if (c2 == 0)
233 return true;
234 const wchar_t c1 = *s1++;
235 if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
236 return false;
237 }
238}
239
240bool StringsAreEqual_Ascii(const char *u, const char *a) throw() 211bool StringsAreEqual_Ascii(const char *u, const char *a) throw()
241{ 212{
242 for (;;) 213 for (;;)
diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h
index ba9914e..639b874 100644
--- a/CPP/Common/MyString.h
+++ b/CPP/Common/MyString.h
@@ -429,11 +429,11 @@ public:
429 // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } 429 // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); }
430 // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } 430 // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
431 bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } 431 bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); }
432 bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); 432 bool IsPrefixedBy_Ascii_NoCase(const char *s) const { return IsString1PrefixedByString2_NoCase_Ascii(_chars, s); }
433 433
434 bool IsAscii() const 434 bool IsAscii() const
435 { 435 {
436 unsigned len = Len(); 436 const unsigned len = Len();
437 const char *s = _chars; 437 const char *s = _chars;
438 for (unsigned i = 0; i < len; i++) 438 for (unsigned i = 0; i < len; i++)
439 if ((unsigned char)s[i] >= 0x80) 439 if ((unsigned char)s[i] >= 0x80)
@@ -727,22 +727,23 @@ public:
727 // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } 727 // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); }
728 // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } 728 // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
729 bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } 729 bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); }
730 bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); }
730 bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } 731 bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); }
731 bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); 732 bool IsPrefixedBy_Ascii_NoCase(const char *s) const { return IsString1PrefixedByString2_NoCase_Ascii(_chars, s); }
732 733
733 bool IsAscii() const 734 bool IsAscii() const
734 { 735 {
735 unsigned len = Len(); 736 const unsigned len = Len();
736 const wchar_t *s = _chars; 737 const wchar_t *s = _chars;
737 for (unsigned i = 0; i < len; i++) 738 for (unsigned i = 0; i < len; i++)
738 if (s[i] >= 0x80) 739 if ((unsigned)(int)s[i] >= 0x80)
739 return false; 740 return false;
740 return true; 741 return true;
741 } 742 }
742 int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } 743 int Find(wchar_t c) const { return FindCharPosInString(_chars, c); }
743 int Find(wchar_t c, unsigned startIndex) const 744 int Find(wchar_t c, unsigned startIndex) const
744 { 745 {
745 int pos = FindCharPosInString(_chars + startIndex, c); 746 const int pos = FindCharPosInString(_chars + startIndex, c);
746 return pos < 0 ? -1 : (int)startIndex + pos; 747 return pos < 0 ? -1 : (int)startIndex + pos;
747 } 748 }
748 749
diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp
index cc891fc..8364aae 100644
--- a/CPP/Common/MyXml.cpp
+++ b/CPP/Common/MyXml.cpp
@@ -24,7 +24,7 @@ static bool IsSpaceChar(char c)
24int CXmlItem::FindProp(const char *propName) const throw() 24int CXmlItem::FindProp(const char *propName) const throw()
25{ 25{
26 FOR_VECTOR (i, Props) 26 FOR_VECTOR (i, Props)
27 if (Props[i].Name == propName) 27 if (Props[i].Name.IsEqualTo(propName))
28 return (int)i; 28 return (int)i;
29 return -1; 29 return -1;
30} 30}
@@ -39,7 +39,7 @@ AString CXmlItem::GetPropVal(const char *propName) const
39 39
40bool CXmlItem::IsTagged(const char *tag) const throw() 40bool CXmlItem::IsTagged(const char *tag) const throw()
41{ 41{
42 return (IsTag && Name == tag); 42 return (IsTag && Name.IsEqualTo(tag));
43} 43}
44 44
45int CXmlItem::FindSubTag(const char *tag) const throw() 45int CXmlItem::FindSubTag(const char *tag) const throw()
diff --git a/CPP/Common/Sha3Reg.cpp b/CPP/Common/Sha3Reg.cpp
new file mode 100644
index 0000000..cd2e288
--- /dev/null
+++ b/CPP/Common/Sha3Reg.cpp
@@ -0,0 +1,76 @@
1// Sha3Reg.cpp
2
3#include "StdAfx.h"
4
5#include "../../C/Sha3.h"
6
7#include "../Common/MyBuffer2.h"
8#include "../Common/MyCom.h"
9
10#include "../7zip/Common/RegisterCodec.h"
11
12Z7_CLASS_IMP_COM_1(
13 CSha3Hasher
14 , IHasher
15)
16 unsigned _digestSize;
17 bool _isShake;
18 CAlignedBuffer1 _buf;
19public:
20 Byte _mtDummy[1 << 7];
21
22 CSha3 *Sha() { return (CSha3 *)(void *)(Byte *)_buf; }
23public:
24 CSha3Hasher(unsigned digestSize, bool isShake, unsigned blockSize):
25 _digestSize(digestSize),
26 _isShake(isShake),
27 _buf(sizeof(CSha3))
28 {
29 CSha3 *p = Sha();
30 Sha3_SET_blockSize(p, blockSize)
31 Sha3_Init(Sha());
32 }
33};
34
35Z7_COM7F_IMF2(void, CSha3Hasher::Init())
36{
37 Sha3_Init(Sha());
38}
39
40Z7_COM7F_IMF2(void, CSha3Hasher::Update(const void *data, UInt32 size))
41{
42 Sha3_Update(Sha(), (const Byte *)data, size);
43}
44
45Z7_COM7F_IMF2(void, CSha3Hasher::Final(Byte *digest))
46{
47 Sha3_Final(Sha(), digest, _digestSize, _isShake);
48}
49
50Z7_COM7F_IMF2(UInt32, CSha3Hasher::GetDigestSize())
51{
52 return (UInt32)_digestSize;
53}
54
55
56#define REGISTER_SHA3_HASHER_2(cls, id, name, digestSize, isShake, digestSize_for_blockSize) \
57 namespace N ## cls { \
58 static IHasher *CreateHasherSpec() \
59 { return new CSha3Hasher(digestSize / 8, isShake, \
60 SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \
61 static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize / 8 }; \
62 struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
63 static REGISTER_HASHER_NAME(cls) g_RegisterHasher; }
64
65#define REGISTER_SHA3_HASHER( cls, id, name, size, isShake) \
66 REGISTER_SHA3_HASHER_2(cls, id, name, size, isShake, size)
67
68// REGISTER_SHA3_HASHER (Sha3_224_Hasher, 0x230, "SHA3-224", 224, false)
69REGISTER_SHA3_HASHER (Sha3_256_Hasher, 0x231, "SHA3-256", 256, false)
70// REGISTER_SHA3_HASHER (Sha3_386_Hasher, 0x232, "SHA3-384", 384, false)
71// REGISTER_SHA3_HASHER (Sha3_512_Hasher, 0x233, "SHA3-512", 512, false)
72// REGISTER_SHA3_HASHER (Shake128_Hasher, 0x240, "SHAKE128", 128, true)
73// REGISTER_SHA3_HASHER (Shake256_Hasher, 0x241, "SHAKE256", 256, true)
74// REGISTER_SHA3_HASHER_2 (Shake128_512_Hasher, 0x248, "SHAKE128-256", 256, true, 128) // -1344 (max)
75// REGISTER_SHA3_HASHER_2 (Shake256_512_Hasher, 0x249, "SHAKE256-512", 512, true, 256) // -1088 (max)
76// Shake supports different digestSize values for same blockSize
diff --git a/CPP/Common/Sha512Prepare.cpp b/CPP/Common/Sha512Prepare.cpp
new file mode 100644
index 0000000..e7beff5
--- /dev/null
+++ b/CPP/Common/Sha512Prepare.cpp
@@ -0,0 +1,7 @@
1// Sha512Prepare.cpp
2
3#include "StdAfx.h"
4
5#include "../../C/Sha512.h"
6
7static struct CSha512Prepare { CSha512Prepare() { Sha512Prepare(); } } g_Sha512Prepare;
diff --git a/CPP/Common/Sha512Reg.cpp b/CPP/Common/Sha512Reg.cpp
new file mode 100644
index 0000000..21df6ba
--- /dev/null
+++ b/CPP/Common/Sha512Reg.cpp
@@ -0,0 +1,83 @@
1// Sha512Reg.cpp
2
3#include "StdAfx.h"
4
5#include "../../C/Sha512.h"
6
7#include "../Common/MyBuffer2.h"
8#include "../Common/MyCom.h"
9
10#include "../7zip/Common/RegisterCodec.h"
11
12Z7_CLASS_IMP_COM_2(
13 CSha512Hasher
14 , IHasher
15 , ICompressSetCoderProperties
16)
17 unsigned _digestSize;
18 CAlignedBuffer1 _buf;
19public:
20 Byte _mtDummy[1 << 7];
21
22 CSha512 *Sha() { return (CSha512 *)(void *)(Byte *)_buf; }
23public:
24 CSha512Hasher(unsigned digestSize):
25 _digestSize(digestSize),
26 _buf(sizeof(CSha512))
27 {
28 Sha512_SetFunction(Sha(), 0);
29 Sha512_InitState(Sha(), _digestSize);
30 }
31};
32
33Z7_COM7F_IMF2(void, CSha512Hasher::Init())
34{
35 Sha512_InitState(Sha(), _digestSize);
36}
37
38Z7_COM7F_IMF2(void, CSha512Hasher::Update(const void *data, UInt32 size))
39{
40 Sha512_Update(Sha(), (const Byte *)data, size);
41}
42
43Z7_COM7F_IMF2(void, CSha512Hasher::Final(Byte *digest))
44{
45 Sha512_Final(Sha(), digest, _digestSize);
46}
47
48Z7_COM7F_IMF2(UInt32, CSha512Hasher::GetDigestSize())
49{
50 return (UInt32)_digestSize;
51}
52
53Z7_COM7F_IMF(CSha512Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
54{
55 unsigned algo = 0;
56 for (UInt32 i = 0; i < numProps; i++)
57 {
58 if (propIDs[i] == NCoderPropID::kDefaultProp)
59 {
60 const PROPVARIANT &prop = coderProps[i];
61 if (prop.vt != VT_UI4)
62 return E_INVALIDARG;
63 if (prop.ulVal > 2)
64 return E_NOTIMPL;
65 algo = (unsigned)prop.ulVal;
66 }
67 }
68 if (!Sha512_SetFunction(Sha(), algo))
69 return E_NOTIMPL;
70 return S_OK;
71}
72
73#define REGISTER_SHA512_HASHER(cls, id, name, size) \
74 namespace N ## cls { \
75 static IHasher *CreateHasherSpec() { return new CSha512Hasher(size); } \
76 static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \
77 struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
78 static REGISTER_HASHER_NAME(cls) g_RegisterHasher; }
79
80// REGISTER_SHA512_HASHER (Sha512_224_Hasher, 0x220, "SHA512-224", SHA512_224_DIGEST_SIZE)
81// REGISTER_SHA512_HASHER (Sha512_256_Hasher, 0x221, "SHA512-256", SHA512_256_DIGEST_SIZE)
82REGISTER_SHA512_HASHER (Sha384Hasher, 0x222, "SHA384", SHA512_384_DIGEST_SIZE)
83REGISTER_SHA512_HASHER (Sha512Hasher, 0x223, "SHA512", SHA512_DIGEST_SIZE)
diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp
index 798cbd9..b561a89 100644
--- a/CPP/Common/Wildcard.cpp
+++ b/CPP/Common/Wildcard.cpp
@@ -255,7 +255,8 @@ ForDir nonrec [0, M) same as ForBoth-File
255 255
256bool CItem::AreAllAllowed() const 256bool CItem::AreAllAllowed() const
257{ 257{
258 return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*"; 258 return ForFile && ForDir && WildcardMatching
259 && PathParts.Size() == 1 && PathParts.Front().IsEqualTo("*");
259} 260}
260 261
261bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const 262bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
@@ -542,7 +543,7 @@ unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts)
542 { 543 {
543 if (pathParts.Size() < 4 544 if (pathParts.Size() < 4
544 || !pathParts[1].IsEmpty() 545 || !pathParts[1].IsEmpty()
545 || pathParts[2] != L"?") 546 || !pathParts[2].IsEqualTo("?"))
546 return 0; 547 return 0;
547 testIndex = 3; 548 testIndex = 3;
548 } 549 }
@@ -574,11 +575,11 @@ static unsigned GetNumPrefixParts(const UStringVector &pathParts)
574 return 1; 575 return 1;
575 if (pathParts.Size() == 2) 576 if (pathParts.Size() == 2)
576 return 2; 577 return 2;
577 if (pathParts[2] == L".") 578 if (pathParts[2].IsEqualTo("."))
578 return 3; 579 return 3;
579 580
580 unsigned networkParts = 2; 581 unsigned networkParts = 2;
581 if (pathParts[2] == L"?") 582 if (pathParts[2].IsEqualTo("?"))
582 { 583 {
583 if (pathParts.Size() == 3) 584 if (pathParts.Size() == 3)
584 return 3; 585 return 3;
@@ -642,7 +643,7 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat
642 if (pathParts.Size() >= 3 643 if (pathParts.Size() >= 3
643 && pathParts[0].IsEmpty() 644 && pathParts[0].IsEmpty()
644 && pathParts[1].IsEmpty() 645 && pathParts[1].IsEmpty()
645 && pathParts[2] == L"?") 646 && pathParts[2].IsEqualTo("?"))
646 ignoreWildcardIndex = 2; 647 ignoreWildcardIndex = 2;
647 // #endif 648 // #endif
648 649
@@ -665,7 +666,7 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat
665 for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) 666 for (unsigned i = numPrefixParts; i < pathParts.Size(); i++)
666 { 667 {
667 const UString &part = pathParts[i]; 668 const UString &part = pathParts[i];
668 if (part == L".." || part == L".") 669 if (part.IsEqualTo("..") || part.IsEqualTo("."))
669 dotsIndex = (int)i; 670 dotsIndex = (int)i;
670 } 671 }
671 672
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
index dfeed82..ad0d8c9 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -15,8 +15,9 @@
15#include <sys/stat.h> 15#include <sys/stat.h>
16#include <sys/types.h> 16#include <sys/types.h>
17 17
18#include "../Common/StringConvert.h"
19#include "../Common/C_FileIO.h" 18#include "../Common/C_FileIO.h"
19#include "../Common/MyBuffer2.h"
20#include "../Common/StringConvert.h"
20#endif 21#endif
21 22
22#include "FileDir.h" 23#include "FileDir.h"
@@ -123,7 +124,7 @@ bool GetSystemDir(FString &path)
123#endif // UNDER_CE 124#endif // UNDER_CE
124 125
125 126
126bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) 127static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD dwFlagsAndAttributes)
127{ 128{
128 #ifndef _UNICODE 129 #ifndef _UNICODE
129 if (!g_IsNT) 130 if (!g_IsNT)
@@ -136,14 +137,14 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF
136 HANDLE hDir = INVALID_HANDLE_VALUE; 137 HANDLE hDir = INVALID_HANDLE_VALUE;
137 IF_USE_MAIN_PATH 138 IF_USE_MAIN_PATH
138 hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 139 hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
139 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 140 NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
140 #ifdef Z7_LONG_PATH 141 #ifdef Z7_LONG_PATH
141 if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) 142 if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
142 { 143 {
143 UString superPath; 144 UString superPath;
144 if (GetSuperPath(path, superPath, USE_MAIN_PATH)) 145 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
145 hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 146 hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
146 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 147 NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
147 } 148 }
148 #endif 149 #endif
149 150
@@ -156,6 +157,15 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF
156 return res; 157 return res;
157} 158}
158 159
160bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
161{
162 return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS);
163}
164
165bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
166{
167 return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT);
168}
159 169
160 170
161bool SetFileAttrib(CFSTR path, DWORD attrib) 171bool SetFileAttrib(CFSTR path, DWORD attrib)
@@ -222,6 +232,8 @@ bool RemoveDir(CFSTR path)
222} 232}
223 233
224 234
235// When moving a directory, oldFile and newFile must be on the same drive.
236
225bool MyMoveFile(CFSTR oldFile, CFSTR newFile) 237bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
226{ 238{
227 #ifndef _UNICODE 239 #ifndef _UNICODE
@@ -250,6 +262,59 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
250 return false; 262 return false;
251} 263}
252 264
265#if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500
266static DWORD WINAPI CopyProgressRoutine_to_ICopyFileProgress(
267 LARGE_INTEGER TotalFileSize, // file size
268 LARGE_INTEGER TotalBytesTransferred, // bytes transferred
269 LARGE_INTEGER /* StreamSize */, // bytes in stream
270 LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream
271 DWORD /* dwStreamNumber */, // current stream
272 DWORD /* dwCallbackReason */, // callback reason
273 HANDLE /* hSourceFile */, // handle to source file
274 HANDLE /* hDestinationFile */, // handle to destination file
275 LPVOID lpData // from CopyFileEx
276)
277{
278 return ((ICopyFileProgress *)lpData)->CopyFileProgress(
279 (UInt64)TotalFileSize.QuadPart,
280 (UInt64)TotalBytesTransferred.QuadPart);
281}
282#endif
283
284bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile,
285 ICopyFileProgress *progress)
286{
287#if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500
288#ifndef _UNICODE
289 if (g_IsNT)
290#endif
291 if (progress)
292 {
293 IF_USE_MAIN_PATH_2(oldFile, newFile)
294 {
295 if (::MoveFileWithProgressW(fs2us(oldFile), fs2us(newFile),
296 CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED))
297 return true;
298 if (::GetLastError() == ERROR_REQUEST_ABORTED)
299 return false;
300 }
301 #ifdef Z7_LONG_PATH
302 if (USE_SUPER_PATH_2)
303 {
304 UString d1, d2;
305 if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
306 return BOOLToBool(::MoveFileWithProgressW(d1, d2,
307 CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED));
308 }
309 #endif
310 return false;
311 }
312#else
313 UNUSED_VAR(progress)
314#endif
315 return MyMoveFile(oldFile, newFile);
316}
317
253#ifndef UNDER_CE 318#ifndef UNDER_CE
254#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 319#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000
255#define Z7_USE_DYN_CreateHardLink 320#define Z7_USE_DYN_CreateHardLink
@@ -595,6 +660,35 @@ bool RemoveDirWithSubItems(const FString &path)
595 return RemoveDir(path); 660 return RemoveDir(path);
596} 661}
597 662
663bool RemoveDirAlways_if_Empty(const FString &path)
664{
665 const DWORD attrib = NFind::GetFileAttrib(path);
666 if (attrib != INVALID_FILE_ATTRIBUTES
667 && (attrib & FILE_ATTRIBUTE_READONLY))
668 {
669 bool need_ClearAttrib = true;
670 if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
671 {
672 FString s (path);
673 s.Add_PathSepar();
674 NFind::CEnumerator enumerator;
675 enumerator.SetDirPrefix(s);
676 NFind::CDirEntry fi;
677 if (enumerator.Next(fi))
678 {
679 // we don't want to change attributes, if there are files
680 // in directory, because RemoveDir(path) will fail.
681 need_ClearAttrib = false;
682 // SetLastError(ERROR_DIR_NOT_EMPTY);
683 // return false;
684 }
685 }
686 if (need_ClearAttrib)
687 SetFileAttrib(path, 0); // we clear read-only attrib to remove read-only dir
688 }
689 return RemoveDir(path);
690}
691
598#endif // _WIN32 692#endif // _WIN32
599 693
600#ifdef UNDER_CE 694#ifdef UNDER_CE
@@ -878,9 +972,9 @@ bool CTempFile::Remove()
878 return !_mustBeDeleted; 972 return !_mustBeDeleted;
879} 973}
880 974
881bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) 975bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore,
976 ICopyFileProgress *progress)
882{ 977{
883 // DWORD attrib = 0;
884 if (deleteDestBefore) 978 if (deleteDestBefore)
885 { 979 {
886 if (NFind::DoesFileExist_Raw(name)) 980 if (NFind::DoesFileExist_Raw(name))
@@ -891,8 +985,8 @@ bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
891 } 985 }
892 } 986 }
893 DisableDeleting(); 987 DisableDeleting();
894 return MyMoveFile(_path, name); 988 // if (!progress) return MyMoveFile(_path, name);
895 989 return MyMoveFile_with_Progress(_path, name, progress);
896 /* 990 /*
897 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) 991 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
898 { 992 {
@@ -941,34 +1035,59 @@ bool RemoveDir(CFSTR path)
941} 1035}
942 1036
943 1037
944static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) 1038static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile, ICopyFileProgress *progress)
945{ 1039{
946 NWindows::NFile::NIO::COutFile outFile;
947 if (!outFile.Create_NEW(newFile))
948 return FALSE;
949
950 NWindows::NFile::NIO::CInFile inFile;
951 if (!inFile.Open(oldFile))
952 return FALSE;
953
954 char buf[1 << 14];
955
956 for (;;)
957 { 1040 {
958 const ssize_t num = inFile.read_part(buf, sizeof(buf)); 1041 NIO::COutFile outFile;
959 if (num == 0) 1042 if (!outFile.Create_NEW(newFile))
960 return TRUE;
961 if (num < 0)
962 return FALSE; 1043 return FALSE;
963 size_t processed; 1044 NIO::CInFile inFile;
964 const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); 1045 if (!inFile.Open(oldFile))
965 if (num2 != num || processed != (size_t)num)
966 return FALSE; 1046 return FALSE;
1047
1048 const size_t k_BufSize = 1 << 16;
1049 CAlignedBuffer1 buf(k_BufSize);
1050
1051 UInt64 length = 0;
1052 if (progress && !inFile.GetLength(length))
1053 length = 0;
1054 UInt64 prev = 0;
1055 UInt64 cur = 0;
1056 for (;;)
1057 {
1058 const ssize_t num = inFile.read_part(buf, k_BufSize);
1059 if (num == 0)
1060 return TRUE;
1061 if (num < 0)
1062 break;
1063 size_t processed;
1064 const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed);
1065 if (num2 != num || processed != (size_t)num)
1066 break;
1067 cur += (size_t)num2;
1068 if (progress && cur - prev >= (1u << 20))
1069 {
1070 prev = cur;
1071 if (progress->CopyFileProgress(length, cur) != PROGRESS_CONTINUE)
1072 {
1073 errno = EINTR; // instead of WIN32::ERROR_REQUEST_ABORTED
1074 break;
1075 }
1076 }
1077 }
967 } 1078 }
1079 // There is file IO error or process was interrupted by user.
1080 // We close output file and delete it.
1081 // DeleteFileAlways doesn't change errno (if successed), but we restore errno.
1082 const int errno_save = errno;
1083 DeleteFileAlways(newFile);
1084 errno = errno_save;
1085 return FALSE;
968} 1086}
969 1087
970 1088
971bool MyMoveFile(CFSTR oldFile, CFSTR newFile) 1089bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile,
1090 ICopyFileProgress *progress)
972{ 1091{
973 int res = rename(oldFile, newFile); 1092 int res = rename(oldFile, newFile);
974 if (res == 0) 1093 if (res == 0)
@@ -976,7 +1095,7 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
976 if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) 1095 if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem)
977 return false; 1096 return false;
978 1097
979 if (My_CopyFile(oldFile, newFile) == FALSE) 1098 if (My_CopyFile(oldFile, newFile, progress) == FALSE)
980 return false; 1099 return false;
981 1100
982 struct stat info_file; 1101 struct stat info_file;
@@ -990,6 +1109,11 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
990 return (unlink(oldFile) == 0); 1109 return (unlink(oldFile) == 0);
991} 1110}
992 1111
1112bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
1113{
1114 return MyMoveFile_with_Progress(oldFile, newFile, NULL);
1115}
1116
993 1117
994bool CreateDir(CFSTR path) 1118bool CreateDir(CFSTR path)
995{ 1119{
@@ -1058,17 +1182,15 @@ bool GetCurrentDir(FString &path)
1058 1182
1059 1183
1060 1184
1061bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) 1185static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, const int flags)
1062{ 1186{
1063 // need testing 1187 // need testing
1064 /* 1188 /*
1065 struct utimbuf buf; 1189 struct utimbuf buf;
1066 struct stat st; 1190 struct stat st;
1067 UNUSED_VAR(cTime) 1191 UNUSED_VAR(cTime)
1068
1069 printf("\nstat = %s\n", path); 1192 printf("\nstat = %s\n", path);
1070 int ret = stat(path, &st); 1193 int ret = stat(path, &st);
1071
1072 if (ret == 0) 1194 if (ret == 0)
1073 { 1195 {
1074 buf.actime = st.st_atime; 1196 buf.actime = st.st_atime;
@@ -1080,47 +1202,42 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF
1080 buf.actime = cur_time; 1202 buf.actime = cur_time;
1081 buf.modtime = cur_time; 1203 buf.modtime = cur_time;
1082 } 1204 }
1083
1084 if (aTime) 1205 if (aTime)
1085 { 1206 {
1086 UInt32 ut; 1207 UInt32 ut;
1087 if (NTime::FileTimeToUnixTime(*aTime, ut)) 1208 if (NTime::FileTimeToUnixTime(*aTime, ut))
1088 buf.actime = ut; 1209 buf.actime = ut;
1089 } 1210 }
1090
1091 if (mTime) 1211 if (mTime)
1092 { 1212 {
1093 UInt32 ut; 1213 UInt32 ut;
1094 if (NTime::FileTimeToUnixTime(*mTime, ut)) 1214 if (NTime::FileTimeToUnixTime(*mTime, ut))
1095 buf.modtime = ut; 1215 buf.modtime = ut;
1096 } 1216 }
1097
1098 return utime(path, &buf) == 0; 1217 return utime(path, &buf) == 0;
1099 */ 1218 */
1100 1219
1101 // if (!aTime && !mTime) return true; 1220 // if (!aTime && !mTime) return true;
1102
1103 struct timespec times[2]; 1221 struct timespec times[2];
1104 UNUSED_VAR(cTime) 1222 UNUSED_VAR(cTime)
1105
1106 bool needChange; 1223 bool needChange;
1107 needChange = FiTime_To_timespec(aTime, times[0]); 1224 needChange = FiTime_To_timespec(aTime, times[0]);
1108 needChange |= FiTime_To_timespec(mTime, times[1]); 1225 needChange |= FiTime_To_timespec(mTime, times[1]);
1109 1226 // if (mTime) { printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); }
1110 /*
1111 if (mTime)
1112 {
1113 printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec);
1114 }
1115 */
1116
1117 if (!needChange) 1227 if (!needChange)
1118 return true; 1228 return true;
1119 const int flags = 0; // follow link
1120 // = AT_SYMLINK_NOFOLLOW; // don't follow link
1121 return utimensat(AT_FDCWD, path, times, flags) == 0; 1229 return utimensat(AT_FDCWD, path, times, flags) == 0;
1122} 1230}
1123 1231
1232bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
1233{
1234 return SetFileTime_Base(path, cTime, aTime, mTime, 0); // (flags = 0) means follow_link
1235}
1236
1237bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
1238{
1239 return SetFileTime_Base(path, cTime, aTime, mTime, AT_SYMLINK_NOFOLLOW);
1240}
1124 1241
1125 1242
1126struct C_umask 1243struct C_umask
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 573ffa2..9ba98fc 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -18,9 +18,20 @@ bool GetSystemDir(FString &path);
18WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file 18WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file
19but linux : allows unix time = 0 in filesystem 19but linux : allows unix time = 0 in filesystem
20*/ 20*/
21 21/*
22SetDirTime() can be used to set time for file or for dir.
23If path is symbolic link, SetDirTime() will follow symbolic link,
24and it will set timestamps of symbolic link's target file or dir.
25*/
22bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); 26bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
23 27
28/*
29SetLinkFileTime() doesn't follow symbolic link,
30and it sets timestamps for symbolic link file itself.
31If (path) is not symbolic link, it still can work (at least in some new OS versions).
32*/
33bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
34
24 35
25#ifdef _WIN32 36#ifdef _WIN32
26 37
@@ -41,7 +52,26 @@ int my_chown(CFSTR path, uid_t owner, gid_t group);
41bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); 52bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib);
42 53
43 54
55#ifndef _WIN32
56#define PROGRESS_CONTINUE 0
57#define PROGRESS_CANCEL 1
58// #define PROGRESS_STOP 2
59// #define PROGRESS_QUIET 3
60#endif
61Z7_PURE_INTERFACES_BEGIN
62DECLARE_INTERFACE(ICopyFileProgress)
63{
64 // in: total, current: include all/processed alt streams.
65 // it returns PROGRESS_CONTINUE or PROGRESS_CANCEL.
66 virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) = 0;
67};
68Z7_PURE_INTERFACES_END
69
44bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); 70bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
71// (progress == NULL) is allowed
72bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile,
73 ICopyFileProgress *progress);
74
45 75
46#ifndef UNDER_CE 76#ifndef UNDER_CE
47bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); 77bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName);
@@ -59,6 +89,11 @@ bool CreateComplexDir(CFSTR path);
59 89
60bool DeleteFileAlways(CFSTR name); 90bool DeleteFileAlways(CFSTR name);
61bool RemoveDirWithSubItems(const FString &path); 91bool RemoveDirWithSubItems(const FString &path);
92#ifdef _WIN32
93bool RemoveDirAlways_if_Empty(const FString &path);
94#else
95#define RemoveDirAlways_if_Empty RemoveDir
96#endif
62 97
63bool MyGetFullPathName(CFSTR path, FString &resFullPath); 98bool MyGetFullPathName(CFSTR path, FString &resFullPath);
64bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); 99bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
@@ -87,7 +122,9 @@ public:
87 bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix 122 bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix
88 bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); 123 bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile);
89 bool Remove(); 124 bool Remove();
90 bool MoveTo(CFSTR name, bool deleteDestBefore); 125 // bool MoveTo(CFSTR name, bool deleteDestBefore);
126 bool MoveTo(CFSTR name, bool deleteDestBefore,
127 ICopyFileProgress *progress);
91}; 128};
92 129
93 130
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp
index ca387f6..64075ab 100644
--- a/CPP/Windows/FileFind.cpp
+++ b/CPP/Windows/FileFind.cpp
@@ -731,7 +731,7 @@ bool CFileInfo::Find(CFSTR path, bool followLink)
731 bool isOK = false; 731 bool isOK = false;
732 if (finder.FindFirst(s, *this)) 732 if (finder.FindFirst(s, *this))
733 { 733 {
734 if (Name == FTEXT(".")) 734 if (Name.IsEqualTo("."))
735 { 735 {
736 Name = path + prefixSize; 736 Name = path + prefixSize;
737 return true; 737 return true;
@@ -769,6 +769,13 @@ bool CFileInfo::Find(CFSTR path, bool followLink)
769 769
770 // return FollowReparse(path, IsDir()); 770 // return FollowReparse(path, IsDir());
771 return Fill_From_ByHandleFileInfo(path); 771 return Fill_From_ByHandleFileInfo(path);
772/*
773 // Fill_From_ByHandleFileInfo returns false (with Access Denied error),
774 // if there is reparse link file (not directory reparse item).
775 if (Fill_From_ByHandleFileInfo(path))
776 return true;
777 return HasReparsePoint();
778*/
772} 779}
773 780
774bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) 781bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path)
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h
index 6ba40eb..26edef4 100644
--- a/CPP/Windows/FileIO.h
+++ b/CPP/Windows/FileIO.h
@@ -11,8 +11,7 @@
11 11
12#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 12#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1
13 13
14// what the meaning of that FLAG or field (2)? 14#define Z7_WIN_LX_SYMLINK_VERSION_2 2
15#define Z7_WIN_LX_SYMLINK_FLAG 2
16 15
17#ifdef _WIN32 16#ifdef _WIN32
18 17
@@ -44,7 +43,33 @@ namespace NWindows {
44namespace NFile { 43namespace NFile {
45 44
46#if defined(_WIN32) && !defined(UNDER_CE) 45#if defined(_WIN32) && !defined(UNDER_CE)
47bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); 46/*
47 in: (CByteBuffer &dest) is empty
48 in: (path) uses Windows path separator (\).
49 out: (path) uses Linux path separator (/).
50 if (isAbsPath == true), then "c:\\" prefix is replaced to "/mnt/c/" prefix
51*/
52void Convert_WinPath_to_WslLinuxPath(FString &path, bool convertDrivePath);
53// (path) must use Linux path separator (/).
54void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path);
55
56/*
57 in: (CByteBuffer &dest) is empty
58 if (isSymLink == false) : MOUNT_POINT : (path) must be absolute.
59 if (isSymLink == true) : SYMLINK : Windows
60 (path) must use Windows path separator (\).
61 (path) must be without link "\\??\\" prefix.
62 link "\\??\\" prefix will be added inside FillLinkData(), if path is absolute.
63*/
64void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink);
65// in: (CByteBuffer &dest) is empty
66inline void FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
67{
68 if (isWSL)
69 FillLinkData_WslLink(dest, path);
70 else
71 FillLinkData_WinLink(dest, path, isSymLink);
72}
48#endif 73#endif
49 74
50struct CReparseShortInfo 75struct CReparseShortInfo
@@ -61,7 +86,6 @@ struct CReparseAttr
61 UInt32 Flags; 86 UInt32 Flags;
62 UString SubsName; 87 UString SubsName;
63 UString PrintName; 88 UString PrintName;
64
65 AString WslName; 89 AString WslName;
66 90
67 bool HeaderError; 91 bool HeaderError;
@@ -71,8 +95,7 @@ struct CReparseAttr
71 95
72 CReparseAttr(): Tag(0), Flags(0) {} 96 CReparseAttr(): Tag(0), Flags(0) {}
73 97
74 // Parse() 98 // returns (true) and (ErrorCode = 0), if (it's correct known link)
75 // returns (true) and (ErrorCode = 0), if (it'a correct known link)
76 // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag 99 // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag
77 bool Parse(const Byte *p, size_t size); 100 bool Parse(const Byte *p, size_t size);
78 101
@@ -80,18 +103,14 @@ struct CReparseAttr
80 bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } 103 bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; }
81 bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } 104 bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; }
82 105
106 // note: "/dir1/path" is marked as relative.
83 bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } 107 bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; }
84 108
85 bool IsRelative_WSL() const 109 bool IsRelative_WSL() const
86 { 110 {
87 if (WslName.IsEmpty()) 111 return WslName[0] != '/'; // WSL uses unix path separator
88 return true;
89 char c = WslName[0];
90 return !IS_PATH_SEPAR(c);
91 } 112 }
92 113
93 // bool IsVolume() const;
94
95 bool IsOkNamePair() const; 114 bool IsOkNamePair() const;
96 UString GetPath() const; 115 UString GetPath() const;
97}; 116};
diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp
index bb380ec..2883c82 100644
--- a/CPP/Windows/FileLink.cpp
+++ b/CPP/Windows/FileLink.cpp
@@ -39,12 +39,24 @@ namespace NFile {
39using namespace NName; 39using namespace NName;
40 40
41/* 41/*
42Win10 Junctions/SymLinks:
43 - (/) slash doesn't work as path separator
44 - Win10 preinstalled junctions don't use tail backslash, but tail backslashes also work.
45 - double backslash works only after drive prefix "c:\\dir1\dir2\",
46 and doesn't work in another places.
47 - absolute path without \??\ prefix doesn't work
48 - absolute path "c:" doesn't work
49*/
50
51/*
42 Reparse Points (Junctions and Symbolic Links): 52 Reparse Points (Junctions and Symbolic Links):
43 struct 53 struct
44 { 54 {
45 UInt32 Tag; 55 UInt32 Tag;
46 UInt16 Size; // not including starting 8 bytes 56 UInt16 Size; // not including starting 8 bytes
47 UInt16 Reserved; // = 0 57 UInt16 Reserved; // = 0, DOCs: // Length, in bytes, of the unparsed portion of
58 // the file name pointed to by the FileName member of the associated file object.
59 // This member is only valid for create operations when the I/O fails with STATUS_REPARSE.
48 60
49 UInt16 SubstituteOffset; // offset in bytes from start of namesChars 61 UInt16 SubstituteOffset; // offset in bytes from start of namesChars
50 UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL 62 UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL
@@ -68,6 +80,16 @@ using namespace NName;
68 2) Default Order in table: 80 2) Default Order in table:
69 Print Path 81 Print Path
70 Substitute Path 82 Substitute Path
83
84DOCS:
85 The print name SHOULD be an informative pathname, suitable for display
86 to a user, that also identifies the target of the mount point.
87 Neither of these pathnames can contain dot directory names.
88
89reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK,
90are processed on the server and are not processed by a client
91after transmission over the wire.
92Clients SHOULD treat associated reparse data as opaque data.
71*/ 93*/
72 94
73/* 95/*
@@ -93,7 +115,8 @@ static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
93#define Get16(p) GetUi16(p) 115#define Get16(p) GetUi16(p)
94#define Get32(p) GetUi32(p) 116#define Get32(p) GetUi32(p)
95 117
96static const wchar_t * const k_LinkPrefix = L"\\??\\"; 118static const char * const k_LinkPrefix = "\\??\\";
119static const char * const k_LinkPrefix_UNC = "\\??\\UNC\\";
97static const unsigned k_LinkPrefix_Size = 4; 120static const unsigned k_LinkPrefix_Size = 4;
98 121
99static bool IsLinkPrefix(const wchar_t *s) 122static bool IsLinkPrefix(const wchar_t *s)
@@ -102,7 +125,7 @@ static bool IsLinkPrefix(const wchar_t *s)
102} 125}
103 126
104/* 127/*
105static const wchar_t * const k_VolumePrefix = L"Volume{"; 128static const char * const k_VolumePrefix = "Volume{";
106static const bool IsVolumeName(const wchar_t *s) 129static const bool IsVolumeName(const wchar_t *s)
107{ 130{
108 return IsString1PrefixedByString2(s, k_VolumePrefix); 131 return IsString1PrefixedByString2(s, k_VolumePrefix);
@@ -118,7 +141,7 @@ static void WriteString(Byte *dest, const wchar_t *path)
118{ 141{
119 for (;;) 142 for (;;)
120 { 143 {
121 wchar_t c = *path++; 144 const wchar_t c = *path++;
122 if (c == 0) 145 if (c == 0)
123 return; 146 return;
124 Set16(dest, (UInt16)c) 147 Set16(dest, (UInt16)c)
@@ -126,62 +149,103 @@ static void WriteString(Byte *dest, const wchar_t *path)
126 } 149 }
127} 150}
128 151
129bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) 152#ifdef _WIN32
153void Convert_WinPath_to_WslLinuxPath(FString &s, bool convertDrivePath)
130{ 154{
131 bool isAbs = IsAbsolutePath(path); 155 if (convertDrivePath && IsDrivePath(s))
132 if (!isAbs && !isSymLink)
133 return false;
134
135 if (isWSL)
136 { 156 {
137 // unsupported characters probably use Replacement Character UTF-16 0xFFFD 157 FChar c = s[0];
138 AString utf; 158 c = MyCharLower_Ascii(c);
139 ConvertUnicodeToUTF8(path, utf); 159 s.DeleteFrontal(2);
140 const size_t size = 4 + utf.Len(); 160 s.InsertAtFront(c);
141 if (size != (UInt16)size) 161 s.Insert(0, FTEXT("/mnt/"));
142 return false;
143 dest.Alloc(8 + size);
144 Byte *p = dest;
145 Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
146 Set16(p + 4, (UInt16)(size))
147 Set16(p + 6, 0)
148 Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG)
149 memcpy(p + 12, utf.Ptr(), utf.Len());
150 return true;
151 } 162 }
163 s.Replace(FCHAR_PATH_SEPARATOR, FTEXT('/'));
164}
165#endif
152 166
153 // usual symbolic LINK (NOT WSL)
154 167
155 bool needPrintName = true; 168static const unsigned k_Link_Size_Limit = 1u << 16; // 16-bit field is used for size.
169
170void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path)
171{
172 // dest.Free(); // it's empty already
173 // WSL probably uses Replacement Character UTF-16 0xFFFD for unsupported characters?
174 AString utf;
175 ConvertUnicodeToUTF8(path, utf);
176 const unsigned size = 4 + utf.Len();
177 if (size >= k_Link_Size_Limit)
178 return;
179 dest.Alloc(8 + size);
180 Byte *p = dest;
181 Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
182 // Set32(p + 4, (UInt32)size)
183 Set16(p + 4, (UInt16)size)
184 Set16(p + 6, 0)
185 Set32(p + 8, Z7_WIN_LX_SYMLINK_VERSION_2)
186 memcpy(p + 12, utf.Ptr(), utf.Len());
187}
188
156 189
157 if (IsSuperPath(path)) 190void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
191{
192 // dest.Free(); // it's empty already
193 bool isAbs = false;
194 if (IS_PATH_SEPAR(path[0]))
158 { 195 {
159 path += kSuperPathPrefixSize; 196 // root paths "\dir1\path" are marked as relative
160 if (!IsDrivePath(path)) 197 if (IS_PATH_SEPAR(path[1]))
161 needPrintName = false; 198 isAbs = true;
199 }
200 else
201 isAbs = IsAbsolutePath(path);
202 if (!isAbs && !isSymLink)
203 {
204 // Win10 allows us to create relative MOUNT_POINT.
205 // But relative MOUNT_POINT will not work when accessing it.
206 // So we prevent useless creation of a relative MOUNT_POINT.
207 return;
162 } 208 }
163 209
164 const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; 210 bool needPrintName = true;
165 211 UString subs (path);
212 if (isAbs)
213 {
214 const bool isSuperPath = IsSuperPath(path);
215 if (!isSuperPath && NName::IsNetworkPath(us2fs(path)))
216 {
217 subs = k_LinkPrefix_UNC;
218 subs += (path + 2);
219 }
220 else
221 {
222 if (isSuperPath)
223 {
224 // we remove super prefix:
225 path += kSuperPathPrefixSize;
226 // we want to get correct abolute path in PrintName still.
227 if (!IsDrivePath(path))
228 needPrintName = false; // we need "\\server\path" for print name.
229 }
230 subs = k_LinkPrefix;
231 subs += path;
232 }
233 }
234 const size_t len1 = subs.Len() * 2;
166 size_t len2 = (size_t)MyStringLen(path) * 2; 235 size_t len2 = (size_t)MyStringLen(path) * 2;
167 const size_t len1 = len2 + add_Prefix_Len * 2;
168 if (!needPrintName) 236 if (!needPrintName)
169 len2 = 0; 237 len2 = 0;
170 238 size_t totalNamesSize = len1 + len2;
171 size_t totalNamesSize = (len1 + len2);
172
173 /* some WIM imagex software uses old scheme for symbolic links. 239 /* some WIM imagex software uses old scheme for symbolic links.
174 so we can old scheme for byte to byte compatibility */ 240 so we can use old scheme for byte to byte compatibility */
175 241 const bool newOrderScheme = isSymLink;
176 bool newOrderScheme = isSymLink;
177 // newOrderScheme = false; 242 // newOrderScheme = false;
178
179 if (!newOrderScheme) 243 if (!newOrderScheme)
180 totalNamesSize += 2 * 2; 244 totalNamesSize += 2 * 2; // we use NULL terminators in old scheme.
181 245
182 const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; 246 const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
183 if (size != (UInt16)size) 247 if (size >= k_Link_Size_Limit)
184 return false; 248 return;
185 dest.Alloc(size); 249 dest.Alloc(size);
186 memset(dest, 0, size); 250 memset(dest, 0, size);
187 const UInt32 tag = isSymLink ? 251 const UInt32 tag = isSymLink ?
@@ -189,6 +253,7 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool i
189 Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; 253 Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
190 Byte *p = dest; 254 Byte *p = dest;
191 Set32(p, tag) 255 Set32(p, tag)
256 // Set32(p + 4, (UInt32)(size - 8))
192 Set16(p + 4, (UInt16)(size - 8)) 257 Set16(p + 4, (UInt16)(size - 8))
193 Set16(p + 6, 0) 258 Set16(p + 6, 0)
194 p += 8; 259 p += 8;
@@ -204,21 +269,16 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool i
204 Set16(p + 2, (UInt16)len1) 269 Set16(p + 2, (UInt16)len1)
205 Set16(p + 4, (UInt16)printOffs) 270 Set16(p + 4, (UInt16)printOffs)
206 Set16(p + 6, (UInt16)len2) 271 Set16(p + 6, (UInt16)len2)
207
208 p += 8; 272 p += 8;
209 if (isSymLink) 273 if (isSymLink)
210 { 274 {
211 UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE; 275 const UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
212 Set32(p, flags) 276 Set32(p, flags)
213 p += 4; 277 p += 4;
214 } 278 }
215 279 WriteString(p + subOffs, subs);
216 if (add_Prefix_Len != 0)
217 WriteString(p + subOffs, k_LinkPrefix);
218 WriteString(p + subOffs + add_Prefix_Len * 2, path);
219 if (needPrintName) 280 if (needPrintName)
220 WriteString(p + printOffs, path); 281 WriteString(p + printOffs, path);
221 return true;
222} 282}
223 283
224#endif // defined(_WIN32) && !defined(UNDER_CE) 284#endif // defined(_WIN32) && !defined(UNDER_CE)
@@ -230,7 +290,7 @@ static void GetString(const Byte *p, unsigned len, UString &res)
230 unsigned i; 290 unsigned i;
231 for (i = 0; i < len; i++) 291 for (i = 0; i < len; i++)
232 { 292 {
233 wchar_t c = Get16(p + i * 2); 293 const wchar_t c = Get16(p + (size_t)i * 2);
234 if (c == 0) 294 if (c == 0)
235 break; 295 break;
236 s[i] = c; 296 s[i] = c;
@@ -239,6 +299,7 @@ static void GetString(const Byte *p, unsigned len, UString &res)
239 res.ReleaseBuf_SetLen(i); 299 res.ReleaseBuf_SetLen(i);
240} 300}
241 301
302
242bool CReparseAttr::Parse(const Byte *p, size_t size) 303bool CReparseAttr::Parse(const Byte *p, size_t size)
243{ 304{
244 ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; 305 ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
@@ -250,7 +311,12 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
250 return false; 311 return false;
251 Tag = Get32(p); 312 Tag = Get32(p);
252 if (Get16(p + 6) != 0) // padding 313 if (Get16(p + 6) != 0) // padding
253 return false; 314 {
315 // DOCs: Reserved : the field SHOULD be set to 0
316 // and MUST be ignored (by parser).
317 // Win10 ignores it.
318 MinorError = true; // optional
319 }
254 unsigned len = Get16(p + 4); 320 unsigned len = Get16(p + 4);
255 p += 8; 321 p += 8;
256 size -= 8; 322 size -= 8;
@@ -262,8 +328,6 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
262 (type & kReparseFlags_Microsoft) == 0 || 328 (type & kReparseFlags_Microsoft) == 0 ||
263 (type & 0xFFFF) != 3) 329 (type & 0xFFFF) != 3)
264 */ 330 */
265
266
267 HeaderError = false; 331 HeaderError = false;
268 332
269 if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT 333 if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
@@ -282,8 +346,7 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
282 { 346 {
283 if (len < 4) 347 if (len < 4)
284 return false; 348 return false;
285 Flags = Get32(p); // maybe it's not Flags 349 if (Get32(p) != Z7_WIN_LX_SYMLINK_VERSION_2)
286 if (Flags != Z7_WIN_LX_SYMLINK_FLAG)
287 return false; 350 return false;
288 len -= 4; 351 len -= 4;
289 p += 4; 352 p += 4;
@@ -291,12 +354,13 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
291 unsigned i; 354 unsigned i;
292 for (i = 0; i < len; i++) 355 for (i = 0; i < len; i++)
293 { 356 {
294 char c = (char)p[i]; 357 const char c = (char)p[i];
295 s[i] = c; 358 s[i] = c;
296 if (c == 0) 359 if (c == 0)
297 break; 360 break;
298 } 361 }
299 WslName.ReleaseBuf_SetEnd(i); 362 s[i] = 0;
363 WslName.ReleaseBuf_SetLen(i);
300 MinorError = (i != len); 364 MinorError = (i != len);
301 ErrorCode = 0; 365 ErrorCode = 0;
302 return true; 366 return true;
@@ -304,10 +368,10 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
304 368
305 if (len < 8) 369 if (len < 8)
306 return false; 370 return false;
307 unsigned subOffs = Get16(p); 371 const unsigned subOffs = Get16(p);
308 unsigned subLen = Get16(p + 2); 372 const unsigned subLen = Get16(p + 2);
309 unsigned printOffs = Get16(p + 4); 373 const unsigned printOffs = Get16(p + 4);
310 unsigned printLen = Get16(p + 6); 374 const unsigned printLen = Get16(p + 6);
311 len -= 8; 375 len -= 8;
312 p += 8; 376 p += 8;
313 377
@@ -335,15 +399,17 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
335 399
336bool CReparseShortInfo::Parse(const Byte *p, size_t size) 400bool CReparseShortInfo::Parse(const Byte *p, size_t size)
337{ 401{
338 const Byte *start = p; 402 const Byte * const start = p;
339 Offset= 0; 403 Offset = 0;
340 Size = 0; 404 Size = 0;
341 if (size < 8) 405 if (size < 8)
342 return false; 406 return false;
343 UInt32 Tag = Get32(p); 407 const UInt32 Tag = Get32(p);
344 UInt32 len = Get16(p + 4); 408 UInt32 len = Get16(p + 4);
409 /*
345 if (len + 8 > size) 410 if (len + 8 > size)
346 return false; 411 return false;
412 */
347 /* 413 /*
348 if ((type & kReparseFlags_Alias) == 0 || 414 if ((type & kReparseFlags_Alias) == 0 ||
349 (type & kReparseFlags_Microsoft) == 0 || 415 (type & kReparseFlags_Microsoft) == 0 ||
@@ -353,16 +419,14 @@ bool CReparseShortInfo::Parse(const Byte *p, size_t size)
353 Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK) 419 Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
354 // return true; 420 // return true;
355 return false; 421 return false;
356 422 /*
357 if (Get16(p + 6) != 0) // padding 423 if (Get16(p + 6) != 0) // padding
358 return false; 424 return false;
359 425 */
360 p += 8; 426 p += 8;
361 size -= 8; 427 size -= 8;
362
363 if (len != size) // do we need that check? 428 if (len != size) // do we need that check?
364 return false; 429 return false;
365
366 if (len < 8) 430 if (len < 8)
367 return false; 431 return false;
368 unsigned subOffs = Get16(p); 432 unsigned subOffs = Get16(p);
@@ -396,10 +460,14 @@ bool CReparseAttr::IsOkNamePair() const
396{ 460{
397 if (IsLinkPrefix(SubsName)) 461 if (IsLinkPrefix(SubsName))
398 { 462 {
463 if (PrintName == GetPath())
464 return true;
465/*
399 if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) 466 if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
400 return PrintName.IsEmpty(); 467 return PrintName.IsEmpty();
401 if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) 468 if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
402 return true; 469 return true;
470*/
403 } 471 }
404 return wcscmp(SubsName, PrintName) == 0; 472 return wcscmp(SubsName, PrintName) == 0;
405} 473}
@@ -415,21 +483,26 @@ bool CReparseAttr::IsVolume() const
415 483
416UString CReparseAttr::GetPath() const 484UString CReparseAttr::GetPath() const
417{ 485{
486 UString s (SubsName);
418 if (IsSymLink_WSL()) 487 if (IsSymLink_WSL())
419 { 488 {
420 UString u;
421 // if (CheckUTF8(attr.WslName) 489 // if (CheckUTF8(attr.WslName)
422 if (!ConvertUTF8ToUnicode(WslName, u)) 490 if (!ConvertUTF8ToUnicode(WslName, s))
423 MultiByteToUnicodeString2(u, WslName); 491 MultiByteToUnicodeString2(s, WslName);
424 return u;
425 } 492 }
426 493 else if (IsLinkPrefix(s))
427 UString s (SubsName);
428 if (IsLinkPrefix(s))
429 { 494 {
430 s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" 495 if (IsString1PrefixedByString2_NoCase_Ascii(s.Ptr(), k_LinkPrefix_UNC))
431 if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) 496 {
432 s.DeleteFrontal(k_LinkPrefix_Size); 497 s.DeleteFrontal(6);
498 s.ReplaceOneCharAtPos(0, '\\');
499 }
500 else
501 {
502 s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
503 if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
504 s.DeleteFrontal(k_LinkPrefix_Size);
505 }
433 } 506 }
434 return s; 507 return s;
435} 508}
@@ -468,7 +541,7 @@ bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMA
468static bool CreatePrefixDirOfFile(CFSTR path) 541static bool CreatePrefixDirOfFile(CFSTR path)
469{ 542{
470 FString path2 (path); 543 FString path2 (path);
471 int pos = path2.ReverseFind_PathSepar(); 544 const int pos = path2.ReverseFind_PathSepar();
472 if (pos < 0) 545 if (pos < 0)
473 return true; 546 return true;
474 #ifdef _WIN32 547 #ifdef _WIN32
@@ -494,6 +567,8 @@ static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD si
494} 567}
495 568
496 569
570// MOUNT_POINT (Junction Point) and LX_SYMLINK (WSL) can be written without administrator rights.
571// SYMLINK requires administrator rights.
497// If there is Reparse data already, it still writes new Reparse data 572// If there is Reparse data already, it still writes new Reparse data
498bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) 573bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
499{ 574{
@@ -540,10 +615,11 @@ bool DeleteReparseData(CFSTR path)
540 SetLastError(ERROR_INVALID_REPARSE_DATA); 615 SetLastError(ERROR_INVALID_REPARSE_DATA);
541 return false; 616 return false;
542 } 617 }
543 BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; 618 // BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
544 memset(buf, 0, sizeof(buf)); 619 // memset(buf, 0, sizeof(buf));
545 memcpy(buf, reparseData, 4); // tag 620 // memcpy(buf, reparseData, 4); // tag
546 return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); 621 memset(reparseData + 4, 0, my_REPARSE_DATA_BUFFER_HEADER_SIZE - 4);
622 return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, reparseData, my_REPARSE_DATA_BUFFER_HEADER_SIZE);
547} 623}
548 624
549} 625}
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp
index c16b3d4..eb62567 100644
--- a/CPP/Windows/FileName.cpp
+++ b/CPP/Windows/FileName.cpp
@@ -65,8 +65,15 @@ void NormalizeDirPathPrefix(UString &dirPath)
65 dirPath.Add_PathSepar(); 65 dirPath.Add_PathSepar();
66} 66}
67 67
68
69#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
70bool IsDrivePath (const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
71// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
72
68#ifdef _WIN32 73#ifdef _WIN32
69 74
75bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
76
70#ifndef USE_UNICODE_FSTRING 77#ifndef USE_UNICODE_FSTRING
71#ifdef Z7_LONG_PATH 78#ifdef Z7_LONG_PATH
72static void NormalizeDirSeparators(UString &s) 79static void NormalizeDirSeparators(UString &s)
@@ -87,13 +94,6 @@ void NormalizeDirSeparators(FString &s)
87 s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); 94 s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR);
88} 95}
89 96
90#endif
91
92
93#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
94
95bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
96
97bool IsAltPathPrefix(CFSTR s) throw() 97bool IsAltPathPrefix(CFSTR s) throw()
98{ 98{
99 unsigned len = MyStringLen(s); 99 unsigned len = MyStringLen(s);
@@ -117,16 +117,23 @@ bool IsAltPathPrefix(CFSTR s) throw()
117 return true; 117 return true;
118} 118}
119 119
120#if defined(_WIN32) && !defined(UNDER_CE) 120#endif // _WIN32
121
121 122
122const char * const kSuperPathPrefix = "\\\\?\\"; 123const char * const kSuperPathPrefix =
124 STRING_PATH_SEPARATOR
125 STRING_PATH_SEPARATOR "?"
126 STRING_PATH_SEPARATOR;
123#ifdef Z7_LONG_PATH 127#ifdef Z7_LONG_PATH
124static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; 128static const char * const kSuperUncPrefix =
129 STRING_PATH_SEPARATOR
130 STRING_PATH_SEPARATOR "?"
131 STRING_PATH_SEPARATOR "UNC"
132 STRING_PATH_SEPARATOR;
125#endif 133#endif
126 134
127#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) 135#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3]))
128#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) 136#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3]))
129#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
130 137
131#define IS_UNC_WITH_SLASH(s) ( \ 138#define IS_UNC_WITH_SLASH(s) ( \
132 ((s)[0] == 'U' || (s)[0] == 'u') \ 139 ((s)[0] == 'U' || (s)[0] == 'u') \
@@ -134,6 +141,16 @@ static const char * const kSuperUncPrefix = "\\\\?\\UNC\\";
134 && ((s)[2] == 'C' || (s)[2] == 'c') \ 141 && ((s)[2] == 'C' || (s)[2] == 'c') \
135 && IS_SEPAR((s)[3])) 142 && IS_SEPAR((s)[3]))
136 143
144static const unsigned kDrivePrefixSize = 3; /* c:\ */
145
146bool IsSuperPath(const wchar_t *s) throw();
147bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
148// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
149
150#if defined(_WIN32) && !defined(UNDER_CE)
151
152#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
153bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
137bool IsDevicePath(CFSTR s) throw() 154bool IsDevicePath(CFSTR s) throw()
138{ 155{
139 #ifdef UNDER_CE 156 #ifdef UNDER_CE
@@ -154,7 +171,7 @@ bool IsDevicePath(CFSTR s) throw()
154 171
155 if (!IS_DEVICE_PATH(s)) 172 if (!IS_DEVICE_PATH(s))
156 return false; 173 return false;
157 unsigned len = MyStringLen(s); 174 const unsigned len = MyStringLen(s);
158 if (len == 6 && s[5] == ':') 175 if (len == 6 && s[5] == ':')
159 return true; 176 return true;
160 if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) 177 if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive"))
@@ -174,7 +191,7 @@ bool IsNetworkPath(CFSTR s) throw()
174 return false; 191 return false;
175 if (IsSuperUncPath(s)) 192 if (IsSuperUncPath(s))
176 return true; 193 return true;
177 FChar c = s[2]; 194 const FChar c = s[2];
178 return (c != '.' && c != '?'); 195 return (c != '.' && c != '?');
179} 196}
180 197
@@ -187,7 +204,7 @@ unsigned GetNetworkServerPrefixSize(CFSTR s) throw()
187 prefixSize = kSuperUncPathPrefixSize; 204 prefixSize = kSuperUncPathPrefixSize;
188 else 205 else
189 { 206 {
190 FChar c = s[2]; 207 const FChar c = s[2];
191 if (c == '.' || c == '?') 208 if (c == '.' || c == '?')
192 return 0; 209 return 0;
193 } 210 }
@@ -209,14 +226,6 @@ bool IsNetworkShareRootPath(CFSTR s) throw()
209 return s[(unsigned)pos + 1] == 0; 226 return s[(unsigned)pos + 1] == 0;
210} 227}
211 228
212static const unsigned kDrivePrefixSize = 3; /* c:\ */
213
214bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
215// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
216bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
217bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
218// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
219
220bool IsAltStreamPrefixWithColon(const UString &s) throw() 229bool IsAltStreamPrefixWithColon(const UString &s) throw()
221{ 230{
222 if (s.IsEmpty()) 231 if (s.IsEmpty())
@@ -278,12 +287,14 @@ bool IsAbsolutePath(const wchar_t *s) throw()
278int FindAltStreamColon(CFSTR path) throw() 287int FindAltStreamColon(CFSTR path) throw()
279{ 288{
280 unsigned i = 0; 289 unsigned i = 0;
281 if (IsDrivePath2(path)) 290 if (IsSuperPath(path))
282 i = 2; 291 i = kSuperPathPrefixSize;
292 if (IsDrivePath2(path + i))
293 i += 2;
283 int colonPos = -1; 294 int colonPos = -1;
284 for (;; i++) 295 for (;; i++)
285 { 296 {
286 FChar c = path[i]; 297 const FChar c = path[i];
287 if (c == 0) 298 if (c == 0)
288 return colonPos; 299 return colonPos;
289 if (c == ':') 300 if (c == ':')
@@ -347,14 +358,16 @@ unsigned GetRootPrefixSize(CFSTR s) throw()
347} 358}
348 359
349#endif // USE_UNICODE_FSTRING 360#endif // USE_UNICODE_FSTRING
361#endif // _WIN32
362
350 363
351static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() 364static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
352{ 365{
353 // Network path: we look "server\path\" as root prefix 366 // Network path: we look "server\path\" as root prefix
354 int pos = FindSepar(s); 367 const int pos = FindSepar(s);
355 if (pos < 0) 368 if (pos < 0)
356 return 0; 369 return 0;
357 int pos2 = FindSepar(s + (unsigned)pos + 1); 370 const int pos2 = FindSepar(s + (unsigned)pos + 1);
358 if (pos2 < 0) 371 if (pos2 < 0)
359 return 0; 372 return 0;
360 return (unsigned)(pos + pos2 + 2); 373 return (unsigned)(pos + pos2 + 2);
@@ -368,7 +381,7 @@ static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw()
368 return 0; 381 return 0;
369 if (s[1] == 0 || !IS_SEPAR(s[1])) 382 if (s[1] == 0 || !IS_SEPAR(s[1]))
370 return 1; 383 return 1;
371 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 384 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
372 return (size == 0) ? 0 : 2 + size; 385 return (size == 0) ? 0 : 2 + size;
373} 386}
374 387
@@ -376,17 +389,21 @@ static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw()
376{ 389{
377 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 390 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
378 { 391 {
379 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 392 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
380 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 393 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
381 } 394 }
382 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 395 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
383 int pos = FindSepar(s + kSuperPathPrefixSize); 396 const int pos = FindSepar(s + kSuperPathPrefixSize);
384 if (pos < 0) 397 if (pos < 0)
385 return 0; 398 return 0;
386 return kSuperPathPrefixSize + (unsigned)(pos + 1); 399 return kSuperPathPrefixSize + (unsigned)(pos + 1);
387} 400}
388 401
402#ifdef _WIN32
389unsigned GetRootPrefixSize(const wchar_t *s) throw() 403unsigned GetRootPrefixSize(const wchar_t *s) throw()
404#else
405unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw()
406#endif
390{ 407{
391 if (IS_DEVICE_PATH(s)) 408 if (IS_DEVICE_PATH(s))
392 return kDevicePathPrefixSize; 409 return kDevicePathPrefixSize;
@@ -395,7 +412,7 @@ unsigned GetRootPrefixSize(const wchar_t *s) throw()
395 return GetRootPrefixSize_Of_SimplePath(s); 412 return GetRootPrefixSize_Of_SimplePath(s);
396} 413}
397 414
398#else // _WIN32 415#ifndef _WIN32
399 416
400bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } 417bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); }
401 418
diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h
index 219b656..ce26e78 100644
--- a/CPP/Windows/FileName.h
+++ b/CPP/Windows/FileName.h
@@ -25,13 +25,13 @@ bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars li
25 25
26bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ 26bool IsAltPathPrefix(CFSTR s) throw(); /* name: */
27 27
28#if defined(_WIN32) && !defined(UNDER_CE)
29
30extern const char * const kSuperPathPrefix; /* \\?\ */ 28extern const char * const kSuperPathPrefix; /* \\?\ */
31const unsigned kDevicePathPrefixSize = 4; 29const unsigned kDevicePathPrefixSize = 4;
32const unsigned kSuperPathPrefixSize = 4; 30const unsigned kSuperPathPrefixSize = 4;
33const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; 31const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
34 32
33#if defined(_WIN32) && !defined(UNDER_CE)
34
35bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ 35bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
36bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ 36bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */
37bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ 37bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */
@@ -86,6 +86,15 @@ int FindAltStreamColon(CFSTR path) throw();
86bool IsAbsolutePath(const wchar_t *s) throw(); 86bool IsAbsolutePath(const wchar_t *s) throw();
87unsigned GetRootPrefixSize(const wchar_t *s) throw(); 87unsigned GetRootPrefixSize(const wchar_t *s) throw();
88 88
89#ifndef _WIN32
90/* GetRootPrefixSize_WINDOWS() is called in linux, but it parses path by windows rules.
91 It supports only paths system (linux) slash separators (STRING_PATH_SEPARATOR),
92 It doesn't parses paths with backslash (windows) separators.
93 "c:/dir/file" is supported.
94*/
95unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw();
96#endif
97
89#ifdef Z7_LONG_PATH 98#ifdef Z7_LONG_PATH
90 99
91const int kSuperPathType_UseOnlyMain = 0; 100const int kSuperPathType_UseOnlyMain = 0;
diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp
index c8b1709..a94a50f 100644
--- a/CPP/Windows/Registry.cpp
+++ b/CPP/Windows/Registry.cpp
@@ -78,7 +78,7 @@ LONG CKey::Close() throw()
78 return res; 78 return res;
79} 79}
80 80
81// win95, win98: deletes sunkey and all its subkeys 81// win95, win98: deletes subkey and all its subkeys
82// winNT to be deleted must not have subkeys 82// winNT to be deleted must not have subkeys
83LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() 83LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
84{ 84{
@@ -88,22 +88,36 @@ LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
88 88
89LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() 89LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
90{ 90{
91 CKey key;
92 LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
93 if (res != ERROR_SUCCESS)
94 return res;
95 FILETIME fileTime;
96 const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
97 DWORD size = kBufSize;
98 TCHAR buffer[kBufSize];
99 while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
100 { 91 {
101 res = key.RecurseDeleteKey(buffer); 92 CKey key;
93 LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
102 if (res != ERROR_SUCCESS) 94 if (res != ERROR_SUCCESS)
103 return res; 95 return res;
104 size = kBufSize; 96 FILETIME fileTime;
97 const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
98 TCHAR buffer[kBufSize];
99 // we use loop limit here for some unexpected code failure
100 for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++)
101 {
102 DWORD size = kBufSize;
103 // we always request starting item (index==0) in each iteration,
104 // because we remove starting item (index==0) in each loop iteration.
105 res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime);
106 if (res != ERROR_SUCCESS)
107 {
108 // possible return codes:
109 // ERROR_NO_MORE_ITEMS : are no more subkeys available
110 // ERROR_MORE_DATA : name buffer is too small
111 // we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error.
112 // if (res != ERROR_NO_MORE_ITEMS) return res;
113 break;
114 }
115 res = key.RecurseDeleteKey(buffer);
116 if (res != ERROR_SUCCESS)
117 return res;
118 }
119 // key.Close();
105 } 120 }
106 key.Close();
107 return DeleteSubKey(subKeyName); 121 return DeleteSubKey(subKeyName);
108} 122}
109 123
@@ -127,7 +141,7 @@ LONG CKey::DeleteValue(LPCWSTR name)
127 MY_ASSUME(_object != NULL); 141 MY_ASSUME(_object != NULL);
128 if (g_IsNT) 142 if (g_IsNT)
129 return ::RegDeleteValueW(_object, name); 143 return ::RegDeleteValueW(_object, name);
130 return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name)); 144 return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name));
131} 145}
132#endif 146#endif
133 147
@@ -143,12 +157,15 @@ LONG CKey::SetValue(LPCTSTR name, bool value) throw()
143 return SetValue(name, BoolToUINT32(value)); 157 return SetValue(name, BoolToUINT32(value));
144} 158}
145 159
160
161// value must be string that is NULL terminated
146LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() 162LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
147{ 163{
148 MYASSERT(value != NULL); 164 MYASSERT(value != NULL);
149 MY_ASSUME(_object != NULL); 165 MY_ASSUME(_object != NULL);
166 // note: RegSetValueEx supports (value == NULL), if (cbData == 0)
150 return RegSetValueEx(_object, name, 0, REG_SZ, 167 return RegSetValueEx(_object, name, 0, REG_SZ,
151 (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)); 168 (const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)));
152} 169}
153 170
154/* 171/*
@@ -156,7 +173,7 @@ LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
156{ 173{
157 MYASSERT(value != NULL); 174 MYASSERT(value != NULL);
158 MY_ASSUME(_object != NULL); 175 MY_ASSUME(_object != NULL);
159 return RegSetValueEx(_object, name, NULL, REG_SZ, 176 return RegSetValueEx(_object, name, 0, REG_SZ,
160 (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); 177 (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
161} 178}
162*/ 179*/
@@ -169,9 +186,10 @@ LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
169 MY_ASSUME(_object != NULL); 186 MY_ASSUME(_object != NULL);
170 if (g_IsNT) 187 if (g_IsNT)
171 return RegSetValueExW(_object, name, 0, REG_SZ, 188 return RegSetValueExW(_object, name, 0, REG_SZ,
172 (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t))); 189 (const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t)));
173 return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), 190 return SetValue(name == NULL ? NULL :
174 value == 0 ? 0 : (LPCSTR)GetSystemString(value)); 191 (LPCSTR)GetSystemString(name),
192 (LPCSTR)GetSystemString(value));
175} 193}
176 194
177#endif 195#endif
@@ -205,99 +223,137 @@ LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(
205 return res; 223 return res;
206} 224}
207 225
208LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw()
209{
210 DWORD type = 0;
211 DWORD count = sizeof(DWORD);
212 LONG res = RegQueryValueEx(_object, name, NULL, &type,
213 (LPBYTE)&value, &count);
214 MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD));
215 MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32)));
216 return res;
217}
218 226
219LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() 227LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw()
220{ 228{
221 UInt32 uintValue = BoolToUINT32(value); 229 DWORD type = 0;
222 LONG res = QueryValue(name, uintValue); 230 DWORD count = sizeof(value);
223 value = UINT32ToBool(uintValue); 231 UInt32 value2; // = value;
232 const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
233 if (res == ERROR_SUCCESS)
234 {
235 // ERROR_UNSUPPORTED_TYPE
236 if (count != sizeof(value) || type != REG_DWORD)
237 return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA;
238 value = value2;
239 }
224 return res; 240 return res;
225} 241}
226 242
227LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() 243LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw()
228{ 244{
229 UInt32 newVal; 245 DWORD type = 0;
230 LONG res = QueryValue(name, newVal); 246 DWORD count = sizeof(value);
247 UInt64 value2; // = value;
248 const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
231 if (res == ERROR_SUCCESS) 249 if (res == ERROR_SUCCESS)
232 value = newVal; 250 {
251 if (count != sizeof(value) || type != REG_QWORD)
252 return ERROR_UNSUPPORTED_TYPE;
253 value = value2;
254 }
233 return res; 255 return res;
234} 256}
235 257
236LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() 258LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw()
237{ 259{
238 bool newVal = false; 260 UInt32 uintValue;
239 LONG res = QueryValue(name, newVal); 261 const LONG res = GetValue_UInt32_IfOk(name, uintValue);
240 if (res == ERROR_SUCCESS) 262 if (res == ERROR_SUCCESS)
241 value = newVal; 263 value = UINT32ToBool(uintValue);
242 return res; 264 return res;
243} 265}
244 266
245LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() 267
246{
247 DWORD type = 0;
248 LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
249 MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
250 return res;
251}
252 268
253LONG CKey::QueryValue(LPCTSTR name, CSysString &value) 269LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
254{ 270{
255 value.Empty(); 271 value.Empty();
256 DWORD type = 0; 272 LONG res = ERROR_SUCCESS;
257 DWORD curSize = 0; 273 {
258 LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, &curSize); 274 // if we don't want multiple calls here,
259 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 275 // we can use big value (264) here.
260 return res; 276 // 3 is default available length in new string.
261 UInt32 curSize2 = curSize; 277 DWORD size_prev = 3 * sizeof(TCHAR);
262 res = QueryValue(name, value.GetBuf(curSize), curSize2); 278 // at least 2 attempts are required. But we use more attempts for cases,
263 if (curSize > curSize2) 279 // where string can be changed by anothner process
264 curSize = curSize2; 280 for (unsigned i = 0; i < 2 + 2; i++)
265 value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR)); 281 {
282 DWORD type = 0;
283 DWORD size = size_prev;
284 {
285 LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR));
286 res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size);
287 // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
288 }
289 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
290 {
291 if (type != REG_SZ && type != REG_EXPAND_SZ)
292 {
293 res = ERROR_UNSUPPORTED_TYPE;
294 size = 0;
295 }
296 }
297 else
298 size = 0;
299 if (size > size_prev)
300 {
301 size_prev = size;
302 size = 0;
303 res = ERROR_MORE_DATA;
304 }
305 value.ReleaseBuf_CalcLen(size / sizeof(TCHAR));
306 if (res != ERROR_MORE_DATA)
307 return res;
308 }
309 }
266 return res; 310 return res;
267} 311}
268 312
269 313
270#ifndef _UNICODE 314#ifndef _UNICODE
271 315
272LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
273{
274 DWORD type = 0;
275 LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
276 MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
277 return res;
278}
279
280LONG CKey::QueryValue(LPCWSTR name, UString &value) 316LONG CKey::QueryValue(LPCWSTR name, UString &value)
281{ 317{
282 value.Empty(); 318 value.Empty();
283 DWORD type = 0; 319 LONG res = ERROR_SUCCESS;
284 DWORD curSize = 0;
285 LONG res;
286 if (g_IsNT) 320 if (g_IsNT)
287 { 321 {
288 res = RegQueryValueExW(_object, name, NULL, &type, NULL, &curSize); 322 DWORD size_prev = 3 * sizeof(wchar_t);
289 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 323 for (unsigned i = 0; i < 2 + 2; i++)
290 return res; 324 {
291 UInt32 curSize2 = curSize; 325 DWORD type = 0;
292 res = QueryValue(name, value.GetBuf(curSize), curSize2); 326 DWORD size = size_prev;
293 if (curSize > curSize2) 327 {
294 curSize = curSize2; 328 LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t));
295 value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t)); 329 res = RegQueryValueExW(_object, name, NULL, &type,
330 size == 0 ? NULL : buf, &size);
331 }
332 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
333 {
334 if (type != REG_SZ && type != REG_EXPAND_SZ)
335 {
336 res = ERROR_UNSUPPORTED_TYPE;
337 size = 0;
338 }
339 }
340 else
341 size = 0;
342 if (size > size_prev)
343 {
344 size_prev = size;
345 size = 0;
346 res = ERROR_MORE_DATA;
347 }
348 value.ReleaseBuf_CalcLen(size / sizeof(wchar_t));
349 if (res != ERROR_MORE_DATA)
350 return res;
351 }
296 } 352 }
297 else 353 else
298 { 354 {
299 AString vTemp; 355 AString vTemp;
300 res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp); 356 res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp);
301 value = GetUnicodeString(vTemp); 357 value = GetUnicodeString(vTemp);
302 } 358 }
303 return res; 359 return res;
@@ -306,26 +362,43 @@ LONG CKey::QueryValue(LPCWSTR name, UString &value)
306#endif 362#endif
307 363
308 364
309LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() 365LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value)
310{ 366{
311 DWORD type = 0; 367 // value.Free();
312 LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); 368 DWORD size_prev = 0;
313 MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); 369 LONG res = ERROR_SUCCESS;
370 for (unsigned i = 0; i < 2 + 2; i++)
371 {
372 DWORD type = 0;
373 DWORD size = size_prev;
374 value.Alloc(size_prev);
375 res = QueryValueEx(name, &type, value.NonConstData(), &size);
376 // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
377 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
378 {
379 if (type != REG_BINARY)
380 {
381 res = ERROR_UNSUPPORTED_TYPE;
382 size = 0;
383 }
384 }
385 else
386 size = 0;
387 if (size > size_prev)
388 {
389 size_prev = size;
390 size = 0;
391 res = ERROR_MORE_DATA;
392 }
393 if (size < value.Size())
394 value.ChangeSize_KeepData(size, size);
395 if (res != ERROR_MORE_DATA)
396 return res;
397 }
314 return res; 398 return res;
315} 399}
316 400
317 401
318LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
319{
320 DWORD type = 0;
321 dataSize = 0;
322 LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize);
323 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
324 return res;
325 value.Alloc(dataSize);
326 return QueryValue(name, (BYTE *)value, dataSize);
327}
328
329LONG CKey::EnumKeys(CSysStringVector &keyNames) 402LONG CKey::EnumKeys(CSysStringVector &keyNames)
330{ 403{
331 keyNames.Clear(); 404 keyNames.Clear();
@@ -334,23 +407,23 @@ LONG CKey::EnumKeys(CSysStringVector &keyNames)
334 { 407 {
335 const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL 408 const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
336 FILETIME lastWriteTime; 409 FILETIME lastWriteTime;
337 UInt32 nameSize = kBufSize; 410 DWORD nameSize = kBufSize;
338 LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize), 411 const LONG res = ::RegEnumKeyEx(_object, index,
339 (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime); 412 keyName.GetBuf(kBufSize), &nameSize,
413 NULL, NULL, NULL, &lastWriteTime);
340 keyName.ReleaseBuf_CalcLen(kBufSize); 414 keyName.ReleaseBuf_CalcLen(kBufSize);
341 if (result == ERROR_NO_MORE_ITEMS) 415 if (res == ERROR_NO_MORE_ITEMS)
342 break; 416 return ERROR_SUCCESS;
343 if (result != ERROR_SUCCESS) 417 if (res != ERROR_SUCCESS)
344 return result; 418 return res;
345 keyNames.Add(keyName); 419 keyNames.Add(keyName);
346 } 420 }
347 return ERROR_SUCCESS;
348} 421}
349 422
423
350LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) 424LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
351{ 425{
352 size_t numChars = 0; 426 size_t numChars = 0;
353
354 unsigned i; 427 unsigned i;
355 428
356 for (i = 0; i < strings.Size(); i++) 429 for (i = 0; i < strings.Size(); i++)
@@ -362,10 +435,11 @@ LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
362 for (i = 0; i < strings.Size(); i++) 435 for (i = 0; i < strings.Size(); i++)
363 { 436 {
364 const UString &s = strings[i]; 437 const UString &s = strings[i];
365 size_t size = s.Len() + 1; 438 const size_t size = s.Len() + 1;
366 wmemcpy(buffer + pos, s, size); 439 wmemcpy(buffer + pos, s, size);
367 pos += size; 440 pos += size;
368 } 441 }
442 // if (pos != numChars) return E_FAIL;
369 return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); 443 return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
370} 444}
371 445
@@ -373,20 +447,18 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
373{ 447{
374 strings.Clear(); 448 strings.Clear();
375 CByteBuffer buffer; 449 CByteBuffer buffer;
376 UInt32 dataSize = 0; 450 const LONG res = QueryValue_Binary(valueName, buffer);
377 const LONG res = QueryValue(valueName, buffer, dataSize);
378 if (res != ERROR_SUCCESS) 451 if (res != ERROR_SUCCESS)
379 return res; 452 return res;
380 if (dataSize > buffer.Size()) 453 const size_t dataSize = buffer.Size();
381 return E_FAIL; 454 if (dataSize % sizeof(wchar_t))
382 if (dataSize % sizeof(wchar_t) != 0) 455 return ERROR_INVALID_DATA;
383 return E_FAIL;
384
385 const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; 456 const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer;
386 const size_t numChars = dataSize / sizeof(wchar_t); 457 const size_t numChars = dataSize / sizeof(wchar_t);
458 // we can check that all names are finished
459 // if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA;
387 size_t prev = 0; 460 size_t prev = 0;
388 UString s; 461 UString s;
389
390 for (size_t i = 0; i < numChars; i++) 462 for (size_t i = 0; i < numChars; i++)
391 { 463 {
392 if (data[i] == 0) 464 if (data[i] == 0)
@@ -396,7 +468,6 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
396 prev = i + 1; 468 prev = i + 1;
397 } 469 }
398 } 470 }
399
400 return res; 471 return res;
401} 472}
402 473
diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h
index 0d3b4fc..74ee919 100644
--- a/CPP/Windows/Registry.h
+++ b/CPP/Windows/Registry.h
@@ -14,6 +14,13 @@ LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
14class CKey 14class CKey
15{ 15{
16 HKEY _object; 16 HKEY _object;
17
18 LONG QueryValueEx(LPCTSTR lpValueName, LPDWORD lpType,
19 LPBYTE lpData, LPDWORD lpcbData)
20 {
21 return RegQueryValueEx(_object, lpValueName, NULL, lpType, lpData, lpcbData);
22 }
23
17public: 24public:
18 CKey(): _object(NULL) {} 25 CKey(): _object(NULL) {}
19 ~CKey() { Close(); } 26 ~CKey() { Close(); }
@@ -22,13 +29,14 @@ public:
22 void Attach(HKEY key) { _object = key; } 29 void Attach(HKEY key) { _object = key; }
23 HKEY Detach() 30 HKEY Detach()
24 { 31 {
25 HKEY key = _object; 32 const HKEY key = _object;
26 _object = NULL; 33 _object = NULL;
27 return key; 34 return key;
28 } 35 }
29 36
30 LONG Create(HKEY parentKey, LPCTSTR keyName, 37 LONG Create(HKEY parentKey, LPCTSTR keyName,
31 LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE, 38 LPTSTR keyClass = REG_NONE,
39 DWORD options = REG_OPTION_NON_VOLATILE,
32 REGSAM accessMask = KEY_ALL_ACCESS, 40 REGSAM accessMask = KEY_ALL_ACCESS,
33 LPSECURITY_ATTRIBUTES securityAttributes = NULL, 41 LPSECURITY_ATTRIBUTES securityAttributes = NULL,
34 LPDWORD disposition = NULL) throw(); 42 LPDWORD disposition = NULL) throw();
@@ -40,18 +48,18 @@ public:
40 LONG RecurseDeleteKey(LPCTSTR subKeyName) throw(); 48 LONG RecurseDeleteKey(LPCTSTR subKeyName) throw();
41 49
42 LONG DeleteValue(LPCTSTR name) throw(); 50 LONG DeleteValue(LPCTSTR name) throw();
43 #ifndef _UNICODE 51#ifndef _UNICODE
44 LONG DeleteValue(LPCWSTR name); 52 LONG DeleteValue(LPCWSTR name);
45 #endif 53#endif
46 54
47 LONG SetValue(LPCTSTR valueName, UInt32 value) throw(); 55 LONG SetValue(LPCTSTR valueName, UInt32 value) throw();
48 LONG SetValue(LPCTSTR valueName, bool value) throw(); 56 LONG SetValue(LPCTSTR valueName, bool value) throw();
49 LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw(); 57 LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw();
50 // LONG SetValue(LPCTSTR valueName, const CSysString &value); 58 // LONG SetValue(LPCTSTR valueName, const CSysString &value);
51 #ifndef _UNICODE 59#ifndef _UNICODE
52 LONG SetValue(LPCWSTR name, LPCWSTR value); 60 LONG SetValue(LPCWSTR name, LPCWSTR value);
53 // LONG SetValue(LPCWSTR name, const UString &value); 61 // LONG SetValue(LPCWSTR name, const UString &value);
54 #endif 62#endif
55 63
56 LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw(); 64 LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw();
57 65
@@ -60,21 +68,25 @@ public:
60 68
61 LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(); 69 LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw();
62 70
63 LONG QueryValue(LPCTSTR name, UInt32 &value) throw(); 71 // GetValue_[type]_IfOk():
64 LONG QueryValue(LPCTSTR name, bool &value) throw(); 72 // if (return_result == ERROR_SUCCESS), (value) variable was read from registry
65 LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize) throw(); 73 // if (return_result != ERROR_SUCCESS), (value) variable was not changed
66 LONG QueryValue(LPCTSTR name, CSysString &value); 74 LONG GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw();
67 75 LONG GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw();
68 LONG GetValue_IfOk(LPCTSTR name, UInt32 &value) throw(); 76 LONG GetValue_bool_IfOk(LPCTSTR name, bool &value) throw();
69 LONG GetValue_IfOk(LPCTSTR name, bool &value) throw();
70 77
71 #ifndef _UNICODE 78 // QueryValue():
72 LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize); 79 // if (return_result == ERROR_SUCCESS), (value) string was read from registry
80 // if (return_result != ERROR_SUCCESS), (value) string was cleared
81 LONG QueryValue(LPCTSTR name, CSysString &value);
82#ifndef _UNICODE
73 LONG QueryValue(LPCWSTR name, UString &value); 83 LONG QueryValue(LPCWSTR name, UString &value);
74 #endif 84#endif
75 85
76 LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize) throw(); 86 // QueryValue_Binary():
77 LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize); 87 // if (return_result == ERROR_SUCCESS), (value) buffer was read from registry (BINARY data)
88 // if (return_result != ERROR_SUCCESS), (value) buffer was cleared
89 LONG QueryValue_Binary(LPCTSTR name, CByteBuffer &value);
78 90
79 LONG EnumKeys(CSysStringVector &keyNames); 91 LONG EnumKeys(CSysStringVector &keyNames);
80}; 92};
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp
index 03c8988..4745785 100644
--- a/CPP/Windows/System.cpp
+++ b/CPP/Windows/System.cpp
@@ -25,6 +25,69 @@ namespace NSystem {
25 25
26#ifdef _WIN32 26#ifdef _WIN32
27 27
28/*
29note: returned value in 32-bit version can be limited by value 32.
30 while 64-bit version returns full value.
31GetMaximumProcessorCount(groupNumber) can return higher value than
32GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added.
33*/
34// typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber);
35typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber);
36typedef WORD (WINAPI *Func_GetActiveProcessorGroupCount)(VOID);
37/*
38#if 0 && defined(ALL_PROCESSOR_GROUPS)
39#define MY_ALL_PROCESSOR_GROUPS ALL_PROCESSOR_GROUPS
40#else
41#define MY_ALL_PROCESSOR_GROUPS 0xffff
42#endif
43*/
44
45Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
46
47bool CCpuGroups::Load()
48{
49 NumThreadsTotal = 0;
50 GroupSizes.Clear();
51 const HMODULE hmodule = ::GetModuleHandleA("kernel32.dll");
52 // Is_Win11_Groups = GetProcAddress(hmodule, "SetThreadSelectedCpuSetMasks") != NULL;
53 const
54 Func_GetActiveProcessorGroupCount
55 fn_GetActiveProcessorGroupCount = Z7_GET_PROC_ADDRESS(
56 Func_GetActiveProcessorGroupCount, hmodule,
57 "GetActiveProcessorGroupCount");
58 const
59 Func_GetActiveProcessorCount
60 fn_GetActiveProcessorCount = Z7_GET_PROC_ADDRESS(
61 Func_GetActiveProcessorCount, hmodule,
62 "GetActiveProcessorCount");
63 if (!fn_GetActiveProcessorGroupCount ||
64 !fn_GetActiveProcessorCount)
65 return false;
66
67 const unsigned numGroups = fn_GetActiveProcessorGroupCount();
68 if (numGroups == 0)
69 return false;
70 UInt32 sum = 0;
71 for (unsigned i = 0; i < numGroups; i++)
72 {
73 const UInt32 num = fn_GetActiveProcessorCount((WORD)i);
74 /*
75 if (num == 0)
76 {
77 // it means error
78 // but is it possible that some group is empty by some reason?
79 // GroupSizes.Clear();
80 // return false;
81 }
82 */
83 sum += num;
84 GroupSizes.Add(num);
85 }
86 NumThreadsTotal = sum;
87 // NumThreadsTotal = fn_GetActiveProcessorCount(MY_ALL_PROCESSOR_GROUPS);
88 return true;
89}
90
28UInt32 CountAffinity(DWORD_PTR mask) 91UInt32 CountAffinity(DWORD_PTR mask)
29{ 92{
30 UInt32 num = 0; 93 UInt32 num = 0;
@@ -38,31 +101,62 @@ UInt32 CountAffinity(DWORD_PTR mask)
38 101
39BOOL CProcessAffinity::Get() 102BOOL CProcessAffinity::Get()
40{ 103{
41 #ifndef UNDER_CE 104 IsGroupMode = false;
42 return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); 105 Groups.Load();
43 #else 106 // SetThreadAffinityMask(GetCurrentThread(), 1);
44 return FALSE; 107 // SetProcessAffinityMask(GetCurrentProcess(), 1);
45 #endif 108 BOOL res = GetProcessAffinityMask(GetCurrentProcess(),
109 &processAffinityMask, &systemAffinityMask);
110 /* DOCs: On a system with more than 64 processors, if the threads
111 of the calling process are in a single processor group, the
112 function sets the variables pointed to by lpProcessAffinityMask
113 and lpSystemAffinityMask to the process affinity mask and the
114 processor mask of active logical processors for that group.
115 If the calling process contains threads in multiple groups,
116 the function returns zero for both affinity masks
117
118 note: tested in Win10: GetProcessAffinityMask() doesn't return 0
119 in (processAffinityMask) and (systemAffinityMask) masks.
120 We need to test it in Win11: how to get mask==0 from GetProcessAffinityMask()?
121 */
122 if (!res)
123 {
124 processAffinityMask = 0;
125 systemAffinityMask = 0;
126 }
127 if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
128 if (// !res ||
129 processAffinityMask == 0 || // to support case described in DOCs and for (!res) case
130 processAffinityMask == systemAffinityMask) // for default nonchanged affinity
131 {
132 // we set IsGroupMode only if processAffinity is default (not changed).
133 res = TRUE;
134 IsGroupMode = true;
135 }
136 return res;
46} 137}
47 138
48 139
140UInt32 CProcessAffinity::Load_and_GetNumberOfThreads()
141{
142 if (Get())
143 {
144 const UInt32 numProcessors = GetNumProcessThreads();
145 if (numProcessors)
146 return numProcessors;
147 }
148 SYSTEM_INFO systemInfo;
149 GetSystemInfo(&systemInfo);
150 // the number of logical processors in the current group
151 return systemInfo.dwNumberOfProcessors;
152}
153
49UInt32 GetNumberOfProcessors() 154UInt32 GetNumberOfProcessors()
50{ 155{
51 // We need to know how many threads we can use. 156 // We need to know how many threads we can use.
52 // By default the process is assigned to one group. 157 // By default the process is assigned to one group.
53 // So we get the number of logical processors (threads)
54 // assigned to current process in the current group.
55 // Group size can be smaller than total number logical processors, for exammple, 2x36
56
57 CProcessAffinity pa; 158 CProcessAffinity pa;
58 159 return pa.Load_and_GetNumberOfThreads();
59 if (pa.Get() && pa.processAffinityMask != 0)
60 return pa.GetNumProcessThreads();
61
62 SYSTEM_INFO systemInfo;
63 GetSystemInfo(&systemInfo);
64 // the number of logical processors in the current group
65 return (UInt32)systemInfo.dwNumberOfProcessors;
66} 160}
67 161
68#else 162#else
@@ -142,9 +236,9 @@ typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer);
142#endif // !UNDER_CE 236#endif // !UNDER_CE
143 237
144 238
145bool GetRamSize(UInt64 &size) 239bool GetRamSize(size_t &size)
146{ 240{
147 size = (UInt64)(sizeof(size_t)) << 29; 241 size = (size_t)sizeof(size_t) << 29;
148 242
149 #ifndef UNDER_CE 243 #ifndef UNDER_CE
150 MY_MEMORYSTATUSEX stat; 244 MY_MEMORYSTATUSEX stat;
@@ -167,11 +261,23 @@ bool GetRamSize(UInt64 &size)
167 "GlobalMemoryStatusEx"); 261 "GlobalMemoryStatusEx");
168 if (fn && fn(&stat)) 262 if (fn && fn(&stat))
169 { 263 {
170 size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); 264 // (MY_MEMORYSTATUSEX::ullTotalVirtual) < 4 GiB in 32-bit mode
265 size_t size2 = (size_t)0 - 1;
266 if (size2 > stat.ullTotalPhys)
267 size2 = (size_t)stat.ullTotalPhys;
268 if (size2 > stat.ullTotalVirtual)
269 size2 = (size_t)stat.ullTotalVirtual;
270 size = size2;
171 return true; 271 return true;
172 } 272 }
173 #endif 273 #endif
174 274
275 // On computers with more than 4 GB of memory:
276 // new docs : GlobalMemoryStatus can report (-1) value to indicate an overflow.
277 // some old docs : GlobalMemoryStatus can report (modulo 4 GiB) value.
278 // (for example, if 5 GB total memory, it could report 1 GB).
279 // We don't want to get (modulo 4 GiB) value.
280 // So we use GlobalMemoryStatusEx() instead.
175 { 281 {
176 MEMORYSTATUS stat2; 282 MEMORYSTATUS stat2;
177 stat2.dwLength = sizeof(stat2); 283 stat2.dwLength = sizeof(stat2);
@@ -187,9 +293,11 @@ bool GetRamSize(UInt64 &size)
187// POSIX 293// POSIX
188// #include <stdio.h> 294// #include <stdio.h>
189 295
190bool GetRamSize(UInt64 &size) 296bool GetRamSize(size_t &size)
191{ 297{
192 size = (UInt64)(sizeof(size_t)) << 29; 298 UInt64 size64;
299 size = (size_t)sizeof(size_t) << 29;
300 size64 = size;
193 301
194#if defined(__APPLE__) || defined(__DragonFly__) || \ 302#if defined(__APPLE__) || defined(__DragonFly__) || \
195 defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 303 defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
@@ -215,7 +323,7 @@ bool GetRamSize(UInt64 &size)
215 // we use strict check (size_sys == sizeof(val)) for returned value 323 // we use strict check (size_sys == sizeof(val)) for returned value
216 // because big-endian encoding is possible: 324 // because big-endian encoding is possible:
217 if (res == 0 && size_sys == sizeof(val) && val) 325 if (res == 0 && size_sys == sizeof(val) && val)
218 size = val; 326 size64 = val;
219 else 327 else
220 { 328 {
221 uint32_t val32 = 0; 329 uint32_t val32 = 0;
@@ -223,12 +331,12 @@ bool GetRamSize(UInt64 &size)
223 res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); 331 res = sysctl(mib, 2, &val32, &size_sys, NULL, 0);
224 // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); 332 // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno);
225 if (res == 0 && size_sys == sizeof(val32) && val32) 333 if (res == 0 && size_sys == sizeof(val32) && val32)
226 size = val32; 334 size64 = val32;
227 } 335 }
228 336
229 #elif defined(_AIX) 337 #elif defined(_AIX)
230 #if defined(_SC_AIX_REALMEM) // AIX 338 #if defined(_SC_AIX_REALMEM) // AIX
231 size = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; 339 size64 = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024;
232 #endif 340 #endif
233 #elif 0 || defined(__sun) 341 #elif 0 || defined(__sun)
234 #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) 342 #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
@@ -240,7 +348,7 @@ bool GetRamSize(UInt64 &size)
240 // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); 348 // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages);
241 // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); 349 // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size);
242 if (phys_pages != -1 && page_size != -1) 350 if (phys_pages != -1 && page_size != -1)
243 size = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; 351 size64 = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size;
244 } 352 }
245 #endif 353 #endif
246 #elif defined(__gnu_hurd__) 354 #elif defined(__gnu_hurd__)
@@ -253,7 +361,7 @@ bool GetRamSize(UInt64 &size)
253 struct sysinfo info; 361 struct sysinfo info;
254 if (::sysinfo(&info) != 0) 362 if (::sysinfo(&info) != 0)
255 return false; 363 return false;
256 size = (UInt64)info.mem_unit * info.totalram; 364 size64 = (UInt64)info.mem_unit * info.totalram;
257 /* 365 /*
258 printf("\n mem_unit = %lld", (UInt64)info.mem_unit); 366 printf("\n mem_unit = %lld", (UInt64)info.mem_unit);
259 printf("\n totalram = %lld", (UInt64)info.totalram); 367 printf("\n totalram = %lld", (UInt64)info.totalram);
@@ -262,10 +370,9 @@ bool GetRamSize(UInt64 &size)
262 370
263 #endif 371 #endif
264 372
265 const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1); 373 size = (size_t)1 << (sizeof(size_t) * 8 - 1);
266 if (size > kLimit) 374 if (size > size64)
267 size = kLimit; 375 size = (size_t)size64;
268
269 return true; 376 return true;
270} 377}
271 378
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h
index b17111c..0c80373 100644
--- a/CPP/Windows/System.h
+++ b/CPP/Windows/System.h
@@ -9,6 +9,7 @@
9#endif 9#endif
10 10
11#include "../Common/MyTypes.h" 11#include "../Common/MyTypes.h"
12#include "../Common/MyVector.h"
12#include "../Common/MyWindows.h" 13#include "../Common/MyWindows.h"
13 14
14namespace NWindows { 15namespace NWindows {
@@ -16,6 +17,34 @@ namespace NSystem {
16 17
17#ifdef _WIN32 18#ifdef _WIN32
18 19
20struct CCpuGroups
21{
22 CRecordVector<UInt32> GroupSizes;
23 UInt32 NumThreadsTotal; // sum of threads in all groups
24 // bool Is_Win11_Groups; // useless
25
26 void Get_GroupSize_Min_Max(UInt32 &minSize, UInt32 &maxSize) const
27 {
28 unsigned num = GroupSizes.Size();
29 UInt32 minSize2 = 0, maxSize2 = 0;
30 if (num)
31 {
32 minSize2 = (UInt32)0 - 1;
33 do
34 {
35 const UInt32 v = GroupSizes[--num];
36 if (minSize2 > v) minSize2 = v;
37 if (maxSize2 < v) maxSize2 = v;
38 }
39 while (num);
40 }
41 minSize = minSize2;
42 maxSize = maxSize2;
43 }
44 bool Load();
45 CCpuGroups(): NumThreadsTotal(0) {}
46};
47
19UInt32 CountAffinity(DWORD_PTR mask); 48UInt32 CountAffinity(DWORD_PTR mask);
20 49
21struct CProcessAffinity 50struct CProcessAffinity
@@ -25,14 +54,28 @@ struct CProcessAffinity
25 DWORD_PTR processAffinityMask; 54 DWORD_PTR processAffinityMask;
26 DWORD_PTR systemAffinityMask; 55 DWORD_PTR systemAffinityMask;
27 56
57 CCpuGroups Groups;
58 bool IsGroupMode;
59 /*
60 IsGroupMode == true, if
61 Groups.GroupSizes.Size() > 1) && { dafalt affinity was not changed }
62 IsGroupMode == false, if single group or affinity was changed
63 */
64
65 UInt32 Load_and_GetNumberOfThreads();
66
28 void InitST() 67 void InitST()
29 { 68 {
30 // numProcessThreads = 1; 69 // numProcessThreads = 1;
31 // numSysThreads = 1; 70 // numSysThreads = 1;
32 processAffinityMask = 1; 71 processAffinityMask = 1;
33 systemAffinityMask = 1; 72 systemAffinityMask = 1;
73 IsGroupMode = false;
74 // Groups.NumThreadsTotal = 0;
75 // Groups.Is_Win11_Groups = false;
34 } 76 }
35 77
78/*
36 void CpuZero() 79 void CpuZero()
37 { 80 {
38 processAffinityMask = 0; 81 processAffinityMask = 0;
@@ -42,9 +85,23 @@ struct CProcessAffinity
42 { 85 {
43 processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); 86 processAffinityMask |= ((DWORD_PTR)1 << cpuIndex);
44 } 87 }
88*/
45 89
46 UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } 90 UInt32 GetNumProcessThreads() const
47 UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } 91 {
92 if (IsGroupMode)
93 return Groups.NumThreadsTotal;
94 // IsGroupMode == false
95 // so we don't want to use groups
96 // we return number of threads in default primary group:
97 return CountAffinity(processAffinityMask);
98 }
99 UInt32 GetNumSystemThreads() const
100 {
101 if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
102 return Groups.NumThreadsTotal;
103 return CountAffinity(systemAffinityMask);
104 }
48 105
49 BOOL Get(); 106 BOOL Get();
50 107
@@ -122,7 +179,7 @@ struct CProcessAffinity
122 179
123UInt32 GetNumberOfProcessors(); 180UInt32 GetNumberOfProcessors();
124 181
125bool GetRamSize(UInt64 &size); // returns false, if unknown ram size 182bool GetRamSize(size_t &size); // returns false, if unknown ram size
126 183
127unsigned long Get_File_OPEN_MAX(); 184unsigned long Get_File_OPEN_MAX();
128unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks(); 185unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks();
diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp
index cfc6a90..35846e0 100644
--- a/CPP/Windows/SystemInfo.cpp
+++ b/CPP/Windows/SystemInfo.cpp
@@ -530,6 +530,28 @@ struct CCpuName
530 AString Microcode; 530 AString Microcode;
531 AString LargePages; 531 AString LargePages;
532 532
533#ifdef _WIN32
534 UInt32 MHz;
535
536#ifdef MY_CPU_ARM64
537#define Z7_SYS_INFO_SHOW_ARM64_REGS
538#endif
539#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS
540 bool Arm64_ISAR0_EL1_Defined;
541 UInt64 Arm64_ISAR0_EL1;
542#endif
543#endif
544
545#ifdef _WIN32
546 CCpuName():
547 MHz(0)
548#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS
549 , Arm64_ISAR0_EL1_Defined(false)
550 , Arm64_ISAR0_EL1(0)
551#endif
552 {}
553#endif
554
533 void Fill(); 555 void Fill();
534 556
535 void Get_Revision_Microcode_LargePages(AString &s) 557 void Get_Revision_Microcode_LargePages(AString &s)
@@ -537,16 +559,46 @@ struct CCpuName
537 s.Empty(); 559 s.Empty();
538 AddBracedString(s, Revision); 560 AddBracedString(s, Revision);
539 AddBracedString(s, Microcode); 561 AddBracedString(s, Microcode);
540 s.Add_OptSpaced(LargePages); 562#ifdef _WIN32
563 if (MHz != 0)
564 {
565 s.Add_Space_if_NotEmpty();
566 s.Add_UInt32(MHz);
567 s += " MHz";
568 }
569#endif
570 if (!LargePages.IsEmpty())
571 s.Add_OptSpaced(LargePages);
572 }
573
574#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS
575 void Get_Registers(AString &s)
576 {
577 if (Arm64_ISAR0_EL1_Defined)
578 {
579 // ID_AA64ISAR0_EL1
580 s.Add_OptSpaced("cp4030:");
581 PrintHex(s, Arm64_ISAR0_EL1);
582 {
583 const unsigned sha2 = ((unsigned)(Arm64_ISAR0_EL1 >> 12) & 0xf) - 1;
584 if (sha2 < 2)
585 {
586 s += ":SHA256";
587 if (sha2)
588 s += ":SHA512";
589 }
590 }
591 }
541 } 592 }
593#endif
542}; 594};
543 595
544void CCpuName::Fill() 596void CCpuName::Fill()
545{ 597{
546 CpuName.Empty(); 598 // CpuName.Empty();
547 Revision.Empty(); 599 // Revision.Empty();
548 Microcode.Empty(); 600 // Microcode.Empty();
549 LargePages.Empty(); 601 // LargePages.Empty();
550 602
551 AString &s = CpuName; 603 AString &s = CpuName;
552 604
@@ -600,21 +652,32 @@ void CCpuName::Fill()
600 Revision += GetAnsiString(name); 652 Revision += GetAnsiString(name);
601 } 653 }
602 } 654 }
655#ifdef _WIN32
656 key.GetValue_UInt32_IfOk(TEXT("~MHz"), MHz);
657#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS
658/*
659mapping arm64 registers to Windows registry:
660CP 4000: MIDR_EL1
661CP 4020: ID_AA64PFR0_EL1
662CP 4021: ID_AA64PFR1_EL1
663CP 4028: ID_AA64DFR0_EL1
664CP 4029: ID_AA64DFR1_EL1
665CP 402C: ID_AA64AFR0_EL1
666CP 402D: ID_AA64AFR1_EL1
667CP 4030: ID_AA64ISAR0_EL1
668CP 4031: ID_AA64ISAR1_EL1
669CP 4038: ID_AA64MMFR0_EL1
670CP 4039: ID_AA64MMFR1_EL1
671CP 403A: ID_AA64MMFR2_EL1
672*/
673 if (key.GetValue_UInt64_IfOk(TEXT("CP 4030"), Arm64_ISAR0_EL1) == ERROR_SUCCESS)
674 Arm64_ISAR0_EL1_Defined = true;
675#endif
676#endif
603 LONG res[2]; 677 LONG res[2];
604 CByteBuffer bufs[2]; 678 CByteBuffer bufs[2];
605 { 679 res[0] = key.QueryValue_Binary(TEXT("Previous Update Revision"), bufs[0]);
606 for (unsigned i = 0; i < 2; i++) 680 res[1] = key.QueryValue_Binary(TEXT("Update Revision"), bufs[1]);
607 {
608 UInt32 size = 0;
609 res[i] = key.QueryValue(i == 0 ?
610 TEXT("Previous Update Revision") :
611 TEXT("Update Revision"),
612 bufs[i], size);
613 if (res[i] == ERROR_SUCCESS)
614 if (size != bufs[i].Size())
615 res[i] = ERROR_SUCCESS + 1;
616 }
617 }
618 if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) 681 if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS)
619 { 682 {
620 for (unsigned i = 0; i < 2; i++) 683 for (unsigned i = 0; i < 2; i++)
@@ -747,9 +810,18 @@ void AddCpuFeatures(AString &s)
747 unsigned long h = MY_getauxval(AT_HWCAP); 810 unsigned long h = MY_getauxval(AT_HWCAP);
748 PrintHex(s, h); 811 PrintHex(s, h);
749 #ifdef MY_CPU_ARM64 812 #ifdef MY_CPU_ARM64
813#ifndef HWCAP_SHA3
814#define HWCAP_SHA3 (1 << 17)
815#endif
816#ifndef HWCAP_SHA512
817#define HWCAP_SHA512 (1 << 21)
818// #pragma message("=== HWCAP_SHA512 define === ")
819#endif
750 if (h & HWCAP_CRC32) s += ":CRC32"; 820 if (h & HWCAP_CRC32) s += ":CRC32";
751 if (h & HWCAP_SHA1) s += ":SHA1"; 821 if (h & HWCAP_SHA1) s += ":SHA1";
752 if (h & HWCAP_SHA2) s += ":SHA2"; 822 if (h & HWCAP_SHA2) s += ":SHA2";
823 if (h & HWCAP_SHA3) s += ":SHA3";
824 if (h & HWCAP_SHA512) s += ":SHA512";
753 if (h & HWCAP_AES) s += ":AES"; 825 if (h & HWCAP_AES) s += ":AES";
754 if (h & HWCAP_ASIMD) s += ":ASIMD"; 826 if (h & HWCAP_ASIMD) s += ":ASIMD";
755 #elif defined(MY_CPU_ARM) 827 #elif defined(MY_CPU_ARM)
@@ -908,13 +980,18 @@ void GetSystemInfoText(AString &sRes)
908 } 980 }
909 } 981 }
910 { 982 {
911 AString s; 983 AString s, registers;
912 GetCpuName_MultiLine(s); 984 GetCpuName_MultiLine(s, registers);
913 if (!s.IsEmpty()) 985 if (!s.IsEmpty())
914 { 986 {
915 sRes += s; 987 sRes += s;
916 sRes.Add_LF(); 988 sRes.Add_LF();
917 } 989 }
990 if (!registers.IsEmpty())
991 {
992 sRes += registers;
993 sRes.Add_LF();
994 }
918 } 995 }
919 /* 996 /*
920 #ifdef MY_CPU_X86_OR_AMD64 997 #ifdef MY_CPU_X86_OR_AMD64
@@ -932,8 +1009,8 @@ void GetSystemInfoText(AString &sRes)
932} 1009}
933 1010
934 1011
935void GetCpuName_MultiLine(AString &s); 1012void GetCpuName_MultiLine(AString &s, AString &registers);
936void GetCpuName_MultiLine(AString &s) 1013void GetCpuName_MultiLine(AString &s, AString &registers)
937{ 1014{
938 CCpuName cpuName; 1015 CCpuName cpuName;
939 cpuName.Fill(); 1016 cpuName.Fill();
@@ -945,6 +1022,10 @@ void GetCpuName_MultiLine(AString &s)
945 s.Add_LF(); 1022 s.Add_LF();
946 s += s2; 1023 s += s2;
947 } 1024 }
1025 registers.Empty();
1026#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS
1027 cpuName.Get_Registers(registers);
1028#endif
948} 1029}
949 1030
950 1031
diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h
index c2e2e3b..4601685 100644
--- a/CPP/Windows/SystemInfo.h
+++ b/CPP/Windows/SystemInfo.h
@@ -6,7 +6,7 @@
6#include "../Common/MyString.h" 6#include "../Common/MyString.h"
7 7
8 8
9void GetCpuName_MultiLine(AString &s); 9void GetCpuName_MultiLine(AString &s, AString &registers);
10 10
11void GetOsInfoText(AString &sRes); 11void GetOsInfoText(AString &sRes);
12void GetSystemInfoText(AString &s); 12void GetSystemInfoText(AString &s);
diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h
index d72f64c..75c1616 100644
--- a/CPP/Windows/Thread.h
+++ b/CPP/Windows/Thread.h
@@ -26,8 +26,10 @@ public:
26 { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } 26 { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); }
27 WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) 27 WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet)
28 { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } 28 { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); }
29 29
30 #ifdef _WIN32 30#ifdef _WIN32
31 WRes Create_With_Group(THREAD_FUNC_TYPE startAddress, LPVOID param, unsigned group, CAffinityMask affinity = 0)
32 { return Thread_Create_With_Group(&thread, startAddress, param, group, affinity); }
31 operator HANDLE() { return thread; } 33 operator HANDLE() { return thread; }
32 void Attach(HANDLE handle) { thread = handle; } 34 void Attach(HANDLE handle) { thread = handle; }
33 HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } 35 HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
@@ -36,7 +38,7 @@ public:
36 bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } 38 bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
37 int GetPriority() { return ::GetThreadPriority(thread); } 39 int GetPriority() { return ::GetThreadPriority(thread); }
38 bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } 40 bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
39 #endif 41#endif
40}; 42};
41 43
42} 44}
diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp
index bbd79ba..4e3bc59 100644
--- a/CPP/Windows/TimeUtils.cpp
+++ b/CPP/Windows/TimeUtils.cpp
@@ -258,8 +258,9 @@ bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
258 FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, 258 FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0,
259 Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, 259 Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3,
260 Cygwin 2.9, mingw, MSVC 14, Android 9.0. 260 Cygwin 2.9, mingw, MSVC 14, Android 9.0.
261 Android NDK defines TIME_UTC but doesn't have the timespec_get().
261*/ 262*/
262#if defined(TIME_UTC) 263#if defined(TIME_UTC) && !defined(__ANDROID__)
263#define ZIP7_USE_timespec_get 264#define ZIP7_USE_timespec_get
264// #pragma message("ZIP7_USE_timespec_get") 265// #pragma message("ZIP7_USE_timespec_get")
265#elif defined(CLOCK_REALTIME) 266#elif defined(CLOCK_REALTIME)