aboutsummaryrefslogtreecommitdiff
path: root/CPP
diff options
context:
space:
mode:
Diffstat (limited to 'CPP')
-rw-r--r--CPP/7zip/7zip_gcc.mak6
-rw-r--r--CPP/7zip/Archive/7z/7zCompressionMode.h2
-rw-r--r--CPP/7zip/Archive/7z/7zHandlerOut.cpp30
-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.h33
-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/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.cpp13
-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.cpp23
-rw-r--r--CPP/7zip/Archive/XzHandler.cpp14
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp47
-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.mak2
-rw-r--r--CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp4
-rw-r--r--CPP/7zip/Common/InBuffer.h10
-rw-r--r--CPP/7zip/Common/MethodProps.cpp34
-rw-r--r--CPP/7zip/Common/MethodProps.h6
-rw-r--r--CPP/7zip/Common/OutBuffer.h29
-rw-r--r--CPP/7zip/Compress/BZip2Const.h2
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.cpp700
-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/ICoder.h3
-rw-r--r--CPP/7zip/Sort.mak6
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp60
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp720
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.h68
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp87
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp55
-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.cpp313
-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/Update.cpp4
-rw-r--r--CPP/7zip/UI/Common/Update.h2
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp110
-rw-r--r--CPP/7zip/UI/Console/Main.cpp9
-rw-r--r--CPP/7zip/UI/Console/makefile2
-rw-r--r--CPP/7zip/UI/Explorer/makefile2
-rw-r--r--CPP/7zip/UI/Far/Plugin.cpp9
-rw-r--r--CPP/7zip/UI/Far/makefile2
-rw-r--r--CPP/7zip/UI/FileManager/FM.cpp2
-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/Panel.h4
-rw-r--r--CPP/7zip/UI/FileManager/PanelCopy.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/PanelFolderChange.cpp14
-rw-r--r--CPP/7zip/UI/FileManager/PanelOperations.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/RootFolder.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/makefile2
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.cpp4
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.rc2
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp23
-rw-r--r--CPP/7zip/UI/GUI/makefile3
-rw-r--r--CPP/Build.mak8
-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.cpp2
-rw-r--r--CPP/Common/Wildcard.cpp13
-rw-r--r--CPP/Windows/FileDir.cpp29
-rw-r--r--CPP/Windows/FileDir.h5
-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.cpp71
-rw-r--r--CPP/Windows/FileName.h13
-rw-r--r--CPP/Windows/System.cpp128
-rw-r--r--CPP/Windows/System.h61
-rw-r--r--CPP/Windows/Thread.h8
-rw-r--r--CPP/Windows/TimeUtils.cpp3
96 files changed, 3079 insertions, 1670 deletions
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
index bcb06a0..12f1ef2 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -1245,8 +1245,6 @@ $O/Sha512.o: ../../../../C/Sha512.c
1245 $(CC) $(CFLAGS) $< 1245 $(CC) $(CFLAGS) $<
1246$O/Sha512Opt.o: ../../../../C/Sha512Opt.c 1246$O/Sha512Opt.o: ../../../../C/Sha512Opt.c
1247 $(CC) $(CFLAGS) $< 1247 $(CC) $(CFLAGS) $<
1248$O/Sort.o: ../../../../C/Sort.c
1249 $(CC) $(CFLAGS) $<
1250$O/SwapBytes.o: ../../../../C/SwapBytes.c 1248$O/SwapBytes.o: ../../../../C/SwapBytes.c
1251 $(CC) $(CFLAGS) $< 1249 $(CC) $(CFLAGS) $<
1252$O/Xxh64.o: ../../../../C/Xxh64.c 1250$O/Xxh64.o: ../../../../C/Xxh64.c
@@ -1285,6 +1283,8 @@ $O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm
1285 $(MY_ASM) $(AFLAGS) $< 1283 $(MY_ASM) $(AFLAGS) $<
1286$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm 1284$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm
1287 $(MY_ASM) $(AFLAGS) $< 1285 $(MY_ASM) $(AFLAGS) $<
1286$O/Sort.o: ../../../../Asm/x86/Sort.asm
1287 $(MY_ASM) $(AFLAGS) $<
1288 1288
1289ifndef USE_JWASM 1289ifndef USE_JWASM
1290USE_X86_ASM_AES=1 1290USE_X86_ASM_AES=1
@@ -1299,6 +1299,8 @@ $O/Sha1Opt.o: ../../../../C/Sha1Opt.c
1299 $(CC) $(CFLAGS) $< 1299 $(CC) $(CFLAGS) $<
1300$O/Sha256Opt.o: ../../../../C/Sha256Opt.c 1300$O/Sha256Opt.o: ../../../../C/Sha256Opt.c
1301 $(CC) $(CFLAGS) $< 1301 $(CC) $(CFLAGS) $<
1302$O/Sort.o: ../../../../C/Sort.c
1303 $(CC) $(CFLAGS) $<
1302endif 1304endif
1303 1305
1304 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/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 9340e1b..3122b05 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -17,11 +17,21 @@ 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 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
25 size_t memAvail = (size_t)sizeof(size_t) << 28; 35 size_t memAvail = (size_t)sizeof(size_t) << 28;
26 _memAvail = memAvail; 36 _memAvail = memAvail;
27 _memUsage_Compress = memAvail; 37 _memUsage_Compress = memAvail;
@@ -46,11 +56,14 @@ 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;
@@ -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/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 7d75aae..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
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 6ef8941..cba546e 100644
--- a/CPP/7zip/Archive/XarHandler.cpp
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -266,7 +266,7 @@ struct CFile
266 266
267 bool IsCopyMethod() const 267 bool IsCopyMethod() const
268 { 268 {
269 return Method.IsEmpty() || Method == "octet-stream"; 269 return Method.IsEmpty() || Method.IsEqualTo("octet-stream");
270 } 270 }
271 271
272 void UpdateTotalPackSize(UInt64 &totalSize) const 272 void UpdateTotalPackSize(UInt64 &totalSize) const
@@ -416,7 +416,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
416 return true; 416 return true;
417 if (level >= 1024) 417 if (level >= 1024)
418 return false; 418 return false;
419 if (item.Name == "file") 419 if (item.Name.IsEqualTo("file"))
420 { 420 {
421 CFile file(parent); 421 CFile file(parent);
422 parent = (int)files.Size(); 422 parent = (int)files.Size();
@@ -435,19 +435,19 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
435 { 435 {
436 file.Type = typeItem->GetSubString(); 436 file.Type = typeItem->GetSubString();
437 // file.LinkFrom = typeItem->GetPropVal("link"); 437 // file.LinkFrom = typeItem->GetPropVal("link");
438 if (file.Type == "directory") 438 if (file.Type.IsEqualTo("directory"))
439 file.IsDir = true; 439 file.IsDir = true;
440 else 440 else
441 { 441 {
442 // file.IsDir = false; 442 // file.IsDir = false;
443 /* 443 /*
444 else if (file.Type == "file") 444 else if (file.Type.IsEqualTo("file"))
445 {} 445 {}
446 else if (file.Type == "hardlink") 446 else if (file.Type.IsEqualTo("hardlink"))
447 {} 447 {}
448 else 448 else
449 */ 449 */
450 if (file.Type == "symlink") 450 if (file.Type.IsEqualTo("symlink"))
451 file.Is_SymLink = true; 451 file.Is_SymLink = true;
452 // file.IsDir = false; 452 // file.IsDir = false;
453 } 453 }
@@ -489,7 +489,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
489 if (s.IsPrefixedBy(xx)) 489 if (s.IsPrefixedBy(xx))
490 { 490 {
491 s.DeleteFrontal(xx.Len()); 491 s.DeleteFrontal(xx.Len());
492 if (s == "gzip") 492 if (s.IsEqualTo("gzip"))
493 s = METHOD_NAME_ZLIB; 493 s = METHOD_NAME_ZLIB;
494 } 494 }
495 } 495 }
@@ -692,12 +692,13 @@ HRESULT CHandler::Open2(IInStream *stream)
692 file.UpdateTotalPackSize(totalPackSize); 692 file.UpdateTotalPackSize(totalPackSize);
693 if (file.Parent == -1) 693 if (file.Parent == -1)
694 { 694 {
695 if (file.Name == "Payload" || file.Name == "Content") 695 if (file.Name.IsEqualTo("Payload") ||
696 file.Name.IsEqualTo("Content"))
696 { 697 {
697 _mainSubfile = (Int32)(int)i; 698 _mainSubfile = (Int32)(int)i;
698 numMainFiles++; 699 numMainFiles++;
699 } 700 }
700 else if (file.Name == "PackageInfo") 701 else if (file.Name.IsEqualTo("PackageInfo"))
701 _is_pkg = true; 702 _is_pkg = true;
702 } 703 }
703 } 704 }
@@ -1210,9 +1211,9 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1210 else 1211 else
1211 opRes = NExtract::NOperationResult::kUnsupportedMethod; 1212 opRes = NExtract::NOperationResult::kUnsupportedMethod;
1212 } 1213 }
1213 else if (item.Method == METHOD_NAME_ZLIB) 1214 else if (item.Method.IsEqualTo(METHOD_NAME_ZLIB))
1214 coder = zlibCoder; 1215 coder = zlibCoder;
1215 else if (item.Method == "bzip2") 1216 else if (item.Method.IsEqualTo("bzip2"))
1216 coder = bzip2Coder; 1217 coder = bzip2Coder;
1217 else 1218 else
1218 opRes = NExtract::NOperationResult::kUnsupportedMethod; 1219 opRes = NExtract::NOperationResult::kUnsupportedMethod;
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp
index 907376c..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 {
@@ -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/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 7166ab3..b1c6fe2 100644
--- a/CPP/7zip/Bundles/Format7zF/Arc.mak
+++ b/CPP/7zip/Bundles/Format7zF/Arc.mak
@@ -291,7 +291,6 @@ C_OBJS = \
291 $O\Sha3.obj \ 291 $O\Sha3.obj \
292 $O\Sha512.obj \ 292 $O\Sha512.obj \
293 $O\Sha512Opt.obj \ 293 $O\Sha512Opt.obj \
294 $O\Sort.obj \
295 $O\SwapBytes.obj \ 294 $O\SwapBytes.obj \
296 $O\Threads.obj \ 295 $O\Threads.obj \
297 $O\Xxh64.obj \ 296 $O\Xxh64.obj \
@@ -308,3 +307,4 @@ C_OBJS = \
308!include "../../LzmaDec.mak" 307!include "../../LzmaDec.mak"
309!include "../../Sha1.mak" 308!include "../../Sha1.mak"
310!include "../../Sha256.mak" 309!include "../../Sha256.mak"
310!include "../../Sort.mak"
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/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 a52f4bc..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
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..f8ee0c9 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,6 +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 {
69#ifdef _WIN32
70 if (Encoder->_props.NumThreadGroups != 0)
71 {
72 const UInt32 group = ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup);
73 wres = Thread.Create_With_Group(MFThread, this, group, 0); // affinity
74 }
75 else
76#endif
63 if (Encoder->_props.Affinity != 0) 77 if (Encoder->_props.Affinity != 0)
64 wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); 78 wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity);
65 else 79 else
@@ -216,94 +230,251 @@ void CEncoder::Free()
216} 230}
217#endif 231#endif
218 232
233struct CRleEncoder
234{
235 const Byte *_src;
236 const Byte *_srcLim;
237 Byte *_dest;
238 const Byte *_destLim;
239 Byte _prevByte;
240 unsigned _numReps;
241
242 void Encode();
243};
244
245Z7_NO_INLINE
246void CRleEncoder::Encode()
247{
248 const Byte *src = _src;
249 const Byte * const srcLim = _srcLim;
250 Byte *dest = _dest;
251 const Byte * const destLim = _destLim;
252 Byte prev = _prevByte;
253 unsigned numReps = _numReps;
254 // (dest < destLim)
255 // src = srcLim; // for debug
256 while (dest < destLim)
257 {
258 if (src == srcLim)
259 break;
260 const Byte b = *src++;
261 if (b != prev)
262 {
263 if (numReps >= kRleModeRepSize)
264 *dest++ = (Byte)(numReps - kRleModeRepSize);
265 *dest++ = b;
266 numReps = 1;
267 prev = b;
268 /*
269 { // speed optimization code:
270 if (dest >= destLim || src == srcLim)
271 break;
272 const Byte b2 = *src++;
273 *dest++ = b2;
274 numReps += (prev == b2);
275 prev = b2;
276 }
277 */
278 continue;
279 }
280 numReps++;
281 if (numReps <= kRleModeRepSize)
282 *dest++ = b;
283 else if (numReps == kRleModeRepSize + 255)
284 {
285 *dest++ = (Byte)(numReps - kRleModeRepSize);
286 numReps = 0;
287 }
288 }
289 _src = src;
290 _dest = dest;
291 _prevByte = prev;
292 _numReps = numReps;
293 // (dest <= destLim + 1)
294}
295
296
297// out: return value is blockSize: size of data filled in buffer[]:
298// (returned_blockSize <= _props.BlockSizeMult * kBlockSizeStep)
219UInt32 CEncoder::ReadRleBlock(Byte *buffer) 299UInt32 CEncoder::ReadRleBlock(Byte *buffer)
220{ 300{
301 CRleEncoder rle;
221 UInt32 i = 0; 302 UInt32 i = 0;
222 Byte prevByte; 303 if (m_InStream.ReadByte(rle._prevByte))
223 if (m_InStream.ReadByte(prevByte))
224 { 304 {
225 NumBlocks++; 305 NumBlocks++;
226 const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; 306 const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; // -1 for RLE
227 unsigned numReps = 1; 307 rle._destLim = buffer + blockSize;
228 buffer[i++] = prevByte; 308 rle._numReps = 1;
229 while (i < blockSize) // "- 1" to support RLE 309 buffer[i++] = rle._prevByte;
310 while (i < blockSize)
230 { 311 {
231 Byte b; 312 rle._dest = buffer + i;
232 if (!m_InStream.ReadByte(b)) 313 size_t rem;
314 const Byte * const ptr = m_InStream.Lookahead(rem);
315 if (rem == 0)
233 break; 316 break;
234 if (b != prevByte) 317 rle._src = ptr;
235 { 318 rle._srcLim = ptr + rem;
236 if (numReps >= kRleModeRepSize) 319 rle.Encode();
237 buffer[i++] = (Byte)(numReps - kRleModeRepSize); 320 m_InStream.Skip((size_t)(rle._src - ptr));
238 buffer[i++] = b; 321 i = (UInt32)(size_t)(rle._dest - buffer);
239 numReps = 1; 322 // (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 } 323 }
252 // it's to support original BZip2 decoder 324 const int n = (int)rle._numReps - (int)kRleModeRepSize;
253 if (numReps >= kRleModeRepSize) 325 if (n >= 0)
254 buffer[i++] = (Byte)(numReps - kRleModeRepSize); 326 buffer[i++] = (Byte)n;
255 } 327 }
256 return i; 328 return i;
257} 329}
258 330
259void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); } 331
260void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); } 332
261void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); } 333Z7_NO_INLINE
262void CThreadInfo::WriteCrc2(UInt32 v) 334void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits)
263{ 335 { m_OutStreamCurrent.WriteBits(value, numBits); }
264 for (unsigned i = 0; i < 4; i++) 336/*
265 WriteByte2(((Byte)(v >> (24 - i * 8)))); 337Z7_NO_INLINE
338void CThreadInfo::WriteByte2(unsigned b)
339 { m_OutStreamCurrent.WriteByte(b); }
340*/
341// void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
342Z7_NO_INLINE
343void CEncoder::WriteByte(Byte b) { m_OutStream.WriteByte(b); }
344
345
346#define WRITE_BITS_UPDATE(value, numBits) \
347{ \
348 numBits -= _bitPos; \
349 const UInt32 hi = value >> numBits; \
350 *_buf++ = (Byte)(_curByte | hi); \
351 value -= hi << numBits; \
352 _bitPos = 8; \
353 _curByte = 0; \
266} 354}
267 355
268void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); } 356#if HUFFMAN_LEN > 16
269void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); } 357
270// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); } 358#define WRITE_BITS_HUFF(value2, numBits2) \
271void CEncoder::WriteCrc(UInt32 v) 359{ \
272{ 360 UInt32 value = value2; \
273 for (unsigned i = 0; i < 4; i++) 361 unsigned numBits = numBits2; \
274 WriteByte(((Byte)(v >> (24 - i * 8)))); 362 while (numBits >= _bitPos) { \
363 WRITE_BITS_UPDATE(value, numBits) \
364 } \
365 _bitPos -= numBits; \
366 _curByte |= (value << _bitPos); \
367}
368
369#else // HUFFMAN_LEN <= 16
370
371// numBits2 <= 16 is supported
372#define WRITE_BITS_HUFF(value2, numBits2) \
373{ \
374 UInt32 value = value2; \
375 unsigned numBits = numBits2; \
376 if (numBits >= _bitPos) \
377 { \
378 WRITE_BITS_UPDATE(value, numBits) \
379 if (numBits >= _bitPos) \
380 { \
381 numBits -= _bitPos; \
382 const UInt32 hi = value >> numBits; \
383 *_buf++ = (Byte)hi; \
384 value -= hi << numBits; \
385 } \
386 } \
387 _bitPos -= numBits; \
388 _curByte |= (value << _bitPos); \
389}
390
391#endif
392
393#define WRITE_BITS_8(value2, numBits2) \
394{ \
395 UInt32 value = value2; \
396 unsigned numBits = numBits2; \
397 if (numBits >= _bitPos) \
398 { \
399 WRITE_BITS_UPDATE(value, numBits) \
400 } \
401 _bitPos -= numBits; \
402 _curByte |= (value << _bitPos); \
403}
404
405#define WRITE_BIT_PRE \
406 { _bitPos--; }
407
408#define WRITE_BIT_POST \
409{ \
410 if (_bitPos == 0) \
411 { \
412 *_buf++ = (Byte)_curByte; \
413 _curByte = 0; \
414 _bitPos = 8; \
415 } \
416}
417
418#define WRITE_BIT_0 \
419{ \
420 WRITE_BIT_PRE \
421 WRITE_BIT_POST \
422}
423
424#define WRITE_BIT_1 \
425{ \
426 WRITE_BIT_PRE \
427 _curByte |= 1u << _bitPos; \
428 WRITE_BIT_POST \
275} 429}
276 430
277 431
278// blockSize > 0 432// blockSize > 0
279void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) 433void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
280{ 434{
281 WriteBit2(0); // Randomised = false 435 // WriteBit2(0); // Randomised = false
282
283 { 436 {
284 UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize); 437 const UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
285 // if (m_BlockSorterIndex[origPtr] != 0) throw 1; 438 // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
286 m_BlockSorterIndex[origPtr] = blockSize; 439 m_BlockSorterIndex[origPtr] = blockSize;
287 WriteBits2(origPtr, kNumOrigBits); 440 WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false)
288 } 441 }
289 442 Byte mtfBuf[256];
290 CMtf8Encoder mtf; 443 // memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning
291 unsigned numInUse = 0; 444 unsigned numInUse;
292 { 445 {
293 Byte inUse[256]; 446 Byte inUse[256];
294 Byte inUse16[16]; 447 Byte inUse16[16];
295 UInt32 i; 448 unsigned i;
296 for (i = 0; i < 256; i++) 449 for (i = 0; i < 256; i++)
297 inUse[i] = 0; 450 inUse[i] = 0;
298 for (i = 0; i < 16; i++) 451 for (i = 0; i < 16; i++)
299 inUse16[i] = 0; 452 inUse16[i] = 0;
300 for (i = 0; i < blockSize; i++) 453 {
301 inUse[block[i]] = 1; 454 const Byte * cur = block;
455 block = block + (size_t)blockSize - 1;
456 if (cur != block)
457 {
458 do
459 {
460 const unsigned b0 = cur[0];
461 const unsigned b1 = cur[1];
462 cur += 2;
463 inUse[b0] = 1;
464 inUse[b1] = 1;
465 }
466 while (cur < block);
467 }
468 if (cur == block)
469 inUse[cur[0]] = 1;
470 block -= blockSize; // block pointer is (original_block - 1)
471 }
472 numInUse = 0;
302 for (i = 0; i < 256; i++) 473 for (i = 0; i < 256; i++)
303 if (inUse[i]) 474 if (inUse[i])
304 { 475 {
305 inUse16[i >> 4] = 1; 476 inUse16[i >> 4] = 1;
306 mtf.Buf[numInUse++] = (Byte)i; 477 mtfBuf[numInUse++] = (Byte)i;
307 } 478 }
308 for (i = 0; i < 16; i++) 479 for (i = 0; i < 16; i++)
309 WriteBit2(inUse16[i]); 480 WriteBit2(inUse16[i]);
@@ -311,65 +482,88 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
311 if (inUse16[i >> 4]) 482 if (inUse16[i >> 4])
312 WriteBit2(inUse[i]); 483 WriteBit2(inUse[i]);
313 } 484 }
314 unsigned alphaSize = numInUse + 2; 485 const unsigned alphaSize = numInUse + 2;
315 486
316 Byte *mtfs = m_MtfArray;
317 UInt32 mtfArraySize = 0;
318 UInt32 symbolCounts[kMaxAlphaSize]; 487 UInt32 symbolCounts[kMaxAlphaSize];
319 { 488 {
320 for (unsigned i = 0; i < kMaxAlphaSize; i++) 489 for (unsigned i = 0; i < kMaxAlphaSize; i++)
321 symbolCounts[i] = 0; 490 symbolCounts[i] = 0;
491 symbolCounts[(size_t)alphaSize - 1] = 1;
322 } 492 }
323 493
494 Byte *mtfs = m_MtfArray;
324 { 495 {
325 UInt32 rleSize = 0;
326 UInt32 i = 0;
327 const UInt32 *bsIndex = m_BlockSorterIndex; 496 const UInt32 *bsIndex = m_BlockSorterIndex;
328 block--; 497 const UInt32 *bsIndex_rle = bsIndex;
498 const UInt32 * const bsIndex_end = bsIndex + blockSize;
499 // block--; // backward fix
500 // block pointer is (original_block - 1)
329 do 501 do
330 { 502 {
331 unsigned pos = mtf.FindAndMove(block[bsIndex[i]]); 503 const Byte v = block[*bsIndex++];
332 if (pos == 0) 504 Byte a = mtfBuf[0];
333 rleSize++; 505 if (v != a)
334 else
335 { 506 {
336 while (rleSize != 0) 507 mtfBuf[0] = v;
337 { 508 {
338 rleSize--; 509 UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle) - 1;
339 mtfs[mtfArraySize++] = (Byte)(rleSize & 1); 510 bsIndex_rle = bsIndex;
340 symbolCounts[rleSize & 1]++; 511 while (rleSize)
341 rleSize >>= 1; 512 {
513 const unsigned sym = (unsigned)(--rleSize & 1);
514 *mtfs++ = (Byte)sym;
515 symbolCounts[sym]++;
516 rleSize >>= 1;
517 }
342 } 518 }
343 if (pos >= 0xFE) 519 unsigned pos1 = 2; // = real_pos + 1
520 Byte b;
521 b = mtfBuf[1]; mtfBuf[1] = a; if (v != b)
522 { a = mtfBuf[2]; mtfBuf[2] = b; if (v == a) pos1 = 3;
523 else { b = mtfBuf[3]; mtfBuf[3] = a; if (v == b) pos1 = 4;
524 else
525 {
526 Byte *m = mtfBuf + 7;
527 for (;;)
528 {
529 a = m[-3]; m[-3] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 2)); break; }
530 b = m[-2]; m[-2] = a; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 1)); break; }
531 a = m[-1]; m[-1] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf )); break; }
532 b = m[ 0]; m[ 0] = a; m += 4; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 3)); break; }
533 }
534 }}}
535 symbolCounts[pos1]++;
536 if (pos1 >= 0xff)
344 { 537 {
345 mtfs[mtfArraySize++] = 0xFF; 538 *mtfs++ = 0xff;
346 mtfs[mtfArraySize++] = (Byte)(pos - 0xFE); 539 // pos1 -= 0xff;
540 pos1++; // we need only low byte
347 } 541 }
348 else 542 *mtfs++ = (Byte)pos1;
349 mtfs[mtfArraySize++] = (Byte)(pos + 1);
350 symbolCounts[(size_t)pos + 1]++;
351 } 543 }
352 } 544 }
353 while (++i < blockSize); 545 while (bsIndex < bsIndex_end);
354 546
355 while (rleSize != 0) 547 UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle);
548 while (rleSize)
356 { 549 {
357 rleSize--; 550 const unsigned sym = (unsigned)(--rleSize & 1);
358 mtfs[mtfArraySize++] = (Byte)(rleSize & 1); 551 *mtfs++ = (Byte)sym;
359 symbolCounts[rleSize & 1]++; 552 symbolCounts[sym]++;
360 rleSize >>= 1; 553 rleSize >>= 1;
361 } 554 }
362 555
363 if (alphaSize < 256) 556 unsigned d = alphaSize - 1;
364 mtfs[mtfArraySize++] = (Byte)(alphaSize - 1); 557 if (alphaSize >= 256)
365 else
366 { 558 {
367 mtfs[mtfArraySize++] = 0xFF; 559 *mtfs++ = 0xff;
368 mtfs[mtfArraySize++] = (Byte)(alphaSize - 256); 560 d = alphaSize; // (-256)
369 } 561 }
370 symbolCounts[(size_t)alphaSize - 1]++; 562 *mtfs++ = (Byte)d;
371 } 563 }
372 564
565 const Byte * const mtf_lim = mtfs;
566
373 UInt32 numSymbols = 0; 567 UInt32 numSymbols = 0;
374 { 568 {
375 for (unsigned i = 0; i < kMaxAlphaSize; i++) 569 for (unsigned i = 0; i < kMaxAlphaSize; i++)
@@ -378,34 +572,30 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
378 572
379 unsigned bestNumTables = kNumTablesMin; 573 unsigned bestNumTables = kNumTablesMin;
380 UInt32 bestPrice = 0xFFFFFFFF; 574 UInt32 bestPrice = 0xFFFFFFFF;
381 UInt32 startPos = m_OutStreamCurrent->GetPos(); 575 const UInt32 startPos = m_OutStreamCurrent.GetPos();
382 Byte startCurByte = m_OutStreamCurrent->GetCurByte(); 576 const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
383 for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) 577 for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
384 { 578 {
385 unsigned numTables; 579 unsigned numTables;
386 580
387 if (m_OptimizeNumTables) 581 if (m_OptimizeNumTables)
388 { 582 {
389 m_OutStreamCurrent->SetPos(startPos); 583 m_OutStreamCurrent.SetPos(startPos);
390 m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); 584 m_OutStreamCurrent.SetCurState(startPos & 7, startCurByte);
391 if (nt <= kNumTablesMax) 585 numTables = (nt <= kNumTablesMax ? nt : bestNumTables);
392 numTables = nt;
393 else
394 numTables = bestNumTables;
395 } 586 }
396 else 587 else
397 { 588 {
398 if (numSymbols < 200) numTables = 2; 589 if (numSymbols < 200) numTables = 2;
399 else if (numSymbols < 600) numTables = 3; 590 else if (numSymbols < 600) numTables = 3;
400 else if (numSymbols < 1200) numTables = 4; 591 else if (numSymbols < 1200) numTables = 4;
401 else if (numSymbols < 2400) numTables = 5; 592 else if (numSymbols < 2400) numTables = 5;
402 else numTables = 6; 593 else numTables = 6;
403 } 594 }
404 595
405 WriteBits2(numTables, kNumTablesBits); 596 WriteBits2(numTables, kNumTablesBits);
406 597 const unsigned numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
407 UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; 598 WriteBits2((UInt32)numSelectors, kNumSelectorsBits);
408 WriteBits2(numSelectors, kNumSelectorsBits);
409 599
410 { 600 {
411 UInt32 remFreq = numSymbols; 601 UInt32 remFreq = numSymbols;
@@ -436,28 +626,23 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
436 626
437 for (unsigned pass = 0; pass < kNumHuffPasses; pass++) 627 for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
438 { 628 {
629 memset(Freqs, 0, sizeof(Freqs[0]) * numTables);
630 // memset(Freqs, 0, sizeof(Freqs));
439 { 631 {
440 unsigned t = 0; 632 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; 633 UInt32 g = 0;
449 do 634 do
450 { 635 {
451 UInt32 symbols[kGroupSize]; 636 unsigned symbols[kGroupSize];
452 unsigned i = 0; 637 unsigned i = 0;
453 do 638 do
454 { 639 {
455 UInt32 symbol = mtfs[mtfPos++]; 640 UInt32 symbol = *mtfs++;
456 if (symbol >= 0xFF) 641 if (symbol >= 0xFF)
457 symbol += mtfs[mtfPos++]; 642 symbol += *mtfs++;
458 symbols[i] = symbol; 643 symbols[i] = symbol;
459 } 644 }
460 while (++i < kGroupSize && mtfPos < mtfArraySize); 645 while (++i < kGroupSize && mtfs < mtf_lim);
461 646
462 UInt32 bestPrice2 = 0xFFFFFFFF; 647 UInt32 bestPrice2 = 0xFFFFFFFF;
463 unsigned t = 0; 648 unsigned t = 0;
@@ -482,7 +667,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
482 freqs[symbols[j]]++; 667 freqs[symbols[j]]++;
483 while (++j < i); 668 while (++j < i);
484 } 669 }
485 while (mtfPos < mtfArraySize); 670 while (mtfs < mtf_lim);
486 } 671 }
487 672
488 unsigned t = 0; 673 unsigned t = 0;
@@ -494,11 +679,15 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
494 if (freqs[i] == 0) 679 if (freqs[i] == 0)
495 freqs[i] = 1; 680 freqs[i] = 1;
496 while (++i < alphaSize); 681 while (++i < alphaSize);
497 Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding); 682 Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, HUFFMAN_LEN);
498 } 683 }
499 while (++t < numTables); 684 while (++t < numTables);
500 } 685 }
501 686
687 unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
688 unsigned _curByte; // low (_bitPos) bits are zeros
689 // high (8 - _bitPos) bits are filled
690 Byte *_buf;
502 { 691 {
503 Byte mtfSel[kNumTablesMax]; 692 Byte mtfSel[kNumTablesMax];
504 { 693 {
@@ -507,81 +696,97 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
507 mtfSel[t] = (Byte)t; 696 mtfSel[t] = (Byte)t;
508 while (++t < numTables); 697 while (++t < numTables);
509 } 698 }
699
700 _bitPos = m_OutStreamCurrent._bitPos;
701 _curByte = m_OutStreamCurrent._curByte;
702 _buf = m_OutStreamCurrent._buf;
703 // stream.Init_from_Global(m_OutStreamCurrent);
510 704
511 UInt32 i = 0; 705 const Byte *selectors = m_Selectors;
706 const Byte * const selectors_lim = selectors + numSelectors;
707 Byte prev = 0; // mtfSel[0];
512 do 708 do
513 { 709 {
514 Byte sel = m_Selectors[i]; 710 const Byte sel = *selectors++;
515 unsigned pos; 711 if (prev != sel)
516 for (pos = 0; mtfSel[pos] != sel; pos++) 712 {
517 WriteBit2(1); 713 Byte *mtfSel_cur = &mtfSel[1];
518 WriteBit2(0); 714 for (;;)
519 for (; pos > 0; pos--) 715 {
520 mtfSel[pos] = mtfSel[(size_t)pos - 1]; 716 WRITE_BIT_1
521 mtfSel[0] = sel; 717 const Byte next = *mtfSel_cur;
718 *mtfSel_cur++ = prev;
719 prev = next;
720 if (next == sel)
721 break;
722 }
723 // mtfSel[0] = sel;
724 }
725 WRITE_BIT_0
522 } 726 }
523 while (++i < numSelectors); 727 while (selectors != selectors_lim);
524 } 728 }
525
526 { 729 {
527 unsigned t = 0; 730 unsigned t = 0;
528 do 731 do
529 { 732 {
530 const Byte *lens = Lens[t]; 733 const Byte *lens = Lens[t];
531 UInt32 len = lens[0]; 734 unsigned len = lens[0];
532 WriteBits2(len, kNumLevelsBits); 735 WRITE_BITS_8(len, kNumLevelsBits)
533 unsigned i = 0; 736 unsigned i = 0;
534 do 737 do
535 { 738 {
536 UInt32 level = lens[i]; 739 const unsigned level = lens[i];
537 while (len != level) 740 while (len != level)
538 { 741 {
539 WriteBit2(1); 742 WRITE_BIT_1
540 if (len < level) 743 if (len < level)
541 { 744 {
542 WriteBit2(0);
543 len++; 745 len++;
746 WRITE_BIT_0
544 } 747 }
545 else 748 else
546 { 749 {
547 WriteBit2(1);
548 len--; 750 len--;
751 WRITE_BIT_1
549 } 752 }
550 } 753 }
551 WriteBit2(0); 754 WRITE_BIT_0
552 } 755 }
553 while (++i < alphaSize); 756 while (++i < alphaSize);
554 } 757 }
555 while (++t < numTables); 758 while (++t < numTables);
556 } 759 }
557
558 { 760 {
559 UInt32 groupSize = 0; 761 UInt32 groupSize = 1;
560 UInt32 groupIndex = 0; 762 const Byte *selectors = m_Selectors;
561 const Byte *lens = NULL; 763 const Byte *lens = NULL;
562 const UInt32 *codes = NULL; 764 const UInt32 *codes = NULL;
563 UInt32 mtfPos = 0; 765 mtfs = m_MtfArray;
564 do 766 do
565 { 767 {
566 UInt32 symbol = mtfs[mtfPos++]; 768 unsigned symbol = *mtfs++;
567 if (symbol >= 0xFF) 769 if (symbol >= 0xFF)
568 symbol += mtfs[mtfPos++]; 770 symbol += *mtfs++;
569 if (groupSize == 0) 771 if (--groupSize == 0)
570 { 772 {
571 groupSize = kGroupSize; 773 groupSize = kGroupSize;
572 unsigned t = m_Selectors[groupIndex++]; 774 const unsigned t = *selectors++;
573 lens = Lens[t]; 775 lens = Lens[t];
574 codes = Codes[t]; 776 codes = Codes[t];
575 } 777 }
576 groupSize--; 778 WRITE_BITS_HUFF(codes[symbol], lens[symbol])
577 m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
578 } 779 }
579 while (mtfPos < mtfArraySize); 780 while (mtfs < mtf_lim);
580 } 781 }
782 // Restore_from_Local:
783 m_OutStreamCurrent._bitPos = _bitPos;
784 m_OutStreamCurrent._curByte = _curByte;
785 m_OutStreamCurrent._buf = _buf;
581 786
582 if (!m_OptimizeNumTables) 787 if (!m_OptimizeNumTables)
583 break; 788 break;
584 UInt32 price = m_OutStreamCurrent->GetPos() - startPos; 789 const UInt32 price = m_OutStreamCurrent.GetPos() - startPos;
585 if (price <= bestPrice) 790 if (price <= bestPrice)
586 { 791 {
587 if (nt == kNumTablesMax) 792 if (nt == kNumTablesMax)
@@ -592,6 +797,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
592 } 797 }
593} 798}
594 799
800
595// blockSize > 0 801// blockSize > 0
596UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) 802UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
597{ 803{
@@ -603,148 +809,134 @@ UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
603 WriteByte2(kBlockSig5); 809 WriteByte2(kBlockSig5);
604 810
605 CBZip2Crc crc; 811 CBZip2Crc crc;
606 unsigned numReps = 0; 812 const Byte * const lim = block + blockSize;
607 Byte prevByte = block[0]; 813 unsigned b = *block++;
608 UInt32 i = 0; 814 crc.UpdateByte(b);
609 do 815 for (;;)
610 { 816 {
611 Byte b = block[i]; 817 const unsigned prev = b;
612 if (numReps == kRleModeRepSize) 818 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
613 { 819 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
614 for (; b > 0; b--) 820 if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
615 crc.UpdateByte(prevByte); 821 if (block >= lim) { break; } b = *block++; if (b) do crc.UpdateByte(prev); while (--b);
616 numReps = 0; 822 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 } 823 }
628 while (++i < blockSize); 824 const UInt32 crcRes = crc.GetDigest();
629 UInt32 crcRes = crc.GetDigest(); 825 for (int i = 24; i >= 0; i -= 8)
630 WriteCrc2(crcRes); 826 WriteByte2((Byte)(crcRes >> i));
631 EncodeBlock(block, blockSize); 827 EncodeBlock(lim - blockSize, blockSize);
632 return crcRes; 828 return crcRes;
633} 829}
634 830
831
635void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses) 832void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
636{ 833{
637 UInt32 numCrcs = m_NumCrcs; 834 const UInt32 numCrcs = m_NumCrcs;
638 bool needCompare = false; 835
639 836 const UInt32 startBytePos = m_OutStreamCurrent.GetBytePos();
640 UInt32 startBytePos = m_OutStreamCurrent->GetBytePos(); 837 const UInt32 startPos = m_OutStreamCurrent.GetPos();
641 UInt32 startPos = m_OutStreamCurrent->GetPos(); 838 const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
642 Byte startCurByte = m_OutStreamCurrent->GetCurByte(); 839 unsigned endCurByte = 0;
643 Byte endCurByte = 0; 840 UInt32 endPos = 0; // 0 means no no additional passes
644 UInt32 endPos = 0;
645 if (numPasses > 1 && blockSize >= (1 << 10)) 841 if (numPasses > 1 && blockSize >= (1 << 10))
646 { 842 {
647 UInt32 blockSize0 = blockSize / 2; // ???? 843 UInt32 bs0 = blockSize / 2;
648 844 for (; bs0 < blockSize &&
649 for (; (block[blockSize0] == block[(size_t)blockSize0 - 1] 845 (block[ bs0 ] ==
650 || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2]) 846 block[(size_t)bs0 - 1] ||
651 && blockSize0 < blockSize; 847 block[(size_t)bs0 - 1] ==
652 blockSize0++); 848 block[(size_t)bs0 - 2]);
849 bs0++)
850 {}
653 851
654 if (blockSize0 < blockSize) 852 if (bs0 < blockSize)
655 { 853 {
656 EncodeBlock2(block, blockSize0, numPasses - 1); 854 EncodeBlock2(block, bs0, numPasses - 1);
657 EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1); 855 EncodeBlock2(block + bs0, blockSize - bs0, numPasses - 1);
658 endPos = m_OutStreamCurrent->GetPos(); 856 endPos = m_OutStreamCurrent.GetPos();
659 endCurByte = m_OutStreamCurrent->GetCurByte(); 857 endCurByte = m_OutStreamCurrent.GetCurByte();
660 if ((endPos & 7) > 0) 858 // we prepare next byte as identical byte to starting byte for main encoding attempt:
859 if (endPos & 7)
661 WriteBits2(0, 8 - (endPos & 7)); 860 WriteBits2(0, 8 - (endPos & 7));
662 m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); 861 m_OutStreamCurrent.SetCurState((startPos & 7), startCurByte);
663 needCompare = true;
664 } 862 }
665 } 863 }
666 864
667 UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos(); 865 const UInt32 startBytePos2 = m_OutStreamCurrent.GetBytePos();
668 UInt32 startPos2 = m_OutStreamCurrent->GetPos(); 866 const UInt32 startPos2 = m_OutStreamCurrent.GetPos();
669 UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize); 867 const UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
670 UInt32 endPos2 = m_OutStreamCurrent->GetPos();
671 868
672 if (needCompare) 869 if (endPos)
673 { 870 {
674 UInt32 size2 = endPos2 - startPos2; 871 const UInt32 size2 = m_OutStreamCurrent.GetPos() - startPos2;
675 if (size2 < endPos - startPos) 872 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 { 873 {
687 m_OutStreamCurrent->SetPos(endPos); 874 m_OutStreamCurrent.SetPos(endPos);
688 m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte); 875 m_OutStreamCurrent.SetCurState((endPos & 7), endCurByte);
876 return;
689 } 877 }
878 const UInt32 numBytes = m_OutStreamCurrent.GetBytePos() - startBytePos2;
879 Byte * const buffer = m_OutStreamCurrent.GetStream();
880 memmove(buffer + startBytePos, buffer + startBytePos2, numBytes);
881 m_OutStreamCurrent.SetPos(startPos + size2);
882 // we don't call m_OutStreamCurrent.SetCurState() here because
883 // m_OutStreamCurrent._curByte is correct already
690 } 884 }
691 else 885 m_CRCs[numCrcs] = crcVal;
692 { 886 m_NumCrcs = numCrcs + 1;
693 m_NumCrcs = numCrcs;
694 m_CRCs[m_NumCrcs++] = crcVal;
695 }
696} 887}
697 888
889
698HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize) 890HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
699{ 891{
700 CMsbfEncoderTemp outStreamTemp; 892 CMsbfEncoderTemp &outStreamTemp = m_OutStreamCurrent;
701 outStreamTemp.SetStream(m_TempArray); 893 outStreamTemp.SetStream(m_TempArray);
702 outStreamTemp.Init(); 894 outStreamTemp.Init();
703 m_OutStreamCurrent = &outStreamTemp;
704
705 m_NumCrcs = 0; 895 m_NumCrcs = 0;
706 896
707 EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses); 897 EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
708 898
709 #ifndef Z7_ST 899#ifndef Z7_ST
710 if (Encoder->MtMode) 900 if (Encoder->MtMode)
711 Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); 901 Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
712 #endif 902#endif
903
713 for (UInt32 i = 0; i < m_NumCrcs; i++) 904 for (UInt32 i = 0; i < m_NumCrcs; i++)
714 Encoder->CombinedCrc.Update(m_CRCs[i]); 905 Encoder->CombinedCrc.Update(m_CRCs[i]);
715 Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); 906 Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetNonFlushedByteBits());
716 HRESULT res = S_OK; 907 HRESULT res = S_OK;
717 #ifndef Z7_ST 908
909#ifndef Z7_ST
718 if (Encoder->MtMode) 910 if (Encoder->MtMode)
719 { 911 {
720 UInt32 blockIndex = m_BlockIndex + 1; 912 UInt32 blockIndex = m_BlockIndex + 1;
721 if (blockIndex == Encoder->NumThreads) 913 if (blockIndex == Encoder->NumThreads)
722 blockIndex = 0; 914 blockIndex = 0;
723
724 if (Encoder->Progress) 915 if (Encoder->Progress)
725 { 916 {
726 const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); 917 const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
727 res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); 918 res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
728 } 919 }
729
730 Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); 920 Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
731 } 921 }
732 #endif 922#endif
733 return res; 923 return res;
734} 924}
735 925
736void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) 926void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits)
737{ 927{
738 UInt32 bytesSize = (sizeInBits >> 3); 928 m_OutStream.WriteBytes(data, sizeInBits >> 3);
739 for (UInt32 i = 0; i < bytesSize; i++) 929 sizeInBits &= 7;
740 m_OutStream.WriteBits(data[i], 8); 930 if (sizeInBits)
741 WriteBits(lastByte, (sizeInBits & 7)); 931 m_OutStream.WriteBits(lastByteBits, sizeInBits);
742} 932}
743 933
744 934
745HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, 935HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
746 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 936 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
747{ 937{
938 ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup
939
748 NumBlocks = 0; 940 NumBlocks = 0;
749 #ifndef Z7_ST 941 #ifndef Z7_ST
750 Progress = progress; 942 Progress = progress;
@@ -823,11 +1015,11 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
823 { 1015 {
824 CThreadInfo &ti = 1016 CThreadInfo &ti =
825 #ifndef Z7_ST 1017 #ifndef Z7_ST
826 ThreadsInfo[0]; 1018 ThreadsInfo[0];
827 #else 1019 #else
828 ThreadsInfo; 1020 ThreadsInfo;
829 #endif 1021 #endif
830 UInt32 blockSize = ReadRleBlock(ti.m_Block); 1022 const UInt32 blockSize = ReadRleBlock(ti.m_Block);
831 if (blockSize == 0) 1023 if (blockSize == 0)
832 break; 1024 break;
833 RINOK(ti.EncodeBlock3(blockSize)) 1025 RINOK(ti.EncodeBlock3(blockSize))
@@ -845,8 +1037,11 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
845 WriteByte(kFinSig3); 1037 WriteByte(kFinSig3);
846 WriteByte(kFinSig4); 1038 WriteByte(kFinSig4);
847 WriteByte(kFinSig5); 1039 WriteByte(kFinSig5);
848 1040 {
849 WriteCrc(CombinedCrc.GetDigest()); 1041 const UInt32 v = CombinedCrc.GetDigest();
1042 for (int i = 24; i >= 0; i -= 8)
1043 WriteByte((Byte)(v >> i));
1044 }
850 RINOK(Flush()) 1045 RINOK(Flush())
851 if (!m_InStream.WasFinished()) 1046 if (!m_InStream.WasFinished())
852 return E_FAIL; 1047 return E_FAIL;
@@ -869,14 +1064,21 @@ Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA
869 for (UInt32 i = 0; i < numProps; i++) 1064 for (UInt32 i = 0; i < numProps; i++)
870 { 1065 {
871 const PROPVARIANT &prop = coderProps[i]; 1066 const PROPVARIANT &prop = coderProps[i];
872 PROPID propID = propIDs[i]; 1067 const PROPID propID = propIDs[i];
873 1068
874 if (propID == NCoderPropID::kAffinity) 1069 if (propID == NCoderPropID::kAffinity)
875 { 1070 {
876 if (prop.vt == VT_UI8) 1071 if (prop.vt != VT_UI8)
877 props.Affinity = prop.uhVal.QuadPart; 1072 return E_INVALIDARG;
878 else 1073 props.Affinity = prop.uhVal.QuadPart;
1074 continue;
1075 }
1076
1077 if (propID == NCoderPropID::kNumThreadGroups)
1078 {
1079 if (prop.vt != VT_UI4)
879 return E_INVALIDARG; 1080 return E_INVALIDARG;
1081 props.NumThreadGroups = (UInt32)prop.ulVal;
880 continue; 1082 continue;
881 } 1083 }
882 1084
@@ -884,7 +1086,7 @@ Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA
884 continue; 1086 continue;
885 if (prop.vt != VT_UI4) 1087 if (prop.vt != VT_UI4)
886 return E_INVALIDARG; 1088 return E_INVALIDARG;
887 UInt32 v = (UInt32)prop.ulVal; 1089 const UInt32 v = (UInt32)prop.ulVal;
888 switch (propID) 1090 switch (propID)
889 { 1091 {
890 case NCoderPropID::kNumPasses: props.NumPasses = v; break; 1092 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/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/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
index 556b25a..de9f43e 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
@@ -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;
@@ -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 67ea29c..3abcd2d 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
@@ -56,6 +56,19 @@ static 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";
57#endif 57#endif
58 58
59static const unsigned k_LinkDataSize_LIMIT = 1 << 12;
60
61#if WCHAR_PATH_SEPARATOR != L'/'
62 // we convert linux slashes to windows slashes for further processing.
63 // also we convert linux backslashes to BackslashReplacement character.
64 #define REPLACE_SLASHES_from_Linux_to_Sys(s) \
65 { NArchive::NItemName::ReplaceToWinSlashes(s, true); } // useBackslashReplacement
66 // { s.Replace(L'/', WCHAR_PATH_SEPARATOR); }
67#else
68 #define REPLACE_SLASHES_from_Linux_to_Sys(s)
69#endif
70
71
59#ifndef Z7_SFX 72#ifndef Z7_SFX
60 73
61Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) 74Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
@@ -217,7 +230,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
217 if (!_arc->Ask_INode) 230 if (!_arc->Ask_INode)
218 return S_OK; 231 return S_OK;
219 232
220 IInArchive *archive = _arc->Archive; 233 IInArchive * const archive = _arc->Archive;
221 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; 234 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;
222 235
223 { 236 {
@@ -574,6 +587,13 @@ HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char
574 return _extractCallback2->MessageError(s); 587 return _extractCallback2->MessageError(s);
575} 588}
576 589
590HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError(
591 const char *message, const FString &path1, const FString &path2)
592{
593 const HRESULT errorCode = GetLastError_noZero_HRESULT();
594 return SendMessageError2(errorCode, message, path1, path2);
595}
596
577#ifndef Z7_SFX 597#ifndef Z7_SFX
578 598
579Z7_CLASS_IMP_COM_1( 599Z7_CLASS_IMP_COM_1(
@@ -604,36 +624,20 @@ Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
604#endif // Z7_SFX 624#endif // Z7_SFX
605 625
606 626
607#ifdef SUPPORT_LINKS
608
609static UString GetDirPrefixOf(const UString &src)
610{
611 UString s (src);
612 if (!s.IsEmpty())
613 {
614 if (IsPathSepar(s.Back()))
615 s.DeleteBack();
616 int pos = s.ReverseFind_PathSepar();
617 s.DeleteFrom((unsigned)(pos + 1));
618 }
619 return s;
620}
621
622#endif // SUPPORT_LINKS
623
624struct CLinkLevelsInfo 627struct CLinkLevelsInfo
625{ 628{
626 bool IsAbsolute; 629 bool IsAbsolute;
627 int LowLevel; 630 int LowLevel;
628 int FinalLevel; 631 int FinalLevel;
629 632
630 void Parse(const UString &path); 633 void Parse(const UString &path, bool isWSL);
631}; 634};
632 635
633void CLinkLevelsInfo::Parse(const UString &path) 636void CLinkLevelsInfo::Parse(const UString &path, bool isWSL)
634{ 637{
635 IsAbsolute = NName::IsAbsolutePath(path); 638 IsAbsolute = isWSL ?
636 639 IS_PATH_SEPAR(path[0]) :
640 NName::IsAbsolutePath(path);
637 LowLevel = 0; 641 LowLevel = 0;
638 FinalLevel = 0; 642 FinalLevel = 0;
639 643
@@ -650,9 +654,9 @@ void CLinkLevelsInfo::Parse(const UString &path)
650 IsAbsolute = true; 654 IsAbsolute = true;
651 continue; 655 continue;
652 } 656 }
653 if (s == L".") 657 if (s.IsEqualTo("."))
654 continue; 658 continue;
655 if (s == L"..") 659 if (s.IsEqualTo(".."))
656 { 660 {
657 level--; 661 level--;
658 if (LowLevel > level) 662 if (LowLevel > level)
@@ -666,16 +670,20 @@ void CLinkLevelsInfo::Parse(const UString &path)
666} 670}
667 671
668 672
669bool IsSafePath(const UString &path); 673static bool IsSafePath(const UString &path, bool isWSL)
670bool IsSafePath(const UString &path)
671{ 674{
672 CLinkLevelsInfo levelsInfo; 675 CLinkLevelsInfo levelsInfo;
673 levelsInfo.Parse(path); 676 levelsInfo.Parse(path, isWSL);
674 return !levelsInfo.IsAbsolute 677 return !levelsInfo.IsAbsolute
675 && levelsInfo.LowLevel >= 0 678 && levelsInfo.LowLevel >= 0
676 && levelsInfo.FinalLevel > 0; 679 && levelsInfo.FinalLevel > 0;
677} 680}
678 681
682bool IsSafePath(const UString &path);
683bool IsSafePath(const UString &path)
684{
685 return IsSafePath(path, false); // isWSL
686}
679 687
680bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); 688bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
681bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) 689bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
@@ -791,159 +799,113 @@ HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
791 799
792HRESULT CArchiveExtractCallback::ReadLink() 800HRESULT CArchiveExtractCallback::ReadLink()
793{ 801{
794 IInArchive *archive = _arc->Archive; 802 IInArchive * const archive = _arc->Archive;
795 const UInt32 index = _index; 803 const UInt32 index = _index;
796 _link.Clear(); 804 // _link.Clear(); // _link.Clear() was called already.
797
798 { 805 {
799 NCOM::CPropVariant prop; 806 NCOM::CPropVariant prop;
800 RINOK(archive->GetProperty(index, kpidHardLink, &prop)) 807 RINOK(archive->GetProperty(index, kpidHardLink, &prop))
801 if (prop.vt == VT_BSTR) 808 if (prop.vt == VT_BSTR)
802 { 809 {
803 _link.isHardLink = true; 810 _link.LinkType = k_LinkType_HardLink;
804 // _link.isCopyLink = false;
805 _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive 811 _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive
806 _link.linkPath.SetFromBstr(prop.bstrVal); 812 _link.LinkPath.SetFromBstr(prop.bstrVal);
813 // 7-Zip 24-: tar handler returned original path (with linux slash in most case)
814 // 7-Zip 24-: rar5 handler returned path with system slash.
815 // 7-Zip 25+: tar/rar5 handlers return linux path in most cases.
807 } 816 }
808 else if (prop.vt != VT_EMPTY) 817 else if (prop.vt != VT_EMPTY)
809 return E_FAIL; 818 return E_FAIL;
810 } 819 }
811
812 /* 820 /*
813 { 821 {
814 NCOM::CPropVariant prop; 822 NCOM::CPropVariant prop;
815 RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); 823 RINOK(archive->GetProperty(index, kpidCopyLink, &prop));
816 if (prop.vt == VT_BSTR) 824 if (prop.vt == VT_BSTR)
817 { 825 {
818 _link.isHardLink = false; 826 _link.LinkType = k_LinkType_CopyLink;
819 _link.isCopyLink = true;
820 _link.isRelative = false; // RAR5: copy links are from root folder of archive 827 _link.isRelative = false; // RAR5: copy links are from root folder of archive
821 _link.linkPath.SetFromBstr(prop.bstrVal); 828 _link.LinkPath.SetFromBstr(prop.bstrVal);
822 } 829 }
823 else if (prop.vt != VT_EMPTY) 830 else if (prop.vt != VT_EMPTY)
824 return E_FAIL; 831 return E_FAIL;
825 } 832 }
826 */ 833 */
827
828 { 834 {
829 NCOM::CPropVariant prop; 835 NCOM::CPropVariant prop;
830 RINOK(archive->GetProperty(index, kpidSymLink, &prop)) 836 RINOK(archive->GetProperty(index, kpidSymLink, &prop))
831 if (prop.vt == VT_BSTR) 837 if (prop.vt == VT_BSTR)
832 { 838 {
833 _link.isHardLink = false; 839 _link.LinkType = k_LinkType_PureSymLink;
834 // _link.isCopyLink = false; 840 _link.isRelative = true; // RAR5, TAR: symbolic links are relative by default
835 _link.isRelative = true; // RAR5, TAR: symbolic links can be relative 841 _link.LinkPath.SetFromBstr(prop.bstrVal);
836 _link.linkPath.SetFromBstr(prop.bstrVal); 842 // 7-Zip 24-: (tar, cpio, xar, ext, iso) handlers returned returned original path (with linux slash in most case)
843 // 7-Zip 24-: rar5 handler returned path with system slash.
844 // 7-Zip 25+: all handlers return linux path in most cases.
837 } 845 }
838 else if (prop.vt != VT_EMPTY) 846 else if (prop.vt != VT_EMPTY)
839 return E_FAIL; 847 return E_FAIL;
840 } 848 }
841 849
842 NtReparse_Data = NULL; 850 // linux path separator in (_link.LinkPath) is expected for most cases,
843 NtReparse_Size = 0; 851 // if new handler code is used, and if data in archive is correct.
844 852 // NtReparse_Data = NULL;
845 if (_link.linkPath.IsEmpty() && _arc->GetRawProps) 853 // NtReparse_Size = 0;
854 if (!_link.LinkPath.IsEmpty())
855 {
856 REPLACE_SLASHES_from_Linux_to_Sys(_link.LinkPath)
857 }
858 else if (_arc->GetRawProps)
846 { 859 {
847 const void *data; 860 const void *data;
848 UInt32 dataSize; 861 UInt32 dataSize, propType;
849 UInt32 propType; 862 if (_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType) == S_OK
850 863 // && dataSize == 1234567 // for debug: unpacking without reparse
851 _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); 864 && dataSize)
852
853 // if (dataSize == 1234567) // for debug: unpacking without reparse
854 if (dataSize != 0)
855 { 865 {
856 if (propType != NPropDataType::kRaw) 866 if (propType != NPropDataType::kRaw)
857 return E_FAIL; 867 return E_FAIL;
858
859 // 21.06: we need kpidNtReparse in linux for wim archives created in Windows 868 // 21.06: we need kpidNtReparse in linux for wim archives created in Windows
860 // #ifdef _WIN32 869 // NtReparse_Data = data;
861 870 // NtReparse_Size = dataSize;
862 NtReparse_Data = data; 871 // we ignore error code here, if there is failure of parsing:
863 NtReparse_Size = dataSize; 872 _link.Parse_from_WindowsReparseData((const Byte *)data, dataSize);
864
865 CReparseAttr reparse;
866 bool isOkReparse = reparse.Parse((const Byte *)data, dataSize);
867 if (isOkReparse)
868 {
869 _link.isHardLink = false;
870 // _link.isCopyLink = false;
871 _link.linkPath = reparse.GetPath();
872 _link.isJunction = reparse.IsMountPoint();
873
874 if (reparse.IsSymLink_WSL())
875 {
876 _link.isWSL = true;
877 _link.isRelative = reparse.IsRelative_WSL();
878 }
879 else
880 _link.isRelative = reparse.IsRelative_Win();
881
882 // const AString s = GetAnsiString(_link.linkPath);
883 // printf("\n_link.linkPath: %s\n", s.Ptr());
884
885 #ifndef _WIN32
886 _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
887 #endif
888 }
889 // #endif
890 } 873 }
891 } 874 }
892 875
893 if (_link.linkPath.IsEmpty()) 876 if (_link.LinkPath.IsEmpty())
894 return S_OK; 877 return S_OK;
895 878 // (_link.LinkPath) uses system path separator.
879 // windows: (_link.LinkPath) doesn't contain linux separator (slash).
896 { 880 {
897 #ifdef _WIN32 881 // _link.LinkPath = "\\??\\r:\\1\\2"; // for debug
898 _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); 882 // rar5+ returns kpidSymLink absolute link path with "\??\" prefix.
899 #endif 883 // we normalize such prefix:
900 884 if (_link.LinkPath.IsPrefixedBy(STRING_PATH_SEPARATOR "??" STRING_PATH_SEPARATOR))
901 // rar5 uses "\??\" prefix for absolute links
902 if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
903 { 885 {
904 _link.isRelative = false; 886 _link.isRelative = false;
905 _link.linkPath.DeleteFrontal(4); 887 // we normalize prefix from "\??\" to "\\?\":
906 } 888 _link.LinkPath.ReplaceOneCharAtPos(1, WCHAR_PATH_SEPARATOR);
907 889 _link.isWindowsPath = true;
908 for (;;) 890 if (_link.LinkPath.IsPrefixedBy_Ascii_NoCase(
909 // while (NName::IsAbsolutePath(linkPath)) 891 STRING_PATH_SEPARATOR
910 { 892 STRING_PATH_SEPARATOR "?"
911 unsigned n = NName::GetRootPrefixSize(_link.linkPath); 893 STRING_PATH_SEPARATOR "UNC"
912 if (n == 0) 894 STRING_PATH_SEPARATOR))
913 break;
914 _link.isRelative = false;
915 _link.linkPath.DeleteFrontal(n);
916 }
917 }
918
919 if (_link.linkPath.IsEmpty())
920 return S_OK;
921
922 if (!_link.isRelative && _removePathParts.Size() != 0)
923 {
924 UStringVector pathParts;
925 SplitPathToParts(_link.linkPath, pathParts);
926 bool badPrefix = false;
927 FOR_VECTOR (i, _removePathParts)
928 {
929 if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
930 { 895 {
931 badPrefix = true; 896 // we normalize prefix from "\\?\UNC\path" to "\\path":
932 break; 897 _link.LinkPath.DeleteFrontal(6);
898 _link.LinkPath.ReplaceOneCharAtPos(0, WCHAR_PATH_SEPARATOR);
899 }
900 else
901 {
902 const unsigned k_prefix_Size = 4;
903 if (NName::IsDrivePath(_link.LinkPath.Ptr(k_prefix_Size)))
904 _link.LinkPath.DeleteFrontal(k_prefix_Size);
933 } 905 }
934 } 906 }
935 if (!badPrefix)
936 pathParts.DeleteFrontal(_removePathParts.Size());
937 _link.linkPath = MakePathFromParts(pathParts);
938 } 907 }
939 908 _link.Normalize_to_RelativeSafe(_removePathParts);
940 /*
941 if (!_link.linkPath.IsEmpty())
942 {
943 printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr());
944 }
945 */
946
947 return S_OK; 909 return S_OK;
948} 910}
949 911
@@ -961,7 +923,7 @@ static HRESULT GetOwner(IInArchive *archive,
961 if (prop.vt == VT_UI4) 923 if (prop.vt == VT_UI4)
962 { 924 {
963 res.Id_Defined = true; 925 res.Id_Defined = true;
964 res.Id = prop.ulVal; // for debug 926 res.Id = prop.ulVal;
965 // res.Id++; // for debug 927 // res.Id++; // for debug
966 // if (pidId == kpidGroupId) res.Id += 7; // for debug 928 // if (pidId == kpidGroupId) res.Id += 7; // for debug
967 // res.Id = 0; // for debug 929 // res.Id = 0; // for debug
@@ -993,7 +955,7 @@ static HRESULT GetOwner(IInArchive *archive,
993 955
994HRESULT CArchiveExtractCallback::Read_fi_Props() 956HRESULT CArchiveExtractCallback::Read_fi_Props()
995{ 957{
996 IInArchive *archive = _arc->Archive; 958 IInArchive * const archive = _arc->Archive;
997 const UInt32 index = _index; 959 const UInt32 index = _index;
998 960
999 _fi.Attrib_Defined = false; 961 _fi.Attrib_Defined = false;
@@ -1134,7 +1096,7 @@ void CArchiveExtractCallback::CreateFolders()
1134 if (!_item.IsDir 1096 if (!_item.IsDir
1135 #ifdef SUPPORT_LINKS 1097 #ifdef SUPPORT_LINKS
1136 #ifndef WIN32 1098 #ifndef WIN32
1137 || !_link.linkPath.IsEmpty() 1099 || !_link.LinkPath.IsEmpty()
1138 #endif 1100 #endif
1139 #endif 1101 #endif
1140 ) 1102 )
@@ -1273,8 +1235,7 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1273 // MyMoveFile can rename folders. So it's OK to use it for folders too 1235 // MyMoveFile can rename folders. So it's OK to use it for folders too
1274 if (!MyMoveFile(fullProcessedPath, existPath)) 1236 if (!MyMoveFile(fullProcessedPath, existPath))
1275 { 1237 {
1276 HRESULT errorCode = GetLastError_noZero_HRESULT(); 1238 RINOK(SendMessageError2_with_LastError(kCantRenameFile, existPath, fullProcessedPath))
1277 RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath))
1278 return E_FAIL; 1239 return E_FAIL;
1279 } 1240 }
1280 } 1241 }
@@ -1341,7 +1302,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1341 RINOK(Read_fi_Props()) 1302 RINOK(Read_fi_Props())
1342 1303
1343 #ifdef SUPPORT_LINKS 1304 #ifdef SUPPORT_LINKS
1344 IInArchive *archive = _arc->Archive; 1305 IInArchive * const archive = _arc->Archive;
1345 #endif 1306 #endif
1346 1307
1347 const UInt32 index = _index; 1308 const UInt32 index = _index;
@@ -1387,7 +1348,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1387 if (isAnti) 1348 if (isAnti)
1388 RemoveDir(_diskFilePath); 1349 RemoveDir(_diskFilePath);
1389 #ifdef SUPPORT_LINKS 1350 #ifdef SUPPORT_LINKS
1390 if (_link.linkPath.IsEmpty()) 1351 if (_link.LinkPath.IsEmpty())
1391 #endif 1352 #endif
1392 { 1353 {
1393 if (!isAnti) 1354 if (!isAnti)
@@ -1416,15 +1377,15 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1416 1377
1417 #ifdef SUPPORT_LINKS 1378 #ifdef SUPPORT_LINKS
1418 1379
1419 if (!_link.linkPath.IsEmpty()) 1380 if (!_link.LinkPath.IsEmpty())
1420 { 1381 {
1421 #ifndef UNDER_CE 1382 #ifndef UNDER_CE
1422 { 1383 {
1423 bool linkWasSet = false; 1384 bool linkWasSet = false;
1424 RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet)) 1385 RINOK(SetLink(fullProcessedPath, _link, linkWasSet))
1425 if (linkWasSet) 1386 if (linkWasSet)
1426 { 1387 {
1427 _isSymLinkCreated = _link.IsSymLink(); 1388 _isSymLinkCreated = _link.Is_AnySymLink();
1428 SetAttrib(); 1389 SetAttrib();
1429 // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); 1390 // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath));
1430 } 1391 }
@@ -1454,12 +1415,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1454 else 1415 else
1455 { 1416 {
1456 if (!MyCreateHardLink(fullProcessedPath, hl)) 1417 if (!MyCreateHardLink(fullProcessedPath, hl))
1457 { 1418 return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath, hl);
1458 const HRESULT errorCode = GetLastError_noZero_HRESULT();
1459 RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl))
1460 return S_OK;
1461 }
1462
1463 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); 1419 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
1464 // _needSetAttrib = true; // do we need to set attribute ? 1420 // _needSetAttrib = true; // do we need to set attribute ?
1465 SetAttrib(); 1421 SetAttrib();
@@ -1491,7 +1447,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1491 1447
1492 bool is_SymLink_in_Data = false; 1448 bool is_SymLink_in_Data = false;
1493 1449
1494 if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12)) 1450 if (_curSize_Defined && _curSize && _curSize < k_LinkDataSize_LIMIT)
1495 { 1451 {
1496 if (_fi.IsLinuxSymLink()) 1452 if (_fi.IsLinuxSymLink())
1497 { 1453 {
@@ -1513,7 +1469,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1513 _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); 1469 _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size());
1514 outStreamLoc = _bufPtrSeqOutStream; 1470 outStreamLoc = _bufPtrSeqOutStream;
1515 } 1471 }
1516 else // not reprase 1472 else // not reparse
1517 { 1473 {
1518 if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) 1474 if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12))
1519 { 1475 {
@@ -1568,7 +1524,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1568 RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) 1524 RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL))
1569 } 1525 }
1570 outStreamLoc = outFileStream_Loc; 1526 outStreamLoc = outFileStream_Loc;
1571 } // if not reprase 1527 } // if not reparse
1572 1528
1573 _outFileStream = outFileStream_Loc; 1529 _outFileStream = outFileStream_Loc;
1574 1530
@@ -1620,8 +1576,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1620 _fileLength_WasSet = false; 1576 _fileLength_WasSet = false;
1621 _isRenamed = false; 1577 _isRenamed = false;
1622 // _fi.Clear(); 1578 // _fi.Clear();
1623 _extractMode = false; 1579 _extractMode = false;
1624 // _is_SymLink_in_Data = false;
1625 _is_SymLink_in_Data_Linux = false; 1580 _is_SymLink_in_Data_Linux = false;
1626 _needSetAttrib = false; 1581 _needSetAttrib = false;
1627 _isSymLinkCreated = false; 1582 _isSymLinkCreated = false;
@@ -1661,7 +1616,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1661 } 1616 }
1662 1617
1663 1618
1664 IInArchive *archive = _arc->Archive; 1619 IInArchive * const archive = _arc->Archive;
1665 1620
1666 RINOK(GetItem(index)) 1621 RINOK(GetItem(index))
1667 1622
@@ -1677,10 +1632,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1677 } 1632 }
1678 } 1633 }
1679 1634
1680 #ifdef SUPPORT_LINKS 1635#ifdef SUPPORT_LINKS
1681 RINOK(ReadLink()) 1636 RINOK(ReadLink())
1682 #endif // SUPPORT_LINKS 1637#endif
1683
1684 1638
1685 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) 1639 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted))
1686 1640
@@ -2016,63 +1970,80 @@ HRESULT CArchiveExtractCallback::CloseFile()
2016 1970
2017#ifdef SUPPORT_LINKS 1971#ifdef SUPPORT_LINKS
2018 1972
1973/*
1974in:
1975 link.LinkPath : must be relative (non-absolute) path in any case !!!
1976 link.isRelative / target path that must stored as created link:
1977 == false / _dirPathPrefix_Full + link.LinkPath
1978 == true / link.LinkPath
1979*/
2019 1980
2020HRESULT CArchiveExtractCallback::SetFromLinkPath( 1981HRESULT CArchiveExtractCallback::SetLink(
2021 const FString &fullProcessedPath, 1982 const FString &fullProcessedPath_from,
2022 const CLinkInfo &linkInfo, 1983 const CLinkInfo &link,
2023 bool &linkWasSet) 1984 bool &linkWasSet)
2024{ 1985{
2025 linkWasSet = false; 1986 linkWasSet = false;
2026 if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink) 1987 if (link.LinkPath.IsEmpty())
1988 return S_OK;
1989 if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink())
2027 return S_OK; 1990 return S_OK;
2028
2029 UString relatPath;
2030
2031 /* if (linkInfo.isRelative)
2032 linkInfo.linkPath is final link path that must be stored to file link field
2033 else
2034 linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath.
2035 */
2036
2037 if (linkInfo.isRelative)
2038 relatPath = GetDirPrefixOf(_item.Path);
2039 relatPath += linkInfo.linkPath;
2040
2041 if (!IsSafePath(relatPath))
2042 { 1991 {
2043 return SendMessageError2( 1992 UString path;
2044 0, // errorCode 1993 if (link.isRelative)
1994 {
1995 // _item.PathParts : parts that will be created in output folder.
1996 // we want to get directory prefix of link item.
1997 // so we remove file name (last non-empty part) from PathParts:
1998 UStringVector v = _item.PathParts;
1999 while (!v.IsEmpty())
2000 {
2001 const unsigned len = v.Back().Len();
2002 v.DeleteBack();
2003 if (len)
2004 break;
2005 }
2006 path = MakePathFromParts(v);
2007 NName::NormalizeDirPathPrefix(path);
2008 }
2009 path += link.LinkPath;
2010 /*
2011 path is calculated virtual target path of link
2012 path is relative to root folder of extracted items
2013 if (!link.isRelative), then (path == link.LinkPath)
2014 */
2015 if (!IsSafePath(path, link.Is_WSL()))
2016 return SendMessageError2(0, // errorCode
2045 "Dangerous link path was ignored", 2017 "Dangerous link path was ignored",
2046 us2fs(_item.Path), 2018 us2fs(_item.Path), us2fs(link.LinkPath));
2047 us2fs(linkInfo.linkPath)); // us2fs(relatPath)
2048 } 2019 }
2049 2020
2050 FString existPath; 2021 FString target; // target path that will be stored to link field
2051 if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative) 2022 if (link.Is_HardLink() /* || link.IsCopyLink */ || !link.isRelative)
2052 { 2023 {
2053 if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) 2024 // isRelative == false
2054 { 2025 // all hard links and absolute symbolic links
2055 RINOK(SendMessageError("Incorrect path", us2fs(relatPath))) 2026 // relatPath == link.LinkPath
2056 } 2027 // we get absolute link path for target:
2028 if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(link.LinkPath), target))
2029 return SendMessageError("Incorrect link path", us2fs(link.LinkPath));
2030 // (target) is (_dirPathPrefix_Full + relatPath)
2057 } 2031 }
2058 else 2032 else
2059 { 2033 {
2060 existPath = us2fs(linkInfo.linkPath); 2034 // link.isRelative == true
2061 // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr()); 2035 // relative symbolic links only
2036 target = us2fs(link.LinkPath);
2062 } 2037 }
2063 2038 if (target.IsEmpty())
2064 if (existPath.IsEmpty()) 2039 return SendMessageError("Empty link", fullProcessedPath_from);
2065 return SendMessageError("Empty link", fullProcessedPath);
2066 2040
2067 if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */) 2041 if (link.Is_HardLink() /* || link.IsCopyLink */)
2068 { 2042 {
2069 // if (linkInfo.isHardLink) 2043 // if (link.isHardLink)
2070 { 2044 {
2071 if (!MyCreateHardLink(fullProcessedPath, existPath)) 2045 if (!MyCreateHardLink(fullProcessedPath_from, target))
2072 { 2046 return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath_from, target);
2073 const HRESULT errorCode = GetLastError_noZero_HRESULT();
2074 RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath))
2075 }
2076 /* 2047 /*
2077 RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) 2048 RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract))
2078 _op_WasReported = true; 2049 _op_WasReported = true;
@@ -2085,19 +2056,19 @@ HRESULT CArchiveExtractCallback::SetFromLinkPath(
2085 // IsCopyLink 2056 // IsCopyLink
2086 { 2057 {
2087 NFind::CFileInfo fi; 2058 NFind::CFileInfo fi;
2088 if (!fi.Find(existPath)) 2059 if (!fi.Find(target))
2089 { 2060 {
2090 RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath)); 2061 RINOK(SendMessageError2("Cannot find the file for copying", target, fullProcessedPath));
2091 } 2062 }
2092 else 2063 else
2093 { 2064 {
2094 if (_curSize_Defined && _curSize == fi.Size) 2065 if (_curSize_Defined && _curSize == fi.Size)
2095 _copyFile_Path = existPath; 2066 _copyFile_Path = target;
2096 else 2067 else
2097 { 2068 {
2098 RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); 2069 RINOK(SendMessageError2("File size collision for file copying", target, fullProcessedPath));
2099 } 2070 }
2100 // RINOK(MyCopyFile(existPath, fullProcessedPath)); 2071 // RINOK(MyCopyFile(target, fullProcessedPath));
2101 } 2072 }
2102 } 2073 }
2103 */ 2074 */
@@ -2111,127 +2082,249 @@ HRESULT CArchiveExtractCallback::SetFromLinkPath(
2111 // Windows before Vista doesn't support symbolic links. 2082 // Windows before Vista doesn't support symbolic links.
2112 // we could convert such symbolic links to Junction Points 2083 // we could convert such symbolic links to Junction Points
2113 // isJunction = true; 2084 // isJunction = true;
2114 // convertToAbs = true;
2115 } 2085 }
2116 */ 2086 */
2117 2087
2118 if (!_ntOptions.SymLinks_AllowDangerous.Val) 2088#ifdef _WIN32
2089 const bool isDir = (_item.IsDir || link.LinkType == k_LinkType_Junction);
2090#endif
2091
2092 if (!_ntOptions.SymLinks_AllowDangerous.Val && link.isRelative)
2119 { 2093 {
2120 #ifdef _WIN32 2094 /*
2121 if (_item.IsDir) 2095 We want to use additional check for links that can link to directory.
2122 #endif 2096 - linux: all symbolic links are files.
2123 if (linkInfo.isRelative) 2097 - windows: we can have file/directory symbolic link,
2124 { 2098 but file symbolic link works like directory link in windows.
2125 CLinkLevelsInfo levelsInfo; 2099 So we use additional check for all relative links.
2126 levelsInfo.Parse(linkInfo.linkPath); 2100
2127 if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute) 2101 We don't allow decreasing of final level of link.
2128 { 2102 So if some another extracted file will use this link,
2129 return SendMessageError2( 2103 then number of real path parts (after link redirection) cannot be
2130 0, // errorCode 2104 smaller than number of requested path parts from archive records.
2131 "Dangerous symbolic link path was ignored", 2105
2132 us2fs(_item.Path), 2106 Now we check only (link.LinkPath) without (_item.PathParts).
2133 us2fs(linkInfo.linkPath)); 2107 */
2134 } 2108 CLinkLevelsInfo levelsInfo;
2135 } 2109 levelsInfo.Parse(link.LinkPath, link.Is_WSL());
2110 if (levelsInfo.FinalLevel < 1
2111 // || levelsInfo.LowLevel < 0 // we allow negative temporary levels
2112 || levelsInfo.IsAbsolute)
2113 return SendMessageError2(0, // errorCode
2114 "Dangerous symbolic link path was ignored",
2115 us2fs(_item.Path), us2fs(link.LinkPath));
2136 } 2116 }
2137 2117
2138 2118
2139 #ifdef _WIN32 2119#ifdef _WIN32
2140
2141 CByteBuffer data; 2120 CByteBuffer data;
2142 // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr()); 2121 // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr());
2143 if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL)) 2122 if (link.Is_WSL())
2123 {
2124 Convert_WinPath_to_WslLinuxPath(target, !link.isRelative);
2125 FillLinkData_WslLink(data, fs2us(target));
2126 }
2127 else
2128 FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction);
2129 if (data.Size() == 0)
2144 return SendMessageError("Cannot fill link data", us2fs(_item.Path)); 2130 return SendMessageError("Cannot fill link data", us2fs(_item.Path));
2145
2146 /* 2131 /*
2147 if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) 2132 if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
2148 { 2133 SendMessageError("reconstructed Reparse is different", fs2us(target));
2149 SendMessageError("reconstructed Reparse is different", fs2us(existPath));
2150 }
2151 */ 2134 */
2152
2153 CReparseAttr attr;
2154 if (!attr.Parse(data, data.Size()))
2155 { 2135 {
2156 RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))) 2136 // we check that reparse data is correct, but we ignore attr.MinorError.
2157 return S_OK; 2137 CReparseAttr attr;
2138 if (!attr.Parse(data, data.Size()))
2139 return SendMessageError("Internal error for symbolic link file", us2fs(_item.Path));
2158 } 2140 }
2159 if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) 2141 if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size()))
2142#else // ! _WIN32
2143 if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target))
2144#endif // ! _WIN32
2160 { 2145 {
2161 RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) 2146 return SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from);
2162 return S_OK;
2163 } 2147 }
2164 linkWasSet = true; 2148 linkWasSet = true;
2165
2166 return S_OK; 2149 return S_OK;
2167 2150}
2168 2151
2169 #else // ! _WIN32 2152
2170 2153
2171 if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath)) 2154bool CLinkInfo::Parse_from_WindowsReparseData(const Byte *data, size_t dataSize)
2155{
2156 CReparseAttr reparse;
2157 if (!reparse.Parse(data, dataSize))
2158 return false;
2159 // const AString s = GetAnsiString(LinkPath);
2160 // printf("\nlinkPath: %s\n", s.Ptr());
2161 LinkPath = reparse.GetPath();
2162 if (reparse.IsSymLink_WSL())
2172 { 2163 {
2173 RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) 2164 LinkType = k_LinkType_WSL;
2174 return S_OK; 2165 isRelative = reparse.IsRelative_WSL(); // detected from LinkPath[0]
2166 // LinkPath is original raw name converted to UString from AString
2167 // Linux separator '/' is expected here.
2168 REPLACE_SLASHES_from_Linux_to_Sys(LinkPath)
2175 } 2169 }
2176 linkWasSet = true; 2170 else
2171 {
2172 LinkType = reparse.IsMountPoint() ? k_LinkType_Junction : k_LinkType_PureSymLink;
2173 isRelative = reparse.IsRelative_Win(); // detected by (Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE)
2174 isWindowsPath = true;
2175 // LinkPath is original windows link path from raparse data with \??\ prefix removed.
2176 // windows '\\' separator is expected here.
2177 // linux '/' separator is not expected here.
2178 // we translate both types of separators to system separator.
2179 LinkPath.Replace(
2180#if WCHAR_PATH_SEPARATOR == L'\\'
2181 L'/'
2182#else
2183 L'\\'
2184#endif
2185 , WCHAR_PATH_SEPARATOR);
2186 }
2187 // (LinkPath) uses system path separator.
2188 // windows: (LinkPath) doesn't contain linux separator (slash).
2189 return true;
2190}
2177 2191
2178 return S_OK;
2179 2192
2180 #endif // ! _WIN32 2193bool CLinkInfo::Parse_from_LinuxData(const Byte *data, size_t dataSize)
2194{
2195 // Clear(); // *this object was cleared by constructor already.
2196 LinkType = k_LinkType_PureSymLink;
2197 AString utf;
2198 if (dataSize >= k_LinkDataSize_LIMIT)
2199 return false;
2200 utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
2201 UString u;
2202 if (!ConvertUTF8ToUnicode(utf, u))
2203 return false;
2204 if (u.IsEmpty())
2205 return false;
2206 const wchar_t c = u[0];
2207 isRelative = (c != L'/');
2208 // linux path separator is expected
2209 REPLACE_SLASHES_from_Linux_to_Sys(u)
2210 LinkPath = u;
2211 // (LinkPath) uses system path separator.
2212 // windows: (LinkPath) doesn't contain linux separator (slash).
2213 return true;
2214}
2215
2216
2217// in/out: (LinkPath) uses system path separator
2218// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
2219// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
2220// out: isRelative changed to false, if any prefix was removed.
2221// note: absolute windows links "c:\" to root will be reduced to empty string:
2222void CLinkInfo::Remove_AbsPathPrefixes()
2223{
2224 while (!LinkPath.IsEmpty())
2225 {
2226 unsigned n = 0;
2227 if (!Is_WSL())
2228 {
2229 n =
2230#ifndef _WIN32
2231 isWindowsPath ?
2232 NName::GetRootPrefixSize_WINDOWS(LinkPath) :
2233#endif
2234 NName::GetRootPrefixSize(LinkPath);
2235/*
2236 // "c:path" will be ignored later as "Dangerous absolute path"
2237 // so check is not required
2238 if (n == 0
2239#ifndef _WIN32
2240 && isWindowsPath
2241#endif
2242 && NName::IsDrivePath2(LinkPath))
2243 n = 2;
2244*/
2245 }
2246 if (n == 0)
2247 {
2248 if (!IS_PATH_SEPAR(LinkPath[0]))
2249 break;
2250 n = 1;
2251 }
2252 isRelative = false; // (LinkPath) will be treated as relative to root folder of archive
2253 LinkPath.DeleteFrontal(n);
2254 }
2181} 2255}
2182 2256
2183 2257
2184bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData) 2258/*
2259 it removes redundant separators, if there are double separators,
2260 but it keeps double separators at start of string //name/.
2261 in/out: system path separator is used
2262 windows: slash character (linux separator) is not treated as separator
2263 windows: (path) doesn't contain linux separator (slash).
2264*/
2265static void RemoveRedundantPathSeparators(UString &path)
2185{ 2266{
2186 Clear(); 2267 wchar_t *dest = path.GetBuf();
2187 // this->isLinux = isLinuxData; 2268 const wchar_t * const start = dest;
2188 2269 const wchar_t *src = dest;
2189 if (isLinuxData) 2270 for (;;)
2190 { 2271 {
2191 isJunction = false; 2272 wchar_t c = *src++;
2192 isHardLink = false; 2273 if (c == 0)
2193 AString utf; 2274 break;
2194 if (dataSize >= (1 << 12)) 2275 // if (IS_PATH_SEPAR(c)) // for Windows: we can change (/) to (\).
2195 return false; 2276 if (c == WCHAR_PATH_SEPARATOR)
2196 utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize); 2277 {
2197 UString u; 2278 if (dest - start >= 2 && dest[-1] == WCHAR_PATH_SEPARATOR)
2198 if (!ConvertUTF8ToUnicode(utf, u)) 2279 continue;
2199 return false; 2280 // c = WCHAR_PATH_SEPARATOR; // for Windows: we can change (/) to (\).
2200 linkPath = u; 2281 }
2201 2282 *dest++ = c;
2202 // in linux symbolic data: we expect that linux separator '/' is used
2203 // if windows link was created, then we also must use linux separator
2204 if (u.IsEmpty())
2205 return false;
2206 const wchar_t c = u[0];
2207 isRelative = !IS_PATH_SEPAR(c);
2208 return true;
2209 } 2283 }
2284 *dest = 0;
2285 path.ReleaseBuf_SetLen((unsigned)(dest - path.Ptr()));
2286}
2210 2287
2211 CReparseAttr reparse; 2288
2212 if (!reparse.Parse(data, dataSize)) 2289// in/out: (LinkPath) uses system path separator
2213 return false; 2290// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
2214 isHardLink = false; 2291// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
2215 // isCopyLink = false; 2292void CLinkInfo::Normalize_to_RelativeSafe(UStringVector &removePathParts)
2216 linkPath = reparse.GetPath(); 2293{
2217 isJunction = reparse.IsMountPoint(); 2294 // We WILL NOT WRITE original absolute link path from archive to filesystem.
2218 2295 // So here we remove all root prefixes from (LinkPath).
2219 if (reparse.IsSymLink_WSL()) 2296 // If we see any absolute root prefix, then we suppose that this prefix is virtual prefix
2297 // that shows that link is relative to root folder of archive
2298 RemoveRedundantPathSeparators(LinkPath);
2299 // LinkPath = "\\\\?\\r:test\\test2"; // for debug
2300 Remove_AbsPathPrefixes();
2301 // (LinkPath) now is relative:
2302 // if (isRelative == false), then (LinkPath) is relative to root folder of archive
2303 // if (isRelative == true ), then (LinkPath) is relative to current item
2304 if (LinkPath.IsEmpty() || isRelative || removePathParts.Size() == 0)
2305 return;
2306
2307 // if LinkPath is prefixed by _removePathParts, we remove these paths
2308 UStringVector pathParts;
2309 SplitPathToParts(LinkPath, pathParts);
2310 bool badPrefix = false;
2220 { 2311 {
2221 isWSL = true; 2312 FOR_VECTOR (i, removePathParts)
2222 isRelative = reparse.IsRelative_WSL(); 2313 {
2314 if (i >= pathParts.Size()
2315 || CompareFileNames(removePathParts[i], pathParts[i]) != 0)
2316 {
2317 badPrefix = true;
2318 break;
2319 }
2320 }
2223 } 2321 }
2224 else 2322 if (!badPrefix)
2225 isRelative = reparse.IsRelative_Win(); 2323 pathParts.DeleteFrontal(removePathParts.Size());
2226 2324 LinkPath = MakePathFromParts(pathParts);
2227 // FIXME !!! 2325 Remove_AbsPathPrefixes();
2228 #ifndef _WIN32
2229 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
2230 #endif
2231
2232 return true;
2233} 2326}
2234 2327
2235#endif // SUPPORT_LINKS 2328#endif // SUPPORT_LINKS
2236 2329
2237 2330
@@ -2239,12 +2332,12 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2239{ 2332{
2240 HRESULT res = S_OK; 2333 HRESULT res = S_OK;
2241 2334
2242 #ifdef SUPPORT_LINKS 2335#ifdef SUPPORT_LINKS
2243 2336
2244 size_t reparseSize = 0; 2337 size_t reparseSize = 0;
2245 bool repraseMode = false; 2338 bool repraseMode = false;
2246 bool needSetReparse = false; 2339 bool needSetReparse = false;
2247 CLinkInfo linkInfo; 2340 CLinkInfo link;
2248 2341
2249 if (_bufPtrSeqOutStream) 2342 if (_bufPtrSeqOutStream)
2250 { 2343 {
@@ -2258,15 +2351,19 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2258 needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); 2351 needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
2259 if (needSetReparse) 2352 if (needSetReparse)
2260 { 2353 {
2261 UString linkPath = reparse.GetPath(); 2354 UString LinkPath = reparse.GetPath();
2262 #ifndef _WIN32 2355 #ifndef _WIN32
2263 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); 2356 LinkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
2264 #endif 2357 #endif
2265 } 2358 }
2266 */ 2359 */
2267 needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux); 2360 needSetReparse = _is_SymLink_in_Data_Linux ?
2361 link.Parse_from_LinuxData(_outMemBuf, reparseSize) :
2362 link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize);
2268 if (!needSetReparse) 2363 if (!needSetReparse)
2269 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); 2364 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
2365 // (link.LinkPath) uses system path separator.
2366 // windows: (link.LinkPath) doesn't contain linux separator (slash).
2270 } 2367 }
2271 else 2368 else
2272 { 2369 {
@@ -2281,23 +2378,18 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2281 _bufPtrSeqOutStream.Release(); 2378 _bufPtrSeqOutStream.Release();
2282 } 2379 }
2283 2380
2284 #endif // SUPPORT_LINKS 2381#endif // SUPPORT_LINKS
2285
2286 2382
2287 const HRESULT res2 = CloseFile(); 2383 const HRESULT res2 = CloseFile();
2288
2289 if (res == S_OK) 2384 if (res == S_OK)
2290 res = res2; 2385 res = res2;
2291
2292 RINOK(res) 2386 RINOK(res)
2293 2387
2294 #ifdef SUPPORT_LINKS 2388#ifdef SUPPORT_LINKS
2295 if (repraseMode) 2389 if (repraseMode)
2296 { 2390 {
2297 _curSize = reparseSize; 2391 _curSize = reparseSize;
2298 _curSize_Defined = true; 2392 _curSize_Defined = true;
2299
2300 #ifdef SUPPORT_LINKS
2301 if (needSetReparse) 2393 if (needSetReparse)
2302 { 2394 {
2303 // in Linux : we must delete empty file before symbolic link creation 2395 // in Linux : we must delete empty file before symbolic link creation
@@ -2307,31 +2399,19 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2307 RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) 2399 RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
2308 } 2400 }
2309 { 2401 {
2310 /*
2311 // for DEBUG ONLY: we can extract sym links as WSL links
2312 // to eliminate (non-admin) errors for sym links.
2313 #ifdef _WIN32
2314 if (!linkInfo.isHardLink && !linkInfo.isJunction)
2315 linkInfo.isWSL = true;
2316 #endif
2317 */
2318 bool linkWasSet = false; 2402 bool linkWasSet = false;
2319 RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet)) 2403 // link.LinkPath = "r:\\1\\2"; // for debug
2404 // link.isJunction = true; // for debug
2405 link.Normalize_to_RelativeSafe(_removePathParts);
2406 RINOK(SetLink(_diskFilePath, link, linkWasSet))
2320 if (linkWasSet) 2407 if (linkWasSet)
2321 _isSymLinkCreated = linkInfo.IsSymLink(); 2408 _isSymLinkCreated = true; // link.IsSymLink();
2322 else 2409 else
2323 _needSetAttrib = false; 2410 _needSetAttrib = false;
2324 } 2411 }
2325 /*
2326 if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
2327 {
2328 res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
2329 }
2330 */
2331 } 2412 }
2332 #endif
2333 } 2413 }
2334 #endif 2414#endif // SUPPORT_LINKS
2335 return res; 2415 return res;
2336} 2416}
2337 2417
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
index f3ee01c..71fa3ef 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -178,36 +178,50 @@ struct CDirPathTime: public CFiTimesCAM
178 178
179#ifdef SUPPORT_LINKS 179#ifdef SUPPORT_LINKS
180 180
181
182enum ELinkType
183{
184 k_LinkType_HardLink,
185 k_LinkType_PureSymLink,
186 k_LinkType_Junction,
187 k_LinkType_WSL
188 // , k_LinkType_CopyLink;
189};
190
191
181struct CLinkInfo 192struct CLinkInfo
182{ 193{
183 // bool isCopyLink; 194 ELinkType LinkType;
184 bool isHardLink;
185 bool isJunction;
186 bool isRelative; 195 bool isRelative;
187 bool isWSL; 196 // if (isRelative == false), then (LinkPath) is relative to root folder of archive
188 UString linkPath; 197 // if (isRelative == true ), then (LinkPath) is relative to current item
198 bool isWindowsPath;
199 UString LinkPath;
200
201 bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; }
202 bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; }
189 203
190 bool IsSymLink() const { return !isHardLink; } 204 bool Is_WSL() const { return LinkType == k_LinkType_WSL; }
191 205
192 CLinkInfo(): 206 CLinkInfo():
193 // IsCopyLink(false), 207 LinkType(k_LinkType_PureSymLink),
194 isHardLink(false),
195 isJunction(false),
196 isRelative(false), 208 isRelative(false),
197 isWSL(false) 209 isWindowsPath(false)
198 {} 210 {}
199 211
200 void Clear() 212 void Clear()
201 { 213 {
202 // IsCopyLink = false; 214 LinkType = k_LinkType_PureSymLink;
203 isHardLink = false;
204 isJunction = false;
205 isRelative = false; 215 isRelative = false;
206 isWSL = false; 216 isWindowsPath = false;
207 linkPath.Empty(); 217 LinkPath.Empty();
208 } 218 }
209 219
210 bool Parse(const Byte *data, size_t dataSize, bool isLinuxData); 220 bool Parse_from_WindowsReparseData(const Byte *data, size_t dataSize);
221 bool Parse_from_LinuxData(const Byte *data, size_t dataSize);
222 void Normalize_to_RelativeSafe(UStringVector &removePathParts);
223private:
224 void Remove_AbsPathPrefixes();
211}; 225};
212 226
213#endif // SUPPORT_LINKS 227#endif // SUPPORT_LINKS
@@ -287,8 +301,8 @@ private:
287 301
288 bool _isRenamed; 302 bool _isRenamed;
289 bool _extractMode; 303 bool _extractMode;
290 // bool _is_SymLink_in_Data; 304 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX.
291 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX 305 // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file.
292 bool _needSetAttrib; 306 bool _needSetAttrib;
293 bool _isSymLinkCreated; 307 bool _isSymLinkCreated;
294 bool _itemFailure; 308 bool _itemFailure;
@@ -420,6 +434,7 @@ public:
420 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); 434 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path);
421 HRESULT SendMessageError_with_LastError(const char *message, const FString &path); 435 HRESULT SendMessageError_with_LastError(const char *message, const FString &path);
422 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); 436 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2);
437 HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2);
423 438
424#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) 439#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
425 NExtract::NZoneIdMode::EEnum ZoneMode; 440 NExtract::NZoneIdMode::EEnum ZoneMode;
@@ -487,11 +502,16 @@ public:
487private: 502private:
488 CHardLinks _hardLinks; 503 CHardLinks _hardLinks;
489 CLinkInfo _link; 504 CLinkInfo _link;
505 // const void *NtReparse_Data;
506 // UInt32 NtReparse_Size;
490 507
491 // FString _copyFile_Path; 508 // FString _copyFile_Path;
492 // HRESULT MyCopyFile(ISequentialOutStream *outStream); 509 // HRESULT MyCopyFile(ISequentialOutStream *outStream);
493 HRESULT Link(const FString &fullProcessedPath);
494 HRESULT ReadLink(); 510 HRESULT ReadLink();
511 HRESULT SetLink(
512 const FString &fullProcessedPath_from,
513 const CLinkInfo &linkInfo,
514 bool &linkWasSet);
495 515
496public: 516public:
497 // call PrepareHardLinks() after Init() 517 // call PrepareHardLinks() after Init()
@@ -538,16 +558,6 @@ private:
538 HRESULT CloseReparseAndFile(); 558 HRESULT CloseReparseAndFile();
539 HRESULT CloseReparseAndFile2(); 559 HRESULT CloseReparseAndFile2();
540 HRESULT SetDirsTimes(); 560 HRESULT SetDirsTimes();
541
542 const void *NtReparse_Data;
543 UInt32 NtReparse_Size;
544
545 #ifdef SUPPORT_LINKS
546 HRESULT SetFromLinkPath(
547 const FString &fullProcessedPath,
548 const CLinkInfo &linkInfo,
549 bool &linkWasSet);
550 #endif
551}; 561};
552 562
553 563
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp
index 05d66aa..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 {
@@ -2962,7 +2984,7 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
2962{ 2984{
2963 AString s; 2985 AString s;
2964 // s.Add_UInt32(ti.numProcessThreads); 2986 // s.Add_UInt32(ti.numProcessThreads);
2965 unsigned numSysThreads = ti.GetNumSystemThreads(); 2987 const unsigned numSysThreads = ti.GetNumSystemThreads();
2966 if (ti.GetNumProcessThreads() != numSysThreads) 2988 if (ti.GetNumProcessThreads() != numSysThreads)
2967 { 2989 {
2968 // if (ti.numProcessThreads != ti.numSysThreads) 2990 // if (ti.numProcessThreads != ti.numSysThreads)
@@ -2992,6 +3014,35 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
2992 } 3014 }
2993 #endif 3015 #endif
2994 } 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
2995 return s; 3046 return s;
2996} 3047}
2997 3048
@@ -3753,9 +3804,13 @@ HRESULT Bench(
3753 UInt64 complexInCommands = kComplexInCommands; 3804 UInt64 complexInCommands = kComplexInCommands;
3754 UInt32 numThreads_Start = 1; 3805 UInt32 numThreads_Start = 1;
3755 3806
3756 #ifndef Z7_ST 3807#ifndef Z7_ST
3757 CAffinityMode affinityMode; 3808 CAffinityMode affinityMode;
3758 #endif 3809#ifdef _WIN32
3810 if (threadsInfo.IsGroupMode && threadsInfo.Groups.GroupSizes.Size() > 1)
3811 affinityMode.NumGroups = threadsInfo.Groups.GroupSizes.Size();
3812#endif
3813#endif
3759 3814
3760 3815
3761 COneMethodInfo method; 3816 COneMethodInfo method;
@@ -4861,7 +4916,7 @@ HRESULT Bench(
4861 if (AreSameMethodNames(benchMethod, methodName)) 4916 if (AreSameMethodNames(benchMethod, methodName))
4862 { 4917 {
4863 if (benchProps.IsEmpty() 4918 if (benchProps.IsEmpty()
4864 || (benchProps == "x5" && method.PropsString.IsEmpty()) 4919 || (benchProps.IsEqualTo("x5") && method.PropsString.IsEmpty())
4865 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) 4920 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
4866 { 4921 {
4867 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 11643ae..cada2e6 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -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 9caac36..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,56 +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 , "sha384" 793 , "sha384"
779 , "sha512" 794 , "sha512"
780// , "sha3-224" 795 , "sha3-224"
781 , "sha3-256" 796 , "sha3-256"
782// , "sha3-384" 797 , "sha3-384"
783// , "sha3-512" 798 , "sha3-512"
784// , "shake128" 799// , "shake128"
785// , "shake256" 800// , "shake256"
786 , "sha1" 801 , "sha1"
802 , "sha2"
803 , "sha3"
804 , "sha"
787 , "md5" 805 , "md5"
788 , "blake2sp" 806 , "blake2s"
789 , "blake2b" 807 , "blake2b"
808 , "blake2sp"
790 , "xxh64" 809 , "xxh64"
791 , "crc64"
792 , "crc32" 810 , "crc32"
811 , "crc64"
793 , "cksum" 812 , "cksum"
794}; 813};
795 814
796static 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)
797{ 818{
819 method.Empty();
798 AString s; 820 AString s;
799 ConvertUnicodeToUTF8(name, s); 821 ConvertUnicodeToUTF8(name, s);
800 const int dotPos = s.ReverseFind_Dot(); 822 const int dotPos = s.ReverseFind_Dot();
801 const char *src = s.Ptr();
802 bool isExtension = false;
803 if (dotPos >= 0) 823 if (dotPos >= 0)
804 { 824 {
805 isExtension = true; 825 method = s.Ptr(dotPos + 1);
806 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 }
807 } 834 }
808 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
809 unsigned i; 849 unsigned i;
810 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) 850 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
811 { 851 {
812 m = k_CsumMethodNames[i]; 852 const char *m = k_CsumMethodNames[i];
813 if (isExtension) 853 if (method.IsEqualTo_Ascii_NoCase(m))
814 { 854 {
815 if (StringsAreEqual_Ascii(src, m)) 855 // method = m; // we can get lowcase
816 break; 856 return true;
817 } 857 }
818 else if (IsString1PrefixedByString2_NoCase_Ascii(src, m))
819 if (StringsAreEqual_Ascii(src + strlen(m), "sums"))
820 break;
821 } 858 }
822 UString res; 859
823 if (i != Z7_ARRAY_SIZE(k_CsumMethodNames)) 860/*
824 res = m; 861 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
825 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;
826} 872}
827 873
828 874
@@ -1047,7 +1093,7 @@ Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
1047 if (propID == kpidChecksum) 1093 if (propID == kpidChecksum)
1048 { 1094 {
1049 const CHashPair &hp = HashPairs[index]; 1095 const CHashPair &hp = HashPairs[index];
1050 if (hp.Hash.Size() > 0) 1096 if (hp.Hash.Size() != 0)
1051 { 1097 {
1052 *data = hp.Hash; 1098 *data = hp.Hash;
1053 *dataSize = (UInt32)hp.Hash.Size(); 1099 *dataSize = (UInt32)hp.Hash.Size();
@@ -1100,11 +1146,6 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1100 s.Add_UInt32(_hashSize * 8); 1146 s.Add_UInt32(_hashSize * 8);
1101 s += "-bit"; 1147 s += "-bit";
1102 } 1148 }
1103 if (!_nameExtenstion.IsEmpty())
1104 {
1105 s.Add_Space_if_NotEmpty();
1106 s += _nameExtenstion;
1107 }
1108 if (_is_PgpMethod) 1149 if (_is_PgpMethod)
1109 { 1150 {
1110 Add_OptSpace_String(s, "PGP"); 1151 Add_OptSpace_String(s, "PGP");
@@ -1120,6 +1161,18 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1120 Add_OptSpace_String(s, "TAG"); 1161 Add_OptSpace_String(s, "TAG");
1121 if (_are_there_Dirs) 1162 if (_are_there_Dirs)
1122 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 }
1123 prop = s; 1176 prop = s;
1124 break; 1177 break;
1125 } 1178 }
@@ -1228,6 +1281,15 @@ static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOp
1228} 1281}
1229 1282
1230 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
1231Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) 1293Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
1232{ 1294{
1233 COM_TRY_BEGIN 1295 COM_TRY_BEGIN
@@ -1239,17 +1301,9 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
1239 1301
1240 CObjectVector<CHashPair> &pairs = HashPairs; 1302 CObjectVector<CHashPair> &pairs = HashPairs;
1241 1303
1242 bool zeroMode = false; 1304 const bool zeroMode = isThere_Zero_Byte(buf, buf.Size());
1243 bool cr_lf_Mode = false;
1244 {
1245 for (size_t i = 0; i < buf.Size(); i++)
1246 if (buf.ConstData()[i] == 0)
1247 {
1248 zeroMode = true;
1249 break;
1250 }
1251 }
1252 _is_ZeroMode = zeroMode; 1305 _is_ZeroMode = zeroMode;
1306 bool cr_lf_Mode = false;
1253 if (!zeroMode) 1307 if (!zeroMode)
1254 cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); 1308 cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size());
1255 1309
@@ -1263,13 +1317,21 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
1263 NCOM::CPropVariant prop; 1317 NCOM::CPropVariant prop;
1264 RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) 1318 RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
1265 if (prop.vt == VT_BSTR) 1319 if (prop.vt == VT_BSTR)
1266 _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); 1320 _is_KnownMethod_in_FileName = GetMethod_from_FileName(prop.bstrVal, _method_from_FileName);
1267 } 1321 }
1268 } 1322 }
1269 1323
1270 bool cksumMode = false; 1324 if (!_methods.IsEmpty())
1271 if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) 1325 {
1272 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");
1273 _is_CksumMode = cksumMode; 1335 _is_CksumMode = cksumMode;
1274 1336
1275 size_t pos = 0; 1337 size_t pos = 0;
@@ -1366,6 +1428,7 @@ void CHandler::ClearVars()
1366 _is_ZeroMode = false; 1428 _is_ZeroMode = false;
1367 _are_there_Tags = false; 1429 _are_there_Tags = false;
1368 _are_there_Dirs = false; 1430 _are_there_Dirs = false;
1431 _is_KnownMethod_in_FileName = false;
1369 _hashSize_Defined = false; 1432 _hashSize_Defined = false;
1370 _hashSize = 0; 1433 _hashSize = 0;
1371} 1434}
@@ -1374,7 +1437,8 @@ void CHandler::ClearVars()
1374Z7_COM7F_IMF(CHandler::Close()) 1437Z7_COM7F_IMF(CHandler::Close())
1375{ 1438{
1376 ClearVars(); 1439 ClearVars();
1377 _nameExtenstion.Empty(); 1440 _method_from_FileName.Empty();
1441 _method_for_Extraction.Empty();
1378 _pgpMethod.Empty(); 1442 _pgpMethod.Empty();
1379 HashPairs.Clear(); 1443 HashPairs.Clear();
1380 return S_OK; 1444 return S_OK;
@@ -1401,19 +1465,73 @@ static bool CheckDigests(const Byte *a, const Byte *b, size_t size)
1401} 1465}
1402 1466
1403 1467
1404static void AddDefaultMethod(UStringVector &methods, unsigned size) 1468static void AddDefaultMethod(UStringVector &methods,
1469 const char *name, unsigned size)
1405{ 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
1406 const char *m = NULL; 1511 const char *m = NULL;
1407 if (size == 32) m = "sha256"; 1512 if (name)
1408 else if (size == 20) m = "sha1"; 1513 m = name;
1409 else if (size == 16) m = "md5";
1410 else if (size == 8) m = "crc64";
1411 else if (size == 4) m = "crc32";
1412 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)
1413 return; 1530 return;
1414 #ifdef Z7_EXTERNAL_CODECS 1531
1532#ifdef Z7_EXTERNAL_CODECS
1415 const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; 1533 const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
1416 #endif 1534#endif
1417 CMethodId id; 1535 CMethodId id;
1418 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS 1536 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS
1419 AString(m), id)) 1537 AString(m), id))
@@ -1444,15 +1562,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1444 CHashBundle hb_Glob; 1562 CHashBundle hb_Glob;
1445 // UStringVector methods = options.Methods; 1563 // UStringVector methods = options.Methods;
1446 UStringVector methods; 1564 UStringVector methods;
1447 1565
1448 if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) 1566/*
1567 if (methods.IsEmpty() && !utf_nameExtenstion.IsEmpty() && !_hashSize_Defined)
1449 { 1568 {
1450 AString utf;
1451 ConvertUnicodeToUTF8(_nameExtenstion, utf);
1452 CMethodId id; 1569 CMethodId id;
1453 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) 1570 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf_nameExtenstion, id))
1454 methods.Add(_nameExtenstion); 1571 methods.Add(_nameExtenstion);
1455 } 1572 }
1573*/
1456 1574
1457 if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) 1575 if (methods.IsEmpty() && !_pgpMethod.IsEmpty())
1458 { 1576 {
@@ -1461,12 +1579,21 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1461 methods.Add(UString(_pgpMethod)); 1579 methods.Add(UString(_pgpMethod));
1462 } 1580 }
1463 1581
1582/*
1464 if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) 1583 if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined)
1465 AddDefaultMethod(methods, _hashSize); 1584 {
1585 AddDefaultMethod(methods,
1586 utf_nameExtenstion.IsEmpty() ? NULL : utf_nameExtenstion.Ptr(),
1587 _hashSize);
1588 }
1589*/
1466 1590
1467 RINOK(hb_Glob.SetMethods( 1591 if (!methods.IsEmpty())
1592 {
1593 RINOK(hb_Glob.SetMethods(
1468 EXTERNAL_CODECS_LOC_VARS 1594 EXTERNAL_CODECS_LOC_VARS
1469 methods)) 1595 methods))
1596 }
1470 1597
1471 Z7_DECL_CMyComPtr_QI_FROM( 1598 Z7_DECL_CMyComPtr_QI_FROM(
1472 IArchiveUpdateCallbackFile, 1599 IArchiveUpdateCallbackFile,
@@ -1561,9 +1688,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1561 { 1688 {
1562 hb_Use = &hb_Loc; 1689 hb_Use = &hb_Loc;
1563 CMethodId id; 1690 CMethodId id;
1564 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))
1565 { 1694 {
1566 methods_loc.Add(UString(hp.Method)); 1695 methods_loc.Add(UString(methodName));
1567 RINOK(hb_Loc.SetMethods( 1696 RINOK(hb_Loc.SetMethods(
1568 EXTERNAL_CODECS_LOC_VARS 1697 EXTERNAL_CODECS_LOC_VARS
1569 methods_loc)) 1698 methods_loc))
@@ -1573,7 +1702,10 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1573 } 1702 }
1574 else if (methods.IsEmpty()) 1703 else if (methods.IsEmpty())
1575 { 1704 {
1576 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());
1577 if (!methods_loc.IsEmpty()) 1709 if (!methods_loc.IsEmpty())
1578 { 1710 {
1579 hb_Use = &hb_Loc; 1711 hb_Use = &hb_Loc;
@@ -1621,7 +1753,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1621 Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; 1753 Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod;
1622 if (isSupportedMode 1754 if (isSupportedMode
1623 && res_SetMethods != E_NOTIMPL 1755 && res_SetMethods != E_NOTIMPL
1624 && hb_Use->Hashers.Size() > 0 1756 && !hb_Use->Hashers.IsEmpty()
1625 ) 1757 )
1626 { 1758 {
1627 const CHasherState &hs = hb_Use->Hashers[0]; 1759 const CHasherState &hs = hb_Use->Hashers[0];
@@ -1774,10 +1906,6 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1774 methods.Add(_methods[k]); 1906 methods.Add(_methods[k]);
1775 } 1907 }
1776 } 1908 }
1777 else if (_crcSize_WasSet)
1778 {
1779 AddDefaultMethod(methods, _crcSize);
1780 }
1781 else 1909 else
1782 { 1910 {
1783 Z7_DECL_CMyComPtr_QI_FROM( 1911 Z7_DECL_CMyComPtr_QI_FROM(
@@ -1789,12 +1917,23 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1789 RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) 1917 RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop))
1790 if (prop.vt == VT_BSTR) 1918 if (prop.vt == VT_BSTR)
1791 { 1919 {
1792 const UString method = GetMethod_from_FileName(prop.bstrVal); 1920 AString method;
1921 /* const bool isKnownMethod = */ GetMethod_from_FileName(prop.bstrVal, method);
1793 if (!method.IsEmpty()) 1922 if (!method.IsEmpty())
1794 methods.Add(method); 1923 {
1924 AddDefaultMethod(methods, method, _crcSize_WasSet ? _crcSize : 0);
1925 if (methods.IsEmpty())
1926 return E_NOTIMPL;
1927 }
1795 } 1928 }
1796 } 1929 }
1797 } 1930 }
1931 if (methods.IsEmpty() && _crcSize_WasSet)
1932 {
1933 AddDefaultMethod(methods,
1934 NULL, // name
1935 _crcSize);
1936 }
1798 1937
1799 RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) 1938 RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods))
1800 1939
@@ -2038,6 +2177,15 @@ HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
2038} 2177}
2039 2178
2040 2179
2180void CHandler::InitProps()
2181{
2182 _supportWindowsBackslash = true;
2183 _crcSize_WasSet = false;
2184 _crcSize = 4;
2185 _methods.Clear();
2186 _options.Init_HashOptionsLocal();
2187}
2188
2041Z7_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))
2042{ 2190{
2043 COM_TRY_BEGIN 2191 COM_TRY_BEGIN
@@ -2088,22 +2236,27 @@ void Codecs_AddHashArcHandler(CCodecs *codecs)
2088 " sha512" 2236 " sha512"
2089 " sha384" 2237 " sha384"
2090 " sha224" 2238 " sha224"
2091 // " sha512-224" 2239 " sha512-224"
2092 // " sha512-256" 2240 " sha512-256"
2093 // " sha3-224" 2241 " sha3-224"
2094 " sha3-256" 2242 " sha3-256"
2095 // " sha3-384" 2243 " sha3-384"
2096 // " sha3-512" 2244 " sha3-512"
2097 // " shake128" 2245 // " shake128"
2098 // " shake256" 2246 // " shake256"
2099 " sha1" 2247 " sha1"
2248 " sha2"
2249 " sha3"
2100 " sha" 2250 " sha"
2101 " md5" 2251 " md5"
2252 " blake2s"
2253 " blake2b"
2102 " blake2sp" 2254 " blake2sp"
2103 " xxh64" 2255 " xxh64"
2104 " crc32 crc64" 2256 " crc32"
2105 " asc" 2257 " crc64"
2106 " cksum" 2258 " cksum"
2259 " asc"
2107 // " b2sum" 2260 // " b2sum"
2108 ), 2261 ),
2109 UString()); 2262 UString());
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/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
index b959a3c..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 {
@@ -1920,7 +1920,7 @@ Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
1920 if (NFind::DoesDirExist(phyPath)) 1920 if (NFind::DoesDirExist(phyPath))
1921 { 1921 {
1922 RINOK(callback->DeletingAfterArchiving(phyPath, true)) 1922 RINOK(callback->DeletingAfterArchiving(phyPath, true))
1923 RemoveDir(phyPath); 1923 RemoveDirAlways_if_Empty(phyPath);
1924 } 1924 }
1925 } 1925 }
1926 1926
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h
index 216339a..ae141e5 100644
--- a/CPP/7zip/UI/Common/Update.h
+++ b/CPP/7zip/UI/Common/Update.h
@@ -94,6 +94,7 @@ struct CUpdateOptions
94 94
95 bool DeleteAfterCompressing; 95 bool DeleteAfterCompressing;
96 bool SetArcMTime; 96 bool SetArcMTime;
97 bool RenameMode;
97 98
98 CBoolPair NtSecurity; 99 CBoolPair NtSecurity;
99 CBoolPair AltStreams; 100 CBoolPair AltStreams;
@@ -139,6 +140,7 @@ struct CUpdateOptions
139 140
140 DeleteAfterCompressing(false), 141 DeleteAfterCompressing(false),
141 SetArcMTime(false), 142 SetArcMTime(false),
143 RenameMode(false),
142 144
143 ArcNameMode(k_ArcNameMode_Smart), 145 ArcNameMode(k_ArcNameMode_Smart),
144 PathMode(NWildcard::k_RelatPath) 146 PathMode(NWildcard::k_RelatPath)
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/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/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/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/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/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/FM.cpp b/CPP/7zip/UI/FileManager/FM.cpp
index 7310802..b2f4c2b 100644
--- a/CPP/7zip/UI/FileManager/FM.cpp
+++ b/CPP/7zip/UI/FileManager/FM.cpp
@@ -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 /*
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/Panel.h b/CPP/7zip/UI/FileManager/Panel.h
index 9c53048..9ef0926 100644
--- a/CPP/7zip/UI/FileManager/Panel.h
+++ b/CPP/7zip/UI/FileManager/Panel.h
@@ -711,8 +711,8 @@ public:
711 } 711 }
712 712
713 // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); } 713 // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); }
714 bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; } 714 bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\.\\"); }
715 bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; } 715 bool IsSuperDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\?\\"); }
716 716
717 /* 717 /*
718 c:\Dir 718 c:\Dir
diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp
index d4f1db7..f070be9 100644
--- a/CPP/7zip/UI/FileManager/PanelCopy.cpp
+++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp
@@ -284,7 +284,7 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options,
284 if (options.hashMethods.Size() == 1) 284 if (options.hashMethods.Size() == 1)
285 { 285 {
286 const UString &s = options.hashMethods[0]; 286 const UString &s = options.hashMethods[0];
287 if (s != L"*") 287 if (!s.IsEqualTo("*"))
288 title = s; 288 title = s;
289 } 289 }
290 } 290 }
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/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp
index 8b16224..427464b 100644
--- a/CPP/7zip/UI/FileManager/PanelOperations.cpp
+++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp
@@ -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/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/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/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
index ce5473a..1686c69 100644
--- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
@@ -1856,7 +1856,7 @@ HRESULT Benchmark(
1856 const CProperty &prop = props[i]; 1856 const CProperty &prop = props[i];
1857 UString name = prop.Name; 1857 UString name = prop.Name;
1858 name.MakeLower_Ascii(); 1858 name.MakeLower_Ascii();
1859 if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*") 1859 if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value.IsEqualTo("*"))
1860 { 1860 {
1861 bd.TotalMode = true; 1861 bd.TotalMode = true;
1862 continue; 1862 continue;
@@ -1865,7 +1865,7 @@ HRESULT Benchmark(
1865 NCOM::CPropVariant propVariant; 1865 NCOM::CPropVariant propVariant;
1866 if (!prop.Value.IsEmpty()) 1866 if (!prop.Value.IsEmpty())
1867 ParseNumberString(prop.Value, propVariant); 1867 ParseNumberString(prop.Value, propVariant);
1868 if (name.IsPrefixedBy(L"mt")) 1868 if (name.IsPrefixedBy("mt"))
1869 { 1869 {
1870 #ifndef Z7_ST 1870 #ifndef Z7_ST
1871 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 58f863e..85d7186 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.cpp
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -2600,11 +2600,17 @@ void CCompressDialog::SetNumThreads2()
2600 UInt32 numAlgoThreadsMax = numHardwareThreads * 2; 2600 UInt32 numAlgoThreadsMax = numHardwareThreads * 2;
2601 const int methodID = GetMethodID(); 2601 const int methodID = GetMethodID();
2602 2602
2603 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)
2604 { 2610 {
2605 case kLZMA: numAlgoThreadsMax = 2; break; 2611 case kLZMA: numAlgoThreadsMax = 2; break;
2606 case kLZMA2: numAlgoThreadsMax = 256; break; 2612 case kLZMA2: numAlgoThreadsMax = 256; break;
2607 case kBZip2: numAlgoThreadsMax = 32; break; 2613 case kBZip2: numAlgoThreadsMax = 64; break;
2608 // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; 2614 // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break;
2609 case kCopy: 2615 case kCopy:
2610 case kPPMd: 2616 case kPPMd:
@@ -2613,17 +2619,6 @@ void CCompressDialog::SetNumThreads2()
2613 case kPPMdZip: 2619 case kPPMdZip:
2614 numAlgoThreadsMax = 1; 2620 numAlgoThreadsMax = 1;
2615 } 2621 }
2616 const bool isZip = IsZipFormat();
2617 if (isZip)
2618 {
2619 numAlgoThreadsMax =
2620 #ifdef _WIN32
2621 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
2622 #else
2623 128;
2624 #endif
2625 }
2626
2627 UInt32 autoThreads = numHardwareThreads; 2622 UInt32 autoThreads = numHardwareThreads;
2628 if (autoThreads > numAlgoThreadsMax) 2623 if (autoThreads > numAlgoThreadsMax)
2629 autoThreads = numAlgoThreadsMax; 2624 autoThreads = numAlgoThreadsMax;
@@ -3008,7 +3003,7 @@ UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads,
3008 else 3003 else
3009 { 3004 {
3010 size += numBlockThreads * (size1 + chunkSize); 3005 size += numBlockThreads * (size1 + chunkSize);
3011 UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; 3006 const UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
3012 if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; 3007 if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++;
3013 if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; 3008 if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++;
3014 if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; 3009 if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++;
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/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/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
index 95db25e..cd2e288 100644
--- a/CPP/Common/Sha3Reg.cpp
+++ b/CPP/Common/Sha3Reg.cpp
@@ -58,7 +58,7 @@ Z7_COM7F_IMF2(UInt32, CSha3Hasher::GetDigestSize())
58 static IHasher *CreateHasherSpec() \ 58 static IHasher *CreateHasherSpec() \
59 { return new CSha3Hasher(digestSize / 8, isShake, \ 59 { return new CSha3Hasher(digestSize / 8, isShake, \
60 SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \ 60 SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \
61 static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize }; \ 61 static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize / 8 }; \
62 struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ 62 struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
63 static REGISTER_HASHER_NAME(cls) g_RegisterHasher; } 63 static REGISTER_HASHER_NAME(cls) g_RegisterHasher; }
64 64
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 2cb83b2..10c4e98 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -651,6 +651,35 @@ bool RemoveDirWithSubItems(const FString &path)
651 return RemoveDir(path); 651 return RemoveDir(path);
652} 652}
653 653
654bool RemoveDirAlways_if_Empty(const FString &path)
655{
656 const DWORD attrib = NFind::GetFileAttrib(path);
657 if (attrib != INVALID_FILE_ATTRIBUTES
658 && (attrib & FILE_ATTRIBUTE_READONLY))
659 {
660 bool need_ClearAttrib = true;
661 if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
662 {
663 FString s (path);
664 s.Add_PathSepar();
665 NFind::CEnumerator enumerator;
666 enumerator.SetDirPrefix(s);
667 NFind::CDirEntry fi;
668 if (enumerator.Next(fi))
669 {
670 // we don't want to change attributes, if there are files
671 // in directory, because RemoveDir(path) will fail.
672 need_ClearAttrib = false;
673 // SetLastError(ERROR_DIR_NOT_EMPTY);
674 // return false;
675 }
676 }
677 if (need_ClearAttrib)
678 SetFileAttrib(path, 0); // we clear read-only attrib to remove read-only dir
679 }
680 return RemoveDir(path);
681}
682
654#endif // _WIN32 683#endif // _WIN32
655 684
656#ifdef UNDER_CE 685#ifdef UNDER_CE
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 74675ee..65e6368 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -78,6 +78,11 @@ bool CreateComplexDir(CFSTR path);
78 78
79bool DeleteFileAlways(CFSTR name); 79bool DeleteFileAlways(CFSTR name);
80bool RemoveDirWithSubItems(const FString &path); 80bool RemoveDirWithSubItems(const FString &path);
81#ifdef _WIN32
82bool RemoveDirAlways_if_Empty(const FString &path);
83#else
84#define RemoveDirAlways_if_Empty RemoveDir
85#endif
81 86
82bool MyGetFullPathName(CFSTR path, FString &resFullPath); 87bool MyGetFullPathName(CFSTR path, FString &resFullPath);
83bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); 88bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
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 1f4a6da..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())
@@ -349,14 +358,16 @@ unsigned GetRootPrefixSize(CFSTR s) throw()
349} 358}
350 359
351#endif // USE_UNICODE_FSTRING 360#endif // USE_UNICODE_FSTRING
361#endif // _WIN32
362
352 363
353static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() 364static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
354{ 365{
355 // Network path: we look "server\path\" as root prefix 366 // Network path: we look "server\path\" as root prefix
356 int pos = FindSepar(s); 367 const int pos = FindSepar(s);
357 if (pos < 0) 368 if (pos < 0)
358 return 0; 369 return 0;
359 int pos2 = FindSepar(s + (unsigned)pos + 1); 370 const int pos2 = FindSepar(s + (unsigned)pos + 1);
360 if (pos2 < 0) 371 if (pos2 < 0)
361 return 0; 372 return 0;
362 return (unsigned)(pos + pos2 + 2); 373 return (unsigned)(pos + pos2 + 2);
@@ -370,7 +381,7 @@ static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw()
370 return 0; 381 return 0;
371 if (s[1] == 0 || !IS_SEPAR(s[1])) 382 if (s[1] == 0 || !IS_SEPAR(s[1]))
372 return 1; 383 return 1;
373 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 384 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
374 return (size == 0) ? 0 : 2 + size; 385 return (size == 0) ? 0 : 2 + size;
375} 386}
376 387
@@ -378,17 +389,21 @@ static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw()
378{ 389{
379 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 390 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
380 { 391 {
381 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 392 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
382 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 393 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
383 } 394 }
384 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 395 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
385 int pos = FindSepar(s + kSuperPathPrefixSize); 396 const int pos = FindSepar(s + kSuperPathPrefixSize);
386 if (pos < 0) 397 if (pos < 0)
387 return 0; 398 return 0;
388 return kSuperPathPrefixSize + (unsigned)(pos + 1); 399 return kSuperPathPrefixSize + (unsigned)(pos + 1);
389} 400}
390 401
402#ifdef _WIN32
391unsigned 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
392{ 407{
393 if (IS_DEVICE_PATH(s)) 408 if (IS_DEVICE_PATH(s))
394 return kDevicePathPrefixSize; 409 return kDevicePathPrefixSize;
@@ -397,7 +412,7 @@ unsigned GetRootPrefixSize(const wchar_t *s) throw()
397 return GetRootPrefixSize_Of_SimplePath(s); 412 return GetRootPrefixSize_Of_SimplePath(s);
398} 413}
399 414
400#else // _WIN32 415#ifndef _WIN32
401 416
402bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } 417bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); }
403 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/System.cpp b/CPP/Windows/System.cpp
index 5fa87f3..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
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h
index 9951b8b..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
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)