diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2022-01-22 21:43:09 +0300 |
---|---|---|
committer | Kornel <kornel@geekhood.net> | 2022-01-22 21:43:09 +0300 |
commit | c3529a41f527101f05e9e834a19205ee33a3b097 (patch) | |
tree | 2a76fa3119a75a39cf3ea7418877f53f1a64b7b4 | |
parent | 52eeaf1ad614fcd03b48423009182e3e3d1ff694 (diff) |
21.0721.07
88 files changed, 3472 insertions, 433 deletions
diff --git a/Asm/x86/7zAsm.asm b/Asm/x86/7zAsm.asm index 8b2c92e0..6275bb74 100644 --- a/Asm/x86/7zAsm.asm +++ b/Asm/x86/7zAsm.asm @@ -1,9 +1,20 @@ ; 7zAsm.asm -- ASM macros -; 2021-08-29 : Igor Pavlov : Public domain +; 2021-12-25 : Igor Pavlov : Public domain + +ifdef @wordsize +; @wordsize is defined only in JWASM and ASMC and is not defined in MASM +; @wordsize eq 8 for 64-bit x64 +; @wordsize eq 2 for 32-bit x86 +if @wordsize eq 8 + x64 equ 1 +endif +else ifdef RAX x64 equ 1 endif +endif + ifdef x64 IS_X64 equ 1 diff --git a/Asm/x86/AesOpt.asm b/Asm/x86/AesOpt.asm index 62c1ba2d..84bf8977 100644 --- a/Asm/x86/AesOpt.asm +++ b/Asm/x86/AesOpt.asm @@ -1,10 +1,18 @@ ; AesOpt.asm -- AES optimized code for x86 AES hardware instructions -; 2021-03-10 : Igor Pavlov : Public domain +; 2021-12-25 : Igor Pavlov : Public domain include 7zAsm.asm +ifdef __ASMC__ + use_vaes_256 equ 1 +else ifdef ymm0 use_vaes_256 equ 1 +endif +endif + + +ifdef use_vaes_256 ECHO "++ VAES 256" else ECHO "-- NO VAES 256" diff --git a/C/7zTypes.h b/C/7zTypes.h index 3f66a7b5..fe4fde3f 100644 --- a/C/7zTypes.h +++ b/C/7zTypes.h @@ -1,5 +1,5 @@ /* 7zTypes.h -- Basic types -2021-07-13 : Igor Pavlov : Public domain */ +2021-12-25 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H @@ -105,6 +105,7 @@ typedef int WRes; // we use errno equivalents for some WIN32 errors: +#define ERROR_INVALID_PARAMETER EINVAL #define ERROR_INVALID_FUNCTION EINVAL #define ERROR_ALREADY_EXISTS EEXIST #define ERROR_FILE_EXISTS EEXIST diff --git a/C/7zVersion.h b/C/7zVersion.h index a8cbdb9c..e9363d37 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h @@ -1,7 +1,7 @@ #define MY_VER_MAJOR 21 -#define MY_VER_MINOR 06 +#define MY_VER_MINOR 07 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "21.06" +#define MY_VERSION_NUMBERS "21.07" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,7 +10,7 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2021-11-24" +#define MY_DATE "2021-12-26" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" diff --git a/C/DllSecur.c b/C/DllSecur.c index 3d215324..d81508c0 100644 --- a/C/DllSecur.c +++ b/C/DllSecur.c @@ -1,5 +1,5 @@ /* DllSecur.c -- DLL loading security -2021-11-18 : Igor Pavlov : Public domain */ +2021-12-25 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -33,17 +33,19 @@ static const char * const g_Dlls = #endif +// #define MY_CAST_FUNC (void(*)()) +#define MY_CAST_FUNC + void My_SetDefaultDllDirectories() { #ifndef UNDER_CE OSVERSIONINFO vi; vi.dwOSVersionInfoSize = sizeof(vi); - GetVersionEx(&vi); if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) { Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) - (void(*)())GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); + MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; @@ -66,7 +68,7 @@ void LoadSecurityDlls() if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0) { Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories) - (void(*)())GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); + MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories"); if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; @@ -1,5 +1,5 @@ /* LzFind.c -- Match finder for LZ algorithms -2021-09-03 : Igor Pavlov : Public domain */ +2021-11-29 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -600,7 +600,9 @@ static #ifdef ATTRIB_SSE41 ATTRIB_SSE41 #endif -void LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim) +void +MY_FAST_CALL +LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim) { v128 sub2 = #ifdef MY_CPU_ARM_OR_ARM64 @@ -632,7 +634,9 @@ static #ifdef ATTRIB_AVX2 ATTRIB_AVX2 #endif -void LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim) +void +MY_FAST_CALL +LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim) { __m256i sub2 = _mm256_set_epi32( (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue, @@ -669,7 +673,10 @@ static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub; #define DEFAULT_SaturSub LzFind_SaturSub_32 MY_NO_INLINE -static void LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim) +static +void +MY_FAST_CALL +LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim) { do { diff --git a/C/LzFindMt.c b/C/LzFindMt.c index da339ebf..4e67fc3f 100644 --- a/C/LzFindMt.c +++ b/C/LzFindMt.c @@ -1,5 +1,5 @@ /* LzFindMt.c -- multithreaded Match finder for LZ algorithms -2021-07-12 : Igor Pavlov : Public domain */ +2021-12-21 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -832,8 +832,8 @@ void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) +static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_DECL BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; unsigned i = 0; diff --git a/C/MtCoder.c b/C/MtCoder.c index 7936c415..99dc9090 100644 --- a/C/MtCoder.c +++ b/C/MtCoder.c @@ -1,5 +1,5 @@ /* MtCoder.c -- Multi-thread Coder -2021-07-12 : Igor Pavlov : Public domain */ +2021-12-21 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -44,7 +44,7 @@ static WRes ArEvent_OptCreate_And_Reset(CEvent *p) } -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp); +static THREAD_FUNC_DECL ThreadFunc(void *pp); static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) @@ -335,7 +335,7 @@ static SRes ThreadFunc2(CMtCoderThread *t) } -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +static THREAD_FUNC_DECL ThreadFunc(void *pp) { CMtCoderThread *t = (CMtCoderThread *)pp; for (;;) @@ -1,5 +1,5 @@ /* MtDec.c -- Multi-thread Decoder -2021-02-27 : Igor Pavlov : Public domain */ +2021-12-21 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -102,7 +102,7 @@ typedef struct __CMtDecBufLink CMtDecBufLink; -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp); +static THREAD_FUNC_DECL ThreadFunc(void *pp); static WRes MtDecThread_CreateEvents(CMtDecThread *t) @@ -836,7 +836,7 @@ static WRes ThreadFunc2(CMtDecThread *t) #endif -static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void *pp) +static THREAD_FUNC_DECL ThreadFunc1(void *pp) { WRes res; @@ -862,7 +862,7 @@ static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void *pp) return (THREAD_FUNC_RET_TYPE)(UINT_PTR)res; } -static MY_NO_INLINE THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp) +static MY_NO_INLINE THREAD_FUNC_DECL ThreadFunc(void *pp) { #ifdef USE_ALLOCA CMtDecThread *t = (CMtDecThread *)pp; diff --git a/C/Threads.c b/C/Threads.c index 7b4f5b5d..58eb90ff 100644 --- a/C/Threads.c +++ b/C/Threads.c @@ -1,11 +1,11 @@ /* Threads.c -- multithreading library -2021-07-12 : Igor Pavlov : Public domain */ +2021-12-21 : Igor Pavlov : Public domain */ #include "Precomp.h" #ifdef _WIN32 -#ifndef UNDER_CE +#ifndef USE_THREADS_CreateThread #include <process.h> #endif @@ -63,10 +63,10 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) { /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ - #ifdef UNDER_CE + #ifdef USE_THREADS_CreateThread DWORD threadId; - *p = CreateThread(0, 0, func, param, 0, &threadId); + *p = CreateThread(NULL, 0, func, param, 0, &threadId); #else @@ -82,7 +82,7 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) { - #ifdef UNDER_CE + #ifdef USE_THREADS_CreateThread UNUSED_VAR(affinity) return Thread_Create(p, func, param); diff --git a/C/Threads.h b/C/Threads.h index 9e70ecab..89ecb92b 100644 --- a/C/Threads.h +++ b/C/Threads.h @@ -1,5 +1,5 @@ /* Threads.h -- multithreading library -2021-07-12 : Igor Pavlov : Public domain */ +2021-12-21 : Igor Pavlov : Public domain */ #ifndef __7Z_THREADS_H #define __7Z_THREADS_H @@ -38,8 +38,14 @@ typedef HANDLE CThread; #define Thread_Close(p) HandlePtr_Close(p) // #define Thread_Wait(p) Handle_WaitObject(*(p)) +#ifdef UNDER_CE + // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() + // if (USE_THREADS_CreateThread is not definned), we use CreateThread() + #define USE_THREADS_CreateThread +#endif + typedef - #ifdef UNDER_CE + #ifdef USE_THREADS_CreateThread DWORD #else unsigned @@ -90,7 +96,30 @@ typedef UInt64 CCpuSet; #define THREAD_FUNC_CALL_TYPE MY_STD_CALL -#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE + +#if defined(_WIN32) && defined(__GNUC__) +/* GCC compiler for x86 32-bit uses the rule: + the stack is 16-byte aligned before CALL instruction for function calling. + But only root function main() contains instructions that + set 16-byte alignment for stack pointer. And another functions + just keep alignment, if it was set in some parent function. + + The problem: + if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), + the root function of thread doesn't set 16-byte alignment. + And stack frames in all child functions also will be unaligned in that case. + + Here we set (force_align_arg_pointer) attribute for root function of new thread. + Do we need (force_align_arg_pointer) also for another systems? */ + + #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) + // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions +#else + #define THREAD_FUNC_ATTRIB_ALIGN_ARG +#endif + +#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE + typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak index b8e5eb3e..e2698a6e 100644 --- a/CPP/7zip/7zip_gcc.mak +++ b/CPP/7zip/7zip_gcc.mak @@ -3,11 +3,15 @@ # IS_X64 = 1 # MY_ARCH = # USE_ASM= +# USE_JWASM=1 MY_ARCH_2 = $(MY_ARCH) -MY_ASM = jwasm MY_ASM = asmc +ifdef USE_JWASM +MY_ASM = jwasm +endif + PROGPATH = $(O)/$(PROG) PROGPATH_STATIC = $(O)/$(PROG)s @@ -95,7 +99,8 @@ ifdef IS_MINGW RM = del MY_MKDIR=mkdir -LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 +LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 +LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE # -Wno-delete-non-virtual-dtor @@ -126,7 +131,7 @@ CFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CC_SHARED) ifdef IS_MINGW AFLAGS_ABI = -coff -DABI_CDECL -AFLAGS = $(AFLAGS_ABI) -Fo$(O)/$(basename $(<F)).o +AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $(<F)).o else ifdef IS_X64 AFLAGS_ABI = -elf64 -DABI_LINUX @@ -136,7 +141,7 @@ AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL # -DABI_LINUX # -DABI_CDECL endif -AFLAGS = $(AFLAGS_ABI) -Fo$(O)/ +AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/ endif ifdef USE_ASM @@ -455,6 +460,8 @@ $O/VdiHandler.o: ../../Archive/VdiHandler.cpp $(CXX) $(CXXFLAGS) $< $O/VhdHandler.o: ../../Archive/VhdHandler.cpp $(CXX) $(CXXFLAGS) $< +$O/VhdxHandler.o: ../../Archive/VhdxHandler.cpp + $(CXX) $(CXXFLAGS) $< $O/VmdkHandler.o: ../../Archive/VmdkHandler.cpp $(CXX) $(CXXFLAGS) $< $O/XarHandler.o: ../../Archive/XarHandler.cpp @@ -996,6 +1003,8 @@ $O/TextPairs.o: ../../UI/FileManager/TextPairs.cpp $(CXX) $(CXXFLAGS) $< $O/UpdateCallback100.o: ../../UI/FileManager/UpdateCallback100.cpp $(CXX) $(CXXFLAGS) $< +$O/VerCtrl.o: ../../UI/FileManager/VerCtrl.cpp + $(CXX) $(CXXFLAGS) $< $O/ViewSettings.o: ../../UI/FileManager/ViewSettings.cpp $(CXX) $(CXXFLAGS) $< @@ -1123,12 +1132,15 @@ $O/7zCrcOpt.o: ../../../../Asm/x86/7zCrcOpt.asm $(MY_ASM) $(AFLAGS) $< $O/XzCrc64Opt.o: ../../../../Asm/x86/XzCrc64Opt.asm $(MY_ASM) $(AFLAGS) $< -$O/AesOpt.o: ../../../../Asm/x86/AesOpt.asm - $(MY_ASM) $(AFLAGS) $< $O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm $(MY_ASM) $(AFLAGS) $< $O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm $(MY_ASM) $(AFLAGS) $< + +ifndef USE_JWASM +USE_X86_ASM_AES=1 +endif + else $O/7zCrcOpt.o: ../../../../C/7zCrcOpt.c $(CC) $(CFLAGS) $< @@ -1138,10 +1150,18 @@ $O/Sha1Opt.o: ../../../../C/Sha1Opt.c $(CC) $(CFLAGS) $< $O/Sha256Opt.o: ../../../../C/Sha256Opt.c $(CC) $(CFLAGS) $< +endif + + +ifdef USE_X86_ASM_AES +$O/AesOpt.o: ../../../../Asm/x86/AesOpt.asm + $(MY_ASM) $(AFLAGS) $< +else $O/AesOpt.o: ../../../../C/AesOpt.c $(CC) $(CFLAGS) $< endif + ifdef USE_X64_ASM $O/LzFindOpt.o: ../../../../Asm/x86/LzFindOpt.asm $(MY_ASM) $(AFLAGS) $< diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 923ad105..8f875ce4 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -130,8 +130,10 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) CMethodFull &methodFull = methodMode.Methods.AddNew(); RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); + #ifndef _7ZIP_ST methodFull.Set_NumThreads = true; methodFull.NumThreads = methodMode.NumThreads; + #endif if (methodFull.Id != k_Copy) needSolid = true; diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 9f50d3aa..fafd7aa0 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -320,7 +320,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; } - case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break; + case kpidBlock: prop.Set_Int32((Int32)m_Database.GetFolderIndex(&mvItem)); break; #ifdef _CAB_DETAILS diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 6c62befa..89012204 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -120,6 +120,15 @@ static void SetMethodProp32(CMethodProps &m, PROPID propID, UInt32 value) m.AddProp32(propID, value); } +void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const +{ + UInt32 level = _level; + if (level != (UInt32)(Int32)-1) + SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); +} + +#ifndef _7ZIP_ST + static void SetMethodProp32_Replace(CMethodProps &m, PROPID propID, UInt32 value) { const int i = m.FindProp(propID); @@ -132,14 +141,6 @@ static void SetMethodProp32_Replace(CMethodProps &m, PROPID propID, UInt32 value m.AddProp32(propID, value); } -void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const -{ - UInt32 level = _level; - if (level != (UInt32)(Int32)-1) - SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); -} - -#ifndef _7ZIP_ST void CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreads) { SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); @@ -149,7 +150,9 @@ void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo, { SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); } -#endif + +#endif // _7ZIP_ST + void CMultiMethodProps::InitMulti() { diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index a08dcac1..1f2ca264 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -234,6 +234,7 @@ static const CAppleName k_Names[] = { true, "hfs", "Apple_HFS" }, { true, "hfsx", "Apple_HFSX" }, { true, "ufs", "Apple_UFS" }, + { true, "apfs", "Apple_APFS" }, // efi_sys partition is FAT32, but it's not main file. So we use (IsFs = false) { false, "efi_sys", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" }, diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index e9808aac..6c095d9a 100644 --- a/CPP/7zip/Archive/ExtHandler.cpp +++ b/CPP/7zip/Archive/ExtHandler.cpp @@ -935,7 +935,10 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned iNodeDir) return S_FALSE; if (_isUTF) - _isUTF = CheckUTF8_AString(item.Name); + { + // 21.07 : we force UTF8 + // _isUTF = CheckUTF8_AString(item.Name); + } if (iNode == 0) { @@ -1835,7 +1838,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidRevision: prop = _h.RevLevel; break; - case kpidINodeSize: prop = _h.InodeSize; break; + case kpidINodeSize: prop = (UInt32)_h.InodeSize; break; case kpidId: { diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp index 7b3d23bb..2b3a673b 100644 --- a/CPP/7zip/Archive/GptHandler.cpp +++ b/CPP/7zip/Archive/GptHandler.cpp @@ -112,6 +112,7 @@ static const CPartType kPartTypes[] = { 0x516E7CB8, "zfs", "FreeBSD ZFS" }, { 0x48465300, "hfsx", "HFS+" }, + { 0x7C3457EF, "apfs", "APFS" }, }; static int FindPartType(const Byte *guid) diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp index 22a8c4a9..6f196de8 100644 --- a/CPP/7zip/Archive/HandlerCont.cpp +++ b/CPP/7zip/Archive/HandlerCont.cpp @@ -105,10 +105,9 @@ STDMETHODIMP CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream) -CHandlerImg::CHandlerImg(): - _imgExt(NULL) +CHandlerImg::CHandlerImg() { - ClearStreamVars(); + Clear_HandlerImg_Vars(); } STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) @@ -121,7 +120,11 @@ STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosit default: return STG_E_INVALIDFUNCTION; } if (offset < 0) + { + if (newPosition) + *newPosition = _virtPos; return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + } _virtPos = offset; if (newPosition) *newPosition = offset; @@ -130,6 +133,7 @@ STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosit static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }; + static const char *GetImgExt(ISequentialInStream *stream) { const size_t kHeaderSize = 1 << 10; @@ -151,6 +155,15 @@ void CHandlerImg::CloseAtError() Stream.Release(); } +void CHandlerImg::Clear_HandlerImg_Vars() +{ + _imgExt = NULL; + _size = 0; + ClearStreamVars(); + Reset_VirtPos(); + Reset_PosInArc(); +} + STDMETHODIMP CHandlerImg::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * openCallback) @@ -165,9 +178,16 @@ STDMETHODIMP CHandlerImg::Open(IInStream *stream, if (res == S_OK) { CMyComPtr<ISequentialInStream> inStream; - HRESULT res2 = GetStream(0, &inStream); + const HRESULT res2 = GetStream(0, &inStream); if (res2 == S_OK && inStream) _imgExt = GetImgExt(inStream); + // _imgExt = GetImgExt(this); // for debug + /* we reset (_virtPos) to support cases, if some code will + call Read() from Handler object instead of GetStream() object. */ + Reset_VirtPos(); + // optional: we reset (_posInArc). if real seek position of stream will be changed in external code + Reset_PosInArc(); + // optional: here we could also reset seek positions in parent streams.. return S_OK; } } diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h index 50a72895..0b92d190 100644 --- a/CPP/7zip/Archive/HandlerCont.h +++ b/CPP/7zip/Archive/HandlerCont.h @@ -78,6 +78,9 @@ protected: // bool _stream_UsePackSize; // UInt64 _stream_PackSize; + void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; } + void Reset_VirtPos() { _virtPos = (UInt64)0; } + void ClearStreamVars() { _stream_unavailData = false; @@ -87,6 +90,7 @@ protected: // _stream_PackSize = 0; } + void Clear_HandlerImg_Vars(); // it doesn't Release (Stream) var. virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; virtual void CloseAtError(); diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp index 200ec62d..4a795eca 100644 --- a/CPP/7zip/Archive/QcowHandler.cpp +++ b/CPP/7zip/Archive/QcowHandler.cpp @@ -601,7 +601,6 @@ STDMETHODIMP CHandler::Close() _table.Free(); _dir.Free(); _phySize = 0; - _size = 0; _cacheCluster = (UInt64)(Int64)-1; _comprPos = 0; @@ -611,7 +610,8 @@ STDMETHODIMP CHandler::Close() _isArc = false; _unsupported = false; - _imgExt = NULL; + // CHandlerImg: + Clear_HandlerImg_Vars(); Stream.Release(); return S_OK; } diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h index 310369d4..96264330 100644 --- a/CPP/7zip/Archive/Rar/RarVol.h +++ b/CPP/7zip/Archive/Rar/RarVol.h @@ -28,12 +28,12 @@ public: { _needChangeForNext = true; _after.Empty(); - UString base = name; - int dotPos = name.ReverseFind_Dot(); + UString base (name); + const int dotPos = name.ReverseFind_Dot(); if (dotPos >= 0) { - const UString ext = name.Ptr(dotPos + 1); + const UString ext (name.Ptr(dotPos + 1)); if (ext.IsEqualTo_Ascii_NoCase("rar")) { _after = name.Ptr(dotPos); diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index 9666c69d..a5ff1877 100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -21,12 +21,20 @@ #include "../Compress/CopyCoder.h" #include "../Compress/LzmaDecoder.h" -#include "../Compress/LzmaEncoder.h" #include "../Compress/ZlibDecoder.h" -#include "../Compress/ZlibEncoder.h" #include "Common/DummyOutStream.h" + +// #define SWF_UPDATE + +#ifdef SWF_UPDATE + +#include "../Compress/LzmaEncoder.h" +#include "../Compress/ZlibEncoder.h" + #include "Common/HandlerOut.h" + +#endif using namespace NWindows; @@ -152,8 +160,10 @@ struct CItem class CHandler: public IInArchive, public IArchiveOpenSeq, + #ifdef SWF_UPDATE public IOutArchive, public ISetProperties, + #endif public CMyUnknownImp { CItem _item; @@ -162,16 +172,22 @@ class CHandler: CMyComPtr<ISequentialInStream> _seqStream; CMyComPtr<IInStream> _stream; + #ifdef SWF_UPDATE CSingleMethodProps _props; bool _lzmaMode; + #endif public: - CHandler(): _lzmaMode(false) {} + #ifdef SWF_UPDATE MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) - INTERFACE_IInArchive(;) + CHandler(): _lzmaMode(false) {} INTERFACE_IOutArchive(;) - STDMETHOD(OpenSeq)(ISequentialInStream *stream); STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); + #else + MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) + #endif + INTERFACE_IInArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); }; static const Byte kProps[] = @@ -416,6 +432,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } + +#ifdef SWF_UPDATE + static HRESULT UpdateArchive(ISequentialOutStream *outStream, UInt64 size, bool lzmaMode, const CSingleMethodProps &props, IArchiveUpdateCallback *updateCallback) @@ -576,11 +595,14 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR return S_OK; } +#endif + + static const Byte k_Signature[] = { 3, 'C', 'W', 'S', 3, 'Z', 'W', 'S' }; -REGISTER_ARC_IO( +REGISTER_ARC_I( "SWFc", "swf", "~.swf", 0xD8, k_Signature, 0, diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index 6fc38e33..2f23dd85 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -107,8 +107,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidCharacts: { - AString s = _encodingCharacts.GetCharactsString(); - prop = s; + prop = _encodingCharacts.GetCharactsString(); break; } } diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index 7a7a2cba..5ddb4b24 100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -130,8 +130,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; else ui.Mode = prop.ulVal; - // FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR. - // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; + // 21.07 : we clear high file type bits as GNU TAR. + ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; } { diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp index a22f36bd..9c16c895 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.cpp +++ b/CPP/7zip/Archive/Tar/TarHeader.cpp @@ -17,7 +17,10 @@ namespace NFileHeader { // const char * const kUsTar = "ustar"; // 5 chars // const char * const kGNUTar = "GNUtar "; // 7 chars and a null // const char * const kEmpty = "\0\0\0\0\0\0\0\0"; - const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; + // 7-Zip used kUsTar_00 before 21.07: + // const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; + // GNU TAR uses such header: + const char kUsTar_GNU[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ; } }}} diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h index 249368f6..b0f0ec34 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.h +++ b/CPP/7zip/Archive/Tar/TarHeader.h @@ -76,7 +76,8 @@ namespace NFileHeader // extern const char * const kUsTar; // = "ustar"; // 5 chars // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0" - extern const char kUsTar_00[8]; + // extern const char kUsTar_00[8]; + extern const char kUsTar_GNU[8]; } } diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index 0099e6f7..58399d0c 100644 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -72,10 +72,7 @@ static bool IsRecordLast(const char *buf) static void ReadString(const char *s, unsigned size, AString &result) { - char temp[NFileHeader::kRecordSize + 1]; - MyStrNCpy(temp, s, size); - temp[size] = '\0'; - result = temp; + result.SetFrom_CalcLen(s, size); } static bool ParseInt64(const char *p, Int64 &val) diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index 8c34b841..f947786f 100644 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -43,6 +43,15 @@ struct CItem CRecordVector<CSparseBlock> SparseBlocks; + void SetDefaultWriteFields() + { + DeviceMajorDefined = false; + DeviceMinorDefined = false; + UID = 0; + GID = 0; + memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 8); + } + bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } @@ -103,7 +112,7 @@ struct CItem bool IsUstarMagic() const { for (int i = 0; i < 5; i++) - if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i]) + if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i]) return false; return true; } diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp index e2da3238..271b854a 100644 --- a/CPP/7zip/Archive/Tar/TarOut.cpp +++ b/CPP/7zip/Archive/Tar/TarOut.cpp @@ -15,17 +15,6 @@ HRESULT COutArchive::WriteBytes(const void *data, unsigned size) return WriteStream(m_Stream, data, size); } -static void MyStrNCpy(char *dest, const char *src, unsigned size) -{ - for (unsigned i = 0; i < size; i++) - { - char c = src[i]; - dest[i] = c; - if (c == 0) - break; - } -} - static bool WriteOctal_8(char *s, UInt32 val) { const unsigned kNumDigits = 8 - 1; @@ -39,6 +28,12 @@ static bool WriteOctal_8(char *s, UInt32 val) return true; } +static void WriteBin_64bit(char *s, UInt64 val) +{ + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[i] = (char)(val >> 56); +} + static void WriteOctal_12(char *s, UInt64 val) { const unsigned kNumDigits = 12 - 1; @@ -47,8 +42,7 @@ static void WriteOctal_12(char *s, UInt64 val) // GNU extension; s[0] = (char)(Byte)0x80; s[1] = s[2] = s[3] = 0; - for (unsigned i = 0; i < 8; i++, val <<= 8) - s[4 + i] = (char)(val >> 56); + WriteBin_64bit(s + 4, val); return; } for (unsigned i = 0; i < kNumDigits; i++) @@ -66,57 +60,67 @@ static void WriteOctal_12_Signed(char *s, Int64 val) return; } s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; - for (unsigned i = 0; i < 8; i++, val <<= 8) - s[4 + i] = (char)(val >> 56); + WriteBin_64bit(s + 4, val); } -static bool CopyString(char *dest, const AString &src, unsigned maxSize) +static void CopyString(char *dest, const AString &src, unsigned maxSize) { - if (src.Len() >= maxSize) - return false; - MyStringCopy(dest, (const char *)src); - return true; + unsigned len = src.Len(); + if (len == 0) + return; + // 21.07: we don't require additional 0 character at the end + if (len > maxSize) + { + len = maxSize; + // return false; + } + memcpy(dest, src.Ptr(), len); + // return true; } #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; } +#define COPY_STRING_CHECK(dest, src, size) \ + CopyString(dest, src, size); dest += (size); + +#define WRITE_OCTAL_8_CHECK(dest, src) \ + RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src)); + + HRESULT COutArchive::WriteHeaderReal(const CItem &item) { char record[NFileHeader::kRecordSize]; memset(record, 0, NFileHeader::kRecordSize); char *cur = record; - if (item.Name.Len() > NFileHeader::kNameSize) - return E_FAIL; - MyStrNCpy(cur, item.Name, NFileHeader::kNameSize); - cur += NFileHeader::kNameSize; + COPY_STRING_CHECK (cur, item.Name, NFileHeader::kNameSize); - RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8; - RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8; - RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8; + WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; + WRITE_OCTAL_8_CHECK (cur, item.UID); cur += 8; + WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8; WriteOctal_12(cur, item.PackSize); cur += 12; WriteOctal_12_Signed(cur, item.MTime); cur += 12; - memset(cur, ' ', 8); + memset(cur, ' ', 8); // checksum field cur += 8; *cur++ = item.LinkFlag; - RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize)); - cur += NFileHeader::kNameSize; + COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize); memcpy(cur, item.Magic, 8); cur += 8; - RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize)); - cur += NFileHeader::kUserNameSize; - RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize)); - cur += NFileHeader::kGroupNameSize; + COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize); + COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize); - - if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8; - if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8; + if (item.DeviceMajorDefined) + WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor); + cur += 8; + if (item.DeviceMinorDefined) + WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor); + cur += 8; if (item.IsSparse()) { @@ -140,7 +144,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) /* we use GNU TAR scheme: checksum field is formatted differently from the other fields: it has [6] digits, a null, then a space. */ - // RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum)); + // WRITE_OCTAL_8_CHECK(record + 148, checkSum); const unsigned kNumDigits = 6; for (unsigned i = 0; i < kNumDigits; i++) { @@ -172,27 +176,42 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) return S_OK; } -HRESULT COutArchive::WriteHeader(const CItem &item) -{ - unsigned nameSize = item.Name.Len(); - unsigned linkSize = item.LinkName.Len(); - /* There two versions of GNU tar: - OLDGNU_FORMAT: it writes short name and zero at the end - GNU_FORMAT: it writes only short name without zero at the end - we write it as OLDGNU_FORMAT with zero at the end */ +/* OLD_GNU_TAR: writes short name with zero at the end + NEW_GNU_TAR: writes short name without zero at the end */ - if (nameSize < NFileHeader::kNameSize && - linkSize < NFileHeader::kNameSize) +static const unsigned kNameSize_Max = + NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 + // NFileHeader::kNameSize - 1; // OLD_GNU_TAR / old 7-Zip + +#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max) + +HRESULT COutArchive::WriteHeader(const CItem &item) +{ + if (DOES_NAME_FIT_IN_FIELD(item.Name) && + DOES_NAME_FIT_IN_FIELD(item.LinkName)) return WriteHeaderReal(item); + // here we can get all fields from main (item) or create new empty item + /* + CItem mi; + mi.SetDefaultWriteFields(); + */ + CItem mi = item; - mi.Name = NFileHeader::kLongLink; mi.LinkName.Empty(); + // SparseBlocks will be ignored by IsSparse() + // mi.SparseBlocks.Clear(); + + mi.Name = NFileHeader::kLongLink; + // 21.07 : we set Mode and MTime props as in GNU TAR: + mi.Mode = 0644; // octal + mi.MTime = 0; + for (int i = 0; i < 2; i++) { const AString *name; - // We suppose that GNU tar also writes item for long link before item for LongName? + // We suppose that GNU TAR also writes item for long link before item for LongName? if (i == 0) { mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink; @@ -203,21 +222,26 @@ HRESULT COutArchive::WriteHeader(const CItem &item) mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; name = &item.Name; } - if (name->Len() < NFileHeader::kNameSize) + if (DOES_NAME_FIT_IN_FIELD(*name)) continue; - unsigned nameStreamSize = name->Len() + 1; + // GNU TAR writes null character after NAME to file. We do same here: + const unsigned nameStreamSize = name->Len() + 1; mi.PackSize = nameStreamSize; RINOK(WriteHeaderReal(mi)); - RINOK(WriteBytes((const char *)*name, nameStreamSize)); + RINOK(WriteBytes(name->Ptr(), nameStreamSize)); RINOK(FillDataResidual(nameStreamSize)); } + // 21.07: WriteHeaderReal() writes short part of (Name) and (LinkName). + return WriteHeaderReal(item); + /* mi = item; - if (mi.Name.Len() >= NFileHeader::kNameSize) - mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1); - if (mi.LinkName.Len() >= NFileHeader::kNameSize) - mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1); + if (!DOES_NAME_FIT_IN_FIELD(mi.Name)) + mi.Name.SetFrom(item.Name, kNameSize_Max); + if (!DOES_NAME_FIT_IN_FIELD(mi.LinkName)) + mi.LinkName.SetFrom(item.LinkName, kNameSize_Max); return WriteHeaderReal(mi); + */ } HRESULT COutArchive::FillDataResidual(UInt64 dataSize) @@ -235,7 +259,17 @@ HRESULT COutArchive::WriteFinishHeader() { Byte record[NFileHeader::kRecordSize]; memset(record, 0, NFileHeader::kRecordSize); - for (unsigned i = 0; i < 2; i++) + + const unsigned kNumFinishRecords = 2; + + /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB) + we also can use cluster alignment: + const unsigned numBlocks = (unsigned)(Pos / NFileHeader::kRecordSize) + kNumFinishRecords; + const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB + const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1)); + */ + + for (unsigned i = 0; i < kNumFinishRecords; i++) { RINOK(WriteBytes(record, NFileHeader::kRecordSize)); } diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index c7598f8d..295e16bb 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -68,6 +68,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, if (ui.NewProps) { + item.SetDefaultWriteFields(); item.Mode = ui.Mode; item.Name = ui.Name; item.User = ui.User; @@ -85,11 +86,6 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, } item.MTime = ui.MTime; - item.DeviceMajorDefined = false; - item.DeviceMinorDefined = false; - item.UID = 0; - item.GID = 0; - memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8); } else item = inputItems[(unsigned)ui.IndexInArc]; diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp index b5e47186..7641cdc9 100644 --- a/CPP/7zip/Archive/VdiHandler.cpp +++ b/CPP/7zip/Archive/VdiHandler.cpp @@ -403,14 +403,14 @@ STDMETHODIMP CHandler::Close() { _table.Free(); _phySize = 0; - _size = 0; _isArc = false; _unsupported = false; for (unsigned i = 0; i < kNumGuids; i++) memset(Guids[i], 0, 16); - _imgExt = NULL; + // CHandlerImg: + Clear_HandlerImg_Vars(); Stream.Release(); return S_OK; } diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index c70d667e..8b9af45a 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -226,9 +226,9 @@ class CHandler: public CHandlerImg CByteBuffer BitMap; UInt32 BitMapTag; UInt32 NumUsedBlocks; - // CMyComPtr<IInStream> Stream; CMyComPtr<IInStream> ParentStream; CHandler *Parent; + UInt64 NumLevels; UString _errorMessage; // bool _unexpectedEnd; @@ -604,11 +604,12 @@ enum static const CStatProp kArcProps[] = { - { NULL, kpidSize, VT_UI8}, { NULL, kpidOffset, VT_UI8}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidClusterSize, VT_UI8}, { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidNumVolumes, VT_UI4}, + { NULL, kpidTotalPhySize, VT_UI8}, { "Parent", kpidParent, VT_BSTR}, { NULL, kpidCreatorApp, VT_BSTR}, { NULL, kpidHostOS, VT_BSTR}, @@ -734,6 +735,21 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidParent: if (NeedParent()) prop = GetParentSequence(); break; case kpidOffset: prop = _startOffset; break; case kpidPhySize: prop = _phySize; break; + case kpidTotalPhySize: + { + const CHandler *p = this; + UInt64 sum = 0; + do + { + sum += p->_phySize; + p = p->Parent; + } + while (p); + prop = sum; + break; + } + case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break; + /* case kpidErrorFlags: { @@ -762,6 +778,7 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback RINOK(Open3()); + NumLevels = 1; if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0) return S_FALSE; if (Footer.Type != kDiskType_Diff) @@ -826,6 +843,10 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback // we must show that error code } } + if (res == S_OK) + { + NumLevels = Parent->NumLevels + 1; + } } { const CHandler *p = this; @@ -845,16 +866,19 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback void CHandler::CloseAtError() { + // CHandlerImg: + Stream.Release(); + Clear_HandlerImg_Vars(); + _phySize = 0; + NumLevels = 0; Bat.Clear(); NumUsedBlocks = 0; Parent = NULL; - Stream.Release(); ParentStream.Release(); Dyn.Clear(); _errorMessage.Empty(); // _unexpectedEnd = false; - _imgExt = NULL; } STDMETHODIMP CHandler::Close() @@ -891,7 +915,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) { COM_TRY_BEGIN - *stream = 0; + *stream = NULL; if (Footer.IsFixed()) { CLimitedInStream *streamSpec = new CLimitedInStream; diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp new file mode 100644 index 00000000..e1e4692d --- /dev/null +++ b/CPP/7zip/Archive/VhdxHandler.cpp @@ -0,0 +1,2062 @@ +// VhdxHandler.cpp + +#include "StdAfx.h" + +// #include <stdio.h> + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + +using namespace NWindows; + + +EXTERN_C_BEGIN + +// CRC-32C (Castagnoli) : reversed for poly 0x1EDC6F41 +#define k_Crc32c_Poly 0x82f63b78 + +static UInt32 g_Crc32c_Table[256]; + +static void MY_FAST_CALL Crc32c_GenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (k_Crc32c_Poly & ((UInt32)0 - (r & 1))); + g_Crc32c_Table[i] = r; + } +} + +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); + +#define CRC32C_INIT_VAL 0xFFFFFFFF + +static UInt32 MY_FAST_CALL Crc32c_Calc(const void *data, size_t size) +{ + return CrcUpdateT1(CRC32C_INIT_VAL, data, size, g_Crc32c_Table) ^ CRC32C_INIT_VAL; +} + +EXTERN_C_END + + +namespace NArchive { +namespace NVhdx { + +static struct C_CRC32c_TableInit { C_CRC32c_TableInit() { Crc32c_GenerateTable(); } } g__CRC32c_TableInit; + +#define SIGNATURE { 'v', 'h', 'd', 'x', 'f', 'i', 'l', 'e' } + +static const unsigned kSignatureSize = 8; +static const Byte kSignature[kSignatureSize] = SIGNATURE; + +static const unsigned kBitmapSize_Log = 20; +static const size_t kBitmapSize = (size_t)1 << kBitmapSize_Log; + + +static bool IsZeroArr(const Byte *p, size_t size) +{ + for (size_t i = 0; i < size; i++) + if (p[i] != 0) + return false; + return true; +} + + +#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10)))) + +static void AddByteToHex2(unsigned val, UString &s) +{ + unsigned t; + t = val >> 4; + s += ValToHex(t); + t = val & 0xF; + s += ValToHex(t); +} + + +static int HexToVal(const wchar_t c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'z') return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') return c - 'A' + 10; + return -1; +} + +static int DecodeFrom2HexChars(const wchar_t *s) +{ + const int v0 = HexToVal(s[0]); if (v0 < 0) return -1; + const int v1 = HexToVal(s[1]); if (v1 < 0) return -1; + return ((unsigned)v0 << 4) | (unsigned)v1; +} + + +struct CGuid +{ + Byte Data[16]; + + bool IsZero() const { return IsZeroArr(Data, 16); } + bool IsEqualTo(const Byte *a) const { return memcmp(Data, a, 16) == 0; } + bool IsEqualTo(const CGuid &g) const { return IsEqualTo(g.Data); } + void AddHexToString(UString &s) const; + + void SetFrom(const Byte *p) { memcpy(Data, p, 16); } + + bool ParseFromFormatedHexString(const UString &s) + { + const unsigned kLen = 16 * 2 + 4 + 2; + if (s.Len() != kLen || s[0] != '{' || s[kLen - 1] != '}') + return false; + unsigned pos = 0; + for (unsigned i = 1; i < kLen - 1;) + { + if (i == 9 || i == 14 || i == 19 || i == 24) + { + if (s[i] != '-') + return false; + i++; + continue; + } + const int v = DecodeFrom2HexChars(s.Ptr(i)); + if (v < 0) + return false; + unsigned pos2 = pos; + if (pos < 8) + pos2 ^= (pos < 4 ? 3 : 1); + Data[pos2] = (Byte)v; + pos++; + i += 2; + } + return true; // pos == 16; + } +}; + +void CGuid::AddHexToString(UString &s) const +{ + for (unsigned i = 0; i < 16; i++) + AddByteToHex2(Data[i], s); +} + + +#define IS_NON_ALIGNED(v) (((v) & 0xFFFFF) != 0) + +static const unsigned kHeader_GUID_Index_FileWriteGuid = 0; +static const unsigned kHeader_GUID_Index_DataWriteGuid = 1; +static const unsigned kHeader_GUID_Index_LogGuid = 2; + +struct CHeader +{ + UInt64 SequenceNumber; + // UInt16 LogVersion; + // UInt16 Version; + UInt32 LogLength; + UInt64 LogOffset; + CGuid Guids[3]; + + bool Parse(Byte *p); +}; + +static const unsigned kHeader2Size = 1 << 12; + +bool CHeader::Parse(Byte *p) +{ + if (Get32(p) != 0x64616568) // "head" + return false; + const UInt32 crc = Get32(p + 4); + SetUi32(p + 4, 0); + if (Crc32c_Calc(p, kHeader2Size) != crc) + return false; + G64(8, SequenceNumber); + for (unsigned i = 0; i < 3; i++) + Guids[i].SetFrom(p + 0x10 + 0x10 * i); + // LogVersion = Get16(p + 0x40); + /* LogVersion MUST be set to zero, for known log format + but we don't parse log so we ignore it */ + G32(0x44, LogLength); + G64(0x48, LogOffset); + if (Get16(p + 0x42) != 1) // Header format Version + return false; + if (IS_NON_ALIGNED(LogLength)) + return false; + if (IS_NON_ALIGNED(LogOffset)) + return false; + return true; + // return IsZeroArr(p + 0x50, kHeader2Size - 0x50); +} + + + +static const Byte kBat[16] = + { 0x66,0x77,0xC2,0x2D,0x23,0xF6,0x00,0x42,0x9D,0x64,0x11,0x5E,0x9B,0xFD,0x4A,0x08 }; +static const Byte kMetadataRegion[16] = + { 0x06,0xA2,0x7C,0x8B,0x90,0x47,0x9A,0x4B,0xB8,0xFE,0x57,0x5F,0x05,0x0F,0x88,0x6E }; + +struct CRegionEntry +{ + // CGuid Guid; + UInt64 Offset; + UInt32 Len; + UInt32 Required; + + UInt64 GetEndPos() const { return Offset + Len; } + bool Parse(const Byte *p); +}; + +bool CRegionEntry::Parse(const Byte *p) +{ + // Guid.SetFrom(p); + G64(0x10, Offset); + G32(0x18, Len); + G32(0x1c, Required); + if (IS_NON_ALIGNED(Offset)) + return false; + if (IS_NON_ALIGNED(Len)) + return false; + if (Offset + Len < Offset) + return false; + return true; +} + + +struct CRegion +{ + bool Bat_Defined; + bool Meta_Defined; + UInt64 EndPos; + UInt64 DataSize; + + CRegionEntry BatEntry; + CRegionEntry MetaEntry; + + bool Parse(Byte *p); +}; + + +static const unsigned kRegionSize = 1 << 16; +static const unsigned kNumRegionEntriesMax = (1 << 11) - 1; + +bool CRegion::Parse(Byte *p) +{ + Bat_Defined = false; + Meta_Defined = false; + EndPos = 0; + DataSize = 0; + + if (Get32(p) != 0x69676572) // "regi" + return false; + const UInt32 crc = Get32(p + 4); + SetUi32(p + 4, 0); + const UInt32 crc_calced = Crc32c_Calc(p, kRegionSize); + if (crc_calced != crc) + return false; + + const UInt32 EntryCount = Get32(p + 8); + if (Get32(p + 12) != 0) // reserved field must be set to 0. + return false; + if (EntryCount > kNumRegionEntriesMax) + return false; + for (UInt32 i = 0; i < EntryCount; i++) + { + CRegionEntry e; + const Byte *p2 = p + 0x10 + 0x20 * (size_t)i; + if (!e.Parse(p2)) + return false; + DataSize += e.Len; + const UInt64 endPos = e.GetEndPos(); + if (EndPos < endPos) + EndPos = endPos; + CGuid Guid; + Guid.SetFrom(p2); + if (Guid.IsEqualTo(kBat)) + { + if (Bat_Defined) + return false; + BatEntry = e; + Bat_Defined = true; + } + else if (Guid.IsEqualTo(kMetadataRegion)) + { + if (Meta_Defined) + return false; + MetaEntry = e; + Meta_Defined = true; + } + else + { + if (e.Required != 0) + return false; + // it's allowed to ignore unknown non-required region entries + } + } + /* + const size_t k = 0x10 + 0x20 * EntryCount; + return IsZeroArr(p + k, kRegionSize - k); + */ + return true; +} + + + + +struct CMetaEntry +{ + CGuid Guid; + UInt32 Offset; + UInt32 Len; + UInt32 Flags0; + // UInt32 Flags1; + + bool IsUser() const { return (Flags0 & 1) != 0; } + bool IsVirtualDisk() const { return (Flags0 & 2) != 0; } + bool IsRequired() const { return (Flags0 & 4) != 0; } + + bool CheckLimit(size_t regionSize) const + { + return Offset <= regionSize && Len <= regionSize - Offset; + } + + bool Parse(const Byte *p); +}; + + +bool CMetaEntry::Parse(const Byte *p) +{ + Guid.SetFrom(p); + + G32(0x10, Offset); + G32(0x14, Len); + G32(0x18, Flags0); + UInt32 Flags1; + G32(0x1C, Flags1); + + if (Offset != 0 && Offset < (1 << 16)) + return false; + if (Len > (1 << 20)) + return false; + if (Len == 0 && Offset != 0) + return false; + if ((Flags0 >> 3) != 0) // Reserved + return false; + if ((Flags1 & 3) != 0) // Reserved2 + return false; + return true; +}; + + +struct CParentPair +{ + UString Key; + UString Value; +}; + + +struct CMetaHeader +{ + // UInt16 EntryCount; + bool Guid_Defined; + bool VirtualDiskSize_Defined; + bool Locator_Defined; + + unsigned BlockSize_Log; + unsigned LogicalSectorSize_Log; + unsigned PhysicalSectorSize_Log; + + UInt32 Flags; + UInt64 VirtualDiskSize; + CGuid Guid; + // CGuid LocatorType; + + CObjectVector<CParentPair> ParentPairs; + + int FindParentKey(const char *name) const + { + FOR_VECTOR (i, ParentPairs) + { + const CParentPair &pair = ParentPairs[i]; + if (pair.Key.IsEqualTo(name)) + return i; + } + return -1; + } + + bool Is_LeaveBlockAllocated() const { return (Flags & 1) != 0; } + bool Is_HasParent() const { return (Flags & 2) != 0; } + + void Clear() + { + Guid_Defined = false; + VirtualDiskSize_Defined = false; + Locator_Defined = false; + BlockSize_Log = 0; + LogicalSectorSize_Log = 0; + PhysicalSectorSize_Log = 0; + Flags = 0; + VirtualDiskSize = 0; + ParentPairs.Clear(); + } + + bool Parse(const Byte *p, size_t size); +}; + + +static unsigned GetLogSize(UInt32 size) +{ + unsigned k; + for (k = 0; k < 32; k++) + if (((UInt32)1 << k) == size) + return k; + return k; +} + + +static const unsigned kMetadataSize = 8; +static const Byte kMetadata[kMetadataSize] = + { 'm','e','t','a','d','a','t','a' }; + +static const unsigned k_Num_MetaEntries_Max = (1 << 11) - 1; + +static const Byte kFileParameters[16] = + { 0x37,0x67,0xa1,0xca,0x36,0xfa,0x43,0x4d,0xb3,0xb6,0x33,0xf0,0xaa,0x44,0xe7,0x6b }; +static const Byte kVirtualDiskSize[16] = + { 0x24,0x42,0xa5,0x2f,0x1b,0xcd,0x76,0x48,0xb2,0x11,0x5d,0xbe,0xd8,0x3b,0xf4,0xb8 }; +static const Byte kVirtualDiskID[16] = + { 0xab,0x12,0xca,0xbe,0xe6,0xb2,0x23,0x45,0x93,0xef,0xc3,0x09,0xe0,0x00,0xc7,0x46 }; +static const Byte kLogicalSectorSize[16] = + { 0x1d,0xbf,0x41,0x81,0x6f,0xa9,0x09,0x47,0xba,0x47,0xf2,0x33,0xa8,0xfa,0xab,0x5f }; +static const Byte kPhysicalSectorSize[16] = + { 0xc7,0x48,0xa3,0xcd,0x5d,0x44,0x71,0x44,0x9c,0xc9,0xe9,0x88,0x52,0x51,0xc5,0x56 }; +static const Byte kParentLocator[16] = + { 0x2d,0x5f,0xd3,0xa8,0x0b,0xb3,0x4d,0x45,0xab,0xf7,0xd3,0xd8,0x48,0x34,0xab,0x0c }; + +static bool GetString16(UString &s, const Byte *p, size_t size) +{ + s.Empty(); + if (size & 1) + return false; + for (size_t i = 0; i < size; i += 2) + { + const wchar_t c = Get16(p + i); + if (c == 0) + return false; + s += c; + } + return true; +} + + +bool CMetaHeader::Parse(const Byte *p, size_t size) +{ + if (memcmp(p, kMetadata, kMetadataSize) != 0) + return false; + if (Get16(p + 8) != 0) // Reserved + return false; + const UInt32 EntryCount = Get16(p + 10); + if (EntryCount > k_Num_MetaEntries_Max) + return false; + if (!IsZeroArr(p + 12, 20)) // Reserved + return false; + + for (unsigned i = 0; i < EntryCount; i++) + { + CMetaEntry e; + if (!e.Parse(p + 32 + 32 * (size_t)i)) + return false; + if (!e.CheckLimit(size)) + return false; + const Byte *p2 = p + e.Offset; + + if (e.Guid.IsEqualTo(kFileParameters)) + { + if (BlockSize_Log != 0) + return false; + if (e.Len != 8) + return false; + const UInt32 v = Get32(p2); + Flags = Get32(p2 + 4); + BlockSize_Log = GetLogSize(v); + if (BlockSize_Log < 20 || BlockSize_Log > 28) // specification from 1 MB to 256 MB + return false; + if ((Flags >> 2) != 0) // reserved + return false; + } + else if (e.Guid.IsEqualTo(kVirtualDiskSize)) + { + if (VirtualDiskSize_Defined) + return false; + if (e.Len != 8) + return false; + VirtualDiskSize = Get64(p2); + VirtualDiskSize_Defined = true; + } + else if (e.Guid.IsEqualTo(kVirtualDiskID)) + { + if (e.Len != 16) + return false; + Guid.SetFrom(p2); + Guid_Defined = true; + } + else if (e.Guid.IsEqualTo(kLogicalSectorSize)) + { + if (LogicalSectorSize_Log != 0) + return false; + if (e.Len != 4) + return false; + const UInt32 v = Get32(p2); + LogicalSectorSize_Log = GetLogSize(v); + if (LogicalSectorSize_Log != 9 && LogicalSectorSize_Log != 12) + return false; + } + else if (e.Guid.IsEqualTo(kPhysicalSectorSize)) + { + if (PhysicalSectorSize_Log != 0) + return false; + if (e.Len != 4) + return false; + const UInt32 v = Get32(p2); + PhysicalSectorSize_Log = GetLogSize(v); + if (PhysicalSectorSize_Log != 9 && PhysicalSectorSize_Log != 12) + return false; + } + else if (e.Guid.IsEqualTo(kParentLocator)) + { + if (Locator_Defined) + return false; + if (e.Len < 20) + return false; + // LocatorType.SetFrom(p2); + /* Specifies the type of the parent virtual disk. + is different for each type: VHDX, VHD or iSCSI. + only "B04AEFB7-D19E-4A81-B789-25B8E9445913" (for VHDX) is supported now + */ + Locator_Defined = true; + if (Get16(p2 + 16) != 0) // reserved + return false; + const UInt32 KeyValueCount = Get16(p2 + 18); + if (20 + (UInt32)KeyValueCount * 12 > e.Len) + return false; + for (unsigned k = 0; k < KeyValueCount; k++) + { + const Byte *p3 = p2 + 20 + (size_t)k * 12; + const UInt32 KeyOffset = Get32(p3); + const UInt32 ValueOffset = Get32(p3 + 4); + const UInt32 KeyLength = Get16(p3 + 8); + const UInt32 ValueLength = Get16(p3 + 10); + if (KeyOffset > e.Len || KeyLength > e.Len - KeyOffset) + return false; + if (ValueOffset > e.Len || ValueLength > e.Len - ValueOffset) + return false; + CParentPair pair; + if (!GetString16(pair.Key, p2 + KeyOffset, KeyLength)) + return false; + if (!GetString16(pair.Value, p2 + ValueOffset, ValueLength)) + return false; + ParentPairs.Add(pair); + } + } + else + { + if (e.IsRequired()) + return false; + // return false; // unknown metadata; + } + } + + // some properties are required for correct processing + + if (BlockSize_Log == 0) + return false; + if (LogicalSectorSize_Log == 0) + return false; + if (!VirtualDiskSize_Defined) + return false; + if (((UInt32)VirtualDiskSize & ((UInt32)1 << LogicalSectorSize_Log)) != 0) + return false; + + // vhdx specification sets limit for 64 TB. + // do we need to check over same limit ? + const UInt64 kVirtualDiskSize_Max = (UInt64)1 << 46; + if (VirtualDiskSize > kVirtualDiskSize_Max) + return false; + + return true; +} + + + +struct CBat +{ + CByteBuffer Data; + + void Clear() { Data.Free(); } + UInt64 GetItem(size_t n) const + { + return Get64(Data + n * 8); + } +}; + + + +class CHandler: public CHandlerImg +{ + UInt64 _phySize; + + CBat Bat; + CObjectVector<CByteBuffer> BitMaps; + + unsigned ChunkRatio_Log; + size_t ChunkRatio; + size_t TotalBatEntries; + + CMetaHeader Meta; + CHeader Header; + + UInt32 NumUsedBlocks; + UInt32 NumUsedBitMaps; + UInt64 HeadersSize; + + UInt32 NumLevels; + UInt64 PackSize_Total; + + /* + UInt64 NumUsed_1MB_Blocks; // data and bitmaps + bool NumUsed_1MB_Blocks_Defined; + */ + + CMyComPtr<IInStream> ParentStream; + CHandler *Parent; + UString _errorMessage; + UString _Creator; + + bool _nonEmptyLog; + bool _isDataContiguous; + // bool _BatOverlap; + + CGuid _parentGuid; + bool _parentGuid_IsDefined; + UStringVector ParentNames; + UString ParentName_Used; + + const CHandler *_child; + unsigned _level; + bool _isCyclic; + bool _isCyclic_or_CyclicParent; + + void AddErrorMessage(const char *message); + void AddErrorMessage(const char *message, const wchar_t *name); + + void UpdatePhySize(UInt64 value) + { + if (_phySize < value) + _phySize = value; + } + + HRESULT Seek2(UInt64 offset); + HRESULT Read_FALSE(Byte *data, size_t size) + { + return ReadStream_FALSE(Stream, data, size); + } + HRESULT ReadToBuf_FALSE(CByteBuffer &buf, size_t size) + { + buf.Alloc(size); + return ReadStream_FALSE(Stream, buf, size); + } + + void InitSeekPositions(); + HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); + + bool IsDiff() const + { + // here we suppose that only HasParent() flag is mandatory for Diff archive type + return Meta.Is_HasParent(); + // return _parentGuid_IsDefined; + } + + void AddTypeString(AString &s) const + { + if (IsDiff()) + s += "Differencing"; + else + { + if (Meta.Is_LeaveBlockAllocated()) + s += _isDataContiguous ? "fixed" : "fixed-non-cont"; + else + s += "dynamic"; + } + } + + void AddComment(UString &s) const; + + UInt64 GetPackSize() const + { + return (UInt64)NumUsedBlocks << Meta.BlockSize_Log; + } + + UString GetParentSequence() const + { + const CHandler *p = this; + UString res; + while (p && p->IsDiff()) + { + if (!res.IsEmpty()) + res += " -> "; + res += ParentName_Used; + p = p->Parent; + } + return res; + } + + bool AreParentsOK() const + { + if (_isCyclic_or_CyclicParent) + return false; + const CHandler *p = this; + while (p->IsDiff()) + { + p = p->Parent; + if (!p) + return false; + } + return true; + } + + // bool ParseLog(CByteBuffer &log); + bool ParseBat(); + bool CheckBat(); + + HRESULT Open3(); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback); + HRESULT OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen); + virtual void CloseAtError(); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + CHandler(): + _child(NULL), + _level(0), + _isCyclic(false), + _isCyclic_or_CyclicParent(false) + {} +}; + + +HRESULT CHandler::Seek2(UInt64 offset) +{ + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); +} + + +void CHandler::InitSeekPositions() +{ + /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). + So we must reset these variables before first call of Read() */ + Reset_VirtPos(); + Reset_PosInArc(); + if (ParentStream) + Parent->InitSeekPositions(); +} + + +HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) +{ + processed = 0; + if (offset > _phySize + || offset + size > _phySize) + { + // we don't expect these cases, if (_phySize) was set correctly. + return S_FALSE; + } + if (offset != _posInArc) + { + const HRESULT res = Seek2(offset); + if (res != S_OK) + { + Reset_PosInArc(); // we don't trust seek_pos in case of error + return res; + } + _posInArc = offset; + } + { + size_t size2 = size; + const HRESULT res = ReadStream(Stream, data, &size2); + processed = (UInt32)size2; + _posInArc += size2; + if (res != S_OK) + Reset_PosInArc(); // we don't trust seek_pos in case of reading error + return res; + } +} + + +#define PAYLOAD_BLOCK_NOT_PRESENT 0 +#define PAYLOAD_BLOCK_UNDEFINED 1 +#define PAYLOAD_BLOCK_ZERO 2 +#define PAYLOAD_BLOCK_UNMAPPED 3 +#define PAYLOAD_BLOCK_FULLY_PRESENT 6 +#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7 + +#define SB_BLOCK_NOT_PRESENT 0 +#define SB_BLOCK_PRESENT 6 + +#define BAT_GET_OFFSET(v) ((v) & ~(UInt64)0xFFFFF); +#define BAT_GET_STATE(v) ((UInt32)(v) & 7); + +/* The log contains only updates to metadata, bat and region tables + The log doesn't contain updates to start header, and 2 headers (first 192 KB of file). + The log is array of 4 KB blocks and each block has 4-byte signature. + So it's possible to scan whole log to find the latest entry sequence (and header for replay). +*/ + +/* +struct CLogEntry +{ + UInt32 EntryLength; + UInt32 Tail; + UInt64 SequenceNumber; + CGuid LogGuid; + UInt32 DescriptorCount; + UInt64 FlushedFileOffset; + UInt64 LastFileOffset; + + bool Parse(const Byte *p); +}; + +bool CLogEntry::Parse(const Byte *p) +{ + G32 (8, EntryLength); + G32 (12,Tail); + G64 (16, SequenceNumber); + G32 (24, DescriptorCount); // it's 32-bit, but specification says 64-bit + if (Get32(p + 28) != 0) // reserved + return false; + LogGuid.SetFrom(p + 32); + G64 (48, FlushedFileOffset); + G64 (56, LastFileOffset); + + if (SequenceNumber == 0) + return false; + if ((Tail & 0xfff) != 0) + return false; + if (IS_NON_ALIGNED(FlushedFileOffset)) + return false; + if (IS_NON_ALIGNED(LastFileOffset)) + return false; + return true; +} + + +bool CHandler::ParseLog(CByteBuffer &log) +{ + CLogEntry lastEntry; + lastEntry.SequenceNumber = 0; + bool lastEntry_found = false; + size_t lastEntry_Offset = 0; + for (size_t i = 0; i < log.Size(); i += 1 << 12) + { + Byte *p = (Byte *)(log + i); + + if (Get32(p) != 0x65676F6C) // "loge" + continue; + const UInt32 crc = Get32(p + 4); + + CLogEntry e; + if (!e.Parse(p)) + { + return false; + continue; + } + const UInt32 entryLength = Get32(p + 8); + if (e.EntryLength > log.Size() || (e.EntryLength & 0xFFF) != 0 || e.EntryLength == 0) + { + return false; + continue; + } + SetUi32(p + 4, 0); + const UInt32 crc_calced = Crc32c_Calc(p, entryLength); + SetUi32(p + 4, crc); // we must restore crc if we want same data in log + if (crc_calced != crc) + continue; + if (!lastEntry_found || lastEntry.SequenceNumber < e.SequenceNumber) + { + lastEntry = e; + lastEntry_found = true; + lastEntry_Offset = i; + } + } + + return true; +} +*/ + + +bool CHandler::ParseBat() +{ + ChunkRatio_Log = kBitmapSize_Log + 3 + Meta.LogicalSectorSize_Log - Meta.BlockSize_Log; + ChunkRatio = (size_t)1 << (ChunkRatio_Log); + + UInt64 totalBatEntries64; + const bool isDiff = IsDiff(); + const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log; + { + const UInt64 up = Meta.VirtualDiskSize + blockSize - 1; + if (up < Meta.VirtualDiskSize) + return false; + const UInt64 numDataBlocks = up >> Meta.BlockSize_Log; + + if (isDiff) + { + // differencing table must be finished with bitmap entry + const UInt64 numBitmaps = (numDataBlocks + ChunkRatio - 1) >> ChunkRatio_Log; + totalBatEntries64 = numBitmaps * (ChunkRatio + 1); + } + else + { + // we don't need last Bitmap entry + totalBatEntries64 = numDataBlocks + ((numDataBlocks - 1) >> ChunkRatio_Log); + } + } + + if (totalBatEntries64 > Bat.Data.Size() / 8) + return false; + + const size_t totalBatEntries = (size_t)totalBatEntries64; + TotalBatEntries = totalBatEntries; + + bool isCont = (!isDiff && Meta.Is_LeaveBlockAllocated()); + UInt64 prevBlockOffset = 0; + UInt64 maxBlockOffset = 0; + + size_t remEntries = ChunkRatio + 1; + + size_t i; + for (i = 0; i < totalBatEntries; i++) + { + const UInt64 v = Bat.GetItem(i); + if ((v & 0xFFFF8) != 0) + return false; + const UInt64 offset = BAT_GET_OFFSET(v); + const unsigned state = BAT_GET_STATE(v); + + /* + UInt64 index64 = v >> 20; + printf("\n%7d", i); + printf("%10d, ", (unsigned)index64); + printf("%4x, ", (unsigned)state); + */ + + remEntries--; + if (remEntries == 0) + { + // printf(" ========"); + // printf("\n"); + remEntries = ChunkRatio + 1; + if (state == SB_BLOCK_PRESENT) + { + isCont = false; + if (!isDiff) + return false; + if (offset == 0) + return false; + const UInt64 lim = offset + kBitmapSize; + if (lim < offset) + return false; + if (_phySize < lim) + _phySize = lim; + NumUsedBitMaps++; + } + else if (state != SB_BLOCK_NOT_PRESENT) + return false; + } + else + { + if (state == PAYLOAD_BLOCK_FULLY_PRESENT + || state == PAYLOAD_BLOCK_PARTIALLY_PRESENT) + { + if (offset == 0) + return false; + if (maxBlockOffset < offset) + maxBlockOffset = offset; + + if (state == PAYLOAD_BLOCK_PARTIALLY_PRESENT) + { + isCont = false; + if (!isDiff) + return false; + } + else if (isCont) + { + if (prevBlockOffset != 0 && prevBlockOffset + blockSize != offset) + isCont = false; + else + prevBlockOffset = offset; + } + + NumUsedBlocks++; + } + else if (state == PAYLOAD_BLOCK_UNMAPPED) + { + isCont = false; + // non-empty (offset) is allowed + } + else if (state == PAYLOAD_BLOCK_NOT_PRESENT + || state == PAYLOAD_BLOCK_UNDEFINED + || state == PAYLOAD_BLOCK_ZERO) + { + isCont = false; + /* (offset) is reserved and (offset == 0) is expected here, + but we ignore (offset) here */ + // if (offset != 0) return false; + } + else + return false; + } + } + + _isDataContiguous = isCont; + + if (maxBlockOffset != 0) + { + const UInt64 lim = maxBlockOffset + blockSize; + if (lim < maxBlockOffset) + return false; + if (_phySize < lim) + _phySize = lim; + const UInt64 kPhyLimit = (UInt64)1 << 62; + if (maxBlockOffset >= kPhyLimit) + return false; + } + return true; +} + + +bool CHandler::CheckBat() +{ + const UInt64 upSize = _phySize + kBitmapSize * 8 - 1; + if (upSize < _phySize) + return false; + const UInt64 useMapSize64 = upSize >> (kBitmapSize_Log + 3); + const size_t useMapSize = (size_t)useMapSize64; + + const UInt32 blockSizeMB = (UInt32)1 << (Meta.BlockSize_Log - kBitmapSize_Log); + + // we don't check useMap, if it's too big. + if (useMapSize != useMapSize64) + return true; + if (useMapSize == 0 || useMapSize > ((size_t)1 << 28)) + return true; + + CByteArr useMap; + useMap.Alloc(useMapSize); + memset(useMap, 0, useMapSize); + // useMap[0] = (Byte)(1 << 0); // first 1 MB is used by headers + // we can also update useMap for log, and region data. + + const size_t totalBatEntries = TotalBatEntries; + size_t remEntries = ChunkRatio + 1; + + size_t i; + for (i = 0; i < totalBatEntries; i++) + { + const UInt64 v = Bat.GetItem(i); + const UInt64 offset = BAT_GET_OFFSET(v); + const unsigned state = BAT_GET_STATE(v); + const UInt64 index = offset >> kBitmapSize_Log; + UInt32 numBlocks = 1; + remEntries--; + if (remEntries == 0) + { + remEntries = ChunkRatio + 1; + if (state != SB_BLOCK_PRESENT) + continue; + } + else + { + if (state != PAYLOAD_BLOCK_FULLY_PRESENT && + state != PAYLOAD_BLOCK_PARTIALLY_PRESENT) + continue; + numBlocks = blockSizeMB; + } + + for (unsigned k = 0; k < numBlocks; k++) + { + const UInt64 index2 = index + k; + const unsigned flag = (unsigned)1 << ((unsigned)index2 & 7); + const size_t byteIndex = (size_t)(index2 >> 3); + if (byteIndex >= useMapSize) + return false; + const unsigned m = useMap[byteIndex]; + if (m & flag) + return false; + useMap[byteIndex] = (Byte)(m | flag); + } + } + + /* + UInt64 num = 0; + for (i = 0; i < useMapSize; i++) + { + Byte b = useMap[i]; + unsigned t = 0; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); + num += t; + } + NumUsed_1MB_Blocks = num; + NumUsed_1MB_Blocks_Defined = true; + */ + + return true; +} + + + +HRESULT CHandler::Open3() +{ + { + static const unsigned kHeaderSize = 512; // + 8 + Byte header[kHeaderSize]; + + RINOK(Read_FALSE(header, kHeaderSize)); + + if (memcmp(header, kSignature, kSignatureSize) != 0) + return S_FALSE; + + const Byte *p = &header[0]; + for (unsigned i = kSignatureSize; i < kHeaderSize; i += 2) + { + const wchar_t c = Get16(p + i); + if (c < 0x20 || c > 0x7F) + break; + _Creator += c; + } + } + + HeadersSize = (UInt32)1 << 20; + CHeader headers[2]; + { + Byte header[kHeader2Size]; + for (unsigned i = 0; i < 2; i++) + { + RINOK(Seek2((1 << 16) * (1 + i))); + RINOK(Read_FALSE(header, kHeader2Size)); + bool headerIsOK = headers[i].Parse(header); + if (!headerIsOK) + return S_FALSE; + } + } + unsigned mainIndex; + if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0; + else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1; + else return S_FALSE; + + const CHeader &h = headers[mainIndex]; + Header = h; + if (h.LogLength != 0) + { + HeadersSize += h.LogLength; + UpdatePhySize(h.LogOffset + h.LogLength); + if (!h.Guids[kHeader_GUID_Index_LogGuid].IsZero()) + { + _nonEmptyLog = true; + AddErrorMessage("non-empty LOG was not replayed"); + /* + if (h.LogVersion != 0) + AddErrorMessage("unknown LogVresion"); + else + { + CByteBuffer log; + RINOK(Seek2(h.LogOffset)); + RINOK(ReadToBuf_FALSE(log, h.LogLength)); + if (!ParseLog(log)) + { + return S_FALSE; + } + } + */ + } + } + CRegion regions[2]; + int correctRegionIndex = -1; + + { + CByteBuffer temp; + temp.Alloc(kRegionSize * 2); + RINOK(Seek2((1 << 16) * 3)); + RINOK(Read_FALSE(temp, kRegionSize * 2)); + unsigned numTables = 1; + if (memcmp(temp, temp + kRegionSize, kRegionSize) != 0) + { + AddErrorMessage("Region tables mismatch"); + numTables = 2; + } + + for (unsigned i = 0; i < numTables; i++) + { + // RINOK(Seek2((1 << 16) * (3 + i))); + // RINOK(Read_FALSE(temp, kRegionSize)); + if (regions[i].Parse(temp)) + { + if (correctRegionIndex < 0) + correctRegionIndex = i; + } + else + { + AddErrorMessage("Incorrect region table"); + } + } + if (correctRegionIndex < 0) + return S_FALSE; + /* + if (!regions[0].IsEqualTo(regions[1])) + return S_FALSE; + */ + } + + // UpdatePhySize((1 << 16) * 5); + UpdatePhySize(1 << 20); + + { + const CRegion ®ion = regions[correctRegionIndex]; + HeadersSize += region.DataSize; + UpdatePhySize(region.EndPos); + { + if (!region.Meta_Defined) + return S_FALSE; + const CRegionEntry &e = region.MetaEntry; + if (e.Len == 0) + return S_FALSE; + { + // static const kMetaTableSize = 1 << 16; + CByteBuffer temp; + { + RINOK(Seek2(e.Offset)); + RINOK(ReadToBuf_FALSE(temp, e.Len)); + } + if (!Meta.Parse(temp, temp.Size())) + return S_FALSE; + } + // UpdatePhySize(e.GetEndPos()); + } + { + if (!region.Bat_Defined) + return S_FALSE; + const CRegionEntry &e = region.BatEntry; + if (e.Len == 0) + return S_FALSE; + // UpdatePhySize(e.GetEndPos()); + { + RINOK(Seek2(e.Offset)); + RINOK(ReadToBuf_FALSE(Bat.Data, e.Len)); + } + if (!ParseBat()) + return S_FALSE; + if (!CheckBat()) + { + AddErrorMessage("BAT overlap"); + // _BatOverlap = true; + // return S_FALSE; + } + } + } + + { + // do we need to check "parent_linkage2" also? + FOR_VECTOR (i, Meta.ParentPairs) + { + const CParentPair &pair = Meta.ParentPairs[i]; + if (pair.Key.IsEqualTo("parent_linkage")) + { + _parentGuid_IsDefined = _parentGuid.ParseFromFormatedHexString(pair.Value); + break; + } + } + } + + { + // absolute paths for parent stream can be rejected later in client callback + // the order of check by specification: + static const char * const g_ParentKeys[] = + { + "relative_path" // "..\..\path2\sub3\parent.vhdx" + , "volume_path" // "\\?\Volume{26A21BDA-A627-11D7-9931-806E6F6E6963}\path2\sub3\parent.vhdx") + , "absolute_win32_path" // "d:\path2\sub3\parent.vhdx" + }; + for (unsigned i = 0; i < ARRAY_SIZE(g_ParentKeys); i++) + { + const int index = Meta.FindParentKey(g_ParentKeys[i]); + if (index < 0) + continue; + ParentNames.Add(Meta.ParentPairs[index].Value); + } + } + + if (Meta.Is_HasParent()) + { + if (!Meta.Locator_Defined) + AddErrorMessage("Parent locator is not defined"); + else + { + if (!_parentGuid_IsDefined) + AddErrorMessage("Parent GUID is not defined"); + if (ParentNames.IsEmpty()) + AddErrorMessage("Parent VHDX file name is not defined"); + } + } + else + { + if (Meta.Locator_Defined) + AddErrorMessage("Unexpected parent locator"); + } + + // here we suppose that and locator can be used only with HasParent flag + + // return S_FALSE; + + _size = Meta.VirtualDiskSize; // CHandlerImg + + // _posInArc = 0; + // Reset_PosInArc(); + // RINOK(Stream->Seek(0, STREAM_SEEK_SET, NULL)); + + return S_OK; +} + + +/* +static UInt32 g_NumCalls = 0; +static UInt32 g_NumCalls2 = 0; +static struct CCounter { ~CCounter() +{ + printf("\nNumCalls = %10u\n", g_NumCalls); + printf("NumCalls2 = %10u\n", g_NumCalls2); +} } g_Counter; +*/ + +STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + // g_NumCalls++; + if (processedSize) + *processedSize = 0; + if (_virtPos >= Meta.VirtualDiskSize) + return S_OK; + { + const UInt64 rem = Meta.VirtualDiskSize - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + const size_t blockIndex = (size_t)(_virtPos >> Meta.BlockSize_Log); + const size_t chunkIndex = blockIndex >> ChunkRatio_Log; + const size_t chunkRatio = (size_t)1 << ChunkRatio_Log; + const size_t blockIndex2 = chunkIndex * (chunkRatio + 1) + (blockIndex & (chunkRatio - 1)); + const UInt64 blockSectVal = Bat.GetItem(blockIndex2); + const UInt64 blockOffset = BAT_GET_OFFSET(blockSectVal); + const UInt32 blockState = BAT_GET_STATE(blockSectVal); + + const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log; + const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + size = MyMin(blockSize - offsetInBlock, size); + + bool needParent = false; + bool needRead = false; + + if (blockState == PAYLOAD_BLOCK_FULLY_PRESENT) + needRead = true; + else if (blockState == PAYLOAD_BLOCK_NOT_PRESENT) + { + /* for a differencing VHDX: parent virtual disk SHOULD be + inspected to determine the associated contents (SPECIFICATION). + we suppose that we should not check BitMap. + for fixed or dynamic VHDX files: the block contents are undefined and + can contain arbitrary data (SPECIFICATION). NTFS::pagefile.sys can use such state. */ + if (IsDiff()) + needParent = true; + } + else if (blockState == PAYLOAD_BLOCK_PARTIALLY_PRESENT) + { + // only allowed for differencing VHDX files. + // associated sector bitmap block MUST be valid + if (chunkIndex >= BitMaps.Size()) + return S_FALSE; + // else + { + const CByteBuffer &bitmap = BitMaps[(unsigned)chunkIndex]; + const Byte *p = (const Byte *)bitmap; + if (!p) + return S_FALSE; + // else + { + // g_NumCalls2++; + const UInt64 sectorIndex = _virtPos >> Meta.LogicalSectorSize_Log; + + #define BIT_MAP_UNIT_LOG 3 // it's for small block (4 KB) + // #define BIT_MAP_UNIT_LOG 5 // speed optimization for large blocks (16 KB) + + const size_t offs = (size_t)(sectorIndex >> 3) & + ( + (kBitmapSize - 1) + & ~(((UInt32)1 << (BIT_MAP_UNIT_LOG - 3)) - 1) + ); + + unsigned sector2 = (unsigned)sectorIndex & ((1 << BIT_MAP_UNIT_LOG) - 1); + #if BIT_MAP_UNIT_LOG == 5 + UInt32 v = GetUi32(p + offs) >> sector2; + #else + unsigned v = (unsigned)p[offs] >> sector2; + #endif + // UInt32 v = GetUi32(p + offs) >> sector2; + const UInt32 sectorSize = (UInt32)1 << Meta.LogicalSectorSize_Log; + const UInt32 offsetInSector = (UInt32)_virtPos & (sectorSize - 1); + const unsigned bit = (unsigned)(v & 1); + if (bit) + needRead = true; + else + needParent = true; // zero - from the parent VHDX file + UInt32 rem = sectorSize - offsetInSector; + for (sector2++; sector2 < (1 << BIT_MAP_UNIT_LOG); sector2++) + { + v >>= 1; + if (bit != (v & 1)) + break; + rem += sectorSize; + } + if (size > rem) + size = rem; + } + } + } + + bool needZero = true; + + HRESULT res = S_OK; + + if (needParent) + { + if (!ParentStream) + return S_FALSE; + // if (ParentStream) + { + RINOK(ParentStream->Seek(_virtPos, STREAM_SEEK_SET, NULL)); + size_t processed = size; + res = ReadStream(ParentStream, (Byte *)data, &processed); + size = (UInt32)processed; + needZero = false; + } + } + else if (needRead) + { + UInt32 processed = 0; + res = ReadPhy(blockOffset + offsetInBlock, data, size, processed); + size = processed; + needZero = false; + } + + if (needZero) + memset(data, 0, size); + + if (processedSize) + *processedSize = size; + + _virtPos += size; + return res; +} + + +enum +{ + kpidParent = kpidUserDefined +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidSectorSize, VT_UI4}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidNumVolumes, VT_UI4}, + { NULL, kpidTotalPhySize, VT_UI8}, + { "Parent", kpidParent, VT_BSTR}, + { NULL, kpidCreatorApp, VT_BSTR}, + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidId, VT_BSTR} + }; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + + +void CHandler::AddErrorMessage(const char *message) +{ + if (!_errorMessage.IsEmpty()) + _errorMessage.Add_LF(); + _errorMessage += message; +} + +void CHandler::AddErrorMessage(const char *message, const wchar_t *name) +{ + AddErrorMessage(message); + _errorMessage += name; +} + + +static void AddComment_Name(UString &s, const char *name) +{ + s += name; + s += ": "; +} + +static void AddComment_Bool(UString &s, const char *name, bool val) +{ + AddComment_Name(s, name); + s += val ? "+" : "-"; + s.Add_LF(); +} + +static void AddComment_UInt64(UString &s, const char *name, UInt64 v, bool showMB = false) +{ + AddComment_Name(s, name); + s.Add_UInt64(v); + if (showMB) + { + s += " ("; + s.Add_UInt64(v >> 20); + s += " MiB)"; + } + s.Add_LF(); +} + +static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize) +{ + if (logSize != 0) + AddComment_UInt64(s, name, ((UInt64)1 << logSize)); +} + + +void CHandler::AddComment(UString &s) const +{ + AddComment_UInt64(s, "PhysicalSize", _phySize); + + if (!_errorMessage.IsEmpty()) + { + AddComment_Name(s, "Error"); + s += _errorMessage; + s.Add_LF(); + } + + if (Meta.Guid_Defined) + { + AddComment_Name(s, "Id"); + Meta.Guid.AddHexToString(s); + s.Add_LF(); + } + + AddComment_UInt64(s, "SequenceNumber", Header.SequenceNumber); + AddComment_UInt64(s, "LogLength", Header.LogLength, true); + + for (unsigned i = 0; i < 3; i++) + { + const CGuid &g = Header.Guids[i]; + if (g.IsZero()) + continue; + if (i == 0) + s += "FileWrite"; + else if (i == 1) + s += "DataWrite"; + else + s += "Log"; + AddComment_Name(s, "Guid"); + g.AddHexToString(s); + s.Add_LF(); + } + + AddComment_Bool(s, "HasParent", Meta.Is_HasParent()); + AddComment_Bool(s, "Fixed", Meta.Is_LeaveBlockAllocated()); + if (Meta.Is_LeaveBlockAllocated()) + AddComment_Bool(s, "DataContiguous", _isDataContiguous); + + AddComment_BlockSize(s, "BlockSize", Meta.BlockSize_Log); + AddComment_BlockSize(s, "LogicalSectorSize", Meta.LogicalSectorSize_Log); + AddComment_BlockSize(s, "PhysicalSectorSize", Meta.PhysicalSectorSize_Log); + + { + const UInt64 packSize = GetPackSize(); + AddComment_UInt64(s, "PackSize", packSize, true); + const UInt64 headersSize = HeadersSize + ((UInt64)NumUsedBitMaps << kBitmapSize_Log); + AddComment_UInt64(s, "HeadersSize", headersSize, true); + AddComment_UInt64(s, "FreeSpace", _phySize - packSize - headersSize, true); + /* + if (NumUsed_1MB_Blocks_Defined) + AddComment_UInt64(s, "used2", (NumUsed_1MB_Blocks << 20)); + */ + } + + if (Meta.ParentPairs.Size() != 0) + { + s += "Parent:"; + s.Add_LF(); + FOR_VECTOR(i, Meta.ParentPairs) + { + const CParentPair &pair = Meta.ParentPairs[i]; + s += " "; + s += pair.Key; + s += ": "; + s += pair.Value; + s.Add_LF(); + } + s.Add_LF(); + } +} + + + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidClusterSize: prop = (UInt32)1 << Meta.BlockSize_Log; break; + case kpidSectorSize: prop = (UInt32)1 << Meta.LogicalSectorSize_Log; break; + case kpidShortComment: + case kpidMethod: + { + AString s; + AddTypeString(s); + if (IsDiff()) + { + s += " -> "; + const CHandler *p = this; + while (p && p->IsDiff()) + p = p->Parent; + if (!p) + s += '?'; + else + p->AddTypeString(s); + } + prop = s; + break; + } + case kpidComment: + { + UString s; + { + if (NumLevels > 1) + { + AddComment_UInt64(s, "NumVolumeLevels", NumLevels); + AddComment_UInt64(s, "PackSizeTotal", PackSize_Total, true); + s += "----"; + s.Add_LF(); + } + + const CHandler *p = this; + for (;;) + { + if (p->_level != 0 || p->Parent) + AddComment_UInt64(s, "VolumeLevel", p->_level + 1); + p->AddComment(s); + if (!p->Parent) + break; + s += "----"; + s.Add_LF(); + { + s.Add_LF(); + if (!p->ParentName_Used.IsEmpty()) + { + AddComment_Name(s, "Name"); + s += p->ParentName_Used; + s.Add_LF(); + } + } + p = p->Parent; + } + } + prop = s; + break; + } + case kpidCreatorApp: + { + if (!_Creator.IsEmpty()) + prop = _Creator; + break; + } + case kpidId: + { + if (Meta.Guid_Defined) + { + UString s; + Meta.Guid.AddHexToString(s); + prop = s; + } + break; + } + case kpidName: + { + if (Meta.Guid_Defined) + { + UString s; + Meta.Guid.AddHexToString(s); + s += ".vhdx"; + prop = s; + } + break; + } + case kpidParent: if (IsDiff()) prop = GetParentSequence(); break; + case kpidPhySize: prop = _phySize; break; + case kpidTotalPhySize: + { + const CHandler *p = this; + UInt64 sum = 0; + do + { + sum += p->_phySize; + p = p->Parent; + } + while (p); + prop = sum; + break; + } + case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break; + case kpidError: + { + UString s; + const CHandler *p = this; + do + { + if (!p->_errorMessage.IsEmpty()) + { + if (!s.IsEmpty()) + s.Add_LF(); + s += p->_errorMessage; + } + p = p->Parent; + } + while (p); + if (!s.IsEmpty()) + prop = s; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) +{ + Stream = stream; + if (_level >= (1 << 20)) + return S_FALSE; + + RINOK(Open3()); + + NumLevels = 1; + PackSize_Total = GetPackSize(); + + if (_child) + { + if (!_child->_parentGuid.IsEqualTo(Header.Guids[kHeader_GUID_Index_DataWriteGuid])) + return S_FALSE; + const CHandler *child = _child; + do + { + /* We suppose that only FileWriteGuid is unique. + Another IDs must be identical in in difference and parent archives. */ + if (Header.Guids[kHeader_GUID_Index_FileWriteGuid].IsEqualTo( + child->Header.Guids[kHeader_GUID_Index_FileWriteGuid]) + && _phySize == child->_phySize) + { + _isCyclic = true; + _isCyclic_or_CyclicParent = true; + AddErrorMessage("Cyclic parent archive was blocked"); + return S_OK; + } + child = child->_child; + } + while (child); + } + + if (!Meta.Is_HasParent()) + return S_OK; + + if (!Meta.Locator_Defined + || !_parentGuid_IsDefined + || ParentNames.IsEmpty()) + { + return S_OK; + } + + ParentName_Used = ParentNames.Front(); + + HRESULT res; + const unsigned kNumLevelsMax = (1 << 8); // Maybe we need to increase that limit + if (_level >= kNumLevelsMax - 1) + { + AddErrorMessage("Too many parent levels"); + return S_OK; + } + + bool _parentFileWasOpen = false; + + if (!openArchiveCallback) + res = S_FALSE; + else + res = OpenParent(openArchiveCallback, _parentFileWasOpen); + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + + if (_parentFileWasOpen) + AddErrorMessage("Can't parse parent VHDX file : ", ParentName_Used); + else + AddErrorMessage("Missing parent VHDX file : ", ParentName_Used); + } + + + return S_OK; +} + + +HRESULT CHandler::OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen) +{ + _parentFileWasOpen = false; + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; + openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + if (!openVolumeCallback) + return S_FALSE; + + { + CMyComPtr<IInStream> nextStream; + HRESULT res = S_FALSE; + UString name; + + FOR_VECTOR (i, ParentNames) + { + name = ParentNames[i]; + + // we remove prefix ".\\', but client already can support any variant + if (name[0] == L'.' && name[1] == L'\\') + name.DeleteFrontal(2); + + res = openVolumeCallback->GetStream(name, &nextStream); + + if (res == S_OK && nextStream) + break; + + if (res != S_OK && res != S_FALSE) + return res; + } + + if (res == S_FALSE || !nextStream) + return S_FALSE; + + ParentName_Used = name; + _parentFileWasOpen = true; + + Parent = new CHandler; + ParentStream = Parent; + + try + { + Parent->_level = _level + 1; + Parent->_child = this; + /* we could call CHandlerImg::Open() here. + but we don't need (_imgExt) in (Parent). So we call Open2() here */ + Parent->Close(); + res = Parent->Open2(nextStream, openArchiveCallback); + } + catch(...) + { + Parent = NULL; + ParentStream.Release(); + res = S_FALSE; + throw; + } + + if (res != S_OK) + { + Parent = NULL; + ParentStream.Release(); + if (res == E_ABORT) + return res; + if (res != S_FALSE) + { + // we must show that error code + } + } + + if (res == S_OK) + { + if (Parent->_isCyclic_or_CyclicParent) + _isCyclic_or_CyclicParent = true; + + NumLevels = Parent->NumLevels + 1; + PackSize_Total += Parent->GetPackSize(); + + // we read BitMaps only if Parent was open + + UInt64 numBytes = (UInt64)NumUsedBitMaps << kBitmapSize_Log; + if (openArchiveCallback && numBytes != 0) + { + RINOK(openArchiveCallback->SetTotal(NULL, &numBytes)); + } + numBytes = 0; + for (size_t i = ChunkRatio; i < TotalBatEntries; i += ChunkRatio + 1) + { + const UInt64 v = Bat.GetItem(i); + const UInt64 offset = BAT_GET_OFFSET(v); + const unsigned state = BAT_GET_STATE(v); + + CByteBuffer &buf = BitMaps.AddNew(); + if (state == SB_BLOCK_PRESENT) + { + if (openArchiveCallback) + { + RINOK(openArchiveCallback->SetCompleted(NULL, &numBytes)); + } + numBytes += kBitmapSize; + buf.Alloc(kBitmapSize); + RINOK(Seek2(offset)); + RINOK(Read_FALSE(buf, kBitmapSize)); + /* + for (unsigned i = 0; i < (1 << 20); i+=4) + { + UInt32 v = GetUi32(buf + i); + if (v != 0 && v != (UInt32)(Int32)-1) + printf("\n%7d %8x", i, v); + } + */ + } + } + } + } + + return S_OK; +} + + +void CHandler::CloseAtError() +{ + // CHandlerImg + Clear_HandlerImg_Vars(); + Stream.Release(); + + _phySize = 0; + Bat.Clear(); + BitMaps.Clear(); + NumUsedBlocks = 0; + NumUsedBitMaps = 0; + HeadersSize = 0; + /* + NumUsed_1MB_Blocks = 0; + NumUsed_1MB_Blocks_Defined = false; + */ + + Parent = NULL; + ParentStream.Release(); + _errorMessage.Empty(); + _Creator.Empty(); + _nonEmptyLog = false; + _parentGuid_IsDefined = false; + _isDataContiguous = false; + // _BatOverlap = false; + + ParentNames.Clear(); + ParentName_Used.Empty(); + + Meta.Clear(); + + ChunkRatio_Log = 0; + ChunkRatio = 0; + TotalBatEntries = 0; + NumLevels = 0; + PackSize_Total = 0; + + _isCyclic = false; + _isCyclic_or_CyclicParent = false; +} + +STDMETHODIMP CHandler::Close() +{ + CloseAtError(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = Meta.VirtualDiskSize; break; + case kpidPackSize: prop = PackSize_Total; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = NULL; + // if some prarent is not OK, we don't create stream + if (!AreParentsOK()) + return S_FALSE; + InitSeekPositions(); + CMyComPtr<ISequentialInStream> streamTemp = this; + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "VHDX", "vhdx avhdx", NULL, 0xc4, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp index 096bd103..fb5bb1f8 100644 --- a/CPP/7zip/Archive/VmdkHandler.cpp +++ b/CPP/7zip/Archive/VmdkHandler.cpp @@ -1430,7 +1430,6 @@ HRESULT CExtent::Open3(IInStream *stream, IArchiveOpenCallback *openCallback, STDMETHODIMP CHandler::Close() { _phySize = 0; - _size = 0; _cacheCluster = (UInt64)(Int64)-1; _cacheExtent = (unsigned)(int)-1; @@ -1450,8 +1449,10 @@ STDMETHODIMP CHandler::Close() _descriptorBuf.Free(); _descriptor.Clear(); - _imgExt = NULL; - Stream.Release(); // Stream vriable is unused + // CHandlerImg: + Clear_HandlerImg_Vars(); + Stream.Release(); + _extents.Clear(); return S_OK; } diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsp b/CPP/7zip/Bundles/Alone7z/Alone.dsp index 76607fdd..217e6d68 100644 --- a/CPP/7zip/Bundles/Alone7z/Alone.dsp +++ b/CPP/7zip/Bundles/Alone7z/Alone.dsp @@ -1942,10 +1942,6 @@ SOURCE=..\..\..\..\C\Threads.c SOURCE=..\..\..\..\C\Threads.h # End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Types.h -# End Source File # End Group # Begin Group "Crypto" diff --git a/CPP/7zip/Bundles/Fm/resource.rc b/CPP/7zip/Bundles/Fm/resource.rc index 6c329588..ffcff11a 100644 --- a/CPP/7zip/Bundles/Fm/resource.rc +++ b/CPP/7zip/Bundles/Fm/resource.rc @@ -3,5 +3,5 @@ STRINGTABLE BEGIN - 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd wim swm esd fat ntfs dmg hfs xar squashfs" + 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs" END diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak index 53a8895a..d8468a6f 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc.mak @@ -89,6 +89,7 @@ AR_OBJS = \ $O\UefiHandler.obj \ $O\VdiHandler.obj \ $O\VhdHandler.obj \ + $O\VhdxHandler.obj \ $O\VmdkHandler.obj \ $O\XarHandler.obj \ $O\XzHandler.obj \ diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak index 73711d3a..8021f68a 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak @@ -118,6 +118,7 @@ AR_OBJS = \ $O/UefiHandler.o \ $O/VdiHandler.o \ $O/VhdHandler.o \ + $O/VhdxHandler.o \ $O/VmdkHandler.o \ $O/XarHandler.o \ $O/XzHandler.o \ @@ -175,10 +176,14 @@ NSIS_OBJS = \ $O/NsisIn.o \ $O/NsisRegister.o \ +ifndef DISABLE_RAR RAR_OBJS = \ $O/RarHandler.o \ $O/Rar5Handler.o \ +endif + + TAR_OBJS = \ $O/TarHandler.o \ $O/TarHandlerOut.o \ @@ -245,12 +250,6 @@ COMPRESS_OBJS = \ $O/PpmdRegister.o \ $O/PpmdZip.o \ $O/QuantumDecoder.o \ - $O/Rar1Decoder.o \ - $O/Rar2Decoder.o \ - $O/Rar3Decoder.o \ - $O/Rar3Vm.o \ - $O/Rar5Decoder.o \ - $O/RarCodecsRegister.o \ $O/ShrinkDecoder.o \ $O/XpressDecoder.o \ $O/XzDecoder.o \ @@ -259,6 +258,20 @@ COMPRESS_OBJS = \ $O/ZlibEncoder.o \ $O/ZDecoder.o \ +ifdef DISABLE_RAR +DISABLE_RAR_COMPRESS=1 +endif + +ifndef DISABLE_RAR_COMPRESS +COMPRESS_OBJS += \ + $O/Rar1Decoder.o \ + $O/Rar2Decoder.o \ + $O/Rar3Decoder.o \ + $O/Rar3Vm.o \ + $O/Rar5Decoder.o \ + $O/RarCodecsRegister.o \ + +endif CRYPTO_OBJS = \ $O/7zAes.o \ @@ -269,13 +282,18 @@ CRYPTO_OBJS = \ $O/MyAesReg.o \ $O/Pbkdf2HmacSha1.o \ $O/RandGen.o \ - $O/Rar20Crypto.o \ - $O/Rar5Aes.o \ - $O/RarAes.o \ $O/WzAes.o \ $O/ZipCrypto.o \ $O/ZipStrong.o \ +ifndef DISABLE_RAR +CRYPTO_OBJS += \ + $O/Rar20Crypto.o \ + $O/Rar5Aes.o \ + $O/RarAes.o \ + +endif + C_OBJS = \ $O/7zBuf2.o \ @@ -323,7 +341,7 @@ C_OBJS = \ $O/Sha1Opt.o \ ARC_OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ + $(LZMA_DEC_OPT_OBJS) \ $(C_OBJS) \ $(MT_OBJS) \ $(COMMON_OBJS) \ diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index 36ac6042..6b55e93d 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -2929,6 +2929,10 @@ SOURCE=..\..\Archive\VhdHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\VhdxHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\VmdkHandler.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Format7zF/resource.rc b/CPP/7zip/Bundles/Format7zF/resource.rc index 5330a415..aaaabeaa 100644 --- a/CPP/7zip/Bundles/Format7zF/resource.rc +++ b/CPP/7zip/Bundles/Format7zF/resource.rc @@ -33,5 +33,5 @@ MY_VERSION_INFO_DLL("7z Plugin" , "7z") STRINGTABLE BEGIN - 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24" + 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24" END diff --git a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp index b149889b..cfa1ee7c 100644 --- a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp +++ b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp @@ -208,7 +208,7 @@ static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, if (!IsWildcardFilePathLegal(name)) return false; */ - bool isWildcard = DoesNameContainWildcard(name); + const bool isWildcard = DoesNameContainWildcard(name); bool recursed = false; switch (type) @@ -223,7 +223,10 @@ static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, recursed = false; break; } - wildcardCensor.AddPreItem(include, name, recursed, true); + + NWildcard::CCensorPathProps props; + props.Recursive = recursed; + wildcardCensor.AddPreItem(include, name, props); return true; } diff --git a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp index 2f809322..23beade2 100644 --- a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp +++ b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp @@ -178,7 +178,7 @@ static int APIENTRY WinMain2() v1.Add(fs2us(fullPath)); v2.Add(fs2us(fullPath)); NWildcard::CCensorNode wildcardCensor; - wildcardCensor.AddItem(true, L"*", true, true, true, true); + wildcardCensor.Add_Wildcard(); bool messageWasDisplayed = false; result = ExtractGUI(codecs, diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp index 466f46e9..9e0e79ca 100644 --- a/CPP/7zip/Common/FileStreams.cpp +++ b/CPP/7zip/Common/FileStreams.cpp @@ -263,8 +263,13 @@ STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPos } #endif - UInt64 realNewPosition; - bool result = File.Seek(offset, seekOrigin, realNewPosition); + UInt64 realNewPosition = 0; + const bool result = File.Seek(offset, seekOrigin, realNewPosition); + const HRESULT hres = ConvertBoolToHRESULT(result); + + /* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition) + in case of error. So we don't need additional code below */ + // if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); } #ifdef SUPPORT_DEVICE_FILE PhyPos = VirtPos = realNewPosition; @@ -272,13 +277,19 @@ STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPos if (newPosition) *newPosition = realNewPosition; - return ConvertBoolToHRESULT(result); + + return hres; #else - off_t res = File.seek((off_t)offset, (int)seekOrigin); + const off_t res = File.seek((off_t)offset, (int)seekOrigin); if (res == -1) - return GetLastError_HRESULT(); + { + const HRESULT hres = GetLastError_HRESULT(); + if (newPosition) + *newPosition = (UInt64)File.seekToCur(); + return hres; + } if (newPosition) *newPosition = (UInt64)res; return S_OK; @@ -435,15 +446,15 @@ STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPo #ifdef USE_WIN_FILE - UInt64 realNewPosition; - bool result = File.Seek(offset, seekOrigin, realNewPosition); + UInt64 realNewPosition = 0; + const bool result = File.Seek(offset, seekOrigin, realNewPosition); if (newPosition) *newPosition = realNewPosition; return ConvertBoolToHRESULT(result); #else - off_t res = File.seek((off_t)offset, (int)seekOrigin); + const off_t res = File.seek((off_t)offset, (int)seekOrigin); if (res == -1) return GetLastError_HRESULT(); if (newPosition) @@ -455,24 +466,7 @@ STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPo STDMETHODIMP COutFileStream::SetSize(UInt64 newSize) { - #ifdef USE_WIN_FILE - - UInt64 currentPos; - if (!File.Seek(0, FILE_CURRENT, currentPos)) - return E_FAIL; - bool result = File.SetLength(newSize); - UInt64 currentPos2; - result = result && File.Seek(currentPos, currentPos2); - return result ? S_OK : E_FAIL; - - #else - - // SetLength() uses ftruncate() that doesn't change file offset - if (!File.SetLength(newSize)) - return GetLastError_HRESULT(); - return S_OK; - - #endif + return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize)); } HRESULT COutFileStream::GetSize(UInt64 *size) diff --git a/CPP/7zip/Compress/CopyCoder.cpp b/CPP/7zip/Compress/CopyCoder.cpp index d8487ad5..a49bba8a 100644 --- a/CPP/7zip/Compress/CopyCoder.cpp +++ b/CPP/7zip/Compress/CopyCoder.cpp @@ -37,12 +37,34 @@ STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, for (;;) { UInt32 size = kBufSize; - if (outSize && size > *outSize - TotalSize) - size = (UInt32)(*outSize - TotalSize); - if (size == 0) - return S_OK; + if (outSize) + { + const UInt64 rem = *outSize - TotalSize; + if (size > rem) + { + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + } - HRESULT readRes = inStream->Read(_buf, size, &size); + HRESULT readRes; + { + UInt32 pos = 0; + do + { + const UInt32 curSize = size - pos; + UInt32 processed = 0; + readRes = inStream->Read(_buf + pos, curSize, &processed); + if (processed > curSize) + return E_FAIL; // internal code failure + pos += processed; + if (readRes != S_OK || processed == 0) + break; + } + while (pos < kBufSize); + size = pos; + } if (size == 0) return readRes; @@ -52,12 +74,15 @@ STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, UInt32 pos = 0; do { - UInt32 curSize = size - pos; - HRESULT res = outStream->Write(_buf + pos, curSize, &curSize); - pos += curSize; - TotalSize += curSize; + const UInt32 curSize = size - pos; + UInt32 processed = 0; + const HRESULT res = outStream->Write(_buf + pos, curSize, &processed); + if (processed > curSize) + return E_FAIL; // internal code failure + pos += processed; + TotalSize += processed; RINOK(res); - if (curSize == 0) + if (processed == 0) return E_FAIL; } while (pos < size); @@ -67,7 +92,10 @@ STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, RINOK(readRes); - if (progress) + if (size != kBufSize) + return S_OK; + + if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0) { RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)); } diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt index 754c9df5..3b654bc8 100644 --- a/CPP/7zip/Guid.txt +++ b/CPP/7zip/Guid.txt @@ -169,6 +169,7 @@ Handler GUIDs: 0C xz 0D ppmd + C4 Vhdx C5 Base64 C6 COFF C7 Ext diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index 31c91e29..cdb0e5d1 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -1887,23 +1887,23 @@ STDMETHODIMP CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value) break; case kpidErrorFlags: { - UInt32 flags = arc.ErrorInfo.GetErrorFlags(); + const UInt32 flags = arc.ErrorInfo.GetErrorFlags(); if (flags != 0) prop = flags; break; } case kpidWarningFlags: { - UInt32 flags = arc.ErrorInfo.GetWarningFlags(); + const UInt32 flags = arc.ErrorInfo.GetWarningFlags(); if (flags != 0) prop = flags; break; } case kpidOffset: { - Int64 v = arc.GetGlobalOffset(); + const Int64 v = arc.GetGlobalOffset(); if (v != 0) - prop = v; + prop.Set_Int64(v); break; } case kpidTailSize: diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index 47e4a852..91ef0382 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -151,6 +151,7 @@ enum Enum kCaseSensitive, kArcNameMode, + kUseSlashMark, kDisableWildcardParsing, kElimDup, kFullPathMode, @@ -294,6 +295,7 @@ static const CSwitchForm kSwitchForms[] = { "ssc", SWFRM_MINUS }, { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, + { "spm", SWFRM_STRING_SINGL(0) }, { "spd", SWFRM_SIMPLE }, { "spe", SWFRM_MINUS }, { "spf", SWFRM_STRING_SINGL(0) }, @@ -407,12 +409,28 @@ static bool ParseArchiveCommand(const UString &commandString, CArcCommand &comma // ------------------------------------------------------------------ // filenames functions +struct CNameOption +{ + bool Include; + bool WildcardMatching; + Byte MarkMode; + NRecursedType::EEnum RecursedType; + + CNameOption(): + Include(true), + WildcardMatching(true), + MarkMode(NWildcard::kMark_FileOrDir), + RecursedType(NRecursedType::kNonRecursed) + {} +}; + + static void AddNameToCensor(NWildcard::CCensor &censor, - const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching) + const CNameOption &nop, const UString &name) { bool recursed = false; - switch (type) + switch (nop.RecursedType) { case NRecursedType::kWildcardOnlyRecursed: recursed = DoesNameContainWildcard(name); @@ -423,7 +441,12 @@ static void AddNameToCensor(NWildcard::CCensor &censor, default: break; } - censor.AddPreItem(include, name, recursed, wildcardMatching); + + NWildcard::CCensorPathProps props; + props.Recursive = recursed; + props.WildcardMatching = nop.WildcardMatching; + props.MarkMode = nop.MarkMode; + censor.AddPreItem(nop.Include, name, props); } static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs, @@ -454,7 +477,7 @@ static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs, static void AddToCensorFromListFile( CObjectVector<CRenamePair> *renamePairs, NWildcard::CCensor &censor, - LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, UInt32 codePage) + const CNameOption &nop, LPCWSTR fileName, UInt32 codePage) { UStringVector names; /* @@ -481,12 +504,12 @@ static void AddToCensorFromListFile( for (unsigned i = 0; i < names.Size(); i += 2) { // change type !!!! - AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching); + AddRenamePair(renamePairs, names[i], names[i + 1], nop.RecursedType, nop.WildcardMatching); } } else FOR_VECTOR (i, names) - AddNameToCensor(censor, names[i], include, type, wildcardMatching); + AddNameToCensor(censor, nop, names[i]); } static void AddToCensorFromNonSwitchesStrings( @@ -495,14 +518,27 @@ static void AddToCensorFromNonSwitchesStrings( NWildcard::CCensor &censor, const UStringVector &nonSwitchStrings, int stopSwitchIndex, - NRecursedType::EEnum type, - bool wildcardMatching, + const CNameOption &nop, bool thereAreSwitchIncludes, UInt32 codePage) { + // another default if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes) - AddNameToCensor(censor, UString(kUniversalWildcard), true, type, - true // wildcardMatching - ); + { + /* for rename command: -i switch sets the mask for archive item reading. + if (thereAreSwitchIncludes), { we don't use UniversalWildcard. } + also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */ + // we use default fileds in (CNameOption) for UniversalWildcard. + CNameOption nop2; + // recursive mode is not important for UniversalWildcard (*) + // nop2.RecursedType = nop.RecursedType; // we don't need it + /* + nop2.RecursedType = NRecursedType::kNonRecursed; + nop2.Include = true; + nop2.WildcardMatching = true; + nop2.MarkMode = NWildcard::kMark_FileOrDir; + */ + AddNameToCensor(censor, nop2, UString(kUniversalWildcard)); + } int oldIndex = -1; @@ -515,7 +551,7 @@ static void AddToCensorFromNonSwitchesStrings( if (s.IsEmpty()) throw CArcCmdLineException(kEmptyFilePath); if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID) - AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage); + AddToCensorFromListFile(renamePairs, censor, nop, s.Ptr(1), codePage); else if (renamePairs) { if (oldIndex == -1) @@ -523,13 +559,13 @@ static void AddToCensorFromNonSwitchesStrings( else { // NRecursedType::EEnum type is used for global wildcard (-i! switches) - AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching); + AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching); // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type); oldIndex = -1; } } else - AddNameToCensor(censor, s, true, type, wildcardMatching); + AddNameToCensor(censor, nop, s); } if (oldIndex != -1) @@ -557,9 +593,8 @@ static const char * const k_IncorrectMapCommand = "Incorrect Map command"; static const char *ParseMapWithPaths( NWildcard::CCensor &censor, - const UString &s2, bool include, - NRecursedType::EEnum commonRecursedType, - bool wildcardMatching) + const UString &s2, + const CNameOption &nop) { UString s (s2); int pos = s.Find(L':'); @@ -598,7 +633,7 @@ static const char *ParseMapWithPaths( if (c == 0) { // MessageBoxW(0, name, L"7-Zip", 0); - AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching); + AddNameToCensor(censor, nop, name); name.Empty(); } else @@ -614,9 +649,8 @@ static const char *ParseMapWithPaths( static void AddSwitchWildcardsToCensor( NWildcard::CCensor &censor, - const UStringVector &strings, bool include, - NRecursedType::EEnum commonRecursedType, - bool wildcardMatching, + const UStringVector &strings, + const CNameOption &nop, UInt32 codePage) { const char *errorMessage = NULL; @@ -624,7 +658,6 @@ static void AddSwitchWildcardsToCensor( for (i = 0; i < strings.Size(); i++) { const UString &name = strings[i]; - NRecursedType::EEnum recursedType; unsigned pos = 0; if (name.Len() < kSomeCludePostStringMinSize) @@ -633,7 +666,7 @@ static void AddSwitchWildcardsToCensor( break; } - if (!include) + if (!nop.Include) { if (name.IsEqualTo_Ascii_NoCase("td")) { @@ -647,20 +680,85 @@ static void AddSwitchWildcardsToCensor( } } - if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar) + CNameOption nop2 = nop; + + bool type_WasUsed = false; + bool recursed_WasUsed = false; + bool matching_WasUsed = false; + bool error = false; + + for (;;) { - pos++; - wchar_t c = name[pos]; - int index = -1; - if (c <= 0x7F) - index = FindCharPosInString(kRecursedPostCharSet, (char)c); - recursedType = GetRecursedTypeFromIndex(index); - if (index >= 0) + wchar_t c = ::MyCharLower_Ascii(name[pos]); + if (c == kRecursedIDChar) + { + if (recursed_WasUsed) + { + error = true; + break; + } + recursed_WasUsed = true; pos++; + c = name[pos]; + int index = -1; + if (c <= 0x7F) + index = FindCharPosInString(kRecursedPostCharSet, (char)c); + nop2.RecursedType = GetRecursedTypeFromIndex(index); + if (index >= 0) + { + pos++; + continue; + } + } + + if (c == 'w') + { + if (matching_WasUsed) + { + error = true; + break; + } + matching_WasUsed = true; + nop2.WildcardMatching = true; + pos++; + if (name[pos] == '-') + { + nop2.WildcardMatching = false; + pos++; + } + } + else if (c == 'm') + { + if (type_WasUsed) + { + error = true; + break; + } + type_WasUsed = true; + pos++; + nop2.MarkMode = NWildcard::kMark_StrictFile; + c = name[pos]; + if (c == '-') + { + nop2.MarkMode = NWildcard::kMark_FileOrDir; + pos++; + } + else if (c == '2') + { + nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; + pos++; + } + } + else + break; } - else - recursedType = commonRecursedType; + if (error) + { + errorMessage = "inorrect switch"; + break; + } + if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize) { errorMessage = "Too short switch"; @@ -668,15 +766,17 @@ static void AddSwitchWildcardsToCensor( } const UString tail = name.Ptr(pos + 1); - - if (name[pos] == kImmediateNameID) - AddNameToCensor(censor, tail, include, recursedType, wildcardMatching); - else if (name[pos] == kFileListID) - AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage); + + const wchar_t c = name[pos]; + + if (c == kImmediateNameID) + AddNameToCensor(censor, nop2, tail); + else if (c == kFileListID) + AddToCensorFromListFile(NULL, censor, nop2, tail, codePage); #ifdef _WIN32 - else if (name[pos] == kMapNameID) + else if (c == kMapNameID) { - errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching); + errorMessage = ParseMapWithPaths(censor, tail, nop2); if (errorMessage) break; } @@ -687,6 +787,7 @@ static void AddSwitchWildcardsToCensor( break; } } + if (i != strings.Size()) throw CArcCmdLineException(errorMessage, strings[i]); } @@ -1165,32 +1266,48 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) if (parser[NKey::kNameTrailReplace].ThereIs) g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus; - NRecursedType::EEnum recursedType; + CNameOption nop; + if (parser[NKey::kRecursed].ThereIs) - recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); - else - recursedType = NRecursedType::kNonRecursed; + nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); - bool wildcardMatching = true; if (parser[NKey::kDisableWildcardParsing].ThereIs) - wildcardMatching = false; + nop.WildcardMatching = false; + + if (parser[NKey::kUseSlashMark].ThereIs) + { + const UString &s = parser[NKey::kUseSlashMark].PostStrings[0]; + if (s.IsEmpty()) + nop.MarkMode = NWildcard::kMark_StrictFile; + else if (s.IsEqualTo_Ascii_NoCase("-")) + nop.MarkMode = NWildcard::kMark_FileOrDir; + else if (s.IsEqualTo_Ascii_NoCase("2")) + nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; + else + throw CArcCmdLineException("Unsupported -spm:", s); + } + options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1); UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8); bool thereAreSwitchIncludes = false; - + if (parser[NKey::kInclude].ThereIs) { thereAreSwitchIncludes = true; + nop.Include = true; AddSwitchWildcardsToCensor(options.Censor, - parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage); + parser[NKey::kInclude].PostStrings, nop, codePage); } if (parser[NKey::kExclude].ThereIs) + { + nop.Include = false; AddSwitchWildcardsToCensor(options.Censor, - parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage); + parser[NKey::kExclude].PostStrings, nop, codePage); + } unsigned curCommandIndex = kCommandIndex + 1; bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && @@ -1198,9 +1315,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) options.Command.CommandType != NCommandType::kInfo && options.Command.CommandType != NCommandType::kHash; - bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); - bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; - bool isRename = options.Command.CommandType == NCommandType::kRename; + const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; + const bool isRename = options.Command.CommandType == NCommandType::kRename; if ((isExtractOrList || isRename) && options.StdInMode) thereIsArchiveName = false; @@ -1220,10 +1337,11 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) #endif } + nop.Include = true; AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, curCommandIndex, options.Censor, nonSwitchStrings, parser.StopSwitchIndex, - recursedType, wildcardMatching, + nop, thereAreSwitchIncludes, codePage); options.YesToAll = parser[NKey::kYes].ThereIs; @@ -1317,13 +1435,28 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) NWildcard::CCensor &arcCensor = options.arcCensor; + CNameOption nopArc; + // nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified + // is it OK, external switches can disable WildcardMatching and MarcMode for arc. + nopArc.WildcardMatching = nop.WildcardMatching; + nopArc.MarkMode = nop.MarkMode; + if (parser[NKey::kArInclude].ThereIs) - AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage); + { + nopArc.Include = true; + AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage); + } if (parser[NKey::kArExclude].ThereIs) - AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage); + { + nopArc.Include = false; + AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage); + } if (thereIsArchiveName) - AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching); + { + nopArc.Include = true; + AddNameToCensor(arcCensor, nopArc, options.ArchiveName); + } arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); @@ -1515,7 +1648,7 @@ FString GetModuleDirPrefix() { FString s; - s = g_ModuleDirPrefix; + s = fas2fs(g_ModuleDirPrefix); if (s.IsEmpty()) s = FTEXT(".") FSTRING_PATH_SEPARATOR; return s; diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 9fea6dc2..73c191e4 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -1000,8 +1000,8 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool if (_overwriteMode == NExtract::NOverwriteMode::kAsk) { - int slashPos = fullProcessedPath.ReverseFind_PathSepar(); - FString realFullProcessedPath (fullProcessedPath.Left((unsigned)(slashPos + 1)) + fileInfo.Name); + const int slashPos = fullProcessedPath.ReverseFind_PathSepar(); + const FString realFullProcessedPath = fullProcessedPath.Left((unsigned)(slashPos + 1)) + fileInfo.Name; /* (fileInfo) can be symbolic link. we can show final file properties here. */ diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp index d3e0d3ce..d5926f8f 100644 --- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -48,7 +48,7 @@ STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) else switch (propID) { - case kpidName: prop = _fileInfo.Name; break; + case kpidName: prop = fs2us(_fileInfo.Name); break; case kpidIsDir: prop = _fileInfo.IsDir(); break; case kpidSize: prop = _fileInfo.Size; break; case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; @@ -103,12 +103,20 @@ STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStre if (!IsSafePath(name2)) return S_FALSE; - // #ifdef _WIN32 - // we don't want to support wildcards in names here here - if (name2.Find(L'?') >= 0 || - name2.Find(L'*') >= 0) + #ifdef _WIN32 + /* WIN32 allows wildcards in Find() function + and doesn't allow wildcard in File.Open() + so we can work without the following wildcard check here */ + if (name2.Find(L'*') >= 0) return S_FALSE; - // #endif + { + int startPos = 0; + if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\")) + startPos = 3; + if (name2.Find(L'?', startPos) >= 0) + return S_FALSE; + } + #endif #endif diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index 2ee29913..cc0cfd0c 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp @@ -866,7 +866,7 @@ struct CAffinityMode DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; bool NeedAffinity() const { return NumBundleThreads != 0; } - WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter, UInt32 bundleIndex) const + WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const { if (NeedAffinity()) { diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp index 84a8d22f..c7efa99e 100644 --- a/CPP/7zip/UI/Common/CompressCall.cpp +++ b/CPP/7zip/UI/Common/CompressCall.cpp @@ -33,12 +33,16 @@ using namespace NWindows; #define k7zGui "7zG.exe" +// 21.07 : we can disable wildcard +// #define ISWITCH_NO_WILDCARD_POSTFIX "w-" +#define ISWITCH_NO_WILDCARD_POSTFIX + #define kShowDialogSwitch " -ad" #define kEmailSwitch " -seml." -#define kIncludeSwitch " -i" #define kArchiveTypeSwitch " -t" -#define kArcIncludeSwitches " -an -ai" -#define kHashIncludeSwitches " -i" +#define kIncludeSwitch " -i" ISWITCH_NO_WILDCARD_POSTFIX +#define kArcIncludeSwitches " -an -ai" ISWITCH_NO_WILDCARD_POSTFIX +#define kHashIncludeSwitches kIncludeSwitch #define kStopSwitchParsing " --" extern HWND g_HWND; diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp index e6e42d64..762342d6 100644 --- a/CPP/7zip/UI/Common/CompressCall2.cpp +++ b/CPP/7zip/UI/Common/CompressCall2.cpp @@ -124,7 +124,7 @@ HRESULT CompressFiles( NWildcard::CCensor censor; FOR_VECTOR (i, names) { - censor.AddPreItem(names[i]); + censor.AddPreItem_NoWildcard(names[i]); } bool messageWasDisplayed = false; @@ -178,7 +178,7 @@ static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, NWildcard::CCensor arcCensor; FOR_VECTOR (i, arcPaths) { - arcCensor.AddPreItem(arcPaths[i]); + arcCensor.AddPreItem_NoWildcard(arcPaths[i]); } arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); CDirItemsStat st; @@ -268,7 +268,7 @@ void CalcChecksum(const UStringVector &paths, NWildcard::CCensor censor; FOR_VECTOR (i, paths) { - censor.AddPreItem(paths[i]); + censor.AddPreItem_NoWildcard(paths[i]); } censor.AddPathsToCensor(NWildcard::k_RelatPath); diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index 59baa092..89cce2ba 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -767,6 +767,15 @@ static HRESULT EnumerateDirItems( const UString &name = item.PathParts.Front(); FString fullPath = phyPrefix + us2fs(name); + /* + // not possible now + if (!item.ForDir && !item.ForFile) + { + RINOK(dirItems.AddError(fullPath, ERROR_INVALID_PARAMETER)); + continue; + } + */ + #if defined(_WIN32) && !defined(UNDER_CE) bool needAltStreams = true; #endif @@ -823,9 +832,20 @@ static HRESULT EnumerateDirItems( continue; } + /* + #ifdef _WIN32 + #define MY_ERROR_IS_DIR ERROR_FILE_NOT_FOUND + #define MY_ERROR_NOT_DIR DI_DEFAULT_ERROR + #else + #define MY_ERROR_IS_DIR EISDIR + #define MY_ERROR_NOT_DIR ENOTDIR + #endif + */ + const bool isDir = fi.IsDir(); - if ((isDir && !item.ForDir) || (!isDir && !item.ForFile)) + if (isDir ? !item.ForDir : !item.ForFile) { + // RINOK(dirItems.AddError(fullPath, isDir ? MY_ERROR_IS_DIR: MY_ERROR_NOT_DIR)); RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR)); continue; } diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp index 654da86b..24177085 100644 --- a/CPP/7zip/UI/Common/HashCalc.cpp +++ b/CPP/7zip/UI/Common/HashCalc.cpp @@ -900,7 +900,7 @@ bool CHashPair::Parse(const char *s) return false; if (escape) { - AString temp = Name; + const AString temp (Name); return CSum_Name_EscapeToOriginal(temp, Name); } return true; diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp index 4bd690d6..032a876d 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp @@ -974,6 +974,17 @@ static HRESULT Compress( +static bool Censor_AreAllAllowed(const NWildcard::CCensor &censor) +{ + if (censor.Pairs.Size() != 1) + return false; + const NWildcard::CPair &pair = censor.Pairs[0]; + /* Censor_CheckPath() ignores (CPair::Prefix). + So we also ignore (CPair::Prefix) here */ + // if (!pair.Prefix.IsEmpty()) return false; + return pair.Head.AreAllAllowed(); +} + bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) @@ -981,9 +992,13 @@ static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcIte bool finded = false; FOR_VECTOR (i, censor.Pairs) { + /* (CPair::Prefix) in not used for matching items in archive. + So we ignore (CPair::Prefix) here */ bool include; if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include)) { + // Check it and FIXME !!!! + // here we can exclude item via some Pair, that is still allowed by another Pair if (!include) return false; finded = true; @@ -1006,6 +1021,8 @@ static HRESULT EnumerateInArchiveItems( CReadArcItem item; + const bool allFilesAreAllowed = Censor_AreAllAllowed(censor); + for (UInt32 i = 0; i < numItems; i++) { CArcItem ai; @@ -1024,7 +1041,10 @@ static HRESULT EnumerateInArchiveItems( if (!storeStreamsMode && ai.IsAltStream) continue; */ - ai.Censored = Censor_CheckPath(censor, item); + if (allFilesAreAllowed) + ai.Censored = true; + else + ai.Censored = Censor_CheckPath(censor, item); RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); @@ -1418,7 +1438,7 @@ HRESULT UpdateArchive( UString s; s = "It is not allowed to include archive to itself"; s.Add_LF(); - s += path; + s += fs2us(path); throw s; } } diff --git a/CPP/7zip/UI/Console/HashCon.cpp b/CPP/7zip/UI/Console/HashCon.cpp index 1bd75c15..5a349765 100644 --- a/CPP/7zip/UI/Console/HashCon.cpp +++ b/CPP/7zip/UI/Console/HashCon.cpp @@ -138,7 +138,7 @@ static unsigned GetColumnWidth(unsigned digestSize) AString CHashCallbackConsole::GetFields() const { - AString s = PrintFields; + AString s (PrintFields); if (s.IsEmpty()) s = "hsn"; s.MakeLower_Ascii(); @@ -313,7 +313,7 @@ HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBun s = kEmptyFileAlias; else { - UString temp = _fileName; + UString temp (_fileName); _so->Normalize_UString(temp); _so->Convert_UString_to_AString(temp, s); } diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp index 14d83eb9..9000e57a 100644 --- a/CPP/7zip/UI/Console/List.cpp +++ b/CPP/7zip/UI/Console/List.cpp @@ -840,7 +840,7 @@ static void UString_Replace_CRLF_to_LF(UString &s) static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val) { - UString s = val; + UString s (val); if (s.Find(L'\n') >= 0) { so << endl; @@ -869,7 +869,7 @@ static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *va PrintPropVal_MultiLine(so, val); return; } - UString s = val; + UString s (val); so.Normalize_UString(s); so << s; so << endl; diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp index 8a0842e1..69070211 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp @@ -947,7 +947,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, else name = fs2us(fi0.Name); name += ".sha256"; - cmi.Folder= folderPrefix; + cmi.Folder = fs2us(folderPrefix); cmi.ArcName = name; s = "SHA-256 -> "; s += name; diff --git a/CPP/7zip/UI/Explorer/MyExplorerCommand.h b/CPP/7zip/UI/Explorer/MyExplorerCommand.h index 6004d929..227b9e02 100644 --- a/CPP/7zip/UI/Explorer/MyExplorerCommand.h +++ b/CPP/7zip/UI/Explorer/MyExplorerCommand.h @@ -13,6 +13,48 @@ #else +/* IShellItem is defined: + ShObjIdl.h : old Windows SDK + ShObjIdl_core.h : new Windows 10 SDK */ + +#include <ShObjIdl.h> + +#ifndef __IShellItem_INTERFACE_DEFINED__ +#define __IShellItem_INTERFACE_DEFINED__ + +// For MINGW we define IShellItem + +// #error Stop_Compiling__NOT_DEFINED__IShellItem_INTERFACE_DEFINED__ + +typedef +enum +{ SIGDN_NORMALDISPLAY = 0, + SIGDN_PARENTRELATIVEPARSING = 0x80018001, + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, + SIGDN_PARENTRELATIVEEDITING = 0x80031001, + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, + SIGDN_FILESYSPATH = 0x80058000, + SIGDN_URL = 0x80068000 +} SIGDN; + + +typedef DWORD SICHINTF; +typedef ULONG SFGAOF; + +struct IShellItem : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) = 0; + virtual HRESULT STDMETHODCALLTYPE GetParent(IShellItem **ppsi) = 0; + virtual HRESULT STDMETHODCALLTYPE GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName) = 0; + virtual HRESULT STDMETHODCALLTYPE GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0; + virtual HRESULT STDMETHODCALLTYPE Compare(IShellItem *psi, SICHINTF hint, int *piOrder) = 0; +}; + +#endif // __IShellItem_INTERFACE_DEFINED__ + + + #ifndef __IShellItemArray_INTERFACE_DEFINED__ #define __IShellItemArray_INTERFACE_DEFINED__ diff --git a/CPP/7zip/UI/Far/FarUtils.cpp b/CPP/7zip/UI/Far/FarUtils.cpp index ddca3cab..3bdb9895 100644 --- a/CPP/7zip/UI/Far/FarUtils.cpp +++ b/CPP/7zip/UI/Far/FarUtils.cpp @@ -213,7 +213,7 @@ void CStartupInfo::RestoreScreen(HANDLE handle) CSysString CStartupInfo::GetFullKeyName(const char *keyName) const { - AString s = m_RegistryPath; + AString s (m_RegistryPath); if (keyName && *keyName) { s += kRegistryKeyDelimiter; diff --git a/CPP/7zip/UI/FileManager/FSDrives.cpp b/CPP/7zip/UI/FileManager/FSDrives.cpp index 208cea4e..c563907f 100644 --- a/CPP/7zip/UI/FileManager/FSDrives.cpp +++ b/CPP/7zip/UI/FileManager/FSDrives.cpp @@ -224,14 +224,14 @@ STDMETHODIMP CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT switch (propID) { case kpidIsDir: prop = !_volumeMode; break; - case kpidName: prop = di.Name; break; + case kpidName: prop = fs2us(di.Name); break; case kpidOutName: if (!di.Name.IsEmpty() && di.Name.Back() == ':') { FString s = di.Name; s.DeleteBack(); AddExt(s, itemIndex); - prop = s; + prop = fs2us(s); } break; diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp index d82ddc27..f3e04b3c 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.cpp +++ b/CPP/7zip/UI/FileManager/FSFolder.cpp @@ -515,7 +515,7 @@ STDMETHODIMP CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va } case kpidPrefix: if (fi.Parent >= 0) - prop = Folders[fi.Parent]; + prop = fs2us(Folders[fi.Parent]); break; case kpidNumSubDirs: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFolders; break; case kpidNumSubFiles: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFiles; break; diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp index 9b78ba0a..ff444b3b 100644 --- a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp +++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp @@ -473,7 +473,10 @@ static HRESULT CopyFile_Ask( static FString CombinePath(const FString &folderPath, const FString &fileName) { - return folderPath + FCHAR_PATH_SEPARATOR + fileName; + FString s (folderPath); + s.Add_PathSepar(); // FCHAR_PATH_SEPARATOR + s += fileName; + return s; } static bool IsDestChild(const FString &src, const FString &dest) diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp index 63167d63..d87dfe38 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp @@ -486,6 +486,8 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos) ReadRegDiff(diffPath); unsigned numRealItems = startPos; + + const bool isBigScreen = NControl::IsDialogSizeOK(40, 200, g_HWND); for (unsigned i = 0;; i++) { @@ -568,8 +570,6 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos) if (item.wID == IDM_ALT_STREAMS) disable = !isAltStreamsSupported; - bool isBigScreen = NControl::IsDialogSizeOK(40, 200); - if (!isBigScreen && (disable || item.IsSeparator())) continue; diff --git a/CPP/7zip/UI/FileManager/OpenCallback.cpp b/CPP/7zip/UI/FileManager/OpenCallback.cpp index ddec3877..e2e03f5e 100644 --- a/CPP/7zip/UI/FileManager/OpenCallback.cpp +++ b/CPP/7zip/UI/FileManager/OpenCallback.cpp @@ -69,7 +69,7 @@ STDMETHODIMP COpenArchiveCallback::GetProperty(PROPID propID, PROPVARIANT *value { switch (propID) { - case kpidName: prop = _fileInfo.Name; break; + case kpidName: prop = fs2us(_fileInfo.Name); break; case kpidIsDir: prop = _fileInfo.IsDir(); break; case kpidSize: prop = _fileInfo.Size; break; case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; diff --git a/CPP/7zip/UI/FileManager/PanelCrc.cpp b/CPP/7zip/UI/FileManager/PanelCrc.cpp index 6c49e897..1d483ca1 100644 --- a/CPP/7zip/UI/FileManager/PanelCrc.cpp +++ b/CPP/7zip/UI/FileManager/PanelCrc.cpp @@ -289,7 +289,7 @@ HRESULT CThreadCrc::ProcessVirt() } if (isFirstFile) { - Hash.FirstFileName = path; + Hash.FirstFileName = fs2us(path); isFirstFile = false; } sync.Set_FilePath(fs2us(path)); @@ -375,7 +375,7 @@ HRESULT CApp::CalculateCrc2(const UString &methodName) t.Enumerator.FilePaths.Add(us2fs(srcPanel.GetItemRelPath(indices[i]))); if (t.Enumerator.FilePaths.Size() == 1) - t.Hash.MainName = t.Enumerator.FilePaths[0]; + t.Hash.MainName = fs2us(t.Enumerator.FilePaths[0]); UString basePrefix = srcPanel.GetFsPath(); UString basePrefix2 = basePrefix; diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp index 6c59ea38..e34e74f7 100644 --- a/CPP/7zip/UI/FileManager/PanelOperations.cpp +++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp @@ -511,7 +511,7 @@ void CPanel::ChangeComment() LangString(IDS_COMMENT2, dlg.Static); if (dlg.Create(GetParent()) != IDOK) return; - NCOM::CPropVariant propVariant = dlg.Value.Ptr(); + NCOM::CPropVariant propVariant (dlg.Value); CDisableNotify disableNotify(*this); HRESULT result = _folderOperations->SetProperty(realIndex, kpidComment, &propVariant, NULL); diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc index d2fee8cf..dc7d797f 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc +++ b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc @@ -65,7 +65,7 @@ CAPTION "Progress" RTEXT "", IDT_PROGRESS_ELAPSED_VAL, x1, y0, x1s, MY_TEXT_NOPREFIX RTEXT "", IDT_PROGRESS_REMAINING_VAL, x1, y1, x1s, MY_TEXT_NOPREFIX RTEXT "", IDT_PROGRESS_FILES_VAL, x1, y2, x1s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_FILES_TOTAL x1, y3, x1s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_FILES_TOTAL, x1, y3, x1s, MY_TEXT_NOPREFIX RTEXT "", IDT_PROGRESS_ERRORS_VAL, x1, y4, x1s, MY_TEXT_NOPREFIX RTEXT "", IDT_PROGRESS_TOTAL_VAL, x3, y0, x3s, MY_TEXT_NOPREFIX diff --git a/CPP/7zip/UI/FileManager/VerCtrl.cpp b/CPP/7zip/UI/FileManager/VerCtrl.cpp index 3eea3942..4bb034f8 100644 --- a/CPP/7zip/UI/FileManager/VerCtrl.cpp +++ b/CPP/7zip/UI/FileManager/VerCtrl.cpp @@ -389,11 +389,11 @@ void CApp::VerCtrl(unsigned id) dialog.OldFileInfo.SetTime(&fdi.Info.ftLastWriteTime); dialog.OldFileInfo.SetSize(fdi.GetSize()); - dialog.OldFileInfo.Name = path; + dialog.OldFileInfo.Name = fs2us(path); dialog.NewFileInfo.SetTime(&fdi2.Info.ftLastWriteTime); dialog.NewFileInfo.SetSize(fdi2.GetSize()); - dialog.NewFileInfo.Name = path2; + dialog.NewFileInfo.Name = fs2us(path2); dialog.ShowExtraButtons = false; dialog.DefaultButton_is_NO = true; diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp index 44d25035..71d28e8d 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp @@ -341,10 +341,10 @@ public: CBenchmarkDialog(): _timer(0), - TotalMode(false), WasStopped_in_GUI(false), ExitWasAsked_in_GUI(false), - NeedRestart(false) + NeedRestart(false), + TotalMode(false) {} ~CBenchmarkDialog(); diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 0ede8292..16a35854 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -1436,7 +1436,7 @@ UString CCompressDialog::GetMethodSpec(UString &estimatedName) UString s; if (methodId >= 0) { - if (methodId < ARRAY_SIZE(kMethodsNames)) + if ((unsigned)methodId < ARRAY_SIZE(kMethodsNames)) estimatedName = kMethodsNames[methodId]; else estimatedName = ExternalMethods[methodId - ARRAY_SIZE(kMethodsNames)]; diff --git a/CPP/7zip/UI/GUI/UpdateGUI.cpp b/CPP/7zip/UI/GUI/UpdateGUI.cpp index 6fd1b60b..a3a1d889 100644 --- a/CPP/7zip/UI/GUI/UpdateGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp @@ -112,9 +112,13 @@ static void ParseAndAddPropertires(CObjectVector<CProperty> &properties, SplitString(propertiesString, strings); FOR_VECTOR (i, strings) { - const UString &s = strings[i]; + UString s = strings[i]; + if (s.Len() > 2 + && s[0] == '-' + && MyCharLower_Ascii(s[1]) == 'm') + s.DeleteFrontal(2); CProperty property; - int index = s.Find(L'='); + const int index = s.Find(L'='); if (index < 0) property.Name = s; else diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp index 1a7b7056..db202f4c 100644 --- a/CPP/Common/MyString.cpp +++ b/CPP/Common/MyString.cpp @@ -1096,14 +1096,14 @@ UString::UString(char c) UString::UString(const wchar_t *s) { - unsigned len = MyStringLen(s); + const unsigned len = MyStringLen(s); SetStartLen(len); wmemcpy(_chars, s, len + 1); } UString::UString(const char *s) { - unsigned len = MyStringLen(s); + const unsigned len = MyStringLen(s); SetStartLen(len); wchar_t *chars = _chars; for (unsigned i = 0; i < len; i++) @@ -1111,6 +1111,17 @@ UString::UString(const char *s) chars[len] = 0; } +UString::UString(const AString &s) +{ + const unsigned len = s.Len(); + SetStartLen(len); + wchar_t *chars = _chars; + const char *s2 = s.Ptr(); + for (unsigned i = 0; i < len; i++) + chars[i] = (unsigned char)s2[i]; + chars[len] = 0; +} + UString::UString(const UString &s) { SetStartLen(s._len); diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h index 3325cc54..aa3c301a 100644 --- a/CPP/Common/MyString.h +++ b/CPP/Common/MyString.h @@ -1,7 +1,7 @@ -// Common/String.h +// Common/MyString.h -#ifndef __COMMON_STRING_H -#define __COMMON_STRING_H +#ifndef __COMMON_MY_STRING_H +#define __COMMON_MY_STRING_H #include <string.h> @@ -15,6 +15,17 @@ #include "MyVector.h" +/* if (DEBUG_FSTRING_INHERITS_ASTRING is defined), then + FString inherits from AString, so we can find bugs related to FString at compile time. + DON'T define DEBUG_FSTRING_INHERITS_ASTRING in release code */ + +// #define DEBUG_FSTRING_INHERITS_ASTRING + +#ifdef DEBUG_FSTRING_INHERITS_ASTRING +class FString; +#endif + + #ifdef _MSC_VER #ifdef _NATIVE_WCHAR_T_DEFINED #define MY_NATIVE_WCHAR_T_DEFINED @@ -290,6 +301,12 @@ class AString FORBID_STRING_OPS_AString(long) FORBID_STRING_OPS_AString(unsigned long) + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + AString(const FString &s); + AString &operator=(const FString &s); + AString &operator+=(const FString &s); + #endif + public: explicit AString(); explicit AString(char c); @@ -550,12 +567,18 @@ class UString FORBID_STRING_OPS_2(UString, char) + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + UString(const FString &s); + UString &operator=(const FString &s); + UString &operator+=(const FString &s); + #endif + public: UString(); explicit UString(wchar_t c); explicit UString(char c); explicit UString(const char *s); - // UString(const AString &s); + explicit UString(const AString &s); UString(const wchar_t *s); UString(const UString &s); ~UString() { MY_STRING_DELETE(_chars); } @@ -795,7 +818,16 @@ class UString2 FORBID_STRING_OPS_UString2(short) UString2 &operator=(wchar_t c); - UString2(wchar_t c); + + UString2(const AString &s); + UString2 &operator=(const AString &s); + UString2 &operator+=(const AString &s); + + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + UString2(const FString &s); + UString2 &operator=(const FString &s); + UString2 &operator+=(const FString &s); + #endif public: UString2(): _chars(NULL), _len(0) {} @@ -871,9 +903,11 @@ typedef CObjectVector<CSysString> CSysStringVector; // ---------- FString ---------- +#ifndef DEBUG_FSTRING_INHERITS_ASTRING #ifdef _WIN32 #define USE_UNICODE_FSTRING #endif +#endif #ifdef USE_UNICODE_FSTRING @@ -893,12 +927,55 @@ typedef CObjectVector<CSysString> CSysStringVector; #define __FTEXT(quote) quote typedef char FChar; + + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + + class FString: public AString + { + // FString &operator=(const char *s); + FString &operator=(const AString &s); + // FString &operator+=(const AString &s); + public: + FString(const AString &s): AString(s.Ptr()) {} + FString(const FString &s): AString(s.Ptr()) {} + FString(const char *s): AString(s) {} + FString() {} + FString &operator=(const FString &s) { AString::operator=((const AString &)s); return *this; } + FString &operator=(char c) { AString::operator=(c); return *this; } + FString &operator+=(char c) { AString::operator+=(c); return *this; } + FString &operator+=(const FString &s) { AString::operator+=((const AString &)s); return *this; } + FString Left(unsigned count) const { return FString(AString::Left(count)); } + }; + void operator+(const AString &s1, const FString &s2); + void operator+(const FString &s1, const AString &s2); + + inline FString operator+(const FString &s1, const FString &s2) + { + AString s =(const AString &)s1 + (const AString &)s2; + return FString(s.Ptr()); + // return FString((const AString &)s1 + (const AString &)s2); + } + inline FString operator+(const FString &s1, const FChar *s2) + { + return s1 + (FString)s2; + } + /* + inline FString operator+(const FChar *s1, const FString &s2) + { + return (FString)s1 + s2; + } + */ + + inline FString fas2fs(const char *s) { return FString(s); } + + #else // DEBUG_FSTRING_INHERITS_ASTRING typedef AString FString; + #define fas2fs(_x_) (_x_) + #endif // DEBUG_FSTRING_INHERITS_ASTRING UString fs2us(const FChar *s); UString fs2us(const FString &s); FString us2fs(const wchar_t *s); - #define fas2fs(_x_) (_x_) #define fs2fas(_x_) (_x_) #endif diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp index e2040120..861f3f71 100644 --- a/CPP/Common/Wildcard.cpp +++ b/CPP/Common/Wildcard.cpp @@ -29,6 +29,70 @@ bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) // #include <stdio.h> +/* +static int MyStringCompare_PathLinux(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + if (c1 == 0) return -1; + if (c2 == 0) return 1; + if (c1 == '/') c1 = 0; + if (c2 == '/') c2 = 0; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + continue; + } + if (c1 == 0) return 0; + } +} +*/ + +static int MyStringCompare_Path(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + if (c1 == 0) return -1; + if (c2 == 0) return 1; + if (IS_PATH_SEPAR(c1)) c1 = 0; + if (IS_PATH_SEPAR(c2)) c2 = 0; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + continue; + } + if (c1 == 0) return 0; + } +} + +static int MyStringCompareNoCase_Path(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + if (c1 == 0) return -1; + if (c2 == 0) return 1; + if (IS_PATH_SEPAR(c1)) c1 = 0; + if (IS_PATH_SEPAR(c2)) c2 = 0; + c1 = MyCharUpper(c1); + c2 = MyCharUpper(c2); + if (c1 < c2) return -1; + if (c1 > c2) return 1; + continue; + } + if (c1 == 0) return 0; + } +} + int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW { /* @@ -37,9 +101,10 @@ int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW printf("\n S2: %ls", s2); printf("\n"); */ + // 21.07 : we parse PATH_SEPARATOR so: 0 < PATH_SEPARATOR < 1 if (g_CaseSensitive) - return MyStringCompare(s1, s2); - return MyStringCompareNoCase(s1, s2); + return MyStringCompare_Path(s1, s2); + return MyStringCompareNoCase_Path(s1, s2); } #ifndef USE_UNICODE_FSTRING @@ -47,9 +112,7 @@ int CompareFileNames(const char *s1, const char *s2) { const UString u1 = fs2us(s1); const UString u2 = fs2us(s2); - if (g_CaseSensitive) - return MyStringCompare(u1, u2); - return MyStringCompareNoCase(u1, u2); + return CompareFileNames(u1, u2); } #endif @@ -312,16 +375,18 @@ void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex) subNode.AddItem(include, item, ignoreWildcardIndex - 1); } -void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching) +/* +void CCensorNode::AddItem(bool include, const UString &path, const CCensorPathProps &props) { CItem item; SplitPathToParts(path, item.PathParts); - item.Recursive = recursive; - item.ForFile = forFile; - item.ForDir = forDir; - item.WildcardMatching = wildcardMatching; + item.Recursive = props.Recursive; + item.ForFile = props.ForFile; + item.ForDir = props.ForDir; + item.WildcardMatching = props.WildcardMatching; AddItem(include, item); } +*/ bool CCensorNode::NeedCheckSubDirs() const { @@ -439,21 +504,6 @@ bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile } */ -void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching) -{ - if (path.IsEmpty()) - return; - bool forFile = true; - bool forFolder = true; - UString path2 (path); - if (IsPathSepar(path.Back())) - { - path2.DeleteBack(); - forFile = false; - } - AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching); -} - void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) { ExcludeItems += fromNodes.ExcludeItems; @@ -509,9 +559,12 @@ static unsigned GetNumPrefixParts(const UStringVector &pathParts) { if (pathParts.IsEmpty()) return 0; + + /* empty last part could be removed already from (pathParts), + if there was tail path separator (slash) in original full path string. */ #ifdef _WIN32 - + if (IsDriveColonName(pathParts[0])) return 1; if (!pathParts[0].IsEmpty()) @@ -552,7 +605,8 @@ static unsigned GetNumPrefixParts(const UStringVector &pathParts) #endif } -void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching) +void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, + const CCensorPathProps &props) { if (path.IsEmpty()) throw "Empty file path"; @@ -560,12 +614,26 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat UStringVector pathParts; SplitPathToParts(path, pathParts); + CCensorPathProps props2 = props; + bool forFile = true; - if (pathParts.Back().IsEmpty()) + bool forDir = true; + const UString &back = pathParts.Back(); + if (back.IsEmpty()) { + // we have tail path separator. So it's directory. + // we delete tail path separator here even for "\" and "c:\" forFile = false; pathParts.DeleteBack(); } + else + { + if (props.MarkMode == kMark_StrictFile + || (props.MarkMode == kMark_StrictFile_IfWildcard + && DoesNameContainWildcard(back))) + forDir = false; + } + UString prefix; @@ -582,6 +650,7 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat if (pathMode != k_AbsPath) { + // detection of the number of Skip Parts for prefix ignoreWildcardIndex = -1; const unsigned numPrefixParts = GetNumPrefixParts(pathParts); @@ -589,6 +658,7 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat if (pathMode != k_FullPath) { + // if absolute path, then all parts before last part will be in prefix if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts) numSkipParts = pathParts.Size() - 1; } @@ -610,12 +680,13 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat } } + // we split (pathParts) to (prefix) and (pathParts). for (unsigned i = 0; i < numSkipParts; i++) { { const UString &front = pathParts.Front(); // WIN32 doesn't support wildcards in file names - if (wildcardMatching) + if (props.WildcardMatching) if (i >= numPrefixParts && DoesNameContainWildcard(front)) break; prefix += front; @@ -640,17 +711,29 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat pathParts.Clear(); pathParts.Add(UString("*")); forFile = true; - wildcardMatching = true; - recursive = false; + forDir = true; + props2.WildcardMatching = true; + props2.Recursive = false; } } + /* + // not possible now + if (!forDir && !forFile) + { + UString s ("file path was blocked for files and directories: "); + s += path; + throw s; + // return; // for debug : ignore item (don't create Item) + } + */ + CItem item; item.PathParts = pathParts; - item.ForDir = true; + item.ForDir = forDir; item.ForFile = forFile; - item.Recursive = recursive; - item.WildcardMatching = wildcardMatching; + item.Recursive = props2.Recursive; + item.WildcardMatching = props2.WildcardMatching; Pairs[(unsigned)index].Head.AddItem(include, item, ignoreWildcardIndex); } @@ -691,18 +774,17 @@ void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) FOR_VECTOR(i, CensorPaths) { const CCensorPath &cp = CensorPaths[i]; - AddItem(censorPathMode, cp.Include, cp.Path, cp.Recursive, cp.WildcardMatching); + AddItem(censorPathMode, cp.Include, cp.Path, cp.Props); } CensorPaths.Clear(); } -void CCensor::AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching) +void CCensor::AddPreItem(bool include, const UString &path, const CCensorPathProps &props) { CCensorPath &cp = CensorPaths.AddNew(); cp.Path = path; cp.Include = include; - cp.Recursive = recursive; - cp.WildcardMatching = wildcardMatching; + cp.Props = props; } } diff --git a/CPP/Common/Wildcard.h b/CPP/Common/Wildcard.h index fb0f1fed..0fa48873 100644 --- a/CPP/Common/Wildcard.h +++ b/CPP/Common/Wildcard.h @@ -52,6 +52,25 @@ struct CItem }; + +const Byte kMark_FileOrDir = 0; +const Byte kMark_StrictFile = 1; +const Byte kMark_StrictFile_IfWildcard = 2; + +struct CCensorPathProps +{ + bool Recursive; + bool WildcardMatching; + Byte MarkMode; + + CCensorPathProps(): + Recursive(false), + WildcardMatching(true), + MarkMode(kMark_FileOrDir) + {} +}; + + class CCensorNode MY_UNCOPYABLE { CCensorNode *Parent; @@ -94,8 +113,19 @@ public: int FindSubNode(const UString &path) const; void AddItem(bool include, CItem &item, int ignoreWildcardIndex = -1); - void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching); - void AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching); + // void AddItem(bool include, const UString &path, const CCensorPathProps &props); + void Add_Wildcard() + { + CItem item; + item.PathParts.Add(L"*"); + item.Recursive = false; + item.ForFile = true; + item.ForDir = true; + item.WildcardMatching = true; + AddItem( + true // include + , item); + } // NeedCheckSubDirs() returns true, if there are IncludeItems rules that affect items in subdirs bool NeedCheckSubDirs() const; @@ -144,14 +174,11 @@ struct CCensorPath { UString Path; bool Include; - bool Recursive; - bool WildcardMatching; + CCensorPathProps Props; CCensorPath(): - Include(true), - Recursive(false), - WildcardMatching(true) - {} + Include(true) + {} }; @@ -174,19 +201,28 @@ public: bool AllAreRelative() const { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } - void AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching); + void AddItem(ECensorPathMode pathMode, bool include, const UString &path, const CCensorPathProps &props); // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; void ExtendExclude(); void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode); - void AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching); - void AddPreItem(const UString &path) + void AddPreItem(bool include, const UString &path, const CCensorPathProps &props); + + void AddPreItem_NoWildcard(const UString &path) { - AddPreItem(true, path, false, false); + CCensorPathProps props; + props.WildcardMatching = false; + AddPreItem( + true, // include + path, props); } void AddPreItem_Wildcard() { - AddPreItem(true, UString("*"), false, true); + CCensorPathProps props; + // props.WildcardMatching = true; + AddPreItem( + true, // include + UString("*"), props); } }; diff --git a/CPP/Windows/Control/Dialog.cpp b/CPP/Windows/Control/Dialog.cpp index 6a9d7d9b..9ddd2342 100644 --- a/CPP/Windows/Control/Dialog.cpp +++ b/CPP/Windows/Control/Dialog.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +// #include "../../Windows/DLL.h" + #ifndef _UNICODE #include "../../Common/StringConvert.h" #endif @@ -88,23 +90,55 @@ bool CDialog::OnButtonClicked(int buttonID, HWND /* buttonHWND */) return true; } -static bool GetWorkAreaRect(RECT *rect) + +static bool GetWorkAreaRect(RECT *rect, HWND hwnd) { - // use another function for multi-monitor. + if (hwnd) + { + #ifndef UNDER_CE + /* MonitorFromWindow() is supported in Win2000+ + MonitorFromWindow() : retrieves a handle to the display monitor that has the + largest area of intersection with the bounding rectangle of a specified window. + dwFlags: Determines the function's return value if the window does not intersect any display monitor. + MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window. + MONITOR_DEFAULTTONULL : Returns NULL. + MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor. + */ + const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + if (hmon) + { + MONITORINFO mi; + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + if (GetMonitorInfoA(hmon, &mi)) + { + *rect = mi.rcWork; + return true; + } + } + #endif + } + + /* Retrieves the size of the work area on the primary display monitor. + The work area is the portion of the screen not obscured + by the system taskbar or by application desktop toolbars. + Any DPI virtualization mode of the caller has no effect on this output. */ + return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0)); } -bool IsDialogSizeOK(int xSize, int ySize) + +bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd) { // it returns for system font. Real font uses another values - LONG v = GetDialogBaseUnits(); - int x = LOWORD(v); - int y = HIWORD(v); + const LONG v = GetDialogBaseUnits(); + const int x = LOWORD(v); + const int y = HIWORD(v); RECT rect; - GetWorkAreaRect(&rect); - int wx = RECT_SIZE_X(rect); - int wy = RECT_SIZE_Y(rect); + GetWorkAreaRect(&rect, hwnd); + const int wx = RECT_SIZE_X(rect); + const int wy = RECT_SIZE_Y(rect); return xSize / 4 * x <= wx && ySize / 8 * y <= wy; @@ -159,46 +193,166 @@ bool CDialog::MoveItem(int id, int x, int y, int width, int height, bool repaint return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint))); } + +/* +typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)( + HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); + +static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect) +{ + // dll load and free is too slow : 300 calls in second. + NDLL::CLibrary dll; + if (!dll.Load(FTEXT("dwmapi.dll"))) + return false; + Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" ); + if (f) + { + #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9 + // 30000 per second + RECT r; + if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK) + { + *rect = r; + return true; + } + } + return false; +} +*/ + + +static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big) +{ + return sm.left >= big.left + && sm.right <= big.right + && sm.top >= big.top + && sm.bottom <= big.bottom; +} + + +static bool AreRectsOverlapped(const RECT &r1, const RECT &r2) +{ + return r1.left < r2.right + && r1.right > r2.left + && r1.top < r2.bottom + && r1.bottom > r2.top; +} + + +static bool AreRectsEqual(const RECT &r1, const RECT &r2) +{ + return r1.left == r2.left + && r1.right == r2.right + && r1.top == r2.top + && r1.bottom == r2.bottom; +} + + void CDialog::NormalizeSize(bool fullNormalize) { RECT workRect; - GetWorkAreaRect(&workRect); - int xSize = RECT_SIZE_X(workRect); - int ySize = RECT_SIZE_Y(workRect); + if (!GetWorkAreaRect(&workRect, *this)) + return; RECT rect; - GetWindowRect(&rect); - int xSize2 = RECT_SIZE_X(rect); - int ySize2 = RECT_SIZE_Y(rect); - bool needMove = (xSize2 > xSize || ySize2 > ySize); - if (xSize2 > xSize || (needMove && fullNormalize)) + if (!GetWindowRect(&rect)) + return; + int xs = RECT_SIZE_X(rect); + int ys = RECT_SIZE_Y(rect); + + // we don't want to change size using workRect, if window is outside of WorkArea + if (!AreRectsOverlapped(rect, workRect)) + return; + + /* here rect and workRect are overlapped, but it can be false + overlapping of small shadow when window in another display. */ + + const int xsW = RECT_SIZE_X(workRect); + const int ysW = RECT_SIZE_Y(workRect); + if (xs <= xsW && ys <= ysW) + return; // size of window is OK + if (fullNormalize) + { + Show(SW_SHOWMAXIMIZED); + return; + } + int x = workRect.left; + int y = workRect.top; + if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW; + if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW; + Move(x, y, xs, ys, true); +} + + +void CDialog::NormalizePosition() +{ + RECT workRect; + if (!GetWorkAreaRect(&workRect, *this)) + return; + + RECT rect2 = workRect; + bool useWorkArea = true; + const HWND parentHWND = GetParent(); + + if (parentHWND) { - rect.left = workRect.left; - rect.right = workRect.right; - xSize2 = xSize; + RECT workRectParent; + if (!GetWorkAreaRect(&workRectParent, parentHWND)) + return; + + // if windows are in different monitors, we use only workArea of current window + + if (AreRectsEqual(workRectParent, workRect)) + { + // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {} + CWindow wnd(parentHWND); + if (wnd.GetWindowRect(&rect2)) + { + // it's same monitor. So we try to use parentHWND rect. + /* we don't want to change position, if parent window is not inside work area. + In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow. + In maximize mode : window is outside of workRect. + if parent window is inside workRect, we will use parent window instead of workRect */ + if (IsRect_Small_Inside_Big(rect2, workRect)) + useWorkArea = false; + } + } } - if (ySize2 > ySize || (needMove && fullNormalize)) + + RECT rect; + if (!GetWindowRect(&rect)) + return; + + if (useWorkArea) { - rect.top = workRect.top; - rect.bottom = workRect.bottom; - ySize2 = ySize; + // we don't want to move window, if it's already inside. + if (IsRect_Small_Inside_Big(rect, workRect)) + return; + // we don't want to move window, if it's outside of workArea + if (!AreRectsOverlapped(rect, workRect)) + return; + rect2 = workRect; } - if (needMove) + { - if (fullNormalize) - Show(SW_SHOWMAXIMIZED); - else - Move(rect.left, rect.top, xSize2, ySize2, true); + const int xs = RECT_SIZE_X(rect); + const int ys = RECT_SIZE_Y(rect); + const int xs2 = RECT_SIZE_X(rect2); + const int ys2 = RECT_SIZE_Y(rect2); + // we don't want to change position if parent is smaller. + if (xs <= xs2 && ys <= ys2) + { + const int x = rect2.left + (xs2 - xs) / 2; + const int y = rect2.top + (ys2 - ys) / 2; + + if (x != rect.left || y != rect.top) + Move(x, y, xs, ys, true); + // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); + return; + } } } -void CDialog::NormalizePosition() -{ - RECT workRect, rect; - GetWorkAreaRect(&workRect); - GetWindowRect(&rect); - if (rect.bottom > workRect.bottom && rect.top > workRect.top) - Move(rect.left, workRect.top, RECT_SIZE_X(rect), RECT_SIZE_Y(rect), true); -} + bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow) { diff --git a/CPP/Windows/Control/Dialog.h b/CPP/Windows/Control/Dialog.h index f804a9e7..8a39e996 100644 --- a/CPP/Windows/Control/Dialog.h +++ b/CPP/Windows/Control/Dialog.h @@ -183,7 +183,7 @@ public: } }; -bool IsDialogSizeOK(int xSize, int ySize); +bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd = NULL); }} diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp index 84aad042..2974b1b7 100644 --- a/CPP/Windows/FileIO.cpp +++ b/CPP/Windows/FileIO.cpp @@ -139,11 +139,6 @@ bool CFileBase::Close() throw() return true; } -bool CFileBase::GetPosition(UInt64 &position) const throw() -{ - return Seek(0, FILE_CURRENT, position); -} - bool CFileBase::GetLength(UInt64 &length) const throw() { #ifdef SUPPORT_DEVICE_FILE @@ -154,13 +149,64 @@ bool CFileBase::GetLength(UInt64 &length) const throw() } #endif - DWORD sizeHigh; - DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh); - if (sizeLow == 0xFFFFFFFF) + DWORD high = 0; + const DWORD low = ::GetFileSize(_handle, &high); + if (low == INVALID_FILE_SIZE) if (::GetLastError() != NO_ERROR) return false; - length = (((UInt64)sizeHigh) << 32) + sizeLow; + length = (((UInt64)high) << 32) + low; + return true; + + /* + LARGE_INTEGER fileSize; + // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+ + if (!GetFileSizeEx(_handle, &fileSize)) + return false; + length = (UInt64)fileSize.QuadPart; + return true; + */ +} + + +/* Specification for SetFilePointer(): + + If a new file pointer is a negative value, + { + the function fails, + the file pointer is not moved, + the code returned by GetLastError() is ERROR_NEGATIVE_SEEK. + } + + If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set + { + an application can move the file pointer only to sector-aligned positions. + A sector-aligned position is a position that is a whole number multiple of + the volume sector size. + An application can obtain a volume sector size by calling the GetDiskFreeSpace. + } + + It is not an error to set a file pointer to a position beyond the end of the file. + The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function. + + If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL, + an application must call GetLastError to determine whether or not the function has succeeded or failed. +*/ + +bool CFileBase::GetPosition(UInt64 &position) const throw() +{ + LONG high = 0; + const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT); + if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + { + // for error case we can set (position) to (-1) or (0) or leave (position) unchanged. + // position = (UInt64)(Int64)-1; // for debug + position = 0; + return false; + } + position = (((UInt64)(UInt32)high) << 32) + low; return true; + // we don't want recursed GetPosition() + // return Seek(0, FILE_CURRENT, position); } bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw() @@ -174,10 +220,18 @@ bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition #endif LONG high = (LONG)(distanceToMove >> 32); - DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod); - if (low == 0xFFFFFFFF) - if (::GetLastError() != NO_ERROR) + const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod); + if (low == INVALID_SET_FILE_POINTER) + { + const DWORD lastError = ::GetLastError(); + if (lastError != NO_ERROR) + { + // 21.07: we set (newPosition) to real position even after error. + GetPosition(newPosition); + SetLastError(lastError); // restore LastError return false; + } + } newPosition = (((UInt64)(UInt32)high) << 32) + low; return true; } @@ -189,8 +243,8 @@ bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw() bool CFileBase::SeekToBegin() const throw() { - UInt64 newPosition; - return Seek(0, newPosition); + UInt64 newPosition = 0; + return Seek(0, newPosition) && (newPosition == 0); } bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw() @@ -531,6 +585,22 @@ bool COutFile::SetLength(UInt64 length) throw() return SetEndOfFile(); } +bool COutFile::SetLength_KeepPosition(UInt64 length) throw() +{ + UInt64 currentPos = 0; + if (!GetPosition(currentPos)) + return false; + DWORD lastError = 0; + const bool result = SetLength(length); + if (!result) + lastError = GetLastError(); + UInt64 currentPos2; + const bool result2 = Seek(currentPos, currentPos2); + if (lastError != 0) + SetLastError(lastError); + return (result && result2); +} + }}} #else // _WIN32 @@ -573,7 +643,9 @@ bool CFileBase::Close() bool CFileBase::GetLength(UInt64 &length) const { - const off_t curPos = seek(0, SEEK_CUR); + length = 0; + // length = (UInt64)(Int64)-1; // for debug + const off_t curPos = seekToCur(); if (curPos == -1) return false; const off_t lengthTemp = seek(0, SEEK_END); @@ -596,6 +668,11 @@ off_t CFileBase::seekToBegin() const throw() return seek(0, SEEK_SET); } +off_t CFileBase::seekToCur() const throw() +{ + return seek(0, SEEK_CUR); +} + /* bool CFileBase::SeekToBegin() const throw() { @@ -705,6 +782,7 @@ bool COutFile::SetLength(UInt64 length) throw() SetLastError(EFBIG); return false; } + // The value of the seek pointer shall not be modified by a call to ftruncate(). int iret = ftruncate(_handle, len2); return (iret == 0); } diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index 85cae631..22998ebe 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h @@ -247,6 +247,7 @@ public: bool WriteFull(const void *data, size_t size) throw(); bool SetEndOfFile() throw(); bool SetLength(UInt64 length) throw(); + bool SetLength_KeepPosition(UInt64 length) throw(); }; } @@ -279,6 +280,7 @@ public: bool GetLength(UInt64 &length) const; off_t seek(off_t distanceToMove, int moveMethod) const; off_t seekToBegin() const throw(); + off_t seekToCur() const throw(); // bool SeekToBegin() throw(); int my_fstat(struct stat *st) const { return fstat(_handle, st); } }; @@ -327,6 +329,10 @@ public: } bool SetLength(UInt64 length) throw(); + bool SetLength_KeepPosition(UInt64 length) throw() + { + return SetLength(length); + } bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); bool SetMTime(const FILETIME *mTime) throw(); }; diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp index 8cc89a3a..6e43c7bc 100644 --- a/CPP/Windows/PropVariant.cpp +++ b/CPP/Windows/PropVariant.cpp @@ -192,17 +192,29 @@ BSTR CPropVariant::AllocBstr(unsigned numChars) return bstrVal; } +#define SET_PROP_id_dest(id, dest) \ + if (vt != id) { InternalClear(); vt = id; } dest = value; + +void CPropVariant::Set_Int32(Int32 value) throw() +{ + SET_PROP_id_dest(VT_I4, lVal); +} + +void CPropVariant::Set_Int64(Int64 value) throw() +{ + SET_PROP_id_dest(VT_I8, hVal.QuadPart); +} + #define SET_PROP_FUNC(type, id, dest) \ CPropVariant& CPropVariant::operator=(type value) throw() \ - { if (vt != id) { InternalClear(); vt = id; } \ - dest = value; return *this; } + { SET_PROP_id_dest(id, dest); return *this; } SET_PROP_FUNC(Byte, VT_UI1, bVal) // SET_PROP_FUNC(Int16, VT_I2, iVal) -SET_PROP_FUNC(Int32, VT_I4, lVal) +// SET_PROP_FUNC(Int32, VT_I4, lVal) SET_PROP_FUNC(UInt32, VT_UI4, ulVal) SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) -SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) +// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() diff --git a/CPP/Windows/PropVariant.h b/CPP/Windows/PropVariant.h index 58e8a0c6..108bf6b9 100644 --- a/CPP/Windows/PropVariant.h +++ b/CPP/Windows/PropVariant.h @@ -45,6 +45,14 @@ inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() class CPropVariant : public tagPROPVARIANT { + // ---------- forbidden functions ---------- + CPropVariant(const char *s); + // CPropVariant(const UString &s); + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + CPropVariant(const FString &s); + CPropVariant& operator=(const FString &s); + #endif + public: CPropVariant() { @@ -64,13 +72,14 @@ public: CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; } private: + CPropVariant(UInt16 value); // { vt = VT_UI2; wReserved1 = 0; uiVal = value; } CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; } CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; } + CPropVariant(Int64 value); // { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } public: CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; } CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; } - CPropVariant(Int64 value) { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; } CPropVariant& operator=(const CPropVariant &varSrc); @@ -88,14 +97,18 @@ public: private: CPropVariant& operator=(Int16 value) throw(); + CPropVariant& operator=(UInt16 value) throw(); + CPropVariant& operator=(Int32 value) throw(); + CPropVariant& operator=(Int64 value) throw(); public: - CPropVariant& operator=(Int32 value) throw(); CPropVariant& operator=(UInt32 value) throw(); CPropVariant& operator=(UInt64 value) throw(); - CPropVariant& operator=(Int64 value) throw(); CPropVariant& operator=(const FILETIME &value) throw(); + void Set_Int32(Int32 value) throw(); + void Set_Int64(Int64 value) throw(); + BSTR AllocBstr(unsigned numChars); HRESULT Clear() throw(); diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h index c9571469..5fca173f 100644 --- a/CPP/Windows/Thread.h +++ b/CPP/Windows/Thread.h @@ -20,11 +20,11 @@ public: // WRes Wait() { return Thread_Wait(&thread); } WRes Wait_Close() { return Thread_Wait_Close(&thread); } - WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID param) + WRes Create(THREAD_FUNC_TYPE startAddress, LPVOID param) { return Thread_Create(&thread, startAddress, param); } - WRes Create_With_Affinity(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID param, CAffinityMask affinity) + WRes Create_With_Affinity(THREAD_FUNC_TYPE startAddress, LPVOID param, CAffinityMask affinity) { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } - WRes Create_With_CpuSet(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID param, const CCpuSet *cpuSet) + WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } #ifdef _WIN32 diff --git a/DOC/7zip.hhp b/DOC/7zip.hhp index 8b865bdd..6c6bd708 100644 --- a/DOC/7zip.hhp +++ b/DOC/7zip.hhp @@ -58,6 +58,7 @@ cmdline\switches\shared.htm cmdline\switches\sni.htm cmdline\switches\sns.htm cmdline\switches\spf.htm +cmdline\switches\spm.htm cmdline\switches\ssc.htm cmdline\switches\stdin.htm cmdline\switches\stdout.htm diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index 6792d74e..fdc63cea 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs @@ -1,7 +1,7 @@ <?xml version="1.0"?> <?define VerMajor = "21" ?> -<?define VerMinor = "06" ?> +<?define VerMinor = "07" ?> <?define VerBuild = "00" ?> <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> diff --git a/DOC/readme.txt b/DOC/readme.txt index 6c6d3146..0f6c77ba 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt @@ -1,4 +1,4 @@ -7-Zip 21.05 Sources +7-Zip 21.07 Sources ------------------- 7-Zip is a file archiver for Windows. @@ -148,6 +148,28 @@ Also you can change some compiler options in the mak files: var_gcc.mak warn_gcc.mak +makefile.gcc supports some variables that can change compile options + +USE_JWASM=1 + use JWasm assembler instead of Asmc. + Note that JWasm doesn't support AES instructions. So AES code from C version AesOpt.c + will be used instead of assembler code from AesOpt.asm. + +DISABLE_RAR=1 + removes whole RAR related code from compilation. + +DISABLE_RAR_COMPRESS=1 + removes "not fully free" code of RAR decompression codecs from compilation. + +RAR decompression codecs in 7-Zip code has some additional license restrictions, +that can be treated as not fully compatible with free-software licenses. +DISABLE_RAR_COMPRESS=1 allows to exclude such "not-fully-free" RAR code from compilation. +if DISABLE_RAR_COMPRESS=1 is specified, 7-zip will not be able to decompress files +from rar archives, but 7-zip still will be able to open rar archives to get list of +files or to extract files that are stored without compression. +if DISABLE_RAR=1 is specified, 7-zip will not be able to work with RAR archives. + + 7-Zip and p7zip =============== diff --git a/DOC/src-history.txt b/DOC/src-history.txt index 00004e9d..0b54fe34 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt @@ -1,6 +1,14 @@ HISTORY of the 7-Zip source code -------------------------------- +21.07 2021-12-26 +------------------------- +- The sorting order of files in archives was slightly changed to be more consistent + for cases where the name of some directory is the same as the prefix part of the name + of another directory or file. +- TAR archives created by 7-Zip now are more consistent with archives created by GNU TAR program. + + 21.06 2021-11-24 ------------------------- - Bug in LZMA encoder in file LzmaEnc.c was fixed: |