Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2022-01-22 21:43:09 +0300
committerKornel <kornel@geekhood.net>2022-01-22 21:43:09 +0300
commitc3529a41f527101f05e9e834a19205ee33a3b097 (patch)
tree2a76fa3119a75a39cf3ea7418877f53f1a64b7b4
parent52eeaf1ad614fcd03b48423009182e3e3d1ff694 (diff)
21.0721.07
-rw-r--r--Asm/x86/7zAsm.asm13
-rw-r--r--Asm/x86/AesOpt.asm10
-rw-r--r--C/7zTypes.h3
-rw-r--r--C/7zVersion.h6
-rw-r--r--C/DllSecur.c10
-rw-r--r--C/LzFind.c15
-rw-r--r--C/LzFindMt.c6
-rw-r--r--C/MtCoder.c6
-rw-r--r--C/MtDec.c8
-rw-r--r--C/Threads.c10
-rw-r--r--C/Threads.h35
-rw-r--r--CPP/7zip/7zip_gcc.mak32
-rw-r--r--CPP/7zip/Archive/7z/7zHandlerOut.cpp2
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.cpp2
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.cpp21
-rw-r--r--CPP/7zip/Archive/DmgHandler.cpp1
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp7
-rw-r--r--CPP/7zip/Archive/GptHandler.cpp1
-rw-r--r--CPP/7zip/Archive/HandlerCont.cpp28
-rw-r--r--CPP/7zip/Archive/HandlerCont.h4
-rw-r--r--CPP/7zip/Archive/QcowHandler.cpp4
-rw-r--r--CPP/7zip/Archive/Rar/RarVol.h6
-rw-r--r--CPP/7zip/Archive/SwfHandler.cpp34
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.cpp3
-rw-r--r--CPP/7zip/Archive/Tar/TarHandlerOut.cpp4
-rw-r--r--CPP/7zip/Archive/Tar/TarHeader.cpp5
-rw-r--r--CPP/7zip/Archive/Tar/TarHeader.h3
-rw-r--r--CPP/7zip/Archive/Tar/TarIn.cpp5
-rw-r--r--CPP/7zip/Archive/Tar/TarItem.h11
-rw-r--r--CPP/7zip/Archive/Tar/TarOut.cpp150
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.cpp6
-rw-r--r--CPP/7zip/Archive/VdiHandler.cpp4
-rw-r--r--CPP/7zip/Archive/VhdHandler.cpp34
-rw-r--r--CPP/7zip/Archive/VhdxHandler.cpp2062
-rw-r--r--CPP/7zip/Archive/VmdkHandler.cpp7
-rw-r--r--CPP/7zip/Bundles/Alone7z/Alone.dsp4
-rw-r--r--CPP/7zip/Bundles/Fm/resource.rc2
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc.mak1
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc_gcc.mak38
-rw-r--r--CPP/7zip/Bundles/Format7zF/Format7z.dsp4
-rw-r--r--CPP/7zip/Bundles/Format7zF/resource.rc2
-rw-r--r--CPP/7zip/Bundles/SFXCon/SfxCon.cpp7
-rw-r--r--CPP/7zip/Bundles/SFXWin/SfxWin.cpp2
-rw-r--r--CPP/7zip/Common/FileStreams.cpp46
-rw-r--r--CPP/7zip/Compress/CopyCoder.cpp50
-rw-r--r--CPP/7zip/Guid.txt1
-rw-r--r--CPP/7zip/UI/Agent/Agent.cpp8
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp247
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp4
-rw-r--r--CPP/7zip/UI/Common/ArchiveOpenCallback.cpp20
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp2
-rw-r--r--CPP/7zip/UI/Common/CompressCall.cpp10
-rw-r--r--CPP/7zip/UI/Common/CompressCall2.cpp6
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp22
-rw-r--r--CPP/7zip/UI/Common/HashCalc.cpp2
-rw-r--r--CPP/7zip/UI/Common/Update.cpp24
-rw-r--r--CPP/7zip/UI/Console/HashCon.cpp4
-rw-r--r--CPP/7zip/UI/Console/List.cpp4
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.cpp2
-rw-r--r--CPP/7zip/UI/Explorer/MyExplorerCommand.h42
-rw-r--r--CPP/7zip/UI/Far/FarUtils.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/FSDrives.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/FSFolderCopy.cpp5
-rw-r--r--CPP/7zip/UI/FileManager/MyLoadMenu.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/OpenCallback.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/PanelCrc.cpp4
-rw-r--r--CPP/7zip/UI/FileManager/PanelOperations.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2a.rc2
-rw-r--r--CPP/7zip/UI/FileManager/VerCtrl.cpp4
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.cpp4
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp2
-rw-r--r--CPP/7zip/UI/GUI/UpdateGUI.cpp8
-rw-r--r--CPP/Common/MyString.cpp15
-rw-r--r--CPP/Common/MyString.h89
-rw-r--r--CPP/Common/Wildcard.cpp158
-rw-r--r--CPP/Common/Wildcard.h62
-rw-r--r--CPP/Windows/Control/Dialog.cpp228
-rw-r--r--CPP/Windows/Control/Dialog.h2
-rw-r--r--CPP/Windows/FileIO.cpp108
-rw-r--r--CPP/Windows/FileIO.h6
-rw-r--r--CPP/Windows/PropVariant.cpp20
-rw-r--r--CPP/Windows/PropVariant.h19
-rw-r--r--CPP/Windows/Thread.h6
-rw-r--r--DOC/7zip.hhp1
-rw-r--r--DOC/7zip.wxs2
-rw-r--r--DOC/readme.txt24
-rw-r--r--DOC/src-history.txt8
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;
diff --git a/C/LzFind.c b/C/LzFind.c
index bf157a0b..1b73c284 100644
--- a/C/LzFind.c
+++ b/C/LzFind.c
@@ -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 (;;)
diff --git a/C/MtDec.c b/C/MtDec.c
index fa533d23..45a67139 100644
--- a/C/MtDec.c
+++ b/C/MtDec.c
@@ -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 &region = 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: