aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--C/7zVersion.h6
-rw-r--r--C/7zip_gcc_c.mak42
-rw-r--r--C/CpuArch.h17
-rw-r--r--C/DllSecur.c8
-rw-r--r--C/LzmaEnc.c11
-rw-r--r--C/Util/7zipInstall/7zipInstall.c8
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.c6
-rw-r--r--CPP/7zip/7zip_gcc.mak39
-rw-r--r--CPP/7zip/Archive/ApfsHandler.cpp447
-rw-r--r--CPP/7zip/Archive/Chm/ChmIn.h1
-rw-r--r--CPP/7zip/Archive/DmgHandler.cpp2
-rw-r--r--CPP/7zip/Archive/HfsHandler.cpp933
-rw-r--r--CPP/7zip/Archive/HfsHandler.h85
-rw-r--r--CPP/7zip/Archive/Udf/UdfHandler.cpp48
-rw-r--r--CPP/7zip/Archive/Udf/UdfHandler.h2
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.cpp994
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.h260
-rw-r--r--CPP/7zip/Bundles/Alone/makefile.gcc13
-rw-r--r--CPP/7zip/Bundles/Alone2/makefile.gcc9
-rw-r--r--CPP/7zip/Bundles/Alone7z/makefile.gcc13
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc_gcc.mak10
-rw-r--r--CPP/7zip/Bundles/Format7zF/Format7z.dsp4
-rw-r--r--CPP/7zip/Bundles/Format7zF/makefile.gcc10
-rw-r--r--CPP/7zip/Bundles/LzmaCon/makefile.gcc11
-rw-r--r--CPP/7zip/Bundles/SFXCon/makefile.gcc13
-rw-r--r--CPP/7zip/Common/FileStreams.cpp7
-rw-r--r--CPP/7zip/Compress/LzfseDecoder.cpp22
-rw-r--r--CPP/7zip/Compress/LzfseDecoder.h11
-rw-r--r--CPP/7zip/UI/Client7z/makefile.gcc10
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp3
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp8
-rw-r--r--CPP/7zip/UI/Console/Console.dsp4
-rw-r--r--CPP/7zip/UI/Console/makefile.gcc13
-rw-r--r--CPP/7zip/UI/Explorer/resource.rc2
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.cpp9
-rw-r--r--CPP/7zip/UI/FileManager/FSFolderCopy.cpp7
-rw-r--r--CPP/7zip/UI/FileManager/MyCom2.h5
-rw-r--r--CPP/7zip/UI/FileManager/PanelOperations.cpp10
-rw-r--r--CPP/7zip/UI/FileManager/SysIconUtils.cpp12
-rw-r--r--CPP/7zip/UI/FileManager/TextPairs.cpp17
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp8
-rw-r--r--CPP/Windows/MemoryLock.cpp2
-rw-r--r--CPP/Windows/SecurityUtils.cpp13
-rw-r--r--CPP/Windows/SecurityUtils.h83
-rw-r--r--CPP/Windows/Shell.cpp19
-rw-r--r--DOC/7zip.wxs2
-rw-r--r--DOC/readme.txt4
47 files changed, 2468 insertions, 795 deletions
diff --git a/C/7zVersion.h b/C/7zVersion.h
index 89fffd9..49ea81d 100644
--- a/C/7zVersion.h
+++ b/C/7zVersion.h
@@ -1,7 +1,7 @@
1#define MY_VER_MAJOR 22 1#define MY_VER_MAJOR 22
2#define MY_VER_MINOR 00 2#define MY_VER_MINOR 01
3#define MY_VER_BUILD 0 3#define MY_VER_BUILD 0
4#define MY_VERSION_NUMBERS "22.00" 4#define MY_VERSION_NUMBERS "22.01"
5#define MY_VERSION MY_VERSION_NUMBERS 5#define MY_VERSION MY_VERSION_NUMBERS
6 6
7#ifdef MY_CPU_NAME 7#ifdef MY_CPU_NAME
@@ -10,7 +10,7 @@
10 #define MY_VERSION_CPU MY_VERSION 10 #define MY_VERSION_CPU MY_VERSION
11#endif 11#endif
12 12
13#define MY_DATE "2022-06-15" 13#define MY_DATE "2022-07-15"
14#undef MY_COPYRIGHT 14#undef MY_COPYRIGHT
15#undef MY_VERSION_COPYRIGHT_DATE 15#undef MY_VERSION_COPYRIGHT_DATE
16#define MY_AUTHOR_NAME "Igor Pavlov" 16#define MY_AUTHOR_NAME "Igor Pavlov"
diff --git a/C/7zip_gcc_c.mak b/C/7zip_gcc_c.mak
index e884440..24505f3 100644
--- a/C/7zip_gcc_c.mak
+++ b/C/7zip_gcc_c.mak
@@ -16,12 +16,32 @@ CFLAGS_BASE = $(MY_ARCH_2) -O2 $(CFLAGS_BASE_LIST) -Wall -Werror -Wextra $(CFLAG
16 -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE 16 -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
17 17
18 18
19LDFLAGS_STATIC = -DNDEBUG
20# -static
21
22ifdef SystemDrive 19ifdef SystemDrive
23IS_MINGW = 1 20IS_MINGW = 1
21else
22ifdef SYSTEMDRIVE
23# ifdef OS
24IS_MINGW = 1
25endif
26endif
27
28ifdef IS_MINGW
29LDFLAGS_STATIC_2 = -static
30else
31ifndef DEF_FILE
32ifndef IS_NOT_STANDALONE
33ifndef MY_DYNAMIC_LINK
34ifneq ($(CC), clang)
35LDFLAGS_STATIC_2 =
36# -static
37# -static-libstdc++ -static-libgcc
38endif
39endif
40endif
24endif 41endif
42endif
43
44LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2)
25 45
26ifdef DEF_FILE 46ifdef DEF_FILE
27 47
@@ -62,15 +82,22 @@ endif
62 82
63ifdef IS_MINGW 83ifdef IS_MINGW
64 84
85ifdef MSYSTEM
86RM = rm -f
87MY_MKDIR=mkdir -p
88DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
89else
65RM = del 90RM = del
66MY_MKDIR=mkdir 91MY_MKDIR=mkdir
67LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 92DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
93endif
94
68 95
96LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32
69 97
70CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE 98CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE
71# -Wno-delete-non-virtual-dtor 99# -Wno-delete-non-virtual-dtor
72 100
73DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
74 101
75else 102else
76 103
@@ -306,7 +333,10 @@ $O/7zMain.o: ../../../C/Util/7z/7zMain.c
306 $(CC) $(CFLAGS) $< 333 $(CC) $(CFLAGS) $<
307$O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c 334$O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c
308 $(CC) $(CFLAGS) $< 335 $(CC) $(CFLAGS) $<
309 336$O/7zipInstall.o: ../../../C/Util/7zipInstall/7zipInstall.c
337 $(CC) $(CFLAGS) $<
338$O/7zipUninstall.o: ../../../C/Util/7zipUninstall/7zipUninstall.c
339 $(CC) $(CFLAGS) $<
310 340
311 341
312clean: 342clean:
diff --git a/C/CpuArch.h b/C/CpuArch.h
index 529d3a5..4856fbb 100644
--- a/C/CpuArch.h
+++ b/C/CpuArch.h
@@ -1,5 +1,5 @@
1/* CpuArch.h -- CPU specific code 1/* CpuArch.h -- CPU specific code
22021-07-13 : Igor Pavlov : Public domain */ 22022-07-15 : Igor Pavlov : Public domain */
3 3
4#ifndef __CPU_ARCH_H 4#ifndef __CPU_ARCH_H
5#define __CPU_ARCH_H 5#define __CPU_ARCH_H
@@ -123,12 +123,15 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
123#endif 123#endif
124 124
125 125
126#if defined(__sparc64__) 126#if defined(__riscv) \
127 #define MY_CPU_NAME "sparc64" 127 || defined(__riscv__)
128 #define MY_CPU_64BIT 128 #if __riscv_xlen == 32
129#elif defined(__sparc__) 129 #define MY_CPU_NAME "riscv32"
130 #define MY_CPU_NAME "sparc" 130 #elif __riscv_xlen == 64
131 /* #define MY_CPU_32BIT */ 131 #define MY_CPU_NAME "riscv64"
132 #else
133 #define MY_CPU_NAME "riscv"
134 #endif
132#endif 135#endif
133 136
134 137
diff --git a/C/DllSecur.c b/C/DllSecur.c
index d81508c..dce0c96 100644
--- a/C/DllSecur.c
+++ b/C/DllSecur.c
@@ -1,5 +1,5 @@
1/* DllSecur.c -- DLL loading security 1/* DllSecur.c -- DLL loading security
22021-12-25 : Igor Pavlov : Public domain */ 22022-07-15 : Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
@@ -11,6 +11,10 @@
11 11
12#ifndef UNDER_CE 12#ifndef UNDER_CE
13 13
14#if defined(__GNUC__) && (__GNUC__ >= 8)
15 #pragma GCC diagnostic ignored "-Wcast-function-type"
16#endif
17
14typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); 18typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags);
15 19
16#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 20#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400
@@ -34,7 +38,7 @@ static const char * const g_Dlls =
34#endif 38#endif
35 39
36// #define MY_CAST_FUNC (void(*)()) 40// #define MY_CAST_FUNC (void(*)())
37#define MY_CAST_FUNC 41#define MY_CAST_FUNC
38 42
39void My_SetDefaultDllDirectories() 43void My_SetDefaultDllDirectories()
40{ 44{
diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c
index b04a7b7..c8b31a1 100644
--- a/C/LzmaEnc.c
+++ b/C/LzmaEnc.c
@@ -1,5 +1,5 @@
1/* LzmaEnc.c -- LZMA Encoder 1/* LzmaEnc.c -- LZMA Encoder
22021-11-18: Igor Pavlov : Public domain */ 22022-07-15: Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
@@ -2970,6 +2970,7 @@ const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
2970} 2970}
2971 2971
2972 2972
2973// (desiredPackSize == 0) is not allowed
2973SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, 2974SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
2974 Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) 2975 Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
2975{ 2976{
@@ -2990,14 +2991,10 @@ SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
2990 if (reInit) 2991 if (reInit)
2991 LzmaEnc_Init(p); 2992 LzmaEnc_Init(p);
2992 LzmaEnc_InitPrices(p); 2993 LzmaEnc_InitPrices(p);
2993
2994 nowPos64 = p->nowPos64;
2995 RangeEnc_Init(&p->rc); 2994 RangeEnc_Init(&p->rc);
2996 p->rc.outStream = &outStream.vt; 2995 p->rc.outStream = &outStream.vt;
2997 2996 nowPos64 = p->nowPos64;
2998 if (desiredPackSize == 0) 2997
2999 return SZ_ERROR_OUTPUT_EOF;
3000
3001 res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); 2998 res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize);
3002 2999
3003 *unpackSize = (UInt32)(p->nowPos64 - nowPos64); 3000 *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
diff --git a/C/Util/7zipInstall/7zipInstall.c b/C/Util/7zipInstall/7zipInstall.c
index 00d0f41..2649734 100644
--- a/C/Util/7zipInstall/7zipInstall.c
+++ b/C/Util/7zipInstall/7zipInstall.c
@@ -1,5 +1,5 @@
1/* 7zipInstall.c - 7-Zip Installer 1/* 7zipInstall.c - 7-Zip Installer
22021-09-02 : Igor Pavlov : Public domain */ 22022-07-15 : Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
@@ -22,6 +22,10 @@
22 22
23#include "resource.h" 23#include "resource.h"
24 24
25#if defined(__GNUC__) && (__GNUC__ >= 8)
26 #pragma GCC diagnostic ignored "-Wcast-function-type"
27#endif
28
25#define LLL_(quote) L##quote 29#define LLL_(quote) L##quote
26#define LLL(quote) LLL_(quote) 30#define LLL(quote) LLL_(quote)
27 31
@@ -70,7 +74,7 @@ static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
70 #endif 74 #endif
71#endif 75#endif
72 76
73#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix 77#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix
74 78
75 79
76static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver; 80static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver;
diff --git a/C/Util/7zipUninstall/7zipUninstall.c b/C/Util/7zipUninstall/7zipUninstall.c
index b4c6ff5..c8e8a89 100644
--- a/C/Util/7zipUninstall/7zipUninstall.c
+++ b/C/Util/7zipUninstall/7zipUninstall.c
@@ -1,5 +1,5 @@
1/* 7zipUninstall.c - 7-Zip Uninstaller 1/* 7zipUninstall.c - 7-Zip Uninstaller
22021-11-24 : Igor Pavlov : Public domain */ 22022-07-15 : Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
@@ -17,6 +17,10 @@
17 17
18#include "resource.h" 18#include "resource.h"
19 19
20#if defined(__GNUC__) && (__GNUC__ >= 8)
21 #pragma GCC diagnostic ignored "-Wcast-function-type"
22#endif
23
20#define LLL_(quote) L##quote 24#define LLL_(quote) L##quote
21#define LLL(quote) LLL_(quote) 25#define LLL(quote) LLL_(quote)
22 26
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
index b242459..f65cff2 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -33,6 +33,11 @@ CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \
33 33
34ifdef SystemDrive 34ifdef SystemDrive
35IS_MINGW = 1 35IS_MINGW = 1
36else
37ifdef SYSTEMDRIVE
38# ifdef OS
39IS_MINGW = 1
40endif
36endif 41endif
37 42
38ifdef IS_MINGW 43ifdef IS_MINGW
@@ -97,20 +102,30 @@ PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT)
97 102
98ifdef IS_MINGW 103ifdef IS_MINGW
99 104
105ifdef MSYSTEM
106RM = rm -f
107MY_MKDIR=mkdir -p
108DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
109LIB_HTMLHELP=-lhtmlhelp
110else
100RM = del 111RM = del
101MY_MKDIR=mkdir 112MY_MKDIR=mkdir
102LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 113DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
114endif
115
116LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 $(LIB_HTMLHELP)
103LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) 117LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI)
104 118
105CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE 119CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE
106# -Wno-delete-non-virtual-dtor 120# -Wno-delete-non-virtual-dtor
107 121
108DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
109 122
110else 123else
111 124
112RM = rm -f 125RM = rm -f
113MY_MKDIR=mkdir -p 126MY_MKDIR=mkdir -p
127DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
128
114# CFLAGS_BASE := $(CFLAGS_BASE) -D_7ZIP_ST 129# CFLAGS_BASE := $(CFLAGS_BASE) -D_7ZIP_ST
115# CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE 130# CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
116 131
@@ -119,9 +134,6 @@ MY_MKDIR=mkdir -p
119LIB2 = -lpthread -ldl 134LIB2 = -lpthread -ldl
120 135
121 136
122
123DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
124
125endif 137endif
126 138
127 139
@@ -130,9 +142,19 @@ CFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CC_SHARED)
130 142
131 143
132ifdef IS_MINGW 144ifdef IS_MINGW
145
146ifdef IS_X64
147AFLAGS_ABI = -win64
148else
133AFLAGS_ABI = -coff -DABI_CDECL 149AFLAGS_ABI = -coff -DABI_CDECL
150# -DABI_CDECL
151# -DABI_LINUX
152# -DABI_CDECL
153endif
134AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $(<F)).o 154AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $(<F)).o
135else 155
156else # IS_MINGW
157
136ifdef IS_X64 158ifdef IS_X64
137AFLAGS_ABI = -elf64 -DABI_LINUX 159AFLAGS_ABI = -elf64 -DABI_LINUX
138else 160else
@@ -142,7 +164,10 @@ AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
142# -DABI_CDECL 164# -DABI_CDECL
143endif 165endif
144AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/ 166AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/
145endif 167
168endif # IS_MINGW
169
170
146 171
147ifdef USE_ASM 172ifdef USE_ASM
148CONSOLE_ASM_FLAGS=-D_7ZIP_ASM 173CONSOLE_ASM_FLAGS=-D_7ZIP_ASM
diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp
index 8312456..2c16de1 100644
--- a/CPP/7zip/Archive/ApfsHandler.cpp
+++ b/CPP/7zip/Archive/ApfsHandler.cpp
@@ -32,6 +32,8 @@
32 32
33#include "Common/ItemNameUtils.h" 33#include "Common/ItemNameUtils.h"
34 34
35#include "HfsHandler.h"
36
35// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files. 37// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files.
36#define APFS_SHOW_ALT_STREAMS 38#define APFS_SHOW_ALT_STREAMS
37 39
@@ -934,11 +936,12 @@ struct CItem
934 unsigned RefIndex; 936 unsigned RefIndex;
935 // unsigned iNode_Index; 937 // unsigned iNode_Index;
936 938
937 CItem(): 939 void Clear()
938 ParentItemIndex(VI_MINUS1), 940 {
939 RefIndex(VI_MINUS1) 941 Name.Empty();
940 // iNode_Index(VI_MINUS1) 942 ParentItemIndex = VI_MINUS1;
941 {} 943 RefIndex = VI_MINUS1;
944 }
942}; 945};
943 946
944 947
@@ -956,9 +959,9 @@ struct CItem
956#define UNIFIED_ID_SPACE_MARK 0x0800000000000000 959#define UNIFIED_ID_SPACE_MARK 0x0800000000000000
957*/ 960*/
958 961
959/*
960typedef enum 962typedef enum
961{ 963{
964/*
962INODE_IS_APFS_PRIVATE = 0x00000001, 965INODE_IS_APFS_PRIVATE = 0x00000001,
963INODE_MAINTAIN_DIR_STATS = 0x00000002, 966INODE_MAINTAIN_DIR_STATS = 0x00000002,
964INODE_DIR_STATS_ORIGIN = 0x00000004, 967INODE_DIR_STATS_ORIGIN = 0x00000004,
@@ -973,11 +976,15 @@ INODE_WAS_EVER_CLONED = 0x00000400,
973INODE_ACTIVE_FILE_TRIMMED = 0x00000800, 976INODE_ACTIVE_FILE_TRIMMED = 0x00000800,
974INODE_PINNED_TO_MAIN = 0x00001000, 977INODE_PINNED_TO_MAIN = 0x00001000,
975INODE_PINNED_TO_TIER2 = 0x00002000, 978INODE_PINNED_TO_TIER2 = 0x00002000,
979*/
976INODE_HAS_RSRC_FORK = 0x00004000, 980INODE_HAS_RSRC_FORK = 0x00004000,
981/*
977INODE_NO_RSRC_FORK = 0x00008000, 982INODE_NO_RSRC_FORK = 0x00008000,
978INODE_ALLOCATION_SPILLEDOVER = 0x00010000, 983INODE_ALLOCATION_SPILLEDOVER = 0x00010000,
979INODE_FAST_PROMOTE = 0x00020000, 984INODE_FAST_PROMOTE = 0x00020000,
985*/
980INODE_HAS_UNCOMPRESSED_SIZE = 0x00040000, 986INODE_HAS_UNCOMPRESSED_SIZE = 0x00040000,
987/*
981INODE_IS_PURGEABLE = 0x00080000, 988INODE_IS_PURGEABLE = 0x00080000,
982INODE_WANTS_TO_BE_PURGEABLE = 0x00100000, 989INODE_WANTS_TO_BE_PURGEABLE = 0x00100000,
983INODE_IS_SYNC_ROOT = 0x00200000, 990INODE_IS_SYNC_ROOT = 0x00200000,
@@ -993,10 +1000,12 @@ INODE_CLONED_INTERNAL_FLAGS = \
993 | INODE_NO_RSRC_FORK \ 1000 | INODE_NO_RSRC_FORK \
994 | INODE_HAS_FINDER_INFO \ 1001 | INODE_HAS_FINDER_INFO \
995 | INODE_SNAPSHOT_COW_EXEMPTION), 1002 | INODE_SNAPSHOT_COW_EXEMPTION),
1003*/
996} 1004}
997j_inode_flags; 1005j_inode_flags;
998 1006
999 1007
1008/*
1000#define APFS_VALID_INTERNAL_INODE_FLAGS \ 1009#define APFS_VALID_INTERNAL_INODE_FLAGS \
1001( INODE_IS_APFS_PRIVATE \ 1010( INODE_IS_APFS_PRIVATE \
1002| INODE_MAINTAIN_DIR_STATS \ 1011| INODE_MAINTAIN_DIR_STATS \
@@ -1192,22 +1201,34 @@ struct CAttr
1192{ 1201{
1193 AString Name; 1202 AString Name;
1194 UInt32 flags; 1203 UInt32 flags;
1204 bool dstream_defined;
1205 bool NeedShow;
1195 CByteBuffer Data; 1206 CByteBuffer Data;
1196 1207
1197 j_dstream dstream; 1208 j_dstream dstream;
1198 bool dstream_defined;
1199 UInt64 Id; 1209 UInt64 Id;
1200 1210
1201 bool Is_dstream_OK_for_SymLink() const 1211 bool Is_dstream_OK_for_SymLink() const
1202 { 1212 {
1203 return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0; 1213 return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0;
1204 } 1214 }
1215
1216 UInt64 GetSize() const
1217 {
1218 if (dstream_defined) // dstream has more priority
1219 return dstream.size;
1220 return Data.Size();
1221 }
1205 1222
1206 CAttr(): 1223 void Clear()
1207 dstream_defined(false) 1224 {
1208 {} 1225 dstream_defined = false;
1226 NeedShow = true;
1227 Data.Free();
1228 Name.Empty();
1229 }
1209 1230
1210 bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; } 1231 bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; }
1211 bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; } 1232 bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; }
1212}; 1233};
1213 1234
@@ -1245,16 +1266,22 @@ struct CNode
1245 MY__gid_t group; 1266 MY__gid_t group;
1246 MY__mode_t mode; 1267 MY__mode_t mode;
1247 UInt16 pad1; 1268 UInt16 pad1;
1248 // UInt64 uncompressed_size; 1269 UInt64 uncompressed_size;
1249 1270
1250 j_dstream dstream; 1271 j_dstream dstream;
1251 AString PrimaryName; 1272 AString PrimaryName;
1273
1252 bool dstream_defined; 1274 bool dstream_defined;
1253 bool refcnt_defined; 1275 bool refcnt_defined;
1276
1254 UInt32 refcnt; // j_dstream_id_val_t 1277 UInt32 refcnt; // j_dstream_id_val_t
1255 CRecordVector<CExtent> Extents; 1278 CRecordVector<CExtent> Extents;
1256 CObjectVector<CAttr> Attrs; 1279 CObjectVector<CAttr> Attrs;
1257 unsigned SymLinkIndex; // index in Attrs 1280 unsigned SymLinkIndex; // index in Attrs
1281 unsigned DecmpfsIndex; // index in Attrs
1282 unsigned ResourceIndex; // index in Attrs
1283
1284 NHfs::CCompressHeader CompressHeader;
1258 1285
1259 CNode(): 1286 CNode():
1260 ItemIndex(VI_MINUS1), 1287 ItemIndex(VI_MINUS1),
@@ -1262,11 +1289,16 @@ struct CNode
1262 // NumItems(0), 1289 // NumItems(0),
1263 dstream_defined(false), 1290 dstream_defined(false),
1264 refcnt_defined(false), 1291 refcnt_defined(false),
1265 SymLinkIndex(VI_MINUS1) 1292 SymLinkIndex(VI_MINUS1),
1293 DecmpfsIndex(VI_MINUS1),
1294 ResourceIndex(VI_MINUS1)
1266 {} 1295 {}
1267 1296
1268 bool IsDir() const { return MY_LIN_S_ISDIR(mode); } 1297 bool IsDir() const { return MY_LIN_S_ISDIR(mode); }
1269 bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); } 1298 bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); }
1299
1300 bool Has_UNCOMPRESSED_SIZE() const { return (internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) != 0; }
1301
1270 unsigned Get_Type_From_mode() const { return mode >> 12; } 1302 unsigned Get_Type_From_mode() const { return mode >> 12; }
1271 1303
1272 bool GetSize(unsigned attrIndex, UInt64 &size) const 1304 bool GetSize(unsigned attrIndex, UInt64 &size) const
@@ -1278,6 +1310,12 @@ struct CNode
1278 size = dstream.size; 1310 size = dstream.size;
1279 return true; 1311 return true;
1280 } 1312 }
1313 size = 0;
1314 if (Has_UNCOMPRESSED_SIZE())
1315 {
1316 size = uncompressed_size;
1317 return true;
1318 }
1281 if (!IsSymLink()) 1319 if (!IsSymLink())
1282 return false; 1320 return false;
1283 attrIndex = SymLinkIndex; 1321 attrIndex = SymLinkIndex;
@@ -1301,9 +1339,23 @@ struct CNode
1301 size = dstream.alloced_size; 1339 size = dstream.alloced_size;
1302 return true; 1340 return true;
1303 } 1341 }
1304 if (!IsSymLink()) 1342 size = 0;
1305 return false; 1343
1306 attrIndex = SymLinkIndex; 1344 if (IsSymLink())
1345 attrIndex = SymLinkIndex;
1346 else
1347 {
1348 if (!CompressHeader.IsCorrect ||
1349 !CompressHeader.IsSupported)
1350 return false;
1351 const CAttr &attr = Attrs[DecmpfsIndex];
1352 if (!CompressHeader.IsMethod_Resource())
1353 {
1354 size = attr.Data.Size() - CompressHeader.DataPos;
1355 return true;
1356 }
1357 attrIndex = ResourceIndex;
1358 }
1307 if (IsViNotDef(attrIndex)) 1359 if (IsViNotDef(attrIndex))
1308 return false; 1360 return false;
1309 } 1361 }
@@ -1339,17 +1391,17 @@ void CNode::Parse(const Byte *p)
1339 G64 (0x28, access_time); 1391 G64 (0x28, access_time);
1340 G64 (0x30, internal_flags); 1392 G64 (0x30, internal_flags);
1341 { 1393 {
1342 G32(0x38, nchildren); 1394 G32 (0x38, nchildren);
1343 // G32(0x38, nlink); 1395 // G32 (0x38, nlink);
1344 } 1396 }
1345 // G32(0x3c, default_protection_class); 1397 // G32 (0x3c, default_protection_class);
1346 G32(0x40, write_generation_counter); 1398 G32 (0x40, write_generation_counter);
1347 G32(0x44, bsd_flags); 1399 G32 (0x44, bsd_flags);
1348 G32(0x48, owner); 1400 G32 (0x48, owner);
1349 G32(0x4c, group); 1401 G32 (0x4c, group);
1350 G16(0x50, mode); 1402 G16 (0x50, mode);
1351 // G16(0x52, pad1); 1403 // G16 (0x52, pad1);
1352 // G64 (0x54, uncompressed_size); 1404 G64 (0x54, uncompressed_size);
1353} 1405}
1354 1406
1355 1407
@@ -1364,6 +1416,7 @@ struct CRef
1364 bool IsAltStream() const { return IsViDef(AttrIndex); } 1416 bool IsAltStream() const { return IsViDef(AttrIndex); }
1365 unsigned GetAttrIndex() const { return AttrIndex; }; 1417 unsigned GetAttrIndex() const { return AttrIndex; };
1366 #else 1418 #else
1419 // bool IsAltStream() const { return false; }
1367 unsigned GetAttrIndex() const { return VI_MINUS1; }; 1420 unsigned GetAttrIndex() const { return VI_MINUS1; };
1368 #endif 1421 #endif
1369}; 1422};
@@ -1667,6 +1720,7 @@ struct CDatabase
1667 UInt64 ProgressVal_NumFilesTotal; 1720 UInt64 ProgressVal_NumFilesTotal;
1668 CObjectVector<CByteBuffer> Buffers; 1721 CObjectVector<CByteBuffer> Buffers;
1669 1722
1723 UInt32 MethodsMask;
1670 UInt64 GetSize(const UInt32 index) const; 1724 UInt64 GetSize(const UInt32 index) const;
1671 1725
1672 void Clear() 1726 void Clear()
@@ -1678,6 +1732,8 @@ struct CDatabase
1678 ProgressVal_Cur = 0; 1732 ProgressVal_Cur = 0;
1679 ProgressVal_Prev = 0; 1733 ProgressVal_Prev = 0;
1680 ProgressVal_NumFilesTotal = 0; 1734 ProgressVal_NumFilesTotal = 0;
1735
1736 MethodsMask = 0;
1681 1737
1682 Vols.Clear(); 1738 Vols.Clear();
1683 Refs2.Clear(); 1739 Refs2.Clear();
@@ -1691,6 +1747,12 @@ struct CDatabase
1691 HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid); 1747 HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid);
1692 HRESULT Open2(); 1748 HRESULT Open2();
1693 1749
1750 HRESULT GetAttrStream(IInStream *apfsInStream, const CVol &vol,
1751 const CAttr &attr, ISequentialInStream **stream);
1752
1753 HRESULT GetAttrStream_dstream(IInStream *apfsInStream, const CVol &vol,
1754 const CAttr &attr, ISequentialInStream **stream);
1755
1694 HRESULT GetStream2( 1756 HRESULT GetStream2(
1695 IInStream *apfsInStream, 1757 IInStream *apfsInStream,
1696 const CRecordVector<CExtent> *extents, UInt64 rem, 1758 const CRecordVector<CExtent> *extents, UInt64 rem,
@@ -2070,7 +2132,7 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2070 RINOK(ReadMap(ov.paddr, map, 0)); 2132 RINOK(ReadMap(ov.paddr, map, 0));
2071 } 2133 }
2072 2134
2073 bool NeedReadSymLink = false; 2135 bool needParseAttr = false;
2074 2136
2075 { 2137 {
2076 const bool isHashed = apfs.IsHashedName(); 2138 const bool isHashed = apfs.IsHashedName();
@@ -2094,6 +2156,9 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2094 } 2156 }
2095 } 2157 }
2096 2158
2159 CAttr attr;
2160 CItem item;
2161
2097 FOR_VECTOR (i, map.Pairs) 2162 FOR_VECTOR (i, map.Pairs)
2098 { 2163 {
2099 if (OpenCallback && (i & 0xffff) == 1) 2164 if (OpenCallback && (i & 0xffff) == 1)
@@ -2232,7 +2297,7 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2232 if (nameOffset + len != pair.Key.Size()) 2297 if (nameOffset + len != pair.Key.Size())
2233 return S_FALSE; 2298 return S_FALSE;
2234 2299
2235 CAttr attr; 2300 attr.Clear();
2236 attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); 2301 attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
2237 if (attr.Name.Len() != len - 1) 2302 if (attr.Name.Len() != len - 1)
2238 return S_FALSE; 2303 return S_FALSE;
@@ -2287,15 +2352,25 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2287 // UnsupportedFeature = true; 2352 // UnsupportedFeature = true;
2288 // continue; 2353 // continue;
2289 } 2354 }
2355
2290 CNode &inode = vol.Nodes.Back(); 2356 CNode &inode = vol.Nodes.Back();
2357
2291 if (attr.Name.IsEqualTo("com.apple.fs.symlink")) 2358 if (attr.Name.IsEqualTo("com.apple.fs.symlink"))
2292 { 2359 {
2293 inode.SymLinkIndex = inode.Attrs.Size(); 2360 inode.SymLinkIndex = inode.Attrs.Size();
2294 if (attr.Is_dstream_OK_for_SymLink()) 2361 if (attr.Is_dstream_OK_for_SymLink())
2295 NeedReadSymLink = true; 2362 needParseAttr = true;
2363 }
2364 else if (attr.Name.IsEqualTo("com.apple.decmpfs"))
2365 {
2366 inode.DecmpfsIndex = inode.Attrs.Size();
2367 // if (attr.dstream_defined)
2368 needParseAttr = true;
2369 }
2370 else if (attr.Name.IsEqualTo("com.apple.ResourceFork"))
2371 {
2372 inode.ResourceIndex = inode.Attrs.Size();
2296 } 2373 }
2297 else
2298 vol.NumAltStreams++;
2299 inode.Attrs.Add(attr); 2374 inode.Attrs.Add(attr);
2300 continue; 2375 continue;
2301 } 2376 }
@@ -2431,7 +2506,10 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2431 } 2506 }
2432 if (nameOffset + len != pair.Key.Size()) 2507 if (nameOffset + len != pair.Key.Size())
2433 return S_FALSE; 2508 return S_FALSE;
2434 CItem item; 2509
2510 // CItem item;
2511 item.Clear();
2512
2435 item.ParentId = id; 2513 item.ParentId = id;
2436 item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); 2514 item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
2437 if (item.Name.Len() != len - 1) 2515 if (item.Name.Len() != len - 1)
@@ -2471,39 +2549,86 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2471 ProgressVal_NumFilesTotal += vol.Items.Size(); 2549 ProgressVal_NumFilesTotal += vol.Items.Size();
2472 } 2550 }
2473 2551
2474 if (NeedReadSymLink) 2552
2553 if (needParseAttr)
2475 { 2554 {
2476 /* we read external streams for SymLinks to CAttr.Data 2555 /* we read external streams for attributes
2477 So we can get SymLink for GetProperty(kpidSymLink) later */ 2556 So we can get SymLink for GetProperty(kpidSymLink) later */
2478 FOR_VECTOR (i, vol.Nodes) 2557 FOR_VECTOR (i, vol.Nodes)
2479 { 2558 {
2480 CNode &node = vol.Nodes[i]; 2559 CNode &node = vol.Nodes[i];
2481 if (IsViNotDef(node.SymLinkIndex)) 2560
2482 continue; 2561 FOR_VECTOR (a, node.Attrs)
2483 CAttr &attr = node.Attrs[(unsigned)node.SymLinkIndex]; 2562 {
2484 // FOR_VECTOR (k, node.Attrs) { CAttr &attr = node.Attrs[(unsigned)k]; // for debug 2563 CAttr &attr = node.Attrs[a];
2485 if (attr.Data.Size() != 0 2564 if (attr.Data.Size() != 0 || !attr.dstream_defined)
2486 || !attr.Is_dstream_OK_for_SymLink()) 2565 continue;
2487 continue; 2566 if (a == node.SymLinkIndex)
2488 const UInt32 size = (UInt32)attr.dstream.size; 2567 {
2489 const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); 2568 if (!attr.Is_dstream_OK_for_SymLink())
2490 if (idIndex == -1) 2569 continue;
2491 continue; 2570 }
2492 CMyComPtr<ISequentialInStream> inStream; 2571 else
2493 const HRESULT res = GetStream2( 2572 {
2494 OpenInStream, 2573 if (a != node.DecmpfsIndex
2495 &vol.SmallNodes[(unsigned)idIndex].Extents, 2574 // && a != node.ResourceIndex
2496 size, &inStream); 2575 )
2497 if (res == S_OK && inStream) 2576 continue;
2577 }
2578 // we don't expect big streams here
2579 // largest dstream for Decmpfs attribute is (2Kib+17)
2580 if (attr.dstream.size > ((UInt32)1 << 16))
2581 continue;
2582 CMyComPtr<ISequentialInStream> inStream;
2583 const HRESULT res = GetAttrStream_dstream(OpenInStream, vol, attr, &inStream);
2584 if (res == S_OK && inStream)
2585 {
2586 CByteBuffer buf2;
2587 const size_t size = (size_t)attr.dstream.size;
2588 buf2.Alloc(size);
2589 if (ReadStream_FAIL(inStream, buf2, size) == S_OK)
2590 attr.Data = buf2;
2591
2592 ProgressVal_Cur += size;
2593 if (OpenCallback)
2594 if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22))
2595 {
2596
2597 RINOK(OpenCallback->SetCompleted(
2598 &ProgressVal_NumFilesTotal,
2599 &ProgressVal_Cur));
2600 ProgressVal_Prev = ProgressVal_Cur;
2601 }
2602 }
2603 }
2604
2605 if (node.Has_UNCOMPRESSED_SIZE())
2606 if (IsViDef(node.DecmpfsIndex))
2498 { 2607 {
2499 CByteBuffer buf2; 2608 CAttr &attr = node.Attrs[node.DecmpfsIndex];
2500 buf2.Alloc(size); 2609 node.CompressHeader.Parse(attr.Data, attr.Data.Size());
2501 if (ReadStream_FAIL(inStream, buf2, size) == S_OK) 2610
2502 attr.Data = buf2; 2611 if (node.CompressHeader.IsCorrect)
2612 if (node.CompressHeader.Method < sizeof(MethodsMask) * 8)
2613 MethodsMask |= ((UInt32)1 << node.CompressHeader.Method);
2614
2615 if (node.CompressHeader.IsCorrect
2616 && node.CompressHeader.IsSupported
2617 && node.CompressHeader.UnpackSize == node.uncompressed_size)
2618 {
2619 attr.NeedShow = false;
2620 if (node.CompressHeader.IsMethod_Resource()
2621 && IsViDef(node.ResourceIndex))
2622 node.Attrs[node.ResourceIndex].NeedShow = false;
2623 }
2624 else
2625 {
2626 vol.UnsupportedFeature = true;
2627 }
2503 } 2628 }
2504 } 2629 }
2505 } 2630 }
2506 2631
2507 const HRESULT res = vol.FillRefs(); 2632 const HRESULT res = vol.FillRefs();
2508 2633
2509 if (vol.ThereAreErrors()) 2634 if (vol.ThereAreErrors())
@@ -2521,9 +2646,10 @@ HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2521HRESULT CVol::FillRefs() 2646HRESULT CVol::FillRefs()
2522{ 2647{
2523 { 2648 {
2649 Refs.Reserve(Items.Size());
2524 // we fill Refs[*] 2650 // we fill Refs[*]
2525 // we 2651 // we
2526 // and set Nodes[*].ItemIndex for Nodes that are dictories; 2652 // and set Nodes[*].ItemIndex for Nodes that are directories;
2527 FOR_VECTOR (i, Items) 2653 FOR_VECTOR (i, Items)
2528 { 2654 {
2529 CItem &item = Items[i]; 2655 CItem &item = Items[i];
@@ -2593,12 +2719,17 @@ HRESULT CVol::FillRefs()
2593 ref.ParentRefIndex = item.RefIndex; 2719 ref.ParentRefIndex = item.RefIndex;
2594 for (unsigned k = 0; k < numAttrs; k++) 2720 for (unsigned k = 0; k < numAttrs; k++)
2595 { 2721 {
2722 // comment it for debug
2723 const CAttr &attr = inode.Attrs[k];
2724 if (!attr.NeedShow)
2725 continue;
2726
2596 if (k == inode.SymLinkIndex) 2727 if (k == inode.SymLinkIndex)
2597 continue; 2728 continue;
2598 ref.AttrIndex = k; 2729 ref.AttrIndex = k;
2730 NumAltStreams++;
2599 Refs.Add(ref); 2731 Refs.Add(ref);
2600 /* 2732 /*
2601 const CAttr &attr = inode.Attrs[k];
2602 if (attr.dstream_defined) 2733 if (attr.dstream_defined)
2603 { 2734 {
2604 const int idIndex = SmallNodeIDs.FindInSorted(attr.Id); 2735 const int idIndex = SmallNodeIDs.FindInSorted(attr.Id);
@@ -2780,6 +2911,7 @@ enum
2780 kpidAddTime, 2911 kpidAddTime,
2781 kpidGeneration, 2912 kpidGeneration,
2782 kpidBsdFlags 2913 kpidBsdFlags
2914 // kpidUncompressedSize
2783}; 2915};
2784 2916
2785static const CStatProp kProps[] = 2917static const CStatProp kProps[] =
@@ -2793,11 +2925,13 @@ static const CStatProp kProps[] =
2793 { NULL, kpidATime, VT_FILETIME }, 2925 { NULL, kpidATime, VT_FILETIME },
2794 { NULL, kpidChangeTime, VT_FILETIME }, 2926 { NULL, kpidChangeTime, VT_FILETIME },
2795 { "Added Time", kpidAddTime, VT_FILETIME }, 2927 { "Added Time", kpidAddTime, VT_FILETIME },
2928 { NULL, kpidMethod, VT_BSTR },
2796 { NULL, kpidINode, VT_UI8 }, 2929 { NULL, kpidINode, VT_UI8 },
2797 { NULL, kpidLinks, VT_UI4 }, 2930 { NULL, kpidLinks, VT_UI4 },
2798 { NULL, kpidSymLink, VT_BSTR }, 2931 { NULL, kpidSymLink, VT_BSTR },
2799 { NULL, kpidUserId, VT_UI4 }, 2932 { NULL, kpidUserId, VT_UI4 },
2800 { NULL, kpidGroupId, VT_UI4 }, 2933 { NULL, kpidGroupId, VT_UI4 },
2934 { NULL, kpidCharacts, VT_BSTR },
2801 #ifdef APFS_SHOW_ALT_STREAMS 2935 #ifdef APFS_SHOW_ALT_STREAMS
2802 { NULL, kpidIsAltStream, VT_BOOL }, 2936 { NULL, kpidIsAltStream, VT_BOOL },
2803 #endif 2937 #endif
@@ -2807,12 +2941,14 @@ static const CStatProp kProps[] =
2807 { "Written Size", kpidBytesWritten, VT_UI8 }, 2941 { "Written Size", kpidBytesWritten, VT_UI8 },
2808 { "Read Size", kpidBytesRead, VT_UI8 }, 2942 { "Read Size", kpidBytesRead, VT_UI8 },
2809 { "BSD Flags", kpidBsdFlags, VT_UI4 } 2943 { "BSD Flags", kpidBsdFlags, VT_UI4 }
2944 // , { "Uncompressed Size", kpidUncompressedSize, VT_UI8 }
2810}; 2945};
2811 2946
2812 2947
2813static const Byte kArcProps[] = 2948static const Byte kArcProps[] =
2814{ 2949{
2815 kpidName, 2950 kpidName,
2951 kpidCharacts,
2816 kpidId, 2952 kpidId,
2817 kpidClusterSize, 2953 kpidClusterSize,
2818 kpidCTime, 2954 kpidCTime,
@@ -2848,6 +2984,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
2848 prop = (UInt64)sb.block_count << sb.block_size_Log; 2984 prop = (UInt64)sb.block_count << sb.block_size_Log;
2849 break; 2985 break;
2850 case kpidClusterSize: prop = (UInt32)(sb.block_size); break; 2986 case kpidClusterSize: prop = (UInt32)(sb.block_size); break;
2987 case kpidCharacts: NHfs::MethodsMaskToProp(MethodsMask, prop); break;
2851 case kpidMTime: 2988 case kpidMTime:
2852 if (apfs) 2989 if (apfs)
2853 ApfsTimeToProp(apfs->modified_by[0].timestamp, prop); 2990 ApfsTimeToProp(apfs->modified_by[0].timestamp, prop);
@@ -2953,7 +3090,6 @@ STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentTyp
2953 const CRef2 &ref2 = Refs2[index]; 3090 const CRef2 &ref2 = Refs2[index];
2954 const CVol &vol = Vols[ref2.VolIndex]; 3091 const CVol &vol = Vols[ref2.VolIndex];
2955 UInt32 parentIndex = (UInt32)(Int32)-1; 3092 UInt32 parentIndex = (UInt32)(Int32)-1;
2956 *parentType = NParentType::kDir;
2957 3093
2958 if (IsViDef(ref2.RefIndex)) 3094 if (IsViDef(ref2.RefIndex))
2959 { 3095 {
@@ -3017,6 +3153,7 @@ void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::
3017 { 3153 {
3018 const CRef &ref = vol.Refs[ref2.RefIndex]; 3154 const CRef &ref = vol.Refs[ref2.RefIndex];
3019 unsigned cur = ref.ItemIndex; 3155 unsigned cur = ref.ItemIndex;
3156 UString s2;
3020 if (IsViNotDef(cur)) 3157 if (IsViNotDef(cur))
3021 { 3158 {
3022 if (inode) 3159 if (inode)
@@ -3032,14 +3169,13 @@ void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::
3032 break; 3169 break;
3033 } 3170 }
3034 const CItem &item = vol.Items[(unsigned)cur]; 3171 const CItem &item = vol.Items[(unsigned)cur];
3035 UString s2;
3036 Utf8Name_to_InterName(item.Name, s2); 3172 Utf8Name_to_InterName(item.Name, s2);
3037 // s2 += "a\\b"; // for debug 3173 // s2 += "a\\b"; // for debug
3038 s.Insert(0, s2); 3174 s.Insert(0, s2);
3039 cur = item.ParentItemIndex; 3175 cur = item.ParentItemIndex;
3040 if (IsViNotDef(cur)) 3176 if (IsViNotDef(cur))
3041 break; 3177 break;
3042 // ParentItemIndex was not set for sch items 3178 // ParentItemIndex was not set for such items
3043 // if (item.ParentId == ROOT_DIR_INO_NUM) break; 3179 // if (item.ParentId == ROOT_DIR_INO_NUM) break;
3044 s.InsertAtFront(WCHAR_PATH_SEPARATOR); 3180 s.InsertAtFront(WCHAR_PATH_SEPARATOR);
3045 } 3181 }
@@ -3049,7 +3185,6 @@ void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::
3049 if (IsViDef(ref.AttrIndex) && inode) 3185 if (IsViDef(ref.AttrIndex) && inode)
3050 { 3186 {
3051 s += ':'; 3187 s += ':';
3052 UString s2;
3053 Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2); 3188 Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2);
3054 // s2 += "a\\b"; // for debug 3189 // s2 += "a\\b"; // for debug
3055 s += s2; 3190 s += s2;
@@ -3110,11 +3245,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3110 break; 3245 break;
3111 case kpidPrimeName: 3246 case kpidPrimeName:
3112 { 3247 {
3113 if (inode 3248 #ifdef APFS_SHOW_ALT_STREAMS
3114 #ifdef APFS_SHOW_ALT_STREAMS 3249 if (!ref.IsAltStream())
3115 && !ref.IsAltStream() 3250 #endif
3116 #endif 3251 if (inode && !inode->PrimaryName.IsEmpty())
3117 && !inode->PrimaryName.IsEmpty())
3118 { 3252 {
3119 UString s; 3253 UString s;
3120 ConvertUTF8ToUnicode(inode->PrimaryName, s); 3254 ConvertUTF8ToUnicode(inode->PrimaryName, s);
@@ -3155,6 +3289,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3155 } 3289 }
3156 3290
3157 case kpidSymLink: 3291 case kpidSymLink:
3292 #ifdef APFS_SHOW_ALT_STREAMS
3293 if (!ref.IsAltStream())
3294 #endif
3158 if (inode) 3295 if (inode)
3159 { 3296 {
3160 if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex)) 3297 if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex))
@@ -3178,8 +3315,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3178 case kpidSize: 3315 case kpidSize:
3179 if (inode) 3316 if (inode)
3180 { 3317 {
3181 UInt64 size; 3318 UInt64 size = 0;
3182 if (inode->GetSize(ref.GetAttrIndex(), size)) 3319 if (inode->GetSize(ref.GetAttrIndex(), size) ||
3320 !inode->IsDir())
3183 prop = size; 3321 prop = size;
3184 } 3322 }
3185 break; 3323 break;
@@ -3188,18 +3326,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3188 if (inode) 3326 if (inode)
3189 { 3327 {
3190 UInt64 size; 3328 UInt64 size;
3191 if (inode->GetPackSize(ref.GetAttrIndex(), size)) 3329 if (inode->GetPackSize(ref.GetAttrIndex(), size) ||
3330 !inode->IsDir())
3192 prop = size; 3331 prop = size;
3193 } 3332 }
3194 break; 3333 break;
3195 3334
3335 case kpidMethod:
3336 #ifdef APFS_SHOW_ALT_STREAMS
3337 if (!ref.IsAltStream())
3338 #endif
3339 if (inode)
3340 {
3341 if (inode->CompressHeader.IsCorrect)
3342 inode->CompressHeader.MethodToProp(prop);
3343 else if (IsViDef(inode->DecmpfsIndex))
3344 prop = "decmpfs";
3345 else if (!inode->IsDir() && !inode->dstream_defined)
3346 {
3347 if (inode->IsSymLink())
3348 {
3349 if (IsViDef(inode->SymLinkIndex))
3350 prop = "symlink";
3351 }
3352 // else prop = "no_dstream";
3353 }
3354 }
3355 break;
3356
3357 /*
3358 case kpidUncompressedSize:
3359 if (inode && inode->Has_UNCOMPRESSED_SIZE())
3360 prop = inode->uncompressed_size;
3361 break;
3362 */
3363
3196 case kpidIsDir: 3364 case kpidIsDir:
3197 { 3365 {
3198 bool isDir = false; 3366 bool isDir = false;
3199 if (inode) 3367 #ifdef APFS_SHOW_ALT_STREAMS
3200 isDir = inode->IsDir(); 3368 if (!ref.IsAltStream())
3201 else if (item) 3369 #endif
3202 isDir = item->Val.IsFlags_Dir(); 3370 {
3371 if (inode)
3372 isDir = inode->IsDir();
3373 else if (item)
3374 isDir = item->Val.IsFlags_Dir();
3375 }
3203 prop = isDir; 3376 prop = isDir;
3204 break; 3377 break;
3205 } 3378 }
@@ -3251,6 +3424,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3251 #endif 3424 #endif
3252 3425
3253 case kpidCharacts: 3426 case kpidCharacts:
3427 #ifdef APFS_SHOW_ALT_STREAMS
3428 if (!ref.IsAltStream())
3429 #endif
3254 if (inode) 3430 if (inode)
3255 { 3431 {
3256 FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop); 3432 FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop);
@@ -3258,6 +3434,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3258 break; 3434 break;
3259 3435
3260 case kpidBsdFlags: 3436 case kpidBsdFlags:
3437 #ifdef APFS_SHOW_ALT_STREAMS
3438 if (!ref.IsAltStream())
3439 #endif
3261 if (inode) 3440 if (inode)
3262 { 3441 {
3263 FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop); 3442 FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop);
@@ -3265,6 +3444,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3265 break; 3444 break;
3266 3445
3267 case kpidGeneration: 3446 case kpidGeneration:
3447 #ifdef APFS_SHOW_ALT_STREAMS
3448 // if (!ref.IsAltStream())
3449 #endif
3268 if (inode) 3450 if (inode)
3269 prop = inode->write_generation_counter; 3451 prop = inode->write_generation_counter;
3270 break; 3452 break;
@@ -3280,6 +3462,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3280 break; 3462 break;
3281 3463
3282 case kpidLinks: 3464 case kpidLinks:
3465 #ifdef APFS_SHOW_ALT_STREAMS
3466 if (!ref.IsAltStream())
3467 #endif
3283 if (inode && !inode->IsDir()) 3468 if (inode && !inode->IsDir())
3284 prop = (UInt32)inode->nlink; 3469 prop = (UInt32)inode->nlink;
3285 break; 3470 break;
@@ -3287,13 +3472,16 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
3287 case kpidINode: 3472 case kpidINode:
3288 #ifdef APFS_SHOW_ALT_STREAMS 3473 #ifdef APFS_SHOW_ALT_STREAMS
3289 // here we can disable iNode for alt stream. 3474 // here we can disable iNode for alt stream.
3290 // if (!ref.IsAltStream()) 3475 if (!ref.IsAltStream())
3291 #endif 3476 #endif
3292 if (IsViDef(ref.NodeIndex)) 3477 if (IsViDef(ref.NodeIndex))
3293 prop = (UInt32)vol.NodeIDs[ref.NodeIndex]; 3478 prop = (UInt32)vol.NodeIDs[ref.NodeIndex];
3294 break; 3479 break;
3295 3480
3296 case kpidParentINode: 3481 case kpidParentINode:
3482 #ifdef APFS_SHOW_ALT_STREAMS
3483 if (!ref.IsAltStream())
3484 #endif
3297 if (inode) 3485 if (inode)
3298 prop = (UInt32)inode->parent_id; 3486 prop = (UInt32)inode->parent_id;
3299 break; 3487 break;
@@ -3351,6 +3539,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
3351 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); 3539 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
3352 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; 3540 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
3353 3541
3542 NHfs::CDecoder decoder;
3543
3354 for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) 3544 for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
3355 { 3545 {
3356 lps->InSize = currentTotalSize; 3546 lps->InSize = currentTotalSize;
@@ -3399,15 +3589,68 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
3399 RINOK(extractCallback->PrepareOperation(askMode)); 3589 RINOK(extractCallback->PrepareOperation(askMode));
3400 int opRes = NExtract::NOperationResult::kDataError; 3590 int opRes = NExtract::NOperationResult::kDataError;
3401 3591
3402 CMyComPtr<ISequentialInStream> inStream; 3592 if (IsViDef(ref.NodeIndex))
3403 if (GetStream(index, &inStream) == S_OK && inStream)
3404 { 3593 {
3405 RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); 3594 const CNode &inode = vol.Nodes[ref.NodeIndex];
3406 opRes = NExtract::NOperationResult::kDataError; 3595 if (
3407 if (copyCoderSpec->TotalSize == currentItemSize) 3596 #ifdef APFS_SHOW_ALT_STREAMS
3408 opRes = NExtract::NOperationResult::kOK; 3597 !ref.IsAltStream() &&
3409 else if (copyCoderSpec->TotalSize < currentItemSize) 3598 #endif
3410 opRes = NExtract::NOperationResult::kUnexpectedEnd; 3599 !inode.dstream_defined
3600 && inode.Extents.IsEmpty()
3601 && inode.Has_UNCOMPRESSED_SIZE()
3602 && inode.uncompressed_size == inode.CompressHeader.UnpackSize)
3603 {
3604 if (inode.CompressHeader.IsSupported)
3605 {
3606 CMyComPtr<ISequentialInStream> inStreamFork;
3607 UInt64 forkSize = 0;
3608 const CByteBuffer *decmpfs_Data = NULL;
3609
3610 if (inode.CompressHeader.IsMethod_Resource())
3611 {
3612 if (IsViDef(inode.ResourceIndex))
3613 {
3614 const CAttr &attr = inode.Attrs[inode.ResourceIndex];
3615 forkSize = attr.GetSize();
3616 GetAttrStream(_stream, vol, attr, &inStreamFork);
3617 }
3618 }
3619 else
3620 {
3621 const CAttr &attr = inode.Attrs[inode.DecmpfsIndex];
3622 decmpfs_Data = &attr.Data;
3623 }
3624
3625 if (inStreamFork || decmpfs_Data)
3626 {
3627 const HRESULT hres = decoder.Extract(
3628 inStreamFork, realOutStream,
3629 forkSize,
3630 inode.CompressHeader,
3631 decmpfs_Data,
3632 currentTotalSize, extractCallback,
3633 opRes);
3634 if (hres != S_FALSE && hres != S_OK)
3635 return hres;
3636 }
3637 }
3638 else
3639 opRes = NExtract::NOperationResult::kUnsupportedMethod;
3640 }
3641 else
3642 {
3643 CMyComPtr<ISequentialInStream> inStream;
3644 if (GetStream(index, &inStream) == S_OK && inStream)
3645 {
3646 RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
3647 opRes = NExtract::NOperationResult::kDataError;
3648 if (copyCoderSpec->TotalSize == currentItemSize)
3649 opRes = NExtract::NOperationResult::kOK;
3650 else if (copyCoderSpec->TotalSize < currentItemSize)
3651 opRes = NExtract::NOperationResult::kUnexpectedEnd;
3652 }
3653 }
3411 } 3654 }
3412 3655
3413 realOutStream.Release(); 3656 realOutStream.Release();
@@ -3478,7 +3721,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
3478 if (inode.IsDir()) 3721 if (inode.IsDir())
3479 return S_FALSE; 3722 return S_FALSE;
3480 if (inode.dstream_defined) 3723 if (inode.dstream_defined)
3724 {
3481 rem = inode.dstream.size; 3725 rem = inode.dstream.size;
3726 }
3727 else
3728 {
3729 // return S_FALSE; // check it !!! How zero size files are stored with dstream_defined?
3730 }
3731
3482 extents = &inode.Extents; 3732 extents = &inode.Extents;
3483 } 3733 }
3484 return GetStream2(_stream, extents, rem, stream); 3734 return GetStream2(_stream, extents, rem, stream);
@@ -3486,6 +3736,35 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
3486 3736
3487 3737
3488 3738
3739HRESULT CDatabase::GetAttrStream(IInStream *apfsInStream, const CVol &vol,
3740 const CAttr &attr, ISequentialInStream **stream)
3741{
3742 *stream = NULL;
3743 if (!attr.dstream_defined)
3744 {
3745 CBufInStream *streamSpec = new CBufInStream;
3746 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
3747 streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this);
3748 *stream = streamTemp.Detach();
3749 return S_OK;
3750 }
3751 return GetAttrStream_dstream(apfsInStream, vol, attr, stream);
3752}
3753
3754
3755HRESULT CDatabase::GetAttrStream_dstream( IInStream *apfsInStream, const CVol &vol,
3756 const CAttr &attr, ISequentialInStream **stream)
3757{
3758 const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
3759 if (idIndex == -1)
3760 return S_FALSE;
3761 return GetStream2(apfsInStream,
3762 &vol.SmallNodes[(unsigned)idIndex].Extents,
3763 attr.dstream.size,
3764 stream);
3765}
3766
3767
3489HRESULT CDatabase::GetStream2( 3768HRESULT CDatabase::GetStream2(
3490 IInStream *apfsInStream, 3769 IInStream *apfsInStream,
3491 const CRecordVector<CExtent> *extents, UInt64 rem, 3770 const CRecordVector<CExtent> *extents, UInt64 rem,
diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h
index 7cba0c7..2d77366 100644
--- a/CPP/7zip/Archive/Chm/ChmIn.h
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -126,6 +126,7 @@ struct CLzxInfo
126 CLzxInfo(): 126 CLzxInfo():
127 Version(0), 127 Version(0),
128 ResetIntervalBits(0), 128 ResetIntervalBits(0),
129 WindowSizeBits(0),
129 CacheSize(0) 130 CacheSize(0)
130 {} 131 {}
131 132
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp
index 1f2ca26..e6166f1 100644
--- a/CPP/7zip/Archive/DmgHandler.cpp
+++ b/CPP/7zip/Archive/DmgHandler.cpp
@@ -1063,6 +1063,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1063 subName.DeleteFrom(pos1); 1063 subName.DeleteFrom(pos1);
1064 } 1064 }
1065 } 1065 }
1066 else
1067 subName = item.Name; // new apfs dmg can be without braces
1066 subName.Trim(); 1068 subName.Trim();
1067 if (!subName.IsEmpty()) 1069 if (!subName.IsEmpty())
1068 { 1070 {
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
index f0a85f1..fa96b73 100644
--- a/CPP/7zip/Archive/HfsHandler.cpp
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -7,19 +7,19 @@
7#include "../../Common/ComTry.h" 7#include "../../Common/ComTry.h"
8#include "../../Common/MyString.h" 8#include "../../Common/MyString.h"
9 9
10#include "../../Windows/PropVariant.h" 10#include "../../Windows/PropVariantUtils.h"
11 11
12#include "../Common/LimitedStreams.h" 12#include "../Common/LimitedStreams.h"
13#include "../Common/RegisterArc.h" 13#include "../Common/RegisterArc.h"
14#include "../Common/StreamObjects.h" 14#include "../Common/StreamObjects.h"
15#include "../Common/StreamUtils.h" 15#include "../Common/StreamUtils.h"
16 16
17#include "../Compress/ZlibDecoder.h" 17#include "HfsHandler.h"
18 18
19/* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files 19/* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files
20 and resource forks. In most cases it looks useless. So we disable it. */ 20 and resource forks. In most cases it looks useless. So we disable it. */
21 21
22// #define HFS_SHOW_ALT_STREAMS 22#define HFS_SHOW_ALT_STREAMS
23 23
24#define Get16(p) GetBe16(p) 24#define Get16(p) GetBe16(p)
25#define Get32(p) GetBe32(p) 25#define Get32(p) GetBe32(p)
@@ -80,6 +80,8 @@ struct CFork
80}; 80};
81 81
82static const unsigned kNumFixedExtents = 8; 82static const unsigned kNumFixedExtents = 8;
83static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8;
84
83 85
84void CFork::Parse(const Byte *p) 86void CFork::Parse(const Byte *p)
85{ 87{
@@ -227,6 +229,121 @@ enum ERecordType
227 RECORD_TYPE_FILE_THREAD 229 RECORD_TYPE_FILE_THREAD
228}; 230};
229 231
232
233
234// static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr
235static const UInt32 kMethod_ZLIB_ATTR = 3;
236static const UInt32 kMethod_ZLIB_RSRC = 4;
237// static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store
238// macos 10.10
239static const UInt32 kMethod_LZVN_ATTR = 7;
240static const UInt32 kMethod_LZVN_RSRC = 8;
241static const UInt32 kMethod_COPY_ATTR = 9;
242static const UInt32 kMethod_COPY_RSRC = 10;
243// macos 10.11
244// static const UInt32 kMethod_LZFSE_ATTR = 11;
245static const UInt32 kMethod_LZFSE_RSRC = 12;
246
247static const char * const g_Methods[] =
248{
249 NULL
250 , NULL
251 , NULL
252 , "ZLIB-attr"
253 , "ZLIB-rsrc"
254 , NULL
255 , NULL
256 , "LZVN-attr"
257 , "LZVN-rsrc"
258 , "COPY-attr"
259 , "COPY-rsrc"
260 , "LZFSE-attr"
261 , "LZFSE-rsrc"
262};
263
264
265static const Byte k_COPY_Uncompressed_Marker = 0xcc;
266static const Byte k_LZVN_Uncompressed_Marker = 6;
267
268void CCompressHeader::Parse(const Byte *p, size_t dataSize)
269{
270 Clear();
271
272 if (dataSize < k_decmpfs_HeaderSize)
273 return;
274 if (GetUi32(p) != 0x636D7066) // magic == "fpmc"
275 return;
276 Method = GetUi32(p + 4);
277 UnpackSize = GetUi64(p + 8);
278 dataSize -= k_decmpfs_HeaderSize;
279 IsCorrect = true;
280
281 if ( Method == kMethod_ZLIB_RSRC
282 || Method == kMethod_COPY_RSRC
283 || Method == kMethod_LZVN_RSRC
284 || Method == kMethod_LZFSE_RSRC)
285 {
286 IsResource = true;
287 if (dataSize == 0)
288 IsSupported = (
289 Method != kMethod_LZFSE_RSRC &&
290 Method != kMethod_COPY_RSRC);
291 return;
292 }
293
294 if ( Method == kMethod_ZLIB_ATTR
295 || Method == kMethod_COPY_ATTR
296 || Method == kMethod_LZVN_ATTR
297 // || Method == kMethod_LZFSE_ATTR
298 )
299 {
300 if (dataSize == 0)
301 return;
302 const Byte b = p[k_decmpfs_HeaderSize];
303 if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf)
304 || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker)
305 || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker))
306 {
307 dataSize--;
308 // if (UnpackSize > dataSize)
309 if (UnpackSize != dataSize)
310 return;
311 DataPos = k_decmpfs_HeaderSize + 1;
312 IsSupported = true;
313 }
314 else
315 {
316 if (Method != kMethod_COPY_ATTR)
317 IsSupported = true;
318 DataPos = k_decmpfs_HeaderSize;
319 }
320 }
321}
322
323
324void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const
325{
326 if (!IsCorrect)
327 return;
328 const UInt32 method = Method;
329 const char *p = NULL;
330 if (method < ARRAY_SIZE(g_Methods))
331 p = g_Methods[method];
332 AString s;
333 if (p)
334 s = p;
335 else
336 s.Add_UInt32(method);
337 // if (!IsSupported) s += "-unsuported";
338 prop = s;
339}
340
341void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop)
342{
343 FLAGS_TO_PROP(g_Methods, methodsMask, prop);
344}
345
346
230struct CItem 347struct CItem
231{ 348{
232 UString Name; 349 UString Name;
@@ -265,54 +382,79 @@ struct CItem
265 CFork DataFork; 382 CFork DataFork;
266 CFork ResourceFork; 383 CFork ResourceFork;
267 384
268 // for compressed attribute 385 // for compressed attribute (decmpfs)
269 UInt64 UnpackSize; 386 int decmpfs_AttrIndex;
270 size_t DataPos; 387 CCompressHeader CompressHeader;
271 UInt32 PackSize;
272 unsigned Method;
273 bool UseAttr;
274 bool UseInlineData;
275 388
276 CItem(): UseAttr(false), UseInlineData(false) {} 389 CItem():
390 decmpfs_AttrIndex(-1)
391 {}
277 bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } 392 bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
278 const CFork &GetFork(bool isResource) const { return (const CFork & )*(isResource ? &ResourceFork: &DataFork ); } 393 // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); }
279}; 394};
280 395
396
281struct CAttr 397struct CAttr
282{ 398{
283 UInt32 ID; 399 UInt32 ID;
284 UInt32 Size; 400 bool Fork_defined;
285 size_t Pos; 401
402 // UInt32 Size; // for (Fork_defined == false) case
403 // size_t DataPos; // for (Fork_defined == false) case
404 CByteBuffer Data;
405
406 CFork Fork;
407
286 UString Name; 408 UString Name;
409
410 UInt64 GetSize() const
411 {
412 if (Fork_defined)
413 return Fork.Size;
414 return Data.Size();
415 }
416
417 CAttr():
418 Fork_defined(false)
419 // Size(0),
420 // DataPos(0),
421 {}
287}; 422};
288 423
424
425static const int kAttrIndex_Item = -1;
426static const int kAttrIndex_Resource = -2;
427
289struct CRef 428struct CRef
290{ 429{
291 unsigned ItemIndex; 430 unsigned ItemIndex;
292 int AttrIndex; 431 int AttrIndex;
293 int Parent; 432 int Parent;
294 bool IsResource;
295 433
296 bool IsAltStream() const { return IsResource || AttrIndex >= 0; } 434 CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {}
297 CRef(): AttrIndex(-1), Parent(-1), IsResource(false) {} 435 bool IsResource() const { return AttrIndex == kAttrIndex_Resource; }
436 bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; }
437 bool IsItem() const { return AttrIndex == kAttrIndex_Item; }
298}; 438};
299 439
440
300class CDatabase 441class CDatabase
301{ 442{
302 HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); 443 HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
303 HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray); 444 HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray);
304 HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); 445 HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress);
305 HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); 446 HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress);
306 bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip); 447 bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip);
307public: 448public:
308 CRecordVector<CRef> Refs; 449 CRecordVector<CRef> Refs;
309 CObjectVector<CItem> Items; 450 CObjectVector<CItem> Items;
310 CObjectVector<CAttr> Attrs; 451 CObjectVector<CAttr> Attrs;
311 452
312 CByteBuffer AttrBuf; 453 // CByteBuffer AttrBuf;
313 454
314 CVolHeader Header; 455 CVolHeader Header;
315 bool HeadersError; 456 bool HeadersError;
457 bool UnsupportedFeature;
316 bool ThereAreAltStreams; 458 bool ThereAreAltStreams;
317 // bool CaseSensetive; 459 // bool CaseSensetive;
318 UString ResFileName; 460 UString ResFileName;
@@ -321,6 +463,7 @@ public:
321 UInt64 PhySize; 463 UInt64 PhySize;
322 UInt64 PhySize2; 464 UInt64 PhySize2;
323 UInt64 ArcFileSize; 465 UInt64 ArcFileSize;
466 UInt32 MethodsMask;
324 467
325 void Clear() 468 void Clear()
326 { 469 {
@@ -328,25 +471,30 @@ public:
328 PhySize = 0; 471 PhySize = 0;
329 PhySize2 = 0; 472 PhySize2 = 0;
330 ArcFileSize = 0; 473 ArcFileSize = 0;
474 MethodsMask = 0;
331 HeadersError = false; 475 HeadersError = false;
476 UnsupportedFeature = false;
332 ThereAreAltStreams = false; 477 ThereAreAltStreams = false;
333 // CaseSensetive = false; 478 // CaseSensetive = false;
479
334 Refs.Clear(); 480 Refs.Clear();
335 Items.Clear(); 481 Items.Clear();
336 Attrs.Clear(); 482 Attrs.Clear();
337 AttrBuf.Free(); 483 // AttrBuf.Free();
338 } 484 }
339 485
340 UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const 486 UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const
341 { 487 {
342 if (ref.AttrIndex >= 0) 488 if (ref.AttrIndex >= 0)
343 return Attrs[ref.AttrIndex].Size; 489 return Attrs[ref.AttrIndex].GetSize();
344 const CItem &item = Items[ref.ItemIndex]; 490 const CItem &item = Items[ref.ItemIndex];
491 if (ref.IsResource())
492 return item.ResourceFork.Size;
345 if (item.IsDir()) 493 if (item.IsDir())
346 return 0; 494 return 0;
347 if (item.UseAttr) 495 else if (item.CompressHeader.IsCorrect)
348 return item.UnpackSize; 496 return item.CompressHeader.UnpackSize;
349 return item.GetFork(ref.IsResource).Size; 497 return item.DataFork.Size;
350 } 498 }
351 499
352 void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const; 500 void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const;
@@ -380,7 +528,7 @@ void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path)
380 const CRef &ref = Refs[cur]; 528 const CRef &ref = Refs[cur];
381 const UString *s; 529 const UString *s;
382 530
383 if (ref.IsResource) 531 if (ref.IsResource())
384 s = &ResFileName; 532 s = &ResFileName;
385 else if (ref.AttrIndex >= 0) 533 else if (ref.AttrIndex >= 0)
386 s = &Attrs[ref.AttrIndex].Name; 534 s = &Attrs[ref.AttrIndex].Name;
@@ -405,7 +553,7 @@ void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path)
405 const UString *s; 553 const UString *s;
406 wchar_t delimChar = L':'; 554 wchar_t delimChar = L':';
407 555
408 if (ref.IsResource) 556 if (ref.IsResource())
409 s = &ResFileName; 557 s = &ResFileName;
410 else if (ref.AttrIndex >= 0) 558 else if (ref.AttrIndex >= 0)
411 s = &Attrs[ref.AttrIndex].Name; 559 s = &Attrs[ref.AttrIndex].Name;
@@ -596,6 +744,8 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec
596 UInt32 node = hr.FirstLeafNode; 744 UInt32 node = hr.FirstLeafNode;
597 if (node == 0) 745 if (node == 0)
598 return S_OK; 746 return S_OK;
747 if (hr.TotalNodes == 0)
748 return S_FALSE;
599 749
600 CByteArr usedBuf(hr.TotalNodes); 750 CByteArr usedBuf(hr.TotalNodes);
601 memset(usedBuf, 0, hr.TotalNodes); 751 memset(usedBuf, 0, hr.TotalNodes);
@@ -617,7 +767,7 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec
617 767
618 for (unsigned i = 0; i < desc.NumRecords; i++) 768 for (unsigned i = 0; i < desc.NumRecords; i++)
619 { 769 {
620 const UInt32 nodeSize = (1 << hr.NodeSizeLog); 770 const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog);
621 const Byte *r = p + nodeOffset + nodeSize - i * 2; 771 const Byte *r = p + nodeOffset + nodeSize - i * 2;
622 const UInt32 offs = Get16(r - 2); 772 const UInt32 offs = Get16(r - 2);
623 UInt32 recSize = Get16(r - 4) - offs; 773 UInt32 recSize = Get16(r - 4) - offs;
@@ -630,7 +780,7 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec
630 if (Get16(r) != kKeyLen) 780 if (Get16(r) != kKeyLen)
631 return S_FALSE; 781 return S_FALSE;
632 782
633 Byte forkType = r[2]; 783 const Byte forkType = r[2];
634 unsigned forkTypeIndex; 784 unsigned forkTypeIndex;
635 if (forkType == kExtentForkType_Data) 785 if (forkType == kExtentForkType_Data)
636 forkTypeIndex = 0; 786 forkTypeIndex = 0;
@@ -640,8 +790,8 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec
640 continue; 790 continue;
641 CObjectVector<CIdExtents> &overflowExtents = overflowExtentsArray[forkTypeIndex]; 791 CObjectVector<CIdExtents> &overflowExtents = overflowExtentsArray[forkTypeIndex];
642 792
643 UInt32 id = Get32(r + 4); 793 const UInt32 id = Get32(r + 4);
644 UInt32 startBlock = Get32(r + 8); 794 const UInt32 startBlock = Get32(r + 8);
645 r += 2 + kKeyLen; 795 r += 2 + kKeyLen;
646 796
647 bool needNew = true; 797 bool needNew = true;
@@ -691,7 +841,7 @@ static void LoadName(const Byte *data, unsigned len, UString &dest)
691 unsigned i; 841 unsigned i;
692 for (i = 0; i < len; i++) 842 for (i = 0; i < len; i++)
693 { 843 {
694 wchar_t c = Get16(data + i * 2); 844 const wchar_t c = Get16(data + i * 2);
695 if (c == 0) 845 if (c == 0)
696 break; 846 break;
697 p[i] = c; 847 p[i] = c;
@@ -704,7 +854,7 @@ static bool IsNameEqualTo(const Byte *data, const char *name)
704{ 854{
705 for (unsigned i = 0;; i++) 855 for (unsigned i = 0;; i++)
706 { 856 {
707 char c = name[i]; 857 const char c = name[i];
708 if (c == 0) 858 if (c == 0)
709 return true; 859 return true;
710 if (Get16(data + i * 2) != (Byte)c) 860 if (Get16(data + i * 2) != (Byte)c)
@@ -713,7 +863,7 @@ static bool IsNameEqualTo(const Byte *data, const char *name)
713} 863}
714 864
715static const UInt32 kAttrRecordType_Inline = 0x10; 865static const UInt32 kAttrRecordType_Inline = 0x10;
716// static const UInt32 kAttrRecordType_Fork = 0x20; 866static const UInt32 kAttrRecordType_Fork = 0x20;
717// static const UInt32 kAttrRecordType_Extents = 0x30; 867// static const UInt32 kAttrRecordType_Extents = 0x30;
718 868
719HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress) 869HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress)
@@ -721,6 +871,7 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe
721 if (fork.NumBlocks == 0) 871 if (fork.NumBlocks == 0)
722 return S_OK; 872 return S_OK;
723 873
874 CByteBuffer AttrBuf;
724 RINOK(ReadFile(fork, AttrBuf, inStream)); 875 RINOK(ReadFile(fork, AttrBuf, inStream));
725 const Byte *p = (const Byte *)AttrBuf; 876 const Byte *p = (const Byte *)AttrBuf;
726 877
@@ -734,7 +885,9 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe
734 UInt32 node = hr.FirstLeafNode; 885 UInt32 node = hr.FirstLeafNode;
735 if (node == 0) 886 if (node == 0)
736 return S_OK; 887 return S_OK;
737 888 if (hr.TotalNodes == 0)
889 return S_FALSE;
890
738 CByteArr usedBuf(hr.TotalNodes); 891 CByteArr usedBuf(hr.TotalNodes);
739 memset(usedBuf, 0, hr.TotalNodes); 892 memset(usedBuf, 0, hr.TotalNodes);
740 893
@@ -755,7 +908,7 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe
755 908
756 for (unsigned i = 0; i < desc.NumRecords; i++) 909 for (unsigned i = 0; i < desc.NumRecords; i++)
757 { 910 {
758 const UInt32 nodeSize = (1 << hr.NodeSizeLog); 911 const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog);
759 const Byte *r = p + nodeOffset + nodeSize - i * 2; 912 const Byte *r = p + nodeOffset + nodeSize - i * 2;
760 const UInt32 offs = Get16(r - 2); 913 const UInt32 offs = Get16(r - 2);
761 UInt32 recSize = Get16(r - 4) - offs; 914 UInt32 recSize = Get16(r - 4) - offs;
@@ -764,18 +917,18 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe
764 return S_FALSE; 917 return S_FALSE;
765 918
766 r = p + nodeOffset + offs; 919 r = p + nodeOffset + offs;
767 UInt32 keyLen = Get16(r); 920 const UInt32 keyLen = Get16(r);
768 921
769 // UInt16 pad = Get16(r + 2); 922 // UInt16 pad = Get16(r + 2);
770 UInt32 fileID = Get32(r + 4); 923 const UInt32 fileID = Get32(r + 4);
771 unsigned startBlock = Get32(r + 8); 924 const unsigned startBlock = Get32(r + 8);
772 if (startBlock != 0) 925 if (startBlock != 0)
773 { 926 {
774 // that case is still unsupported 927 // that case is still unsupported
775 HeadersError = true; 928 UnsupportedFeature = true;
776 continue; 929 continue;
777 } 930 }
778 unsigned nameLen = Get16(r + 12); 931 const unsigned nameLen = Get16(r + 12);
779 932
780 if (keyLen + 2 > recSize || 933 if (keyLen + 2 > recSize ||
781 keyLen != kHeadSize - 2 + nameLen * 2) 934 keyLen != kHeadSize - 2 + nameLen * 2)
@@ -790,36 +943,56 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe
790 if (recSize < 4) 943 if (recSize < 4)
791 return S_FALSE; 944 return S_FALSE;
792 945
793 UInt32 recordType = Get32(r); 946 const UInt32 recordType = Get32(r);
794 if (recordType != kAttrRecordType_Inline) 947
948 if (progress && (Attrs.Size() & 0xFFF) == 0)
795 { 949 {
796 // Probably only kAttrRecordType_Inline now is used in real HFS files 950 const UInt64 numFiles = 0;
797 HeadersError = true; 951 RINOK(progress->SetCompleted(&numFiles, NULL));
798 continue;
799 } 952 }
800 953
801 const UInt32 kRecordHeaderSize = 16; 954 if (Attrs.Size() >= ((UInt32)1 << 31))
802 if (recSize < kRecordHeaderSize)
803 return S_FALSE;
804 UInt32 dataSize = Get32(r + 12);
805
806 r += kRecordHeaderSize;
807 recSize -= kRecordHeaderSize;
808
809 if (recSize < dataSize)
810 return S_FALSE; 955 return S_FALSE;
811 956
812 CAttr &attr = Attrs.AddNew(); 957 CAttr &attr = Attrs.AddNew();
813 attr.ID = fileID; 958 attr.ID = fileID;
814 attr.Pos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize;
815 attr.Size = dataSize;
816 LoadName(name, nameLen, attr.Name); 959 LoadName(name, nameLen, attr.Name);
817 960
818 if (progress && (i & 0xFFF) == 0) 961 if (recordType == kAttrRecordType_Fork)
819 { 962 {
820 const UInt64 numFiles = 0; 963 // 22.00 : some hfs files contain it;
821 RINOK(progress->SetCompleted(&numFiles, NULL)); 964 /* spec: If the attribute has more than 8 extents, there will be additional
965 records (of type kAttrRecordType_Extents) for this attribute. */
966 if (recSize != 8 + kForkRecSize)
967 return S_FALSE;
968 if (Get32(r + 4) != 0) // reserved
969 return S_FALSE;
970 attr.Fork.Parse(r + 8);
971 attr.Fork_defined = true;
972 continue;
973 }
974 else if (recordType != kAttrRecordType_Inline)
975 {
976 UnsupportedFeature = true;
977 continue;
822 } 978 }
979
980 const unsigned kRecordHeaderSize = 16;
981 if (recSize < kRecordHeaderSize)
982 return S_FALSE;
983 if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved
984 return S_FALSE;
985 const UInt32 dataSize = Get32(r + 12);
986
987 r += kRecordHeaderSize;
988 recSize -= kRecordHeaderSize;
989
990 if (recSize < dataSize)
991 return S_FALSE;
992
993 attr.Data.CopyFrom(r, dataSize);
994 // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize;
995 // attr.Size = dataSize;
823 } 996 }
824 997
825 node = desc.fLink; 998 node = desc.fLink;
@@ -827,62 +1000,28 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe
827 return S_OK; 1000 return S_OK;
828} 1001}
829 1002
830static const UInt32 kMethod_Attr = 3; // data stored in attribute file
831static const UInt32 kMethod_Resource = 4; // data stored in resource fork
832 1003
833bool CDatabase::Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip) 1004bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip)
834{ 1005{
1006 const CAttr &attr = Attrs[attrIndex];
835 skip = false; 1007 skip = false;
836 if (!attr.Name.IsEqualTo("com.apple.decmpfs")) 1008 if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty())
837 return true;
838 if (item.UseAttr || !item.DataFork.IsEmpty())
839 return false; 1009 return false;
840 1010
841 const UInt32 k_decmpfs_headerSize = 16; 1011 item.CompressHeader.Parse(attr.Data, attr.Data.Size());
842 UInt32 dataSize = attr.Size; 1012
843 if (dataSize < k_decmpfs_headerSize) 1013 if (item.CompressHeader.IsCorrect)
844 return false;
845 const Byte *r = AttrBuf + attr.Pos;
846 if (GetUi32(r) != 0x636D7066) // magic == "fpmc"
847 return false;
848 item.Method = GetUi32(r + 4);
849 item.UnpackSize = GetUi64(r + 8);
850 dataSize -= k_decmpfs_headerSize;
851 r += k_decmpfs_headerSize;
852 if (item.Method == kMethod_Resource)
853 { 1014 {
854 if (dataSize != 0) 1015 item.decmpfs_AttrIndex = attrIndex;
855 return false; 1016 skip = true;
856 item.UseAttr = true; 1017 if (item.CompressHeader.Method < sizeof(MethodsMask) * 8)
1018 MethodsMask |= ((UInt32)1 << item.CompressHeader.Method);
857 } 1019 }
858 else if (item.Method == kMethod_Attr) 1020
859 {
860 if (dataSize == 0)
861 return false;
862 Byte b = r[0];
863 if ((b & 0xF) == 0xF)
864 {
865 dataSize--;
866 if (item.UnpackSize > dataSize)
867 return false;
868 item.DataPos = attr.Pos + k_decmpfs_headerSize + 1;
869 item.PackSize = dataSize;
870 item.UseAttr = true;
871 item.UseInlineData = true;
872 }
873 else
874 {
875 item.DataPos = attr.Pos + k_decmpfs_headerSize;
876 item.PackSize = dataSize;
877 item.UseAttr = true;
878 }
879 }
880 else
881 return false;
882 skip = true;
883 return true; 1021 return true;
884} 1022}
885 1023
1024
886HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) 1025HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress)
887{ 1026{
888 CByteBuffer buf; 1027 CByteBuffer buf;
@@ -911,7 +1050,8 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
911 // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); 1050 // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
912 1051
913 CByteArr usedBuf(hr.TotalNodes); 1052 CByteArr usedBuf(hr.TotalNodes);
914 memset(usedBuf, 0, hr.TotalNodes); 1053 if (hr.TotalNodes != 0)
1054 memset(usedBuf, 0, hr.TotalNodes);
915 1055
916 CFork resFork; 1056 CFork resFork;
917 1057
@@ -1037,7 +1177,6 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1037 else 1177 else
1038 { 1178 {
1039 numFiles++; 1179 numFiles++;
1040 const unsigned kForkRecSize = 16 + kNumFixedExtents * 8;
1041 if (recSize != kForkRecSize * 2) 1180 if (recSize != kForkRecSize * 2)
1042 return S_FALSE; 1181 return S_FALSE;
1043 1182
@@ -1051,7 +1190,7 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1051 { 1190 {
1052 if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog)) 1191 if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog))
1053 HeadersError = true; 1192 HeadersError = true;
1054 ThereAreAltStreams = true; 1193 // ThereAreAltStreams = true;
1055 } 1194 }
1056 } 1195 }
1057 if (progress && (Items.Size() & 0xFFF) == 0) 1196 if (progress && (Items.Size() & 0xFFF) == 0)
@@ -1086,14 +1225,18 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1086 { 1225 {
1087 const CAttr &attr = Attrs[i]; 1226 const CAttr &attr = Attrs[i];
1088 1227
1089 int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); 1228 const int itemIndex = FindItemIndex(IdToIndexMap, attr.ID);
1090 if (itemIndex < 0) 1229 if (itemIndex < 0)
1091 { 1230 {
1092 HeadersError = true; 1231 HeadersError = true;
1093 continue; 1232 continue;
1094 } 1233 }
1095 if (!Parse_decmpgfs(attr, Items[itemIndex], skipAttr[i])) 1234
1096 HeadersError = true; 1235 if (attr.Name.IsEqualTo("com.apple.decmpfs"))
1236 {
1237 if (!Parse_decmpgfs(i, Items[itemIndex], skipAttr[i]))
1238 HeadersError = true;
1239 }
1097 } 1240 }
1098 } 1241 }
1099 1242
@@ -1117,13 +1260,13 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1117 1260
1118 if (item.ResourceFork.IsEmpty()) 1261 if (item.ResourceFork.IsEmpty())
1119 continue; 1262 continue;
1120 if (item.UseAttr && item.Method == kMethod_Resource) 1263 if (item.CompressHeader.IsSupported && item.CompressHeader.IsMethod_Resource())
1121 continue; 1264 continue;
1122 CRef resRef; 1265
1123 resRef.ItemIndex = i; 1266 ThereAreAltStreams = true;
1124 resRef.IsResource = true; 1267 ref.AttrIndex = kAttrIndex_Resource;
1125 resRef.Parent = Refs.Size() - 1; 1268 ref.Parent = Refs.Size() - 1;
1126 Refs.Add(resRef); 1269 Refs.Add(ref);
1127 1270
1128 #endif 1271 #endif
1129 } 1272 }
@@ -1135,9 +1278,9 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1135 FOR_VECTOR (i, Refs) 1278 FOR_VECTOR (i, Refs)
1136 { 1279 {
1137 CRef &ref = Refs[i]; 1280 CRef &ref = Refs[i];
1138 if (ref.IsResource) 1281 if (ref.IsResource())
1139 continue; 1282 continue;
1140 CItem &item = Items[ref.ItemIndex]; 1283 const CItem &item = Items[ref.ItemIndex];
1141 ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID); 1284 ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID);
1142 if (ref.Parent >= 0) 1285 if (ref.Parent >= 0)
1143 { 1286 {
@@ -1158,13 +1301,15 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1158 continue; 1301 continue;
1159 const CAttr &attr = Attrs[i]; 1302 const CAttr &attr = Attrs[i];
1160 1303
1161 int refIndex = FindItemIndex(IdToIndexMap, attr.ID); 1304 const int refIndex = FindItemIndex(IdToIndexMap, attr.ID);
1162 if (refIndex < 0) 1305 if (refIndex < 0)
1163 { 1306 {
1164 HeadersError = true; 1307 HeadersError = true;
1165 continue; 1308 continue;
1166 } 1309 }
1167 1310
1311 ThereAreAltStreams = true;
1312
1168 CRef ref; 1313 CRef ref;
1169 ref.AttrIndex = i; 1314 ref.AttrIndex = i;
1170 ref.Parent = refIndex; 1315 ref.Parent = refIndex;
@@ -1381,13 +1526,6 @@ class CHandler:
1381 1526
1382 HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); 1527 HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream);
1383 1528
1384 HRESULT ExtractZlibFile(
1385 ISequentialOutStream *realOutStream,
1386 const CItem &item,
1387 NCompress::NZlib::CDecoder *_zlibDecoderSpec,
1388 CByteBuffer &buf,
1389 UInt64 progressStart,
1390 IArchiveExtractCallback *extractCallback);
1391public: 1529public:
1392 MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) 1530 MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream)
1393 INTERFACE_IInArchive(;) 1531 INTERFACE_IInArchive(;)
@@ -1405,12 +1543,21 @@ static const Byte kProps[] =
1405 kpidMTime, 1543 kpidMTime,
1406 kpidATime, 1544 kpidATime,
1407 kpidChangeTime, 1545 kpidChangeTime,
1408 kpidPosixAttrib 1546 kpidPosixAttrib,
1547 /*
1548 kpidUserId,
1549 kpidGroupId,
1550 */
1551#ifdef HFS_SHOW_ALT_STREAMS
1552 kpidIsAltStream,
1553#endif
1554 kpidMethod
1409}; 1555};
1410 1556
1411static const Byte kArcProps[] = 1557static const Byte kArcProps[] =
1412{ 1558{
1413 kpidMethod, 1559 kpidMethod,
1560 kpidCharacts,
1414 kpidClusterSize, 1561 kpidClusterSize,
1415 kpidFreeSpace, 1562 kpidFreeSpace,
1416 kpidCTime, 1563 kpidCTime,
@@ -1437,6 +1584,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
1437 { 1584 {
1438 case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; 1585 case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break;
1439 case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break; 1586 case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break;
1587 case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break;
1440 case kpidPhySize: 1588 case kpidPhySize:
1441 { 1589 {
1442 UInt64 v = SpecOffset + PhySize; 1590 UInt64 v = SpecOffset + PhySize;
@@ -1464,6 +1612,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
1464 { 1612 {
1465 UInt32 flags = 0; 1613 UInt32 flags = 0;
1466 if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; 1614 if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
1615 if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature;
1467 if (flags != 0) 1616 if (flags != 0)
1468 prop = flags; 1617 prop = flags;
1469 break; 1618 break;
@@ -1508,7 +1657,7 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
1508 { 1657 {
1509 const CRef &ref = Refs[index]; 1658 const CRef &ref = Refs[index];
1510 const UString *s; 1659 const UString *s;
1511 if (ref.IsResource) 1660 if (ref.IsResource())
1512 s = &ResFileName; 1661 s = &ResFileName;
1513 else if (ref.AttrIndex >= 0) 1662 else if (ref.AttrIndex >= 0)
1514 s = &Attrs[ref.AttrIndex].Name; 1663 s = &Attrs[ref.AttrIndex].Name;
@@ -1536,8 +1685,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1536 { 1685 {
1537 case kpidPath: GetItemPath(index, prop); break; 1686 case kpidPath: GetItemPath(index, prop); break;
1538 case kpidName: 1687 case kpidName:
1688 {
1539 const UString *s; 1689 const UString *s;
1540 if (ref.IsResource) 1690 if (ref.IsResource())
1541 s = &ResFileName; 1691 s = &ResFileName;
1542 else if (ref.AttrIndex >= 0) 1692 else if (ref.AttrIndex >= 0)
1543 s = &Attrs[ref.AttrIndex].Name; 1693 s = &Attrs[ref.AttrIndex].Name;
@@ -1545,22 +1695,31 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1545 s = &item.Name; 1695 s = &item.Name;
1546 prop = *s; 1696 prop = *s;
1547 break; 1697 break;
1698 }
1548 case kpidPackSize: 1699 case kpidPackSize:
1549 { 1700 {
1550 UInt64 size; 1701 UInt64 size;
1551 if (ref.AttrIndex >= 0) 1702 if (ref.AttrIndex >= 0)
1552 size = Attrs[ref.AttrIndex].Size; 1703 size = Attrs[ref.AttrIndex].GetSize();
1704 else if (ref.IsResource())
1705 size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog;
1553 else if (item.IsDir()) 1706 else if (item.IsDir())
1554 break; 1707 break;
1555 else if (item.UseAttr) 1708 else if (item.CompressHeader.IsCorrect)
1556 { 1709 {
1557 if (item.Method == kMethod_Resource) 1710 if (item.CompressHeader.IsMethod_Resource())
1558 size = item.ResourceFork.NumBlocks << Header.BlockSizeLog; 1711 size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog;
1712 else if (item.decmpfs_AttrIndex >= 0)
1713 {
1714 // size = item.PackSize;
1715 const CAttr &attr = Attrs[item.decmpfs_AttrIndex];
1716 size = attr.Data.Size() - item.CompressHeader.DataPos;
1717 }
1559 else 1718 else
1560 size = item.PackSize; 1719 size = 0;
1561 } 1720 }
1562 else 1721 else
1563 size = item.GetFork(ref.IsResource).NumBlocks << Header.BlockSizeLog; 1722 size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog;
1564 prop = size; 1723 prop = size;
1565 break; 1724 break;
1566 } 1725 }
@@ -1568,25 +1727,34 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1568 { 1727 {
1569 UInt64 size; 1728 UInt64 size;
1570 if (ref.AttrIndex >= 0) 1729 if (ref.AttrIndex >= 0)
1571 size = Attrs[ref.AttrIndex].Size; 1730 size = Attrs[ref.AttrIndex].GetSize();
1731 else if (ref.IsResource())
1732 size = item.ResourceFork.Size;
1572 else if (item.IsDir()) 1733 else if (item.IsDir())
1573 break; 1734 break;
1574 else if (item.UseAttr) 1735 else if (item.CompressHeader.IsCorrect)
1575 size = item.UnpackSize; 1736 size = item.CompressHeader.UnpackSize;
1576 else 1737 else
1577 size = item.GetFork(ref.IsResource).Size; 1738 size = item.DataFork.Size;
1578 prop = size; 1739 prop = size;
1579 break; 1740 break;
1580 } 1741 }
1581 case kpidIsDir: prop = item.IsDir(); break; 1742 case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break;
1582 case kpidIsAltStream: prop = ref.IsAltStream(); break; 1743 case kpidIsAltStream: prop = ref.IsAltStream(); break;
1583
1584 case kpidCTime: HfsTimeToProp(item.CTime, prop); break; 1744 case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
1585 case kpidMTime: HfsTimeToProp(item.MTime, prop); break; 1745 case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
1586 case kpidATime: HfsTimeToProp(item.ATime, prop); break; 1746 case kpidATime: HfsTimeToProp(item.ATime, prop); break;
1587 case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break; 1747 case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break;
1748 case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break;
1749 /*
1750 case kpidUserId: prop = (UInt32)item.OwnerID; break;
1751 case kpidGroupId: prop = (UInt32)item.GroupID; break;
1752 */
1588 1753
1589 case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; 1754 case kpidMethod:
1755 if (ref.IsItem())
1756 item.CompressHeader.MethodToProp(prop);
1757 break;
1590 } 1758 }
1591 prop.Detach(value); 1759 prop.Detach(value);
1592 return S_OK; 1760 return S_OK;
@@ -1614,65 +1782,77 @@ STDMETHODIMP CHandler::Close()
1614 1782
1615static const UInt32 kCompressionBlockSize = 1 << 16; 1783static const UInt32 kCompressionBlockSize = 1 << 16;
1616 1784
1617HRESULT CHandler::ExtractZlibFile( 1785CDecoder::CDecoder()
1618 ISequentialOutStream *outStream, 1786{
1619 const CItem &item, 1787 _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
1620 NCompress::NZlib::CDecoder *_zlibDecoderSpec, 1788 _zlibDecoder = _zlibDecoderSpec;
1621 CByteBuffer &buf, 1789
1622 UInt64 progressStart, 1790 _lzfseDecoderSpec = new NCompress::NLzfse::CDecoder();
1623 IArchiveExtractCallback *extractCallback) 1791 _lzfseDecoder = _lzfseDecoderSpec;
1792 _lzfseDecoderSpec->LzvnMode = true;
1793}
1794
1795HRESULT CDecoder::ExtractResourceFork_ZLIB(
1796 ISequentialInStream *inStream, ISequentialOutStream *outStream,
1797 UInt64 forkSize, UInt64 unpackSize,
1798 UInt64 progressStart, IArchiveExtractCallback *extractCallback)
1624{ 1799{
1625 CMyComPtr<ISequentialInStream> inStream;
1626 const CFork &fork = item.ResourceFork;
1627 RINOK(GetForkStream(fork, &inStream));
1628 const unsigned kHeaderSize = 0x100 + 8; 1800 const unsigned kHeaderSize = 0x100 + 8;
1629 RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); 1801
1630 UInt32 dataPos = Get32(buf); 1802 const size_t kBufSize = kCompressionBlockSize;
1631 UInt32 mapPos = Get32(buf + 4); 1803 _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
1632 UInt32 dataSize = Get32(buf + 8); 1804
1633 UInt32 mapSize = Get32(buf + 12); 1805 RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize));
1806 Byte *buf = _buf;
1807 const UInt32 dataPos = Get32(buf);
1808 const UInt32 mapPos = Get32(buf + 4);
1809 const UInt32 dataSize = Get32(buf + 8);
1810 const UInt32 mapSize = Get32(buf + 12);
1634 1811
1635 const UInt32 kResMapSize = 50; 1812 const UInt32 kResMapSize = 50;
1636 1813
1637 if (mapSize != kResMapSize 1814 if (mapSize != kResMapSize
1638 || dataPos + dataSize != mapPos 1815 || dataPos > mapPos
1639 || mapPos + mapSize != fork.Size) 1816 || dataSize != mapPos - dataPos
1817 || mapSize > forkSize
1818 || mapPos != forkSize - mapSize)
1640 return S_FALSE; 1819 return S_FALSE;
1641 1820
1642 UInt32 dataSize2 = Get32(buf + 0x100); 1821 const UInt32 dataSize2 = Get32(buf + 0x100);
1643 if (4 + dataSize2 != dataSize || dataSize2 < 8) 1822 if (4 + dataSize2 != dataSize
1823 || dataSize2 < 8
1824 || dataSize2 > dataSize)
1644 return S_FALSE; 1825 return S_FALSE;
1645 1826
1646 UInt32 numBlocks = GetUi32(buf + 0x100 + 4); 1827 const UInt32 numBlocks = GetUi32(buf + 0x100 + 4);
1647 if (((dataSize2 - 4) >> 3) < numBlocks) 1828 if (((dataSize2 - 4) >> 3) < numBlocks)
1648 return S_FALSE; 1829 return S_FALSE;
1649 if (item.UnpackSize > (UInt64)numBlocks * kCompressionBlockSize) 1830 {
1650 return S_FALSE; 1831 const UInt64 up = unpackSize + kCompressionBlockSize - 1;
1651 1832 if (up < unpackSize || up / kCompressionBlockSize != numBlocks)
1652 if (item.UnpackSize + kCompressionBlockSize < (UInt64)numBlocks * kCompressionBlockSize) 1833 return S_FALSE;
1653 return S_FALSE; 1834 }
1654 1835
1655 UInt32 tableSize = (numBlocks << 3); 1836 const UInt32 tableSize = (numBlocks << 3);
1656 1837
1657 CByteBuffer tableBuf(tableSize); 1838 _tableBuf.AllocAtLeast(tableSize);
1658 1839
1659 RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); 1840 RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize));
1841 const Byte *tableBuf = _tableBuf;
1660 1842
1661 UInt32 prev = 4 + tableSize; 1843 UInt32 prev = 4 + tableSize;
1662 1844
1663 UInt32 i; 1845 UInt32 i;
1664 for (i = 0; i < numBlocks; i++) 1846 for (i = 0; i < numBlocks; i++)
1665 { 1847 {
1666 UInt32 offset = GetUi32(tableBuf + i * 8); 1848 const UInt32 offs = GetUi32(tableBuf + i * 8);
1667 UInt32 size = GetUi32(tableBuf + i * 8 + 4); 1849 const UInt32 size = GetUi32(tableBuf + i * 8 + 4);
1668 if (size == 0) 1850 if (size == 0
1669 return S_FALSE; 1851 || prev != offs
1670 if (prev != offset) 1852 || offs > dataSize2
1853 || size > dataSize2 - offs)
1671 return S_FALSE; 1854 return S_FALSE;
1672 if (offset > dataSize2 || 1855 prev = offs + size;
1673 size > dataSize2 - offset)
1674 return S_FALSE;
1675 prev = offset + size;
1676 } 1856 }
1677 1857
1678 if (prev != dataSize2) 1858 if (prev != dataSize2)
@@ -1681,26 +1861,29 @@ HRESULT CHandler::ExtractZlibFile(
1681 CBufInStream *bufInStreamSpec = new CBufInStream; 1861 CBufInStream *bufInStreamSpec = new CBufInStream;
1682 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; 1862 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
1683 1863
1864 // bool padError = false;
1684 UInt64 outPos = 0; 1865 UInt64 outPos = 0;
1866
1685 for (i = 0; i < numBlocks; i++) 1867 for (i = 0; i < numBlocks; i++)
1686 { 1868 {
1687 UInt64 rem = item.UnpackSize - outPos; 1869 const UInt64 rem = unpackSize - outPos;
1688 if (rem == 0) 1870 if (rem == 0)
1689 return S_FALSE; 1871 return S_FALSE;
1690 UInt32 blockSize = kCompressionBlockSize; 1872 UInt32 blockSize = kCompressionBlockSize;
1691 if (rem < kCompressionBlockSize) 1873 if (rem < kCompressionBlockSize)
1692 blockSize = (UInt32)rem; 1874 blockSize = (UInt32)rem;
1693 1875
1694 UInt32 size = GetUi32(tableBuf + i * 8 + 4); 1876 const UInt32 size = GetUi32(tableBuf + i * 8 + 4);
1695 1877
1696 if (size > buf.Size() || size > kCompressionBlockSize + 1) 1878 if (size > kCompressionBlockSize + 1)
1697 return S_FALSE; 1879 return S_FALSE;
1698 1880
1699 RINOK(ReadStream_FALSE(inStream, buf, size)); 1881 RINOK(ReadStream_FALSE(inStream, buf, size));
1700 1882
1701 if ((buf[0] & 0xF) == 0xF) 1883 if ((buf[0] & 0xF) == 0xF)
1702 { 1884 {
1703 // that code was not tested. Are there HFS archives with uncompressed block 1885 // (buf[0] = 0xff) is marker of uncompressed block in APFS
1886 // that code was not tested in HFS
1704 if (size - 1 != blockSize) 1887 if (size - 1 != blockSize)
1705 return S_FALSE; 1888 return S_FALSE;
1706 1889
@@ -1711,54 +1894,251 @@ HRESULT CHandler::ExtractZlibFile(
1711 } 1894 }
1712 else 1895 else
1713 { 1896 {
1714 UInt64 blockSize64 = blockSize; 1897 const UInt64 blockSize64 = blockSize;
1715 bufInStreamSpec->Init(buf, size); 1898 bufInStreamSpec->Init(buf, size);
1716 RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL)); 1899 RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL));
1717 if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize || 1900 if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize)
1718 _zlibDecoderSpec->GetInputProcessedSize() != size)
1719 return S_FALSE; 1901 return S_FALSE;
1902 const UInt64 inSize = _zlibDecoderSpec->GetInputProcessedSize();
1903 if (inSize != size)
1904 {
1905 if (inSize > size)
1906 return S_FALSE;
1907 // apfs file can contain junk (non-zeros) after data block.
1908 /*
1909 if (!padError)
1910 {
1911 const Byte *p = buf + (UInt32)inSize;
1912 const Byte *e = p + (size - (UInt32)inSize);
1913 do
1914 {
1915 if (*p != 0)
1916 {
1917 padError = true;
1918 break;
1919 }
1920 }
1921 while (++p != e);
1922 }
1923 */
1924 }
1720 } 1925 }
1721 1926
1722 outPos += blockSize; 1927 outPos += blockSize;
1723 const UInt64 progressPos = progressStart + outPos; 1928 if ((i & 0xFF) == 0)
1724 RINOK(extractCallback->SetCompleted(&progressPos)); 1929 {
1930 const UInt64 progressPos = progressStart + outPos;
1931 RINOK(extractCallback->SetCompleted(&progressPos));
1932 }
1725 } 1933 }
1726 1934
1727 if (outPos != item.UnpackSize) 1935 if (outPos != unpackSize)
1728 return S_FALSE; 1936 return S_FALSE;
1729 1937
1938 // if (padError) return S_FALSE;
1939
1730 /* We check Resource Map 1940 /* We check Resource Map
1731 Are there HFS files with another values in Resource Map ??? */ 1941 Are there HFS files with another values in Resource Map ??? */
1732 1942
1733 RINOK(ReadStream_FALSE(inStream, buf, mapSize)); 1943 RINOK(ReadStream_FALSE(inStream, buf, mapSize));
1734 UInt32 types = Get16(buf + 24); 1944 const UInt32 types = Get16(buf + 24);
1735 UInt32 names = Get16(buf + 26); 1945 const UInt32 names = Get16(buf + 26);
1736 UInt32 numTypes = Get16(buf + 28); 1946 const UInt32 numTypes = Get16(buf + 28);
1737 if (numTypes != 0 || types != 28 || names != kResMapSize) 1947 if (numTypes != 0 || types != 28 || names != kResMapSize)
1738 return S_FALSE; 1948 return S_FALSE;
1739 UInt32 resType = Get32(buf + 30); 1949 const UInt32 resType = Get32(buf + 30);
1740 UInt32 numResources = Get16(buf + 34); 1950 const UInt32 numResources = Get16(buf + 34);
1741 UInt32 resListOffset = Get16(buf + 36); 1951 const UInt32 resListOffset = Get16(buf + 36);
1742 if (resType != 0x636D7066) // cmpf 1952 if (resType != 0x636D7066) // cmpf
1743 return S_FALSE; 1953 return S_FALSE;
1744 if (numResources != 0 || resListOffset != 10) 1954 if (numResources != 0 || resListOffset != 10)
1745 return S_FALSE; 1955 return S_FALSE;
1746 1956
1747 UInt32 entryId = Get16(buf + 38); 1957 const UInt32 entryId = Get16(buf + 38);
1748 UInt32 nameOffset = Get16(buf + 40); 1958 const UInt32 nameOffset = Get16(buf + 40);
1749 // Byte attrib = buf[42]; 1959 // Byte attrib = buf[42];
1750 UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; 1960 const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF;
1751 if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) 1961 if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0)
1752 return S_FALSE; 1962 return S_FALSE;
1753 1963
1754 return S_OK; 1964 return S_OK;
1755} 1965}
1756 1966
1967
1968
1969HRESULT CDecoder::ExtractResourceFork_LZFSE(
1970 ISequentialInStream *inStream, ISequentialOutStream *outStream,
1971 UInt64 forkSize, UInt64 unpackSize,
1972 UInt64 progressStart, IArchiveExtractCallback *extractCallback)
1973{
1974 const UInt32 kNumBlocksMax = (UInt32)1 << 29;
1975 if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize)
1976 return S_FALSE;
1977 const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize);
1978 const UInt32 numBlocks2 = numBlocks + 1;
1979 const UInt32 tableSize = (numBlocks2 << 2);
1980 if (tableSize > forkSize)
1981 return S_FALSE;
1982 _tableBuf.AllocAtLeast(tableSize);
1983 RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize));
1984 const Byte *tableBuf = _tableBuf;
1985
1986 {
1987 UInt32 prev = GetUi32(tableBuf);
1988 if (prev != tableSize)
1989 return S_FALSE;
1990 for (UInt32 i = 1; i < numBlocks2; i++)
1991 {
1992 const UInt32 offs = GetUi32(tableBuf + i * 4);
1993 if (offs <= prev)
1994 return S_FALSE;
1995 prev = offs;
1996 }
1997 if (prev != forkSize)
1998 return S_FALSE;
1999 }
2000
2001 const size_t kBufSize = kCompressionBlockSize;
2002 _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
2003
2004 CBufInStream *bufInStreamSpec = new CBufInStream;
2005 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
2006
2007 UInt64 outPos = 0;
2008
2009 for (UInt32 i = 0; i < numBlocks; i++)
2010 {
2011 const UInt64 rem = unpackSize - outPos;
2012 if (rem == 0)
2013 return S_FALSE;
2014 UInt32 blockSize = kCompressionBlockSize;
2015 if (rem < kCompressionBlockSize)
2016 blockSize = (UInt32)rem;
2017
2018 const UInt32 size =
2019 GetUi32(tableBuf + i * 4 + 4) -
2020 GetUi32(tableBuf + i * 4);
2021
2022 if (size > kCompressionBlockSize + 1)
2023 return S_FALSE;
2024
2025 RINOK(ReadStream_FALSE(inStream, _buf, size));
2026 const Byte *buf = _buf;
2027
2028 if (buf[0] == k_LZVN_Uncompressed_Marker)
2029 {
2030 if (size - 1 != blockSize)
2031 return S_FALSE;
2032 if (outStream)
2033 {
2034 RINOK(WriteStream(outStream, buf, blockSize));
2035 }
2036 }
2037 else
2038 {
2039 const UInt64 blockSize64 = blockSize;
2040 const UInt64 packSize64 = size;
2041 bufInStreamSpec->Init(buf, size);
2042 RINOK(_lzfseDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL));
2043 // in/out sizes were checked in Code()
2044 }
2045
2046 outPos += blockSize;
2047 if ((i & 0xFF) == 0)
2048 {
2049 const UInt64 progressPos = progressStart + outPos;
2050 RINOK(extractCallback->SetCompleted(&progressPos));
2051 }
2052 }
2053
2054 return S_OK;
2055}
2056
2057
2058HRESULT CDecoder::Extract(
2059 ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream,
2060 UInt64 forkSize,
2061 const CCompressHeader &compressHeader,
2062 const CByteBuffer *data,
2063 UInt64 progressStart, IArchiveExtractCallback *extractCallback,
2064 int &opRes)
2065{
2066 opRes = NExtract::NOperationResult::kDataError;
2067
2068 if (compressHeader.IsMethod_Uncompressed_Inline())
2069 {
2070 const size_t packSize = data->Size() - compressHeader.DataPos;
2071 if (realOutStream)
2072 {
2073 RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize));
2074 }
2075 opRes = NExtract::NOperationResult::kOK;
2076 return S_OK;
2077 }
2078
2079 if (compressHeader.Method == kMethod_ZLIB_ATTR ||
2080 compressHeader.Method == kMethod_LZVN_ATTR)
2081 {
2082 CBufInStream *bufInStreamSpec = new CBufInStream;
2083 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
2084 const size_t packSize = data->Size() - compressHeader.DataPos;
2085 bufInStreamSpec->Init(*data + compressHeader.DataPos, packSize);
2086
2087 if (compressHeader.Method == kMethod_ZLIB_ATTR)
2088 {
2089 const HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream,
2090 NULL, &compressHeader.UnpackSize, NULL);
2091 if (hres == S_OK)
2092 if (_zlibDecoderSpec->GetOutputProcessedSize() == compressHeader.UnpackSize
2093 && _zlibDecoderSpec->GetInputProcessedSize() == packSize)
2094 opRes = NExtract::NOperationResult::kOK;
2095 return hres;
2096 }
2097 {
2098 const UInt64 packSize64 = packSize;
2099 const HRESULT hres = _lzfseDecoder->Code(bufInStream, realOutStream,
2100 &packSize64, &compressHeader.UnpackSize, NULL);
2101 if (hres == S_OK)
2102 {
2103 // in/out sizes were checked in Code()
2104 opRes = NExtract::NOperationResult::kOK;
2105 }
2106 return hres;
2107 }
2108 }
2109
2110 HRESULT hres;
2111 if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC)
2112 {
2113 hres = ExtractResourceFork_ZLIB(
2114 inStreamFork, realOutStream,
2115 forkSize, compressHeader.UnpackSize,
2116 progressStart, extractCallback);
2117 }
2118 else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC)
2119 {
2120 hres = ExtractResourceFork_LZFSE(
2121 inStreamFork, realOutStream,
2122 forkSize, compressHeader.UnpackSize,
2123 progressStart, extractCallback);
2124 }
2125 else
2126 {
2127 opRes = NExtract::NOperationResult::kUnsupportedMethod;
2128 hres = S_FALSE;
2129 }
2130
2131 if (hres == S_OK)
2132 opRes = NExtract::NOperationResult::kOK;
2133 return hres;
2134}
2135
2136
1757STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, 2137STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1758 Int32 testMode, IArchiveExtractCallback *extractCallback) 2138 Int32 testMode, IArchiveExtractCallback *extractCallback)
1759{ 2139{
1760 COM_TRY_BEGIN 2140 COM_TRY_BEGIN
1761 bool allFilesMode = (numItems == (UInt32)(Int32)-1); 2141 const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1762 if (allFilesMode) 2142 if (allFilesMode)
1763 numItems = Refs.Size(); 2143 numItems = Refs.Size();
1764 if (numItems == 0) 2144 if (numItems == 0)
@@ -1777,12 +2157,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1777 const size_t kBufSize = kCompressionBlockSize; 2157 const size_t kBufSize = kCompressionBlockSize;
1778 CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header 2158 CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
1779 2159
1780 NCompress::NZlib::CDecoder *_zlibDecoderSpec = NULL; 2160 CDecoder decoder;
1781 CMyComPtr<ICompressCoder> _zlibDecoder;
1782 2161
1783 for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) 2162 for (i = 0;; i++, currentTotalSize += currentItemSize)
1784 { 2163 {
1785 RINOK(extractCallback->SetCompleted(&currentTotalSize)); 2164 RINOK(extractCallback->SetCompleted(&currentTotalSize));
2165 if (i == numItems)
2166 break;
1786 UInt32 index = allFilesMode ? i : indices[i]; 2167 UInt32 index = allFilesMode ? i : indices[i];
1787 const CRef &ref = Refs[index]; 2168 const CRef &ref = Refs[index];
1788 const CItem &item = Items[ref.ItemIndex]; 2169 const CItem &item = Items[ref.ItemIndex];
@@ -1794,7 +2175,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1794 NExtract::NAskMode::kExtract; 2175 NExtract::NAskMode::kExtract;
1795 RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); 2176 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
1796 2177
1797 if (ref.AttrIndex < 0 && item.IsDir()) 2178 if (ref.IsItem() && item.IsDir())
1798 { 2179 {
1799 RINOK(extractCallback->PrepareOperation(askMode)); 2180 RINOK(extractCallback->PrepareOperation(askMode));
1800 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); 2181 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
@@ -1802,89 +2183,91 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1802 } 2183 }
1803 if (!testMode && !realOutStream) 2184 if (!testMode && !realOutStream)
1804 continue; 2185 continue;
2186
1805 RINOK(extractCallback->PrepareOperation(askMode)); 2187 RINOK(extractCallback->PrepareOperation(askMode));
2188
1806 UInt64 pos = 0; 2189 UInt64 pos = 0;
1807 int res = NExtract::NOperationResult::kDataError; 2190 int opRes = NExtract::NOperationResult::kDataError;
2191 const CFork *fork = NULL;
2192
1808 if (ref.AttrIndex >= 0) 2193 if (ref.AttrIndex >= 0)
1809 { 2194 {
1810 res = NExtract::NOperationResult::kOK; 2195 const CAttr &attr = Attrs[ref.AttrIndex];
1811 if (realOutStream) 2196 if (attr.Fork_defined && attr.Data.Size() == 0)
2197 fork = &attr.Fork;
2198 else
1812 { 2199 {
1813 const CAttr &attr = Attrs[ref.AttrIndex]; 2200 opRes = NExtract::NOperationResult::kOK;
1814 RINOK(WriteStream(realOutStream, AttrBuf + attr.Pos, attr.Size)); 2201 if (realOutStream)
2202 {
2203 RINOK(WriteStream(realOutStream,
2204 // AttrBuf + attr.Pos, attr.Size
2205 attr.Data, attr.Data.Size()
2206 ));
2207 }
1815 } 2208 }
1816 } 2209 }
1817 else if (item.UseAttr) 2210 else if (ref.IsResource())
2211 fork = &item.ResourceFork;
2212 else if (item.CompressHeader.IsSupported)
1818 { 2213 {
1819 if (item.UseInlineData) 2214 CMyComPtr<ISequentialInStream> inStreamFork;
2215 UInt64 forkSize = 0;
2216 const CByteBuffer *decmpfs_Data = NULL;
2217
2218 if (item.CompressHeader.IsMethod_Resource())
1820 { 2219 {
1821 res = NExtract::NOperationResult::kOK; 2220 const CFork &resourceFork = item.ResourceFork;
1822 if (realOutStream) 2221 forkSize = resourceFork.Size;
1823 { 2222 GetForkStream(resourceFork, &inStreamFork);
1824 RINOK(WriteStream(realOutStream, AttrBuf + item.DataPos, (size_t)item.UnpackSize));
1825 }
1826 } 2223 }
1827 else 2224 else
1828 { 2225 {
1829 if (!_zlibDecoder) 2226 const CAttr &attr = Attrs[item.decmpfs_AttrIndex];
1830 { 2227 decmpfs_Data = &attr.Data;
1831 _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); 2228 }
1832 _zlibDecoder = _zlibDecoderSpec; 2229
1833 } 2230 if (inStreamFork || decmpfs_Data)
1834 2231 {
1835 if (item.Method == kMethod_Attr) 2232 const HRESULT hres = decoder.Extract(
1836 { 2233 inStreamFork, realOutStream,
1837 CBufInStream *bufInStreamSpec = new CBufInStream; 2234 forkSize,
1838 CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; 2235 item.CompressHeader,
1839 bufInStreamSpec->Init(AttrBuf + item.DataPos, item.PackSize); 2236 decmpfs_Data,
1840 2237 currentTotalSize, extractCallback,
1841 HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, NULL, &item.UnpackSize, NULL); 2238 opRes);
1842 if (hres != S_FALSE) 2239 if (hres != S_FALSE && hres != S_OK)
1843 { 2240 return hres;
1844 if (hres != S_OK)
1845 return hres;
1846 if (_zlibDecoderSpec->GetOutputProcessedSize() == item.UnpackSize &&
1847 _zlibDecoderSpec->GetInputProcessedSize() == item.PackSize)
1848 res = NExtract::NOperationResult::kOK;
1849 }
1850 }
1851 else
1852 {
1853 HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf,
1854 currentTotalSize, extractCallback);
1855 if (hres != S_FALSE)
1856 {
1857 if (hres != S_OK)
1858 return hres;
1859 res = NExtract::NOperationResult::kOK;
1860 }
1861 }
1862 } 2241 }
1863 } 2242 }
2243 else if (item.CompressHeader.IsCorrect)
2244 opRes = NExtract::NOperationResult::kUnsupportedMethod;
1864 else 2245 else
2246 fork = &item.DataFork;
2247
2248 if (fork)
1865 { 2249 {
1866 const CFork &fork = item.GetFork(ref.IsResource); 2250 if (fork->IsOk(Header.BlockSizeLog))
1867 if (fork.IsOk(Header.BlockSizeLog))
1868 { 2251 {
1869 res = NExtract::NOperationResult::kOK; 2252 opRes = NExtract::NOperationResult::kOK;
1870 unsigned extentIndex; 2253 unsigned extentIndex;
1871 for (extentIndex = 0; extentIndex < fork.Extents.Size(); extentIndex++) 2254 for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++)
1872 { 2255 {
1873 if (res != NExtract::NOperationResult::kOK) 2256 if (opRes != NExtract::NOperationResult::kOK)
1874 break; 2257 break;
1875 if (fork.Size == pos) 2258 if (fork->Size == pos)
1876 break; 2259 break;
1877 const CExtent &e = fork.Extents[extentIndex]; 2260 const CExtent &e = fork->Extents[extentIndex];
1878 RINOK(_stream->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); 2261 RINOK(_stream->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL));
1879 UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; 2262 UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog;
1880 while (extentRem != 0) 2263 while (extentRem != 0)
1881 { 2264 {
1882 UInt64 rem = fork.Size - pos; 2265 const UInt64 rem = fork->Size - pos;
1883 if (rem == 0) 2266 if (rem == 0)
1884 { 2267 {
1885 // Here we check that there are no extra (empty) blocks in last extent. 2268 // Here we check that there are no extra (empty) blocks in last extent.
1886 if (extentRem >= ((UInt64)1 << Header.BlockSizeLog)) 2269 if (extentRem >= ((UInt64)1 << Header.BlockSizeLog))
1887 res = NExtract::NOperationResult::kDataError; 2270 opRes = NExtract::NOperationResult::kDataError;
1888 break; 2271 break;
1889 } 2272 }
1890 size_t cur = kBufSize; 2273 size_t cur = kBufSize;
@@ -1895,7 +2278,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1895 RINOK(ReadStream(_stream, buf, &cur)); 2278 RINOK(ReadStream(_stream, buf, &cur));
1896 if (cur == 0) 2279 if (cur == 0)
1897 { 2280 {
1898 res = NExtract::NOperationResult::kDataError; 2281 opRes = NExtract::NOperationResult::kDataError;
1899 break; 2282 break;
1900 } 2283 }
1901 if (realOutStream) 2284 if (realOutStream)
@@ -1908,12 +2291,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1908 RINOK(extractCallback->SetCompleted(&processed)); 2291 RINOK(extractCallback->SetCompleted(&processed));
1909 } 2292 }
1910 } 2293 }
1911 if (extentIndex != fork.Extents.Size() || fork.Size != pos) 2294 if (extentIndex != fork->Extents.Size() || fork->Size != pos)
1912 res = NExtract::NOperationResult::kDataError; 2295 opRes = NExtract::NOperationResult::kDataError;
1913 } 2296 }
1914 } 2297 }
1915 realOutStream.Release(); 2298 realOutStream.Release();
1916 RINOK(extractCallback->SetOperationResult(res)); 2299 RINOK(extractCallback->SetOperationResult(opRes));
1917 } 2300 }
1918 return S_OK; 2301 return S_OK;
1919 COM_TRY_END 2302 COM_TRY_END
@@ -1976,13 +2359,27 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
1976 *stream = 0; 2359 *stream = 0;
1977 2360
1978 const CRef &ref = Refs[index]; 2361 const CRef &ref = Refs[index];
2362 const CFork *fork = NULL;
1979 if (ref.AttrIndex >= 0) 2363 if (ref.AttrIndex >= 0)
1980 return S_FALSE; 2364 {
1981 const CItem &item = Items[ref.ItemIndex]; 2365 const CAttr &attr = Attrs[ref.AttrIndex];
1982 if (item.IsDir() || item.UseAttr) 2366 if (!attr.Fork_defined || attr.Data.Size() != 0)
1983 return S_FALSE; 2367 return S_FALSE;
1984 2368 fork = &attr.Fork;
1985 return GetForkStream(item.GetFork(ref.IsResource), stream); 2369 }
2370 else
2371 {
2372 const CItem &item = Items[ref.ItemIndex];
2373 if (ref.IsResource())
2374 fork = &item.ResourceFork;
2375 else if (item.IsDir())
2376 return S_FALSE;
2377 else if (item.CompressHeader.IsCorrect)
2378 return S_FALSE;
2379 else
2380 fork = &item.DataFork;
2381 }
2382 return GetForkStream(*fork, stream);
1986} 2383}
1987 2384
1988static const Byte k_Signature[] = { 2385static const Byte k_Signature[] = {
diff --git a/CPP/7zip/Archive/HfsHandler.h b/CPP/7zip/Archive/HfsHandler.h
new file mode 100644
index 0000000..2461f6b
--- /dev/null
+++ b/CPP/7zip/Archive/HfsHandler.h
@@ -0,0 +1,85 @@
1// HfsHandler.h
2
3#ifndef __HFS_HANDLER_H
4#define __HFS_HANDLER_H
5
6#include "../../Windows/PropVariant.h"
7
8#include "../Compress/LzfseDecoder.h"
9#include "../Compress/ZlibDecoder.h"
10
11namespace NArchive {
12namespace NHfs {
13
14static const UInt32 k_decmpfs_HeaderSize = 16;
15
16struct CCompressHeader
17{
18 UInt64 UnpackSize;
19 UInt32 Method;
20 Byte DataPos;
21 bool IsCorrect;
22 bool IsSupported;
23 bool IsResource;
24
25 bool IsMethod_Compressed_Inline() const { return DataPos == k_decmpfs_HeaderSize; }
26 bool IsMethod_Uncompressed_Inline() const { return DataPos == k_decmpfs_HeaderSize + 1; }
27 bool IsMethod_Resource() const { return IsResource; }
28
29 void Parse(const Byte *p, size_t size);
30
31 void Clear()
32 {
33 UnpackSize = 0;
34 Method = 0;
35 DataPos = 0;
36 IsCorrect = false;
37 IsSupported = false;
38 IsResource = false;
39 }
40
41 CCompressHeader() { Clear(); }
42
43 void MethodToProp(NWindows::NCOM::CPropVariant &prop) const;
44};
45
46void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop);
47
48
49class CDecoder
50{
51 NCompress::NZlib::CDecoder *_zlibDecoderSpec;
52 CMyComPtr<ICompressCoder> _zlibDecoder;
53
54 NCompress::NLzfse::CDecoder *_lzfseDecoderSpec;
55 CMyComPtr<ICompressCoder> _lzfseDecoder;
56
57 CByteBuffer _tableBuf;
58 CByteBuffer _buf;
59
60 HRESULT ExtractResourceFork_ZLIB(
61 ISequentialInStream *inStream, ISequentialOutStream *realOutStream,
62 UInt64 forkSize, UInt64 unpackSize,
63 UInt64 progressStart, IArchiveExtractCallback *extractCallback);
64
65 HRESULT ExtractResourceFork_LZFSE(
66 ISequentialInStream *inStream, ISequentialOutStream *realOutStream,
67 UInt64 forkSize, UInt64 unpackSize,
68 UInt64 progressStart, IArchiveExtractCallback *extractCallback);
69
70public:
71
72 HRESULT Extract(
73 ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream,
74 UInt64 forkSize,
75 const CCompressHeader &compressHeader,
76 const CByteBuffer *data,
77 UInt64 progressStart, IArchiveExtractCallback *extractCallback,
78 int &opRes);
79
80 CDecoder();
81};
82
83}}
84
85#endif
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
index 2232c64..691199e 100644
--- a/CPP/7zip/Archive/Udf/UdfHandler.cpp
+++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -48,14 +48,22 @@ static const Byte kProps[] =
48 kpidPackSize, 48 kpidPackSize,
49 kpidMTime, 49 kpidMTime,
50 kpidATime, 50 kpidATime,
51 kpidChangeTime 51 kpidCTime,
52 kpidChangeTime,
53 // kpidUserId,
54 // kpidGroupId,
55 // kpidPosixAttrib,
56 kpidLinks
52}; 57};
53 58
54static const Byte kArcProps[] = 59static const Byte kArcProps[] =
55{ 60{
56 kpidComment, 61 kpidUnpackVer,
57 kpidClusterSize, 62 kpidClusterSize,
58 kpidCTime 63 kpidSectorSize,
64 kpidCTime,
65 kpidMTime,
66 kpidComment
59}; 67};
60 68
61IMP_IInArchive_Props 69IMP_IInArchive_Props
@@ -69,6 +77,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
69 { 77 {
70 case kpidPhySize: prop = _archive.PhySize; break; 78 case kpidPhySize: prop = _archive.PhySize; break;
71 79
80 case kpidUnpackVer:
81 {
82 if (_archive.LogVols.Size() == 1)
83 {
84 UString s;
85 const CLogVol &vol = _archive.LogVols[0];
86 vol.DomainId.AddUdfVersionTo(s);
87 if (!s.IsEmpty())
88 prop = s;
89 }
90 break;
91 }
72 case kpidComment: 92 case kpidComment:
73 { 93 {
74 UString comment = _archive.GetComment(); 94 UString comment = _archive.GetComment();
@@ -90,12 +110,21 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
90 } 110 }
91 break; 111 break;
92 112
113 case kpidSectorSize: prop = ((UInt32)1 << _archive.SecLogSize); break;
114
93 case kpidCTime: 115 case kpidCTime:
94 if (_archive.LogVols.Size() == 1) 116 if (_archive.LogVols.Size() == 1)
95 { 117 {
96 const CLogVol &vol = _archive.LogVols[0]; 118 const CLogVol &vol = _archive.LogVols[0];
97 if (vol.FileSets.Size() >= 1) 119 if (vol.FileSets.Size() >= 1)
98 UdfTimeToFileTime(vol.FileSets[0].RecodringTime, prop); 120 UdfTimeToFileTime(vol.FileSets[0].RecordingTime, prop);
121 }
122 break;
123 case kpidMTime:
124 if (_archive.PrimeVols.Size() == 1)
125 {
126 const CPrimeVol &pv = _archive.PrimeVols[0];
127 UdfTimeToFileTime(pv.RecordingTime, prop);
99 } 128 }
100 break; 129 break;
101 130
@@ -160,6 +189,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
160 { 189 {
161 const CLogVol &vol = _archive.LogVols[volIndex]; 190 const CLogVol &vol = _archive.LogVols[volIndex];
162 bool showFileSetName = (vol.FileSets.Size() > 1); 191 bool showFileSetName = (vol.FileSets.Size() > 1);
192 // showFileSetName = true; // for debug
163 FOR_VECTOR (fsIndex, vol.FileSets) 193 FOR_VECTOR (fsIndex, vol.FileSets)
164 { 194 {
165 const CFileSet &fs = vol.FileSets[fsIndex]; 195 const CFileSet &fs = vol.FileSets[fsIndex];
@@ -212,7 +242,15 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
212 case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; 242 case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
213 case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; 243 case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
214 case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; 244 case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
245 case kpidCTime:
246 if (item.IsExtended)
247 UdfTimeToFileTime(item.CreateTime, prop);
248 break;
215 case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break; 249 case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
250 // case kpidUserId: prop = item.Uid; break;
251 // case kpidGroupId: prop = item.Gid; break;
252 // case kpidPosixAttrib: prop = (UInt32)item.Permissions; break;
253 case kpidLinks: prop = (UInt32)item.FileLinkCount; break;
216 } 254 }
217 } 255 }
218 prop.Detach(value); 256 prop.Detach(value);
@@ -255,7 +293,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
255 if (size < len) 293 if (size < len)
256 return S_FALSE; 294 return S_FALSE;
257 295
258 int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; 296 const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
259 UInt32 logBlockNumber = extent.Pos; 297 UInt32 logBlockNumber = extent.Pos;
260 const CPartition &partition = _archive.Partitions[partitionIndex]; 298 const CPartition &partition = _archive.Partitions[partitionIndex];
261 UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + 299 UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) +
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h
index da44b23..462faee 100644
--- a/CPP/7zip/Archive/Udf/UdfHandler.h
+++ b/CPP/7zip/Archive/Udf/UdfHandler.h
@@ -24,9 +24,9 @@ class CHandler:
24 public IInArchiveGetStream, 24 public IInArchiveGetStream,
25 public CMyUnknownImp 25 public CMyUnknownImp
26{ 26{
27 CRecordVector<CRef2> _refs2;
27 CMyComPtr<IInStream> _inStream; 28 CMyComPtr<IInStream> _inStream;
28 CInArchive _archive; 29 CInArchive _archive;
29 CRecordVector<CRef2> _refs2;
30public: 30public:
31 MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) 31 MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
32 INTERFACE_IInArchive(;) 32 INTERFACE_IInArchive(;)
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index d2d2b20..70496e4 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -10,6 +10,8 @@
10 10
11#include "../../../../C/CpuArch.h" 11#include "../../../../C/CpuArch.h"
12 12
13#include "../../../Windows/PropVariantUtils.h"
14
13#include "../../Common/RegisterArc.h" 15#include "../../Common/RegisterArc.h"
14#include "../../Common/StreamUtils.h" 16#include "../../Common/StreamUtils.h"
15 17
@@ -25,6 +27,10 @@
25#define Get32(p) GetUi32(p) 27#define Get32(p) GetUi32(p)
26#define Get64(p) GetUi64(p) 28#define Get64(p) GetUi64(p)
27 29
30#define G16(_offs_, dest) dest = Get16(p + (_offs_));
31#define G32(_offs_, dest) dest = Get32(p + (_offs_));
32#define G64(_offs_, dest) dest = Get64(p + (_offs_));
33
28namespace NArchive { 34namespace NArchive {
29namespace NUdf { 35namespace NUdf {
30 36
@@ -39,7 +45,6 @@ static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
39static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; 45static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
40 46
41#define CRC16_INIT_VAL 0 47#define CRC16_INIT_VAL 0
42// #define CRC16_GET_DIGEST(crc) (crc)
43#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) 48#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)))
44 49
45#define kCrc16Poly 0x1021 50#define kCrc16Poly 0x1021
@@ -57,22 +62,20 @@ static void MY_FAST_CALL Crc16GenerateTable(void)
57 } 62 }
58} 63}
59 64
60static UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size) 65static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size)
61{ 66{
67 UInt32 v = CRC16_INIT_VAL;
62 const Byte *p = (const Byte *)data; 68 const Byte *p = (const Byte *)data;
63 for (; size > 0 ; size--, p++) 69 const Byte *pEnd = p + size;
70 for (; p != pEnd; p++)
64 v = CRC16_UPDATE_BYTE(v, *p); 71 v = CRC16_UPDATE_BYTE(v, *p);
65 return v; 72 return v;
66} 73}
67 74
68static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size)
69{
70 return Crc16_Update(CRC16_INIT_VAL, data, size);
71}
72
73static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; 75static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
74 76
75 77
78// ---------- ECMA Part 1 ----------
76 79
77void CDString::Parse(const Byte *p, unsigned size) 80void CDString::Parse(const Byte *p, unsigned size)
78{ 81{
@@ -82,16 +85,17 @@ void CDString::Parse(const Byte *p, unsigned size)
82static UString ParseDString(const Byte *data, unsigned size) 85static UString ParseDString(const Byte *data, unsigned size)
83{ 86{
84 UString res; 87 UString res;
85 if (size > 0) 88 if (size != 0)
86 { 89 {
87 wchar_t *p; 90 wchar_t *p;
88 Byte type = data[0]; 91 const Byte type = *data++;
92 size--;
89 if (type == 8) 93 if (type == 8)
90 { 94 {
91 p = res.GetBuf(size); 95 p = res.GetBuf(size);
92 for (unsigned i = 1; i < size; i++) 96 for (unsigned i = 0; i < size; i++)
93 { 97 {
94 wchar_t c = data[i]; 98 const wchar_t c = data[i];
95 if (c == 0) 99 if (c == 0)
96 break; 100 break;
97 *p++ = c; 101 *p++ = c;
@@ -99,10 +103,11 @@ static UString ParseDString(const Byte *data, unsigned size)
99 } 103 }
100 else if (type == 16) 104 else if (type == 16)
101 { 105 {
106 size &= ~(unsigned)1;
102 p = res.GetBuf(size / 2); 107 p = res.GetBuf(size / 2);
103 for (unsigned i = 1; i + 2 <= size; i += 2) 108 for (unsigned i = 0; i < size; i += 2)
104 { 109 {
105 wchar_t c = GetBe16(data + i); 110 const wchar_t c = GetBe16(data + i);
106 if (c == 0) 111 if (c == 0)
107 break; 112 break;
108 *p++ = c; 113 *p++ = c;
@@ -116,75 +121,117 @@ static UString ParseDString(const Byte *data, unsigned size)
116 return res; 121 return res;
117} 122}
118 123
124UString CDString32::GetString() const
125{
126 const unsigned size = Data[sizeof(Data) - 1];
127 return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
128}
129
119UString CDString128::GetString() const 130UString CDString128::GetString() const
120{ 131{
121 unsigned size = Data[sizeof(Data) - 1]; 132 const unsigned size = Data[sizeof(Data) - 1];
122 return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); 133 return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
123} 134}
124 135
125UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); } 136UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); }
126 137
127void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } 138void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); }
128 139
129/* 140
130void CRegId::Parse(const Byte *buf) 141static void AddCommentChars(UString &dest, const char *s, size_t size)
131{ 142{
132 Flags = buf[0]; 143 for (size_t i = 0; i < size; i++)
133 memcpy(Id, buf + 1, sizeof(Id)); 144 {
134 memcpy(Suffix, buf + 24, sizeof(Suffix)); 145 char c = s[i];
146 if (c == 0)
147 break;
148 if (c < 0x20)
149 c = '_';
150 dest += (wchar_t)c;
151 }
135} 152}
136*/
137 153
138// ECMA 3/7.1
139 154
140struct CExtent 155void CRegId::Parse(const Byte *p)
141{ 156{
142 UInt32 Len; 157 Flags = p[0];
143 UInt32 Pos; 158 memcpy(Id, p + 1, sizeof(Id));
159 memcpy(Suffix, p + 24, sizeof(Suffix));
160}
144 161
145 void Parse(const Byte *buf); 162void CRegId::AddCommentTo(UString &s) const
146}; 163{
164 AddCommentChars(s, Id, sizeof(Id));
165}
147 166
148void CExtent::Parse(const Byte *buf) 167void CRegId::AddUdfVersionTo(UString &s) const
149{ 168{
150 Len = Get32(buf); 169 // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix"
151 Pos = Get32(buf + 4); 170 // UDF 2.1.5.3
171 // Revision in hex (3 digits)
172 const Byte minor = Suffix[0];
173 const Byte major = Suffix[1];
174 if (major != 0 || minor != 0)
175 {
176 char temp[16];
177 ConvertUInt32ToHex(major, temp);
178 s += temp;
179 s += '.';
180 ConvertUInt32ToHex8Digits(minor, temp);
181 s += &temp[8 - 2];
182 }
152} 183}
153 184
185
186// ---------- ECMA Part 3: Volume Structure ----------
187
188void CExtent::Parse(const Byte *p)
189{
190 /* Len shall be less than < 2^30.
191 Unless otherwise specified, the length shall be an integral multiple of the logical sector size.
192 If (Len == 0), no extent is specified and (Pos) shall contain 0 */
193 G32 (0, Len);
194 G32 (4, Pos);
195}
196
197
154// ECMA 3/7.2 198// ECMA 3/7.2
155 199
156struct CTag 200struct CTag
157{ 201{
158 UInt16 Id; 202 UInt16 Id;
159 UInt16 Version; 203 // UInt16 Version;
160 // Byte Checksum; 204 // Byte Checksum;
161 // UInt16 SerialNumber; 205 // UInt16 SerialNumber;
162 // UInt16 Crc; 206 // UInt16 Crc;
163 // UInt16 CrcLen; 207 UInt16 CrcLen;
164 // UInt32 TagLocation; 208 // UInt32 TagLocation; // the number of the logical sector
165 209
166 HRESULT Parse(const Byte *buf, size_t size); 210 HRESULT Parse(const Byte *p, size_t size);
167}; 211};
168 212
169HRESULT CTag::Parse(const Byte *buf, size_t size) 213HRESULT CTag::Parse(const Byte *p, size_t size)
170{ 214{
171 if (size < 16) 215 if (size < 16)
172 return S_FALSE; 216 return S_FALSE;
173 Byte sum = 0; 217 {
174 int i; 218 unsigned sum = 0;
175 for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); 219 for (unsigned i = 0; i < 16; i++)
176 for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); 220 sum = sum + p[i];
177 if (sum != buf[4] || buf[5] != 0) return S_FALSE; 221 if ((Byte)(sum - p[4]) != p[4] || p[5] != 0)
178 222 return S_FALSE;
179 Id = Get16(buf); 223 }
180 Version = Get16(buf + 2); 224 Id = Get16(p);
181 // SerialNumber = Get16(buf + 6); 225 const UInt16 Version = Get16(p + 2);
182 UInt32 crc = Get16(buf + 8); 226 if (Version != 2 && Version != 3)
183 UInt32 crcLen = Get16(buf + 10); 227 return S_FALSE;
184 // TagLocation = Get32(buf + 12); 228 // SerialNumber = Get16(p + 6);
185 229 const UInt32 crc = Get16(p + 8);
186 if (size >= 16 + crcLen) 230 CrcLen = Get16(p + 10);
187 if (crc == Crc16Calc(buf + 16, (size_t)crcLen)) 231 // TagLocation = Get32(p + 12);
232
233 if (size >= 16 + (size_t)CrcLen)
234 if (crc == Crc16Calc(p + 16, (size_t)CrcLen))
188 return S_OK; 235 return S_OK;
189 return S_FALSE; 236 return S_FALSE;
190} 237}
@@ -210,52 +257,78 @@ enum EDescriptorType
210 DESC_TYPE_Terminal = 260, 257 DESC_TYPE_Terminal = 260,
211 DESC_TYPE_File = 261, 258 DESC_TYPE_File = 261,
212 DESC_TYPE_ExtendedAttrHeader = 262, 259 DESC_TYPE_ExtendedAttrHeader = 262,
213 DESC_TYPE_UnallocatedSpace = 263, 260 DESC_TYPE_UnallocatedSpaceEntry = 263,
214 DESC_TYPE_SpaceBitmap = 264, 261 DESC_TYPE_SpaceBitmap = 264,
215 DESC_TYPE_PartitionIntegrity = 265, 262 DESC_TYPE_PartitionIntegrity = 265,
216 DESC_TYPE_ExtendedFile = 266 263 DESC_TYPE_ExtendedFile = 266
217}; 264};
218 265
219 266
220void CLogBlockAddr::Parse(const Byte *buf) 267void CLogBlockAddr::Parse(const Byte *p)
221{ 268{
222 Pos = Get32(buf); 269 G32 (0, Pos);
223 PartitionRef = Get16(buf + 4); 270 G16 (4, PartitionRef);
224} 271}
225 272
226void CShortAllocDesc::Parse(const Byte *buf) 273void CShortAllocDesc::Parse(const Byte *p)
227{ 274{
228 Len = Get32(buf); 275 G32 (0, Len);
229 Pos = Get32(buf + 4); 276 G32 (4, Pos);
230} 277}
231 278
232/* 279/*
233void CADImpUse::Parse(const Byte *buf) 280void CADImpUse::Parse(const Byte *p)
234{ 281{
235 Flags = Get16(buf); 282 G16 (0, Flags);
236 UdfUniqueId = Get32(buf + 2); 283 G32 (2, UdfUniqueId);
237} 284}
238*/ 285*/
239 286
240void CLongAllocDesc::Parse(const Byte *buf) 287void CLongAllocDesc::Parse(const Byte *p)
241{ 288{
242 Len = Get32(buf); 289 G32 (0, Len);
243 Location.Parse(buf + 4); 290 Location.Parse(p + 4);
244 // memcpy(ImplUse, buf + 10, sizeof(ImplUse)); 291 // memcpy(ImplUse, p + 10, sizeof(ImplUse));
245 // adImpUse.Parse(ImplUse); 292 // adImpUse.Parse(ImplUse);
246} 293}
247 294
248bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const 295
296void CPrimeVol::Parse(const Byte *p)
297{
298 // G32 (16, VolumeDescriptorSequenceNumber);
299 G32 (20, PrimaryVolumeDescriptorNumber);
300 VolumeId.Parse(p + 24);
301 G16 (56, VolumeSequenceNumber);
302 G16 (58, MaximumVolumeSequenceNumber);
303 // G16 (60, InterchangeLevel);
304 // G16 (62, MaximumInterchangeLevel);
305 // G32 (64, CharacterSetList)
306 // G32 (68, MaximumCharacterSetList)
307 VolumeSetId.Parse(p + 72);
308 // 200 64 Descriptor Character Set charspec (1/7.2.1)
309 // 264 64 Explanatory Character Set charspec (1/7.2.1)
310 // VolumeAbstract.Parse(p + 328);
311 // VolumeCopyrightNotice.Parse(p + 336);
312 ApplicationId.Parse(p + 344);
313 RecordingTime.Parse(p + 376);
314 ImplId.Parse(p + 388);
315 // 420 64 Implementation Use bytes
316 // G32 (484, PredecessorVolumeDescriptorSequenceLocation);
317 // G16 (488, Flags);
318}
319
320
321
322bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const
249{ 323{
250 const CLogVol &vol = LogVols[volIndex]; 324 const CLogVol &vol = LogVols[volIndex];
251 if (partitionRef >= (int)vol.PartitionMaps.Size()) 325 if (partitionRef >= vol.PartitionMaps.Size())
252 return false; 326 return false;
253 const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; 327 const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
254 UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; 328 return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize);
255 return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize);
256} 329}
257 330
258bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const 331bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const
259{ 332{
260 FOR_VECTOR (i, item.Extents) 333 FOR_VECTOR (i, item.Extents)
261 { 334 {
@@ -266,7 +339,7 @@ bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const
266 return true; 339 return true;
267} 340}
268 341
269HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) 342HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf)
270{ 343{
271 if (!CheckExtent(volIndex, partitionRef, blockPos, len)) 344 if (!CheckExtent(volIndex, partitionRef, blockPos, len))
272 return S_FALSE; 345 return S_FALSE;
@@ -274,20 +347,20 @@ HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32
274 const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; 347 const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
275 UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; 348 UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
276 RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); 349 RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
277 HRESULT res = ReadStream_FALSE(_stream, buf, len); 350 offset += len;
278 if (res == S_FALSE && offset + len > FileSize) 351 UpdatePhySize(offset);
352 const HRESULT res = ReadStream_FALSE(_stream, buf, len);
353 if (res == S_FALSE && offset > FileSize)
279 UnexpectedEnd = true; 354 UnexpectedEnd = true;
280 RINOK(res); 355 return res;
281 UpdatePhySize(offset + len);
282 return S_OK;
283} 356}
284 357
285HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) 358HRESULT CInArchive::ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf)
286{ 359{
287 return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); 360 return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf);
288} 361}
289 362
290HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf) 363HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf)
291{ 364{
292 if (item.Size >= (UInt32)1 << 30) 365 if (item.Size >= (UInt32)1 << 30)
293 return S_FALSE; 366 return S_FALSE;
@@ -301,7 +374,7 @@ HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &b
301 FOR_VECTOR (i, item.Extents) 374 FOR_VECTOR (i, item.Extents)
302 { 375 {
303 const CMyExtent &e = item.Extents[i]; 376 const CMyExtent &e = item.Extents[i];
304 UInt32 len = e.GetLen(); 377 const UInt32 len = e.GetLen();
305 RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)); 378 RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos));
306 pos += len; 379 pos += len;
307 } 380 }
@@ -311,36 +384,70 @@ HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &b
311 384
312void CIcbTag::Parse(const Byte *p) 385void CIcbTag::Parse(const Byte *p)
313{ 386{
314 // PriorDirectNum = Get32(p); 387 // G32 (0, PriorDirectNum);
315 // StrategyType = Get16(p + 4); 388 // G16 (4, StrategyType);
316 // StrategyParam = Get16(p + 6); 389 // G16 (6, StrategyParam);
317 // MaxNumOfEntries = Get16(p + 8); 390 // G16 (8, MaxNumOfEntries);
318 FileType = p[11]; 391 FileType = p[11];
319 // ParentIcb.Parse(p + 12); 392 // ParentIcb.Parse(p + 12);
320 Flags = Get16(p + 18); 393 G16 (18, Flags);
321} 394}
322 395
396
397// ECMA 4/14.9 File Entry
398// UDF FileEntry 2.3.6
399
400// ECMA 4/14.17 Extended File Entry
401
323void CItem::Parse(const Byte *p) 402void CItem::Parse(const Byte *p)
324{ 403{
325 // Uid = Get32(p + 36); 404 // (-1) can be stored in Uid/Gid.
326 // Gid = Get32(p + 40); 405 // G32 (36, Uid);
327 // Permissions = Get32(p + 44); 406 // G32 (40, Gid);
328 // FileLinkCount = Get16(p + 48); 407 // G32 (44, Permissions);
408 G16 (48, FileLinkCount);
329 // RecordFormat = p[50]; 409 // RecordFormat = p[50];
330 // RecordDisplayAttr = p[51]; 410 // RecordDisplayAttr = p[51];
331 // RecordLen = Get32(p + 52); 411 // G32 (52, RecordLen);
332 Size = Get64(p + 56); 412 G64 (56, Size);
333 NumLogBlockRecorded = Get64(p + 64); 413 if (IsExtended)
414 {
415 // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no
416 // streams, the Object Size shall be equal to the Information Length.
417 // G64 (64, ObjectSize);
418 p += 8;
419 }
420 G64 (64, NumLogBlockRecorded);
334 ATime.Parse(p + 72); 421 ATime.Parse(p + 72);
335 MTime.Parse(p + 84); 422 MTime.Parse(p + 84);
423 if (IsExtended)
424 {
425 CreateTime.Parse(p + 96);
426 p += 12;
427 }
336 AttribTime.Parse(p + 96); 428 AttribTime.Parse(p + 96);
337 // CheckPoint = Get32(p + 108); 429 // G32 (108, CheckPoint);
430 /*
431 if (IsExtended)
432 {
433 // Get32(p + 112); // reserved
434 p += 4;
435 }
338 // ExtendedAttrIcb.Parse(p + 112); 436 // ExtendedAttrIcb.Parse(p + 112);
437 if (IsExtended)
438 {
439 StreamDirectoryIcb.Parse(p + 128);
440 p += 16;
441 }
442 */
443
339 // ImplId.Parse(p + 128); 444 // ImplId.Parse(p + 128);
340 // UniqueId = Get64(p + 160); 445 // G64 (160, UniqueId);
341} 446}
342 447
343// 4/14.4 448
449// ECMA 4/14.4
450
344struct CFileId 451struct CFileId
345{ 452{
346 // UInt16 FileVersion; 453 // UInt16 FileVersion;
@@ -350,38 +457,40 @@ struct CFileId
350 CLongAllocDesc Icb; 457 CLongAllocDesc Icb;
351 458
352 bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } 459 bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; }
353 HRESULT Parse(const Byte *p, size_t size, size_t &processed); 460 size_t Parse(const Byte *p, size_t size);
354}; 461};
355 462
356HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed) 463size_t CFileId::Parse(const Byte *p, size_t size)
357{ 464{
358 processed = 0; 465 size_t processed = 0;
359 if (size < 38) 466 if (size < 38)
360 return S_FALSE; 467 return 0;
361 CTag tag; 468 CTag tag;
362 RINOK(tag.Parse(p, size)); 469 RINOK(tag.Parse(p, size));
363 if (tag.Id != DESC_TYPE_FileId) 470 if (tag.Id != DESC_TYPE_FileId)
364 return S_FALSE; 471 return 0;
365 // FileVersion = Get16(p + 16); 472 // FileVersion = Get16(p + 16);
366 FileCharacteristics = p[18]; 473 FileCharacteristics = p[18];
367 unsigned idLen = p[19]; 474 const unsigned idLen = p[19];
368 Icb.Parse(p + 20); 475 Icb.Parse(p + 20);
369 unsigned impLen = Get16(p + 36); 476 const unsigned impLen = Get16(p + 36);
370 if (size < 38 + idLen + impLen) 477 if (size < 38 + idLen + impLen)
371 return S_FALSE; 478 return 0;
372 // ImplUse.SetCapacity(impLen);
373 processed = 38; 479 processed = 38;
374 // memcpy(ImplUse, p + processed, impLen); 480 // ImplUse.CopyFrom(p + processed, impLen);
375 processed += impLen; 481 processed += impLen;
376 Id.Parse(p + processed, idLen); 482 Id.Parse(p + processed, idLen);
377 processed += idLen; 483 processed += idLen;
378 for (;(processed & 3) != 0; processed++) 484 for (;(processed & 3) != 0; processed++)
379 if (p[processed] != 0) 485 if (p[processed] != 0)
380 return S_FALSE; 486 return 0;
381 return (processed <= size) ? S_OK : S_FALSE; 487 if ((size_t)tag.CrcLen + 16 != processed) return 0;
488 return (processed <= size) ? processed : 0;
382} 489}
383 490
384HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) 491
492
493HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
385{ 494{
386 if (Files.Size() % 100 == 0) 495 if (Files.Size() % 100 == 0)
387 RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)); 496 RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes));
@@ -389,12 +498,12 @@ HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc
389 return S_FALSE; 498 return S_FALSE;
390 CFile &file = Files.Back(); 499 CFile &file = Files.Back();
391 const CLogVol &vol = LogVols[volIndex]; 500 const CLogVol &vol = LogVols[volIndex];
392 unsigned partitionRef = lad.Location.PartitionRef; 501 const unsigned partitionRef = lad.Location.PartitionRef;
393 if (partitionRef >= vol.PartitionMaps.Size()) 502 if (partitionRef >= vol.PartitionMaps.Size())
394 return S_FALSE; 503 return S_FALSE;
395 CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; 504 CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
396 505
397 UInt32 key = lad.Location.Pos; 506 const UInt32 key = lad.Location.Pos;
398 UInt32 value; 507 UInt32 value;
399 const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; 508 const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1;
400 if (partition.Map.Find(key, value)) 509 if (partition.Map.Find(key, value))
@@ -416,32 +525,47 @@ HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc
416 return S_OK; 525 return S_OK;
417} 526}
418 527
419HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) 528
529// (fsIndex = -1) means that it's metadata file
530
531HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
420{ 532{
421 if (Items.Size() > kNumItemsMax) 533 if (Items.Size() >= kNumItemsMax)
422 return S_FALSE; 534 return S_FALSE;
423 Items.Add(CItem()); 535 CItem &item = Items.AddNew();
424 CItem &item = Items.Back();
425 536
426 const CLogVol &vol = LogVols[volIndex]; 537 const CLogVol &vol = LogVols[volIndex];
427 538
428 if (lad.GetLen() != vol.BlockSize) 539 const size_t size = lad.GetLen();
540 if (size != vol.BlockSize)
429 return S_FALSE; 541 return S_FALSE;
430 542
431 const size_t size = lad.GetLen();
432 CByteBuffer buf(size); 543 CByteBuffer buf(size);
433 RINOK(Read(volIndex, lad, buf)); 544 RINOK(ReadLad(volIndex, lad, buf));
434 545
435 CTag tag; 546 CTag tag;
436 const Byte *p = buf; 547 const Byte *p = buf;
437 RINOK(tag.Parse(p, size)); 548 RINOK(tag.Parse(p, size));
438 if (size < 176) 549
550 item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile);
551 const size_t kExtendOffset = item.IsExtended ? 40 : 0;
552
553 if (size < kExtendOffset + 176)
439 return S_FALSE; 554 return S_FALSE;
440 if (tag.Id != DESC_TYPE_File) 555 if (tag.Id != DESC_TYPE_File &&
556 tag.Id != DESC_TYPE_ExtendedFile)
441 return S_FALSE; 557 return S_FALSE;
442 558
443 item.IcbTag.Parse(p + 16); 559 item.IcbTag.Parse(p + 16);
444 if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR && 560
561 if (fsIndex < 0)
562 {
563 if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA &&
564 item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR)
565 return S_FALSE;
566 }
567 else if (
568 item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
445 item.IcbTag.FileType != ICB_FILE_TYPE_FILE) 569 item.IcbTag.FileType != ICB_FILE_TYPE_FILE)
446 return S_FALSE; 570 return S_FALSE;
447 571
@@ -449,12 +573,12 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
449 573
450 _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; 574 _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size;
451 575
452 UInt32 extendedAttrLen = Get32(p + 168); 576 const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset);
453 UInt32 allocDescriptorsLen = Get32(p + 172); 577 const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset);
454 578
455 if ((extendedAttrLen & 3) != 0) 579 if ((extendedAttrLen & 3) != 0)
456 return S_FALSE; 580 return S_FALSE;
457 size_t pos = 176; 581 size_t pos = 176 + kExtendOffset;
458 if (extendedAttrLen > size - pos) 582 if (extendedAttrLen > size - pos)
459 return S_FALSE; 583 return S_FALSE;
460 /* 584 /*
@@ -472,10 +596,10 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
472 */ 596 */
473 pos += extendedAttrLen; 597 pos += extendedAttrLen;
474 598
475 int desctType = item.IcbTag.GetDescriptorType(); 599 const int descType = item.IcbTag.GetDescriptorType();
476 if (allocDescriptorsLen > size - pos) 600 if (allocDescriptorsLen > size - pos)
477 return S_FALSE; 601 return S_FALSE;
478 if (desctType == ICB_DESC_TYPE_INLINE) 602 if (descType == ICB_DESC_TYPE_INLINE)
479 { 603 {
480 item.IsInline = true; 604 item.IsInline = true;
481 item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); 605 item.InlineData.CopyFrom(p + pos, allocDescriptorsLen);
@@ -483,12 +607,12 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
483 else 607 else
484 { 608 {
485 item.IsInline = false; 609 item.IsInline = false;
486 if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG) 610 if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG)
487 return S_FALSE; 611 return S_FALSE;
488 for (UInt32 i = 0; i < allocDescriptorsLen;) 612 for (UInt32 i = 0; i < allocDescriptorsLen;)
489 { 613 {
490 CMyExtent e; 614 CMyExtent e;
491 if (desctType == ICB_DESC_TYPE_SHORT) 615 if (descType == ICB_DESC_TYPE_SHORT)
492 { 616 {
493 if (i + 8 > allocDescriptorsLen) 617 if (i + 8 > allocDescriptorsLen)
494 return S_FALSE; 618 return S_FALSE;
@@ -516,6 +640,9 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
516 640
517 if (item.IcbTag.IsDir()) 641 if (item.IcbTag.IsDir())
518 { 642 {
643 if (fsIndex < 0)
644 return S_FALSE;
645
519 if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) 646 if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
520 return S_FALSE; 647 return S_FALSE;
521 CByteBuffer buf2; 648 CByteBuffer buf2;
@@ -525,13 +652,17 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
525 item.InlineData.Free(); 652 item.InlineData.Free();
526 653
527 const Byte *p2 = buf2; 654 const Byte *p2 = buf2;
528 const size_t size2 = buf2.Size(); 655 size_t size2 = buf2.Size();
529 size_t processedTotal = 0; 656 while (size2 != 0)
530 for (; processedTotal < size2;)
531 { 657 {
532 size_t processedCur;
533 CFileId fileId; 658 CFileId fileId;
534 RINOK(fileId.Parse(p2 + processedTotal, size2 - processedTotal, processedCur)); 659 {
660 const size_t cur = fileId.Parse(p2, size2);
661 if (cur == 0)
662 return S_FALSE;
663 p2 += cur;
664 size2 -= cur;
665 }
535 if (!fileId.IsItLinkParent()) 666 if (!fileId.IsItLinkParent())
536 { 667 {
537 CFile file; 668 CFile file;
@@ -545,12 +676,11 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
545 return S_FALSE; 676 return S_FALSE;
546 677
547 item.SubFiles.Add(Files.Size()); 678 item.SubFiles.Add(Files.Size());
548 if (Files.Size() > kNumFilesMax) 679 if (Files.Size() >= kNumFilesMax)
549 return S_FALSE; 680 return S_FALSE;
550 Files.Add(file); 681 Files.Add(file);
551 RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed)); 682 RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed));
552 } 683 }
553 processedTotal += processedCur;
554 } 684 }
555 } 685 }
556 else 686 else
@@ -567,6 +697,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
567 return S_OK; 697 return S_OK;
568} 698}
569 699
700
570HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed) 701HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed)
571{ 702{
572 if ((_numRefs & 0xFFF) == 0) 703 if ((_numRefs & 0xFFF) == 0)
@@ -591,6 +722,7 @@ HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int n
591 return S_OK; 722 return S_OK;
592} 723}
593 724
725
594API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) 726API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size)
595{ 727{
596 UInt32 res = k_IsArc_Res_NO; 728 UInt32 res = k_IsArc_Res_NO;
@@ -608,7 +740,11 @@ API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size)
608 CTag tag; 740 CTag tag;
609 if (tag.Parse(p + offset, bufSize) == S_OK) 741 if (tag.Parse(p + offset, bufSize) == S_OK)
610 if (tag.Id == DESC_TYPE_AnchorVolPtr) 742 if (tag.Id == DESC_TYPE_AnchorVolPtr)
611 return k_IsArc_Res_YES; 743 {
744 if (Get32(p + offset + 12) == 256 && // TagLocation
745 tag.CrcLen >= 16)
746 return k_IsArc_Res_YES;
747 }
612 } 748 }
613 } 749 }
614} 750}
@@ -656,7 +792,7 @@ HRESULT CInArchive::Open2()
656 { 792 {
657 if (SecLogSize < 8) 793 if (SecLogSize < 8)
658 return S_FALSE; 794 return S_FALSE;
659 UInt32 offset = (UInt32)256 << SecLogSize; 795 const UInt32 offset = (UInt32)256 << SecLogSize;
660 if (offset >= fileSize) 796 if (offset >= fileSize)
661 continue; 797 continue;
662 RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); 798 RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
@@ -668,71 +804,86 @@ HRESULT CInArchive::Open2()
668 CTag tag; 804 CTag tag;
669 if (tag.Parse(buf, readSize) == S_OK) 805 if (tag.Parse(buf, readSize) == S_OK)
670 if (tag.Id == DESC_TYPE_AnchorVolPtr) 806 if (tag.Id == DESC_TYPE_AnchorVolPtr)
671 break; 807 {
808 if (Get32(buf + 12) == 256 &&
809 tag.CrcLen >= 16) // TagLocation
810 break;
811 }
672 } 812 }
673 } 813 }
674 814
675 PhySize = (UInt32)(256 + 1) << SecLogSize; 815 PhySize = (UInt32)(256 + 1) << SecLogSize;
676 IsArc = true; 816 IsArc = true;
677 817
818 // UDF 2.2.3 AnchorVolumeDescriptorPointer
819
678 CExtent extentVDS; 820 CExtent extentVDS;
679 extentVDS.Parse(buf + 16); 821 extentVDS.Parse(buf + 16);
680 { 822 {
681 CExtent extentVDS2; 823 CExtent extentVDS2;
682 extentVDS2.Parse(buf + 24); 824 extentVDS2.Parse(buf + 24);
683 UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len); 825 UpdatePhySize(extentVDS);
684 UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len); 826 UpdatePhySize(extentVDS2);
685 } 827 }
686 828
687 for (UInt32 location = 0; ; location++) 829 for (UInt32 location = 0; ; location++)
688 { 830 {
689 const size_t bufSize = (size_t)1 << SecLogSize; 831 if (location >= (extentVDS.Len >> SecLogSize))
690 if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len)
691 return S_FALSE; 832 return S_FALSE;
692 833
693 UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize; 834 const size_t bufSize = (size_t)1 << SecLogSize;
694 RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL));
695 HRESULT res = ReadStream_FALSE(_stream, buf, bufSize);
696 if (res == S_FALSE && offs + bufSize > FileSize)
697 UnexpectedEnd = true;
698 RINOK(res);
699
700
701 CTag tag;
702 { 835 {
703 const size_t pos = 0; 836 const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize;
704 RINOK(tag.Parse(buf + pos, bufSize - pos)); 837 RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL));
838 const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize);
839 if (res == S_FALSE && offs + bufSize > FileSize)
840 UnexpectedEnd = true;
841 RINOK(res);
705 } 842 }
843
844 CTag tag;
845 RINOK(tag.Parse(buf, bufSize));
846
706 if (tag.Id == DESC_TYPE_Terminating) 847 if (tag.Id == DESC_TYPE_Terminating)
707 break; 848 break;
708 849
850 if (tag.Id == DESC_TYPE_PrimVol)
851 {
852 CPrimeVol &pm = PrimeVols.AddNew();
853 pm.Parse(buf);
854 continue;
855 }
856
709 if (tag.Id == DESC_TYPE_Partition) 857 if (tag.Id == DESC_TYPE_Partition)
710 { 858 {
711 // Partition Descriptor 859 // Partition Descriptor
712 // ECMA 167 3/10.5 860 // ECMA 3/10.5
713 // UDF / 2.2.14 861 // UDF 2.2.14
714
715 if (Partitions.Size() >= kNumPartitionsMax) 862 if (Partitions.Size() >= kNumPartitionsMax)
716 return S_FALSE; 863 return S_FALSE;
717 CPartition partition; 864 CPartition partition;
718 // UInt32 volDescSeqNumer = Get32(buf + 16); 865 // const UInt32 volDescSeqNumer = Get32(buf + 16);
719 // partition.Flags = Get16(buf + 20); 866 partition.Flags = Get16(buf + 20);
720 partition.Number = Get16(buf + 22); 867 partition.Number = Get16(buf + 22);
721 // partition.ContentsId.Parse(buf + 24); 868 partition.ContentsId.Parse(buf + 24);
722 869
723 // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); 870 // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse));
724 // ContentsUse is Partition Header Description. 871 // ContentsUse contains Partition Header Description.
872 // ECMA 4/14.3
873 // UDF PartitionHeaderDescriptor 2.3.3
725 874
726 // partition.AccessType = Get32(buf + 184); 875 partition.AccessType = Get32(buf + 184);
727 partition.Pos = Get32(buf + 188); 876 partition.Pos = Get32(buf + 188);
728 partition.Len = Get32(buf + 192); 877 partition.Len = Get32(buf + 192);
729 // partition.ImplId.Parse(buf + 196); 878 partition.ImplId.Parse(buf + 196);
730 // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); 879 // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse));
731 880
732 PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); 881 PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len));
733 Partitions.Add(partition); 882 Partitions.Add(partition);
883 continue;
734 } 884 }
735 else if (tag.Id == DESC_TYPE_LogicalVol) 885
886 if (tag.Id == DESC_TYPE_LogicalVol)
736 { 887 {
737 /* Logical Volume Descriptor 888 /* Logical Volume Descriptor
738 ECMA 3/10.6 889 ECMA 3/10.6
@@ -740,46 +891,65 @@ HRESULT CInArchive::Open2()
740 891
741 if (LogVols.Size() >= kNumLogVolumesMax) 892 if (LogVols.Size() >= kNumLogVolumesMax)
742 return S_FALSE; 893 return S_FALSE;
743 CLogVol vol; 894 CLogVol &vol = LogVols.AddNew();
895
744 vol.Id.Parse(buf + 84); 896 vol.Id.Parse(buf + 84);
745 vol.BlockSize = Get32(buf + 212); 897 vol.BlockSize = Get32(buf + 212);
746 // vol.DomainId.Parse(buf + 216); 898 if (vol.BlockSize != ((UInt32)1 << SecLogSize))
747 899 {
900 // UDF 2.2.4.2 LogicalBlockSize
901 // UDF probably doesn't allow different sizes
902 return S_FALSE;
903 }
904 /*
748 if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) 905 if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30))
749 return S_FALSE; 906 return S_FALSE;
750 907 */
751 // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); 908
752 vol.FileSetLocation.Parse(buf + 248); 909 vol.DomainId.Parse(buf + 216);
910
911 // ECMA 4/3.1
912 // UDF 2.2.4.4 LogicalVolumeContentsUse
753 /* the extent in which the first File Set Descriptor Sequence 913 /* the extent in which the first File Set Descriptor Sequence
754 of the logical volume is recorded */ 914 of the logical volume is recorded */
915 vol.FileSetLocation.Parse(buf + 248);
916 // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse));
755 917
756 // UInt32 mapTableLength = Get32(buf + 264); 918 vol.ImplId.Parse(buf + 272);
757 UInt32 numPartitionMaps = Get32(buf + 268); 919 // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse));
920 // vol.IntegritySequenceExtent.Parse(buf + 432);
921
922 const UInt32 mapTableLen = Get32(buf + 264);
923 const UInt32 numPartitionMaps = Get32(buf + 268);
758 if (numPartitionMaps > kNumPartitionsMax) 924 if (numPartitionMaps > kNumPartitionsMax)
759 return S_FALSE; 925 return S_FALSE;
760 // vol.ImplId.Parse(buf + 272);
761 // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse));
762 926
763 PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); 927 PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps));
928
764 size_t pos = 440; 929 size_t pos = 440;
930 if (mapTableLen > bufSize - pos)
931 return S_FALSE;
932 const size_t posLimit = pos + mapTableLen;
933
765 for (UInt32 i = 0; i < numPartitionMaps; i++) 934 for (UInt32 i = 0; i < numPartitionMaps; i++)
766 { 935 {
767 if (pos + 2 > bufSize) 936 // ECMA 3/10.7 Partition maps
937 if (pos + 2 > posLimit)
768 return S_FALSE; 938 return S_FALSE;
769 CPartitionMap pm; 939 CPartitionMap pm;
770 pm.Type = buf[pos]; 940 pm.Type = buf[pos + 0];
771 // pm.Length = buf[pos + 1]; 941 // pm.Length = buf[pos + 1];
772 Byte len = buf[pos + 1]; 942 const Byte len = buf[pos + 1];
773 943 if (pos + len > posLimit)
774 if (pos + len > bufSize)
775 return S_FALSE; 944 return S_FALSE;
776 945
777 // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); 946 // memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
778 if (pm.Type == 1) 947 if (pm.Type == 1)
779 { 948 {
780 if (len != 6) // < 6 949 // ECMA 3/10.7.2
950 if (len != 6)
781 return S_FALSE; 951 return S_FALSE;
782 // pm.VolSeqNumber = Get16(buf + pos + 2); 952 pm.VolumeSequenceNumber = Get16(buf + pos + 2);
783 pm.PartitionNumber = Get16(buf + pos + 4); 953 pm.PartitionNumber = Get16(buf + pos + 4);
784 PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber)); 954 PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber));
785 } 955 }
@@ -790,28 +960,60 @@ HRESULT CInArchive::Open2()
790 /* ECMA 10.7.3 / Type 2 Partition Map 960 /* ECMA 10.7.3 / Type 2 Partition Map
791 62 bytes: Partition Identifier. */ 961 62 bytes: Partition Identifier. */
792 962
793 /* UDF 2.6 963 /* UDF
794 2.2.8 Virtual Partition Map 964 2.2.8 "*UDF Virtual Partition"
795 This is an extension of ECMA 167 to expand its scope to include 965 2.2.9 "*UDF Sparable Partition"
796 sequentially written media (eg. CD-R). This extension is for a 966 2.2.10 "*UDF Metadata Partition"
797 Partition Map entry to describe a virtual space. */ 967 */
798 968
799 // It's not implemented still. 969 if (Get16(buf + pos + 2) != 0) // reserved
800 if (Get16(buf + pos + 2) != 0)
801 return S_FALSE; 970 return S_FALSE;
802 // pm.VolSeqNumber = Get16(buf + pos + 36); 971
972 pm.PartitionTypeId.Parse(buf + pos + 4);
973 pm.VolumeSequenceNumber = Get16(buf + pos + 36);
803 pm.PartitionNumber = Get16(buf + pos + 38); 974 pm.PartitionNumber = Get16(buf + pos + 38);
975
976 if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0)
977 return S_FALSE;
978
979 // UDF 2.2.10 Metadata Partition Map
980 pm.MetadataFileLocation = Get32(buf + pos + 40);
981 // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44);
982 // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48);
983 // pm.AllocationUnitSize = Get32(buf + pos + 52);
984 // pm.AlignmentUnitSize = Get16(buf + pos + 56);
985 // pm.Flags = buf[pos + 58];
986
804 PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); 987 PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber));
805 // Unsupported = true; 988 // Unsupported = true;
806 return S_FALSE; 989 // return S_FALSE;
807 } 990 }
808 else 991 else
809 return S_FALSE; 992 return S_FALSE;
810 pos += len; 993 pos += len;
811 vol.PartitionMaps.Add(pm); 994 vol.PartitionMaps.Add(pm);
812 } 995 }
813 LogVols.Add(vol); 996 continue;
997 }
998
999 /*
1000 if (tag.Id == DESC_TYPE_UnallocSpace)
1001 {
1002 // UInt32 volDescSeqNumer = Get32(buf + 16);
1003 const UInt32 numAlocDescs = Get32(buf + 20);
1004 // we need examples for (numAlocDescs != 0) case
1005 if (numAlocDescs > (bufSize - 24) / 8)
1006 return S_FALSE;
1007 for (UInt32 i = 0; i < numAlocDescs; i++)
1008 {
1009 CExtent e;
1010 e.Parse(buf + 24 + i * 8);
1011 }
1012 continue;
814 } 1013 }
1014 else
1015 continue;
1016 */
815 } 1017 }
816 1018
817 UInt64 totalSize = 0; 1019 UInt64 totalSize = 0;
@@ -823,12 +1025,18 @@ HRESULT CInArchive::Open2()
823 FOR_VECTOR (pmIndex, vol.PartitionMaps) 1025 FOR_VECTOR (pmIndex, vol.PartitionMaps)
824 { 1026 {
825 CPartitionMap &pm = vol.PartitionMaps[pmIndex]; 1027 CPartitionMap &pm = vol.PartitionMaps[pmIndex];
826 unsigned i; 1028 for (unsigned i = 0;; i++)
827 for (i = 0; i < Partitions.Size(); i++)
828 { 1029 {
1030 if (i == Partitions.Size())
1031 return S_FALSE;
829 CPartition &part = Partitions[i]; 1032 CPartition &part = Partitions[i];
830 if (part.Number == pm.PartitionNumber) 1033 if (part.Number == pm.PartitionNumber)
831 { 1034 {
1035 pm.PartitionIndex = i;
1036 if (pm.Type == 2)
1037 break;
1038
1039 /*
832 if (part.VolIndex >= 0) 1040 if (part.VolIndex >= 0)
833 { 1041 {
834 // it's for 2.60. Fix it 1042 // it's for 2.60. Fix it
@@ -836,15 +1044,85 @@ HRESULT CInArchive::Open2()
836 return S_FALSE; 1044 return S_FALSE;
837 // return S_FALSE; 1045 // return S_FALSE;
838 } 1046 }
839 pm.PartitionIndex = i;
840 part.VolIndex = volIndex; 1047 part.VolIndex = volIndex;
1048 */
841 1049
842 totalSize += (UInt64)part.Len << SecLogSize; 1050 totalSize += (UInt64)part.Len << SecLogSize;
843 break; 1051 break;
844 } 1052 }
845 } 1053 }
846 if (i == Partitions.Size()) 1054 }
1055 }
1056
1057 for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
1058 {
1059 CLogVol &vol = LogVols[volIndex];
1060 FOR_VECTOR (pmIndex, vol.PartitionMaps)
1061 {
1062 CPartitionMap &pm = vol.PartitionMaps[pmIndex];
1063 if (pm.Type != 2)
1064 continue;
1065
1066 {
1067 CLongAllocDesc lad;
1068 lad.Len = vol.BlockSize;
1069 lad.Location.Pos = pm.MetadataFileLocation;
1070 // lad.Location.Pos = pm.MetadataMirrorFileLocation;
1071
1072 lad.Location.PartitionRef = (UInt16)pmIndex;
1073
1074 /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex.
1075 so we can use pmIndex or find (Type==1) PartitionMap */
1076 FOR_VECTOR (pmIndex2, vol.PartitionMaps)
1077 {
1078 const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2];
1079 if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1)
1080 {
1081 lad.Location.PartitionRef = (UInt16)pmIndex2;
1082 break;
1083 }
1084 }
1085
1086 RINOK(ReadItem(volIndex,
1087 -1, // (fsIndex = -1) means that it's metadata
1088 lad,
1089 1)); // numRecurseAllowed
1090 }
1091 {
1092 const CItem &item = Items.Back();
1093 if (!CheckItemExtents(volIndex, item))
1094 return S_FALSE;
1095 if (item.Extents.Size() != 1)
1096 return S_FALSE;
1097
1098 const CMyExtent &e = item.Extents[0];
1099 const CPartition &part = Partitions[pm.PartitionIndex];
1100 CPartition mp = part;
1101 mp.IsMetadata = true;
1102 // mp.Number = part.Number;
1103 mp.Pos = part.Pos + e.Pos;
1104 mp.Len = e.Len >> SecLogSize;
1105 pm.PartitionIndex = Partitions.Add(mp);
1106 }
1107 // Items.DeleteBack(); // we can delete that metadata item
1108
1109 /*
1110 // short version of code to read metadata file.
1111 RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf));
1112 CTag tag;
1113 RINOK(tag.Parse(buf, 224));
1114 if (tag.Id != DESC_TYPE_ExtendedFile)
847 return S_FALSE; 1115 return S_FALSE;
1116 CShortAllocDesc sad;
1117 sad.Parse(buf + 216);
1118 const CPartition &part = Partitions[pm.PartitionIndex];
1119 CPartition mp = part;
1120 mp.IsMetadata = true;
1121 // mp.Number = part.Number;
1122 mp.Pos = part.Pos + sad.Pos;
1123 mp.Len = sad.Len >> SecLogSize;
1124 pm.PartitionIndex = Partitions.Add(mp);
1125 */
848 } 1126 }
849 } 1127 }
850 1128
@@ -865,37 +1143,41 @@ HRESULT CInArchive::Open2()
865 if (nextExtent.GetLen() < 512) 1143 if (nextExtent.GetLen() < 512)
866 return S_FALSE; 1144 return S_FALSE;
867 CByteBuffer buf2(nextExtent.GetLen()); 1145 CByteBuffer buf2(nextExtent.GetLen());
868 RINOK(Read(volIndex, nextExtent, buf2)); 1146 RINOK(ReadLad(volIndex, nextExtent, buf2));
869 const Byte *p = buf2; 1147 const Byte *p = buf2;
870 size_t size = nextExtent.GetLen(); 1148 const size_t size = nextExtent.GetLen();
871 1149
872 CTag tag; 1150 CTag tag;
873 RINOK(tag.Parse(p, size)); 1151 RINOK(tag.Parse(p, size));
874 1152
1153 /*
1154 // commented in 22.01
875 if (tag.Id == DESC_TYPE_ExtendedFile) 1155 if (tag.Id == DESC_TYPE_ExtendedFile)
876 { 1156 {
877 // ECMA 4 / 14.17 1157 // ECMA 4 / 14.17
878 // 2.60 ?? 1158 // 2.60 ??
879 return S_FALSE; 1159 return S_FALSE;
880 } 1160 }
1161 */
881 1162
882 if (tag.Id != DESC_TYPE_FileSet) 1163 if (tag.Id != DESC_TYPE_FileSet)
883 return S_FALSE; 1164 return S_FALSE;
884 1165
885 PRF(printf("\n FileSet", volIndex)); 1166 PRF(printf("\n FileSet", volIndex));
886 CFileSet fs; 1167 CFileSet fs;
887 fs.RecodringTime.Parse(p + 16); 1168 fs.RecordingTime.Parse(p + 16);
888 // fs.InterchangeLevel = Get16(p + 18); 1169 // fs.InterchangeLevel = Get16(p + 18);
889 // fs.MaxInterchangeLevel = Get16(p + 20); 1170 // fs.MaxInterchangeLevel = Get16(p + 20);
890 // fs.FileSetNumber = Get32(p + 40); 1171 fs.FileSetNumber = Get32(p + 40);
891 // fs.FileSetDescNumber = Get32(p + 44); 1172 fs.FileSetDescNumber = Get32(p + 44);
892 1173
893 // fs.Id.Parse(p + 304); 1174 fs.LogicalVolumeId.Parse(p + 112);
894 // fs.CopyrightId.Parse(p + 336); 1175 fs.Id.Parse(p + 304);
895 // fs.AbstractId.Parse(p + 368); 1176 fs.CopyrightId.Parse(p + 336);
1177 fs.AbstractId.Parse(p + 368);
896 1178
897 fs.RootDirICB.Parse(p + 400); 1179 fs.RootDirICB.Parse(p + 400);
898 // fs.DomainId.Parse(p + 416); 1180 fs.DomainId.Parse(p + 416);
899 1181
900 // fs.SystemStreamDirICB.Parse(p + 464); 1182 // fs.SystemStreamDirICB.Parse(p + 464);
901 1183
@@ -907,7 +1189,7 @@ HRESULT CInArchive::Open2()
907 FOR_VECTOR (fsIndex, vol.FileSets) 1189 FOR_VECTOR (fsIndex, vol.FileSets)
908 { 1190 {
909 CFileSet &fs = vol.FileSets[fsIndex]; 1191 CFileSet &fs = vol.FileSets[fsIndex];
910 unsigned fileIndex = Files.Size(); 1192 const unsigned fileIndex = Files.Size();
911 Files.AddNew(); 1193 Files.AddNew();
912 RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax)); 1194 RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax));
913 RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax)); 1195 RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax));
@@ -937,16 +1219,16 @@ HRESULT CInArchive::Open2()
937 FOR_VECTOR (extentIndex, item.Extents) 1219 FOR_VECTOR (extentIndex, item.Extents)
938 { 1220 {
939 const CMyExtent &extent = item.Extents[extentIndex]; 1221 const CMyExtent &extent = item.Extents[extentIndex];
940 UInt32 len = extent.GetLen(); 1222 const UInt32 len = extent.GetLen();
941 if (len == 0) 1223 if (len == 0)
942 continue; 1224 continue;
943 if (size < len) 1225 if (size < len)
944 break; 1226 break;
945 1227
946 int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; 1228 const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
947 UInt32 logBlockNumber = extent.Pos; 1229 const UInt32 logBlockNumber = extent.Pos;
948 const CPartition &partition = Partitions[partitionIndex]; 1230 const CPartition &partition = Partitions[partitionIndex];
949 UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + 1231 const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) +
950 (UInt64)logBlockNumber * vol.BlockSize; 1232 (UInt64)logBlockNumber * vol.BlockSize;
951 UpdatePhySize(offset + len); 1233 UpdatePhySize(offset + len);
952 } 1234 }
@@ -984,7 +1266,8 @@ HRESULT CInArchive::Open2()
984 if (readSize == 0) 1266 if (readSize == 0)
985 break; 1267 break;
986 1268
987 if (readSize == secSize && NoEndAnchor) 1269 // some udf contain many EndAnchors
1270 if (readSize == secSize /* && NoEndAnchor */)
988 { 1271 {
989 CTag tag; 1272 CTag tag;
990 if (tag.Parse(buf, readSize) == S_OK && 1273 if (tag.Parse(buf, readSize) == S_OK &&
@@ -1051,6 +1334,7 @@ void CInArchive::Clear()
1051 1334
1052 Partitions.Clear(); 1335 Partitions.Clear();
1053 LogVols.Clear(); 1336 LogVols.Clear();
1337 PrimeVols.Clear();
1054 Items.Clear(); 1338 Items.Clear();
1055 Files.Clear(); 1339 Files.Clear();
1056 _fileNameLengthTotal = 0; 1340 _fileNameLengthTotal = 0;
@@ -1060,16 +1344,291 @@ void CInArchive::Clear()
1060 _processedProgressBytes = 0; 1344 _processedProgressBytes = 0;
1061} 1345}
1062 1346
1347
1348static const char * const g_PartitionTypes[] =
1349{
1350 "Pseudo-Overwritable" // UDF
1351 , "Read-Only"
1352 , "Write-Once"
1353 , "Rewritable"
1354 , "Overwritable"
1355};
1356
1357
1358static void AddComment_Align(UString &s)
1359{
1360 s += " ";
1361}
1362
1363static void AddComment_PropName(UString &s, const char *name)
1364{
1365 AddComment_Align(s);
1366 s += name;
1367 s += ": ";
1368}
1369
1370static void AddComment_UInt32(UString &s, const char *name, UInt32 val)
1371{
1372 AddComment_PropName(s, name);
1373 s.Add_UInt32(val);
1374 s.Add_LF();
1375}
1376
1377static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val)
1378{
1379 AddComment_Align(s);
1380 AddComment_UInt32(s, name, val);
1381}
1382
1383
1384static void AddComment_UInt64(UString &s, const char *name, UInt64 val)
1385{
1386 AddComment_PropName(s, name);
1387 s.Add_UInt64(val);
1388 s.Add_LF();
1389}
1390
1391static void AddComment_RegId(UString &s, const char *name, const CRegId &ri)
1392{
1393 AddComment_PropName(s, name);
1394 ri.AddCommentTo(s);
1395 s.Add_LF();
1396}
1397
1398static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri)
1399{
1400 AddComment_PropName(s, name);
1401 ri.AddCommentTo(s);
1402 {
1403 UString s2;
1404 ri.AddUdfVersionTo(s2);
1405 if (!s2.IsEmpty())
1406 {
1407 s += "::";
1408 s += s2;
1409 }
1410 }
1411 s.Add_LF();
1412}
1413
1414
1415// UDF 6.3.1 OS Class
1416
1417static const char * const g_OsClasses[] =
1418{
1419 NULL
1420 , "DOS"
1421 , "OS/2"
1422 , "Macintosh OS"
1423 , "UNIX"
1424 , "Windows 9x"
1425 , "Windows NT"
1426 , "OS/400"
1427 , "BeOS"
1428 , "Windows CE"
1429};
1430
1431// UDF 6.3.2 OS Identifier
1432
1433static const char * const g_OsIds_Unix[] =
1434{
1435 NULL // "Generic"
1436 , "AIX"
1437 , "SUN OS / Solaris"
1438 , "HP/UX"
1439 , "Silicon Graphics Irix"
1440 , "Linux"
1441 , "MKLinux"
1442 , "FreeBSD"
1443 , "NetBSD"
1444};
1445
1446static void AddOs_Class_Id(UString &s, const char *p)
1447{
1448 // UDF 2.1.5.3 Implementation Identifier Suffix
1449 // Appendix 6.3 Operating System Identifiers.
1450 const Byte osClass = p[0];
1451 if (osClass != 0)
1452 {
1453 s += "::";
1454 s += TypeToString(g_OsClasses, ARRAY_SIZE(g_OsClasses), osClass);
1455 }
1456 const Byte osId = p[1];
1457 if (osId != 0)
1458 {
1459 s += "::";
1460 if (osClass == 4) // unix
1461 {
1462 s += TypeToString(g_OsIds_Unix, ARRAY_SIZE(g_OsIds_Unix), osId);
1463 }
1464 else
1465 s.Add_UInt32(osId);
1466 }
1467}
1468
1469
1470static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri)
1471{
1472 AddComment_PropName(s, name);
1473 ri.AddCommentTo(s);
1474 {
1475 AddOs_Class_Id(s, ri.Suffix);
1476 }
1477 s.Add_LF();
1478}
1479
1480
1481static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri)
1482{
1483 AddComment_PropName(s, name);
1484 ri.AddCommentTo(s);
1485 {
1486 // UDF 2.1.5.3
1487 // UDF Identifier Suffix format
1488 UString s2;
1489 ri.AddUdfVersionTo(s2);
1490 if (!s2.IsEmpty())
1491 {
1492 s += "::";
1493 s += s2;
1494 }
1495 AddOs_Class_Id(s, &ri.Suffix[2]);
1496 }
1497 s.Add_LF();
1498}
1499
1500static void AddComment_DString32(UString &s, const char *name, const CDString32 &d)
1501{
1502 AddComment_Align(s);
1503 AddComment_PropName(s, name);
1504 s += d.GetString();
1505 s.Add_LF();
1506}
1507
1063UString CInArchive::GetComment() const 1508UString CInArchive::GetComment() const
1064{ 1509{
1065 UString res; 1510 UString s;
1066 FOR_VECTOR (i, LogVols)
1067 { 1511 {
1068 if (i != 0) 1512 s += "Primary Volumes:";
1069 res.Add_Space(); 1513 s.Add_LF();
1070 res += LogVols[i].GetName(); 1514 FOR_VECTOR (i, PrimeVols)
1515 {
1516 if (i != 0)
1517 s.Add_LF();
1518 const CPrimeVol &pv = PrimeVols[i];
1519 // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber);
1520 // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0)
1521 AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber);
1522 // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1)
1523 AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber);
1524 if (pv.MaximumVolumeSequenceNumber != 1)
1525 AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber);
1526 AddComment_PropName(s, "VolumeId");
1527 s += pv.VolumeId.GetString();
1528 s.Add_LF();
1529 AddComment_PropName(s, "VolumeSetId");
1530 s += pv.VolumeSetId.GetString();
1531 s.Add_LF();
1532 // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel);
1533 // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel);
1534 AddComment_RegId(s, "ApplicationId", pv.ApplicationId);
1535 AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId);
1536 }
1071 } 1537 }
1072 return res; 1538 {
1539 s += "Partitions:";
1540 s.Add_LF();
1541 FOR_VECTOR (i, Partitions)
1542 {
1543 if (i != 0)
1544 s.Add_LF();
1545 const CPartition &part = Partitions[i];
1546 AddComment_UInt32(s, "PartitionIndex", i);
1547 AddComment_UInt32(s, "PartitionNumber", part.Number);
1548 if (part.IsMetadata)
1549 AddComment_UInt32(s, "IsMetadata", 1);
1550 else
1551 {
1552 AddComment_RegId(s, "ContentsId", part.ContentsId);
1553 AddComment_RegId_Impl(s, "ImplementationId", part.ImplId);
1554 AddComment_PropName(s, "AccessType");
1555 s += TypeToString(g_PartitionTypes, ARRAY_SIZE(g_PartitionTypes), part.AccessType);
1556 s.Add_LF();
1557 }
1558 AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize);
1559 AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize);
1560 }
1561 }
1562 s += "Logical Volumes:";
1563 s.Add_LF();
1564 {
1565 FOR_VECTOR (i, LogVols)
1566 {
1567 if (i != 0)
1568 s.Add_LF();
1569 const CLogVol &vol = LogVols[i];
1570 if (LogVols.Size() != 1)
1571 AddComment_UInt32(s, "Number", i);
1572 AddComment_PropName(s, "Id");
1573 s += vol.Id.GetString();
1574 s.Add_LF();
1575 AddComment_UInt32(s, "BlockSize", vol.BlockSize);
1576 AddComment_RegId_Domain(s, "DomainId", vol.DomainId);
1577 AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId);
1578 // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len);
1579 // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize);
1580
1581 s += " Partition Maps:";
1582 s.Add_LF();
1583 {
1584 FOR_VECTOR (j, vol.PartitionMaps)
1585 {
1586 if (j != 0)
1587 s.Add_LF();
1588 const CPartitionMap &pm = vol.PartitionMaps[j];
1589 AddComment_UInt32_2(s, "PartitionMap", j);
1590 AddComment_UInt32_2(s, "Type", pm.Type);
1591 AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber);
1592 AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber);
1593 if (pm.Type == 2)
1594 {
1595 AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation);
1596 // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation);
1597 // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation);
1598 // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize);
1599 // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize);
1600 // AddComment_UInt32_2(s, "Flags", pm.Flags);
1601 AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId);
1602 }
1603 }
1604 }
1605 s += " File Sets:";
1606 s.Add_LF();
1607 {
1608 FOR_VECTOR (j, vol.FileSets)
1609 {
1610 if (j != 0)
1611 s.Add_LF();
1612 const CFileSet &fs = vol.FileSets[j];
1613 AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber);
1614 AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber);
1615
1616 AddComment_Align(s);
1617 AddComment_PropName(s, "LogicalVolumeId");
1618 s += fs.LogicalVolumeId.GetString();
1619 s.Add_LF();
1620
1621 AddComment_DString32(s, "Id", fs.Id);
1622 AddComment_DString32(s, "CopyrightId", fs.CopyrightId);
1623 AddComment_DString32(s, "AbstractId", fs.AbstractId);
1624
1625 AddComment_Align(s);
1626 AddComment_RegId_Domain(s, "DomainId", fs.DomainId);
1627 }
1628 }
1629 }
1630 }
1631 return s;
1073} 1632}
1074 1633
1075static UString GetSpecName(const UString &name) 1634static UString GetSpecName(const UString &name)
@@ -1089,7 +1648,7 @@ static void UpdateWithName(UString &res, const UString &addString)
1089 res.Insert(0, addString + WCHAR_PATH_SEPARATOR); 1648 res.Insert(0, addString + WCHAR_PATH_SEPARATOR);
1090} 1649}
1091 1650
1092UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, 1651UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex,
1093 bool showVolName, bool showFsName) const 1652 bool showVolName, bool showFsName) const
1094{ 1653{
1095 // showVolName = true; 1654 // showVolName = true;
@@ -1101,9 +1660,10 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
1101 for (;;) 1660 for (;;)
1102 { 1661 {
1103 const CRef &ref = fs.Refs[refIndex]; 1662 const CRef &ref = fs.Refs[refIndex];
1104 refIndex = ref.Parent; 1663 // we break on root file (that probably has empty name)
1105 if (refIndex < 0) 1664 if (ref.Parent < 0)
1106 break; 1665 break;
1666 refIndex = ref.Parent;
1107 UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); 1667 UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName()));
1108 } 1668 }
1109 1669
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
index 4e7dfa1..d962e7d 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.h
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -17,16 +17,15 @@ namespace NUdf {
17// ---------- ECMA Part 1 ---------- 17// ---------- ECMA Part 1 ----------
18 18
19// ECMA 1/7.2.12 19// ECMA 1/7.2.12
20// UDF 2.1.3
20 21
21/*
22struct CDString32 22struct CDString32
23{ 23{
24 Byte Data[32]; 24 Byte Data[32];
25 25
26 void Parse(const Byte *buf); 26 void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
27 // UString GetString() const; 27 UString GetString() const;
28}; 28};
29*/
30 29
31struct CDString128 30struct CDString128
32{ 31{
@@ -46,6 +45,7 @@ struct CDString
46 45
47 46
48// ECMA 1/7.3 47// ECMA 1/7.3
48// UDF 2.1.4 timestamp
49 49
50struct CTime 50struct CTime
51{ 51{
@@ -65,9 +65,9 @@ struct CTime
65}; 65};
66 66
67 67
68// ECMA 1/7.4 68// ECMA 1/7.4 regid
69// UDF 2.1.5 EntityID
69 70
70/*
71struct CRegId 71struct CRegId
72{ 72{
73 Byte Flags; 73 Byte Flags;
@@ -75,44 +75,97 @@ struct CRegId
75 char Suffix[8]; 75 char Suffix[8];
76 76
77 void Parse(const Byte *buf); 77 void Parse(const Byte *buf);
78 void AddCommentTo(UString &s) const;
79 void AddUdfVersionTo(UString &s) const;
78}; 80};
79*/ 81
82
80 83
81// ---------- ECMA Part 3: Volume Structure ---------- 84// ---------- ECMA Part 3: Volume Structure ----------
82 85
83// ECMA 3/10.5 86// ECMA 3/7.1
84 87
85struct CPartition 88struct CExtent
89{
90 UInt32 Len;
91 UInt32 Pos; // logical sector number
92
93 void Parse(const Byte *p);
94};
95
96
97// ECMA 3/10.1
98// UDF 2.2.2 PrimaryVolumeDescriptor
99
100struct CPrimeVol
86{ 101{
102 // UInt32 VolumeDescriptorSequenceNumber;
103 UInt32 PrimaryVolumeDescriptorNumber;
104 CDString32 VolumeId;
105 UInt16 VolumeSequenceNumber;
106 UInt16 MaximumVolumeSequenceNumber;
107 // UInt16 InterchangeLevel;
108 // UInt16 MaximumInterchangeLevel;
109 // UInt32 CharacterSetList;
110 // UInt32 MaximumCharacterSetList;
111 CDString128 VolumeSetId;
112 // charspec DescriptorCharacterSet; // (1/7.2.1)
113 // charspec ExplanatoryCharacterSet; // (1/7.2.1)
114 // CExtent VolumeAbstract;
115 // CExtent VolumeCopyrightNotice;
116 CRegId ApplicationId;
117 CTime RecordingTime;
118 CRegId ImplId;
119 // bytes ImplementationUse
120 // UInt32 PredecessorVolumeDescriptorSequenceLocation;
87 // UInt16 Flags; 121 // UInt16 Flags;
88 UInt16 Number;
89 // CRegId ContentsId;
90 // Byte ContentsUse[128];
91 // UInt32 AccessType;
92 122
123 void Parse(const Byte *p);
124};
125
126
127// ECMA 3/10.5
128// UDF 2.2.14 PartitionDescriptor
129
130struct CPartition
131{
93 UInt32 Pos; 132 UInt32 Pos;
94 UInt32 Len; 133 UInt32 Len;
95 134
96 // CRegId ImplId; 135 UInt16 Flags;
136 UInt16 Number;
137 CRegId ContentsId;
138 // Byte ContentsUse[128];
139 UInt32 AccessType;
140
141 CRegId ImplId;
97 // Byte ImplUse[128]; 142 // Byte ImplUse[128];
98 143
99 int VolIndex; 144 // int VolIndex;
100 CMap32 Map; 145 CMap32 Map;
101 146
102 CPartition(): VolIndex(-1) {} 147 bool IsMetadata;
148
149 CPartition():
150 // VolIndex(-1),
151 IsMetadata(false) {}
103 152
104 // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } 153 // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); }
105 // bool IsAllocated() const { return ((Flags & 1) != 0); } 154 // bool IsAllocated() const { return ((Flags & 1) != 0); }
106}; 155};
107 156
157
158// ECMA 4/7.1 lb_addr
159
108struct CLogBlockAddr 160struct CLogBlockAddr
109{ 161{
110 UInt32 Pos; 162 UInt32 Pos;
111 UInt16 PartitionRef; 163 UInt16 PartitionRef;
112 164
113 void Parse(const Byte *buf); 165 void Parse(const Byte *p);
114}; 166};
115 167
168
116enum EShortAllocDescType 169enum EShortAllocDescType
117{ 170{
118 SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, 171 SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0,
@@ -121,16 +174,18 @@ enum EShortAllocDescType
121 SHORT_ALLOC_DESC_TYPE_NextExtent = 3 174 SHORT_ALLOC_DESC_TYPE_NextExtent = 3
122}; 175};
123 176
177
178// ECMA 4/14.14.1 short_ad
179
124struct CShortAllocDesc 180struct CShortAllocDesc
125{ 181{
126 UInt32 Len; 182 UInt32 Len;
127 UInt32 Pos; 183 UInt32 Pos;
128 184
129 // 4/14.14.1
130 // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } 185 // UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
131 // UInt32 GetType() const { return Len >> 30; } 186 // UInt32 GetType() const { return Len >> 30; }
132 // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } 187 // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
133 void Parse(const Byte *buf); 188 void Parse(const Byte *p);
134}; 189};
135 190
136/* 191/*
@@ -138,10 +193,13 @@ struct CADImpUse
138{ 193{
139 UInt16 Flags; 194 UInt16 Flags;
140 UInt32 UdfUniqueId; 195 UInt32 UdfUniqueId;
141 void Parse(const Byte *buf); 196 void Parse(const Byte *p);
142}; 197};
143*/ 198*/
144 199
200// ECMA 4/14.14.2 long_ad
201// UDF 2.3.10.1
202
145struct CLongAllocDesc 203struct CLongAllocDesc
146{ 204{
147 UInt32 Len; 205 UInt32 Len;
@@ -153,29 +211,48 @@ struct CLongAllocDesc
153 UInt32 GetLen() const { return Len & 0x3FFFFFFF; } 211 UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
154 UInt32 GetType() const { return Len >> 30; } 212 UInt32 GetType() const { return Len >> 30; }
155 bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } 213 bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
156 void Parse(const Byte *buf); 214 void Parse(const Byte *p);
157}; 215};
158 216
217
218// ECMA 3/10.7 Partition maps
219// UDF 2.2.8-2.2.10 Partition Maps
220
159struct CPartitionMap 221struct CPartitionMap
160{ 222{
223 unsigned PartitionIndex;
224
161 Byte Type; 225 Byte Type;
162 // Byte Len; 226 // Byte Len;
163 227
164 // Type - 1 228 // ECMA 10.7.2
165 // UInt16 VolSeqNumber; 229 UInt16 VolumeSequenceNumber;
166 UInt16 PartitionNumber; 230 UInt16 PartitionNumber;
231
232 CRegId PartitionTypeId;
167 233
168 // Byte Data[256]; 234 // UDF 2.2.10 Metadata Partition Map
235 UInt32 MetadataFileLocation;
236 // UInt32 MetadataMirrorFileLocation;
237 // UInt32 MetadataBitmapFileLocation;
238 // UInt32 AllocationUnitSize; // (Blocks)
239 // UInt16 AlignmentUnitSize; // (Blocks)
240 // Byte Flags;
169 241
170 int PartitionIndex; 242 // Byte Data[256];
243 // CPartitionMap(): PartitionIndex(-1) {}
171}; 244};
172 245
173// ECMA 4/14.6 246
247// ECMA 4/14.6.6
174 248
175enum EIcbFileType 249enum EIcbFileType
176{ 250{
177 ICB_FILE_TYPE_DIR = 4, 251 ICB_FILE_TYPE_DIR = 4,
178 ICB_FILE_TYPE_FILE = 5 252 ICB_FILE_TYPE_FILE = 5,
253
254 ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File
255 ICB_FILE_TYPE_METADATA_MIRROR = 251
179}; 256};
180 257
181enum EIcbDescriptorType 258enum EIcbDescriptorType
@@ -186,6 +263,9 @@ enum EIcbDescriptorType
186 ICB_DESC_TYPE_INLINE = 3 263 ICB_DESC_TYPE_INLINE = 3
187}; 264};
188 265
266// ECMA 4/14.6
267// UDF 3.3.2
268
189struct CIcbTag 269struct CIcbTag
190{ 270{
191 // UInt32 PriorDirectNum; 271 // UInt32 PriorDirectNum;
@@ -201,33 +281,35 @@ struct CIcbTag
201 void Parse(const Byte *p); 281 void Parse(const Byte *p);
202}; 282};
203 283
284// ECMA 4/14.4.3
204// const Byte FILEID_CHARACS_Existance = (1 << 0); 285// const Byte FILEID_CHARACS_Existance = (1 << 0);
205const Byte FILEID_CHARACS_Parent = (1 << 3); 286const Byte FILEID_CHARACS_Parent = (1 << 3);
206 287
207struct CFile 288struct CFile
208{ 289{
290 int ItemIndex;
209 // UInt16 FileVersion; 291 // UInt16 FileVersion;
210 // Byte FileCharacteristics; 292 // Byte FileCharacteristics;
211 // CByteBuffer ImplUse; 293 // CByteBuffer ImplUse;
212 CDString Id; 294 CDString Id;
213 295
214 int ItemIndex;
215
216 CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} 296 CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {}
217 UString GetName() const { return Id.GetString(); } 297 UString GetName() const { return Id.GetString(); }
218}; 298};
219 299
300
220struct CMyExtent 301struct CMyExtent
221{ 302{
222 UInt32 Pos; 303 UInt32 Pos;
223 UInt32 Len; 304 UInt32 Len;
224 unsigned PartitionRef; 305 unsigned PartitionRef; // index in CLogVol::PartitionMaps
225 306
226 UInt32 GetLen() const { return Len & 0x3FFFFFFF; } 307 UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
227 UInt32 GetType() const { return Len >> 30; } 308 UInt32 GetType() const { return Len >> 30; }
228 bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } 309 bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
229}; 310};
230 311
312
231struct CItem 313struct CItem
232{ 314{
233 CIcbTag IcbTag; 315 CIcbTag IcbTag;
@@ -235,26 +317,30 @@ struct CItem
235 // UInt32 Uid; 317 // UInt32 Uid;
236 // UInt32 Gid; 318 // UInt32 Gid;
237 // UInt32 Permissions; 319 // UInt32 Permissions;
238 // UInt16 FileLinkCount; 320 UInt16 FileLinkCount;
239 // Byte RecordFormat; 321 // Byte RecordFormat;
240 // Byte RecordDisplayAttr; 322 // Byte RecordDisplayAttr;
241 // UInt32 RecordLen; 323 // UInt32 RecordLen;
242 UInt64 Size; 324 UInt64 Size;
243 UInt64 NumLogBlockRecorded; 325 UInt64 NumLogBlockRecorded;
326 // UInt64 ObjectSize;
327
244 CTime ATime; 328 CTime ATime;
245 CTime MTime; 329 CTime MTime;
246 CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of. 330 CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of.
331 CTime CreateTime;
247 // UInt32 CheckPoint; 332 // UInt32 CheckPoint;
248 // CLongAllocDesc ExtendedAttrIcb; 333 // CLongAllocDesc ExtendedAttrIcb;
249 // CRegId ImplId; 334 // CRegId ImplId;
250 // UInt64 UniqueId; 335 // UInt64 UniqueId;
251 336
337 bool IsExtended;
252 bool IsInline; 338 bool IsInline;
253 CByteBuffer InlineData; 339 CByteBuffer InlineData;
254 CRecordVector<CMyExtent> Extents; 340 CRecordVector<CMyExtent> Extents;
255 CUIntVector SubFiles; 341 CUIntVector SubFiles;
256 342
257 void Parse(const Byte *buf); 343 void Parse(const Byte *p);
258 344
259 bool IsRecAndAlloc() const 345 bool IsRecAndAlloc() const
260 { 346 {
@@ -279,53 +365,65 @@ struct CItem
279 bool IsDir() const { return IcbTag.IsDir(); } 365 bool IsDir() const { return IcbTag.IsDir(); }
280}; 366};
281 367
368
282struct CRef 369struct CRef
283{ 370{
284 int Parent;
285 unsigned FileIndex; 371 unsigned FileIndex;
372 int Parent;
286}; 373};
287 374
288 375
289// ECMA 4 / 14.1 376// ECMA 4 / 14.1
290struct CFileSet 377struct CFileSet
291{ 378{
292 CTime RecodringTime; 379 CRecordVector<CRef> Refs;
380
381 CTime RecordingTime;
293 // UInt16 InterchangeLevel; 382 // UInt16 InterchangeLevel;
294 // UInt16 MaxInterchangeLevel; 383 // UInt16 MaxInterchangeLevel;
295 // UInt32 FileSetNumber; 384 UInt32 FileSetNumber;
296 // UInt32 FileSetDescNumber; 385 UInt32 FileSetDescNumber;
297 // CDString32 Id; 386 CDString128 LogicalVolumeId;
298 // CDString32 CopyrightId; 387 CDString32 Id;
299 // CDString32 AbstractId; 388 CDString32 CopyrightId;
389 CDString32 AbstractId;
300 390
301 CLongAllocDesc RootDirICB; 391 CLongAllocDesc RootDirICB;
302 // CRegId DomainId; 392 CRegId DomainId;
303 // CLongAllocDesc SystemStreamDirICB; 393 // CLongAllocDesc SystemStreamDirICB;
304
305 CRecordVector<CRef> Refs;
306}; 394};
307 395
308 396
397/* 8.3 Volume descriptors
3988.4
399A Volume Descriptor Sequence:
400 shall contain one or more Primary Volume Descriptors.
401*/
402
309// ECMA 3/10.6 403// ECMA 3/10.6
404// UDF 2.2.4 LogicalVolumeDescriptor
310 405
311struct CLogVol 406struct CLogVol
312{ 407{
313 CDString128 Id; 408 CObjectVector<CPartitionMap> PartitionMaps;
409 CObjectVector<CFileSet> FileSets;
410
314 UInt32 BlockSize; 411 UInt32 BlockSize;
315 // CRegId DomainId; 412 CDString128 Id;
413 CRegId DomainId;
316 414
317 // Byte ContentsUse[16]; 415 // Byte ContentsUse[16];
318 CLongAllocDesc FileSetLocation; // UDF 416 CLongAllocDesc FileSetLocation; // UDF
319 417
320 // CRegId ImplId; 418 CRegId ImplId;
321 // Byte ImplUse[128]; 419 // Byte ImplUse[128];
322 420 // CExtent IntegritySequenceExtent;
323 CObjectVector<CPartitionMap> PartitionMaps;
324 CObjectVector<CFileSet> FileSets;
325 421
326 UString GetName() const { return Id.GetString(); } 422 UString GetName() const { return Id.GetString(); }
327}; 423};
328 424
425
426
329struct CProgressVirt 427struct CProgressVirt
330{ 428{
331 virtual HRESULT SetTotal(UInt64 numBytes) PURE; 429 virtual HRESULT SetTotal(UInt64 numBytes) PURE;
@@ -335,15 +433,42 @@ struct CProgressVirt
335 433
336class CInArchive 434class CInArchive
337{ 435{
436public:
437 CObjectVector<CLogVol> LogVols;
438 CObjectVector<CItem> Items;
439 CObjectVector<CFile> Files;
440 CObjectVector<CPartition> Partitions;
441
442 unsigned SecLogSize;
443 UInt64 PhySize;
444 UInt64 FileSize;
445
446 bool IsArc;
447 bool Unsupported;
448 bool UnexpectedEnd;
449 bool NoEndAnchor;
450
451 CObjectVector<CPrimeVol> PrimeVols;
452
453 HRESULT Open(IInStream *inStream, CProgressVirt *progress);
454 void Clear();
455
456 UString GetComment() const;
457 UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex,
458 bool showVolName, bool showFsName) const;
459
460 bool CheckItemExtents(unsigned volIndex, const CItem &item) const;
461
462private:
338 IInStream *_stream; 463 IInStream *_stream;
339 CProgressVirt *_progress; 464 CProgressVirt *_progress;
340 465
341 HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); 466 HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf);
342 HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf); 467 HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf);
343 HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf); 468 HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf);
344 469
345 HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); 470 HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
346 HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); 471 HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
347 472
348 HRESULT Open2(); 473 HRESULT Open2();
349 HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); 474 HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed);
@@ -354,37 +479,18 @@ class CInArchive
354 unsigned _numRefs; 479 unsigned _numRefs;
355 UInt32 _numExtents; 480 UInt32 _numExtents;
356 UInt64 _inlineExtentsSize; 481 UInt64 _inlineExtentsSize;
357 bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const; 482 bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const;
358
359public:
360 CObjectVector<CPartition> Partitions;
361 CObjectVector<CLogVol> LogVols;
362
363 CObjectVector<CItem> Items;
364 CObjectVector<CFile> Files;
365
366 unsigned SecLogSize;
367 UInt64 PhySize;
368 UInt64 FileSize;
369
370 bool IsArc;
371 bool Unsupported;
372 bool UnexpectedEnd;
373 bool NoEndAnchor;
374 483
375 void UpdatePhySize(UInt64 val) 484 void UpdatePhySize(UInt64 val)
376 { 485 {
377 if (PhySize < val) 486 if (PhySize < val)
378 PhySize = val; 487 PhySize = val;
379 } 488 }
380 HRESULT Open(IInStream *inStream, CProgressVirt *progress);
381 void Clear();
382
383 UString GetComment() const;
384 UString GetItemPath(int volIndex, int fsIndex, int refIndex,
385 bool showVolName, bool showFsName) const;
386 489
387 bool CheckItemExtents(int volIndex, const CItem &item) const; 490 void UpdatePhySize(const CExtent &e)
491 {
492 UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len);
493 }
388}; 494};
389 495
390API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); 496API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size);
diff --git a/CPP/7zip/Bundles/Alone/makefile.gcc b/CPP/7zip/Bundles/Alone/makefile.gcc
index 38f8d59..20d6a86 100644
--- a/CPP/7zip/Bundles/Alone/makefile.gcc
+++ b/CPP/7zip/Bundles/Alone/makefile.gcc
@@ -13,11 +13,20 @@ LOCAL_FLAGS_ST =
13MT_OBJS = 13MT_OBJS =
14 14
15 15
16ifdef SystemDrive
17IS_MINGW = 1
18else
19ifdef SYSTEMDRIVE
20# ifdef OS
21IS_MINGW = 1
22endif
23endif
24
16ifdef ST_MODE 25ifdef ST_MODE
17 26
18LOCAL_FLAGS_ST = -D_7ZIP_ST 27LOCAL_FLAGS_ST = -D_7ZIP_ST
19 28
20ifdef SystemDrive 29ifdef IS_MINGW
21MT_OBJS = \ 30MT_OBJS = \
22 $O/Threads.o \ 31 $O/Threads.o \
23 32
@@ -41,7 +50,7 @@ endif
41 50
42LOCAL_FLAGS_SYS = 51LOCAL_FLAGS_SYS =
43 52
44ifdef SystemDrive 53ifdef IS_MINGW
45 54
46LOCAL_FLAGS_SYS = \ 55LOCAL_FLAGS_SYS = \
47 -D_7ZIP_LARGE_PAGES \ 56 -D_7ZIP_LARGE_PAGES \
diff --git a/CPP/7zip/Bundles/Alone2/makefile.gcc b/CPP/7zip/Bundles/Alone2/makefile.gcc
index f8d31db..49f9fd0 100644
--- a/CPP/7zip/Bundles/Alone2/makefile.gcc
+++ b/CPP/7zip/Bundles/Alone2/makefile.gcc
@@ -9,6 +9,15 @@ CONSOLE_VARIANT_FLAGS=-DPROG_VARIANT_Z
9include ../Format7zF/Arc_gcc.mak 9include ../Format7zF/Arc_gcc.mak
10 10
11ifdef SystemDrive 11ifdef SystemDrive
12IS_MINGW = 1
13else
14ifdef SYSTEMDRIVE
15# ifdef OS
16IS_MINGW = 1
17endif
18endif
19
20ifdef IS_MINGW
12 21
13LOCAL_FLAGS_SYS = \ 22LOCAL_FLAGS_SYS = \
14 -D_7ZIP_LARGE_PAGES \ 23 -D_7ZIP_LARGE_PAGES \
diff --git a/CPP/7zip/Bundles/Alone7z/makefile.gcc b/CPP/7zip/Bundles/Alone7z/makefile.gcc
index 8565452..f11fcde 100644
--- a/CPP/7zip/Bundles/Alone7z/makefile.gcc
+++ b/CPP/7zip/Bundles/Alone7z/makefile.gcc
@@ -6,6 +6,15 @@ CONSOLE_VARIANT_FLAGS=-DPROG_VARIANT_R
6# USE_ASM = 1 6# USE_ASM = 1
7# ST_MODE = 1 7# ST_MODE = 1
8 8
9ifdef SystemDrive
10IS_MINGW = 1
11else
12ifdef SYSTEMDRIVE
13# ifdef OS
14IS_MINGW = 1
15endif
16endif
17
9include ../../LzmaDec_gcc.mak 18include ../../LzmaDec_gcc.mak
10 19
11 20
@@ -17,7 +26,7 @@ ifdef ST_MODE
17 26
18LOCAL_FLAGS_ST = -D_7ZIP_ST 27LOCAL_FLAGS_ST = -D_7ZIP_ST
19 28
20ifdef SystemDrive 29ifdef IS_MINGW
21MT_OBJS = \ 30MT_OBJS = \
22 $O/Threads.o \ 31 $O/Threads.o \
23 32
@@ -41,7 +50,7 @@ endif
41 50
42LOCAL_FLAGS_SYS = 51LOCAL_FLAGS_SYS =
43 52
44ifdef SystemDrive 53ifdef IS_MINGW
45 54
46LOCAL_FLAGS_SYS = \ 55LOCAL_FLAGS_SYS = \
47 -D_7ZIP_LARGE_PAGES \ 56 -D_7ZIP_LARGE_PAGES \
diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
index e5e1e21..1292dd8 100644
--- a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
+++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
@@ -3,12 +3,20 @@ include ../../LzmaDec_gcc.mak
3LOCAL_FLAGS_ST = 3LOCAL_FLAGS_ST =
4MT_OBJS = 4MT_OBJS =
5 5
6ifdef SystemDrive
7IS_MINGW = 1
8else
9ifdef SYSTEMDRIVE
10# ifdef OS
11IS_MINGW = 1
12endif
13endif
6 14
7ifdef ST_MODE 15ifdef ST_MODE
8 16
9LOCAL_FLAGS_ST = -D_7ZIP_ST 17LOCAL_FLAGS_ST = -D_7ZIP_ST
10 18
11ifdef SystemDrive 19ifdef IS_MINGW
12MT_OBJS = \ 20MT_OBJS = \
13 $O/Threads.o \ 21 $O/Threads.o \
14 22
diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
index cf2d9e8..bd2ed44 100644
--- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
@@ -2847,6 +2847,10 @@ SOURCE=..\..\Archive\HfsHandler.cpp
2847# End Source File 2847# End Source File
2848# Begin Source File 2848# Begin Source File
2849 2849
2850SOURCE=..\..\Archive\HfsHandler.h
2851# End Source File
2852# Begin Source File
2853
2850SOURCE=..\..\Archive\IArchive.h 2854SOURCE=..\..\Archive\IArchive.h
2851# End Source File 2855# End Source File
2852# Begin Source File 2856# Begin Source File
diff --git a/CPP/7zip/Bundles/Format7zF/makefile.gcc b/CPP/7zip/Bundles/Format7zF/makefile.gcc
index 1953dd5..e468d7c 100644
--- a/CPP/7zip/Bundles/Format7zF/makefile.gcc
+++ b/CPP/7zip/Bundles/Format7zF/makefile.gcc
@@ -8,6 +8,16 @@ DEF_FILE = ../../Archive/Archive2.def
8include Arc_gcc.mak 8include Arc_gcc.mak
9 9
10ifdef SystemDrive 10ifdef SystemDrive
11IS_MINGW = 1
12else
13ifdef SYSTEMDRIVE
14# ifdef OS
15IS_MINGW = 1
16endif
17endif
18
19
20ifdef IS_MINGW
11 21
12LOCAL_FLAGS_WIN = \ 22LOCAL_FLAGS_WIN = \
13 -D_7ZIP_LARGE_PAGES \ 23 -D_7ZIP_LARGE_PAGES \
diff --git a/CPP/7zip/Bundles/LzmaCon/makefile.gcc b/CPP/7zip/Bundles/LzmaCon/makefile.gcc
index 58c204a..e45ebb6 100644
--- a/CPP/7zip/Bundles/LzmaCon/makefile.gcc
+++ b/CPP/7zip/Bundles/LzmaCon/makefile.gcc
@@ -10,6 +10,15 @@ LOCAL_FLAGS_ST =
10MT_OBJS = 10MT_OBJS =
11 11
12 12
13ifdef SystemDrive
14IS_MINGW = 1
15else
16ifdef SYSTEMDRIVE
17# ifdef OS
18IS_MINGW = 1
19endif
20endif
21
13ifdef ST_MODE 22ifdef ST_MODE
14 23
15LOCAL_FLAGS_ST = -D_7ZIP_ST 24LOCAL_FLAGS_ST = -D_7ZIP_ST
@@ -30,7 +39,7 @@ endif
30 39
31LOCAL_FLAGS_SYS = 40LOCAL_FLAGS_SYS =
32 41
33ifdef SystemDrive 42ifdef IS_MINGW
34 43
35SYS_OBJS = \ 44SYS_OBJS = \
36 $O/Registry.o \ 45 $O/Registry.o \
diff --git a/CPP/7zip/Bundles/SFXCon/makefile.gcc b/CPP/7zip/Bundles/SFXCon/makefile.gcc
index 889ec1f..551b3e1 100644
--- a/CPP/7zip/Bundles/SFXCon/makefile.gcc
+++ b/CPP/7zip/Bundles/SFXCon/makefile.gcc
@@ -11,11 +11,20 @@ LOCAL_FLAGS_ST =
11MT_OBJS = 11MT_OBJS =
12 12
13 13
14ifdef SystemDrive
15IS_MINGW = 1
16else
17ifdef SYSTEMDRIVE
18# ifdef OS
19IS_MINGW = 1
20endif
21endif
22
14ifdef ST_MODE 23ifdef ST_MODE
15 24
16LOCAL_FLAGS_ST = -D_7ZIP_ST 25LOCAL_FLAGS_ST = -D_7ZIP_ST
17 26
18ifdef SystemDrive 27ifdef IS_MINGW
19MT_OBJS = \ 28MT_OBJS = \
20 $O/Threads.o \ 29 $O/Threads.o \
21 30
@@ -35,7 +44,7 @@ endif
35 44
36LOCAL_FLAGS_SYS = 45LOCAL_FLAGS_SYS =
37 46
38ifdef SystemDrive 47ifdef IS_MINGW
39 48
40LOCAL_FLAGS_SYS = \ 49LOCAL_FLAGS_SYS = \
41 50
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp
index 6862a9b..0349e90 100644
--- a/CPP/7zip/Common/FileStreams.cpp
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -11,9 +11,12 @@
11#include <grp.h> 11#include <grp.h>
12#include <pwd.h> 12#include <pwd.h>
13 13
14// for major minor 14// for major()/minor():
15// BSD: <sys/types.h> 15#if defined(__FreeBSD__) || defined(BSD)
16#include <sys/types.h>
17#else
16#include <sys/sysmacros.h> 18#include <sys/sysmacros.h>
19#endif
17 20
18#endif 21#endif
19 22
diff --git a/CPP/7zip/Compress/LzfseDecoder.cpp b/CPP/7zip/Compress/LzfseDecoder.cpp
index 41c7445..0eb10af 100644
--- a/CPP/7zip/Compress/LzfseDecoder.cpp
+++ b/CPP/7zip/Compress/LzfseDecoder.cpp
@@ -89,11 +89,8 @@ HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize)
89 89
90 90
91 91
92HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize) 92HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize)
93{ 93{
94 UInt32 packSize;
95 RINOK(GetUInt32(packSize));
96
97 PRF(printf("\nLZVN %7u %7u", unpackSize, packSize)); 94 PRF(printf("\nLZVN %7u %7u", unpackSize, packSize));
98 95
99 UInt32 D = 0; 96 UInt32 D = 0;
@@ -854,6 +851,16 @@ STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStr
854 UInt64 prevOut = 0; 851 UInt64 prevOut = 0;
855 UInt64 prevIn = 0; 852 UInt64 prevIn = 0;
856 853
854 if (LzvnMode)
855 {
856 const UInt64 unpackSize = *outSize;
857 const UInt64 packSize = *inSize;
858 if (unpackSize > (UInt32)(Int32)-1
859 || packSize > (UInt32)(Int32)-1)
860 return S_FALSE;
861 RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize));
862 }
863 else
857 for (;;) 864 for (;;)
858 { 865 {
859 const UInt64 pos = m_OutWindowStream.GetProcessedSize(); 866 const UInt64 pos = m_OutWindowStream.GetProcessedSize();
@@ -889,7 +896,12 @@ STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStr
889 if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2) 896 if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2)
890 res = DecodeLzfse(cur, (Byte)v); 897 res = DecodeLzfse(cur, (Byte)v);
891 else if (v == 0x6E) // 'n' 898 else if (v == 0x6E) // 'n'
892 res = DecodeLzvn(cur); 899 {
900 UInt32 packSize;
901 res = GetUInt32(packSize);
902 if (res == S_OK)
903 res = DecodeLzvn(cur, packSize);
904 }
893 else if (v == 0x2D) // '-' 905 else if (v == 0x2D) // '-'
894 res = DecodeUncompressed(cur); 906 res = DecodeUncompressed(cur);
895 else 907 else
diff --git a/CPP/7zip/Compress/LzfseDecoder.h b/CPP/7zip/Compress/LzfseDecoder.h
index 0156a08..401e0ba 100644
--- a/CPP/7zip/Compress/LzfseDecoder.h
+++ b/CPP/7zip/Compress/LzfseDecoder.h
@@ -41,14 +41,23 @@ class CDecoder:
41 HRESULT GetUInt32(UInt32 &val); 41 HRESULT GetUInt32(UInt32 &val);
42 42
43 HRESULT DecodeUncompressed(UInt32 unpackSize); 43 HRESULT DecodeUncompressed(UInt32 unpackSize);
44 HRESULT DecodeLzvn(UInt32 unpackSize); 44 HRESULT DecodeLzvn(UInt32 unpackSize, UInt32 packSize);
45 HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); 45 HRESULT DecodeLzfse(UInt32 unpackSize, Byte version);
46 46
47 STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream, 47 STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
48 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); 48 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
49public: 49public:
50 bool LzvnMode;
50 MY_UNKNOWN_IMP 51 MY_UNKNOWN_IMP
51 52
53 CDecoder():
54 LzvnMode(false)
55 {}
56
57 // sizes are checked in Code()
58 // UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); }
59 // UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); }
60
52 STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, 61 STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize,
53 const UInt64 *outSize, ICompressProgressInfo *progress); 62 const UInt64 *outSize, ICompressProgressInfo *progress);
54}; 63};
diff --git a/CPP/7zip/UI/Client7z/makefile.gcc b/CPP/7zip/UI/Client7z/makefile.gcc
index b65095b..3f97205 100644
--- a/CPP/7zip/UI/Client7z/makefile.gcc
+++ b/CPP/7zip/UI/Client7z/makefile.gcc
@@ -6,6 +6,16 @@ IS_NOT_STANDALONE = 1
6 6
7 7
8ifdef SystemDrive 8ifdef SystemDrive
9IS_MINGW = 1
10else
11ifdef SYSTEMDRIVE
12# ifdef OS
13IS_MINGW = 1
14endif
15endif
16
17
18ifdef IS_MINGW
9 19
10SYS_OBJS = \ 20SYS_OBJS = \
11 $O/resource.o \ 21 $O/resource.o \
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp
index a4ac413..dab3725 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -187,7 +187,7 @@ CDirItems::CDirItems():
187 , ReadSecure(false) 187 , ReadSecure(false)
188 #endif 188 #endif
189 #ifndef _WIN32 189 #ifndef _WIN32
190 , StoreOwnerName(true) 190 , StoreOwnerName(false)
191 #endif 191 #endif
192 , Callback(NULL) 192 , Callback(NULL)
193{ 193{
@@ -1361,6 +1361,7 @@ HRESULT CDirItems::FillDeviceSizes()
1361 // 200K/sec speed 1361 // 200K/sec speed
1362 u.Empty(); 1362 u.Empty();
1363 const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]); 1363 const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]);
1364 // printf("\ngetpwuid=%s\n", pw->pw_name);
1364 if (pw) 1365 if (pw)
1365 { 1366 {
1366 a = pw->pw_name; 1367 a = pw->pw_name;
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
index 926a275..c93bfc7 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -8,11 +8,15 @@
8// #include <grp.h> 8// #include <grp.h>
9// #include <pwd.h> 9// #include <pwd.h>
10 10
11// for major minor: 11// for major()/minor():
12// BSD: <sys/types.h> 12#if defined(__FreeBSD__) || defined(BSD)
13#include <sys/types.h>
14#else
13#include <sys/sysmacros.h> 15#include <sys/sysmacros.h>
14#endif 16#endif
15 17
18#endif
19
16#ifndef _7ZIP_ST 20#ifndef _7ZIP_ST
17#include "../../../Windows/Synchronization.h" 21#include "../../../Windows/Synchronization.h"
18#endif 22#endif
diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp
index f6a3254..ea336cf 100644
--- a/CPP/7zip/UI/Console/Console.dsp
+++ b/CPP/7zip/UI/Console/Console.dsp
@@ -345,6 +345,10 @@ SOURCE=..\..\..\Windows\Registry.h
345# End Source File 345# End Source File
346# Begin Source File 346# Begin Source File
347 347
348SOURCE=..\..\..\Windows\SecurityUtils.h
349# End Source File
350# Begin Source File
351
348SOURCE=..\..\..\Windows\Synchronization.h 352SOURCE=..\..\..\Windows\Synchronization.h
349# End Source File 353# End Source File
350# Begin Source File 354# Begin Source File
diff --git a/CPP/7zip/UI/Console/makefile.gcc b/CPP/7zip/UI/Console/makefile.gcc
index ed05a14..d7e4447 100644
--- a/CPP/7zip/UI/Console/makefile.gcc
+++ b/CPP/7zip/UI/Console/makefile.gcc
@@ -9,11 +9,20 @@ IS_NOT_STANDALONE = 1
9LOCAL_FLAGS_ST = 9LOCAL_FLAGS_ST =
10MT_OBJS = 10MT_OBJS =
11 11
12ifdef SystemDrive
13IS_MINGW = 1
14else
15ifdef SYSTEMDRIVE
16# ifdef OS
17IS_MINGW = 1
18endif
19endif
20
12ifdef ST_MODE 21ifdef ST_MODE
13 22
14LOCAL_FLAGS_ST = -D_7ZIP_ST 23LOCAL_FLAGS_ST = -D_7ZIP_ST
15 24
16ifdef SystemDrive 25ifdef IS_MINGW
17MT_OBJS = \ 26MT_OBJS = \
18 $O/Threads.o \ 27 $O/Threads.o \
19 28
@@ -31,7 +40,7 @@ endif
31 40
32LOCAL_FLAGS_WIN= 41LOCAL_FLAGS_WIN=
33 42
34ifdef SystemDrive 43ifdef IS_MINGW
35 44
36LOCAL_FLAGS_WIN = \ 45LOCAL_FLAGS_WIN = \
37 -D_7ZIP_LARGE_PAGES \ 46 -D_7ZIP_LARGE_PAGES \
diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc
index 6659290..acfa6e5 100644
--- a/CPP/7zip/UI/Explorer/resource.rc
+++ b/CPP/7zip/UI/Explorer/resource.rc
@@ -7,4 +7,4 @@ MY_VERSION_INFO_DLL("7-Zip Shell Extension", "7-zip")
71 24 MOVEABLE PURE "7-zip.dll.manifest" 71 24 MOVEABLE PURE "7-zip.dll.manifest"
8#endif 8#endif
9 9
10IDI_ICON ICON "..\FileManager\FM.ico" 10IDI_ICON ICON "../FileManager/FM.ico"
diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp
index 72cb0ce..f603061 100644
--- a/CPP/7zip/UI/FileManager/FSFolder.cpp
+++ b/CPP/7zip/UI/FileManager/FSFolder.cpp
@@ -5,8 +5,13 @@
5#if defined(_MSC_VER) 5#if defined(_MSC_VER)
6#include <winternl.h> 6#include <winternl.h>
7#else 7#else
8// mingw 8#if defined(__GNUC__) && (__GNUC__ >= 10)
9#include <ddk/winddk.h> 9 // new mingw:
10 #include <winternl.h>
11#else
12 // old mingw:
13 #include <ddk/winddk.h>
14#endif
10#endif 15#endif
11 16
12#include "../../../Common/ComTry.h" 17#include "../../../Common/ComTry.h"
diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp
index ff444b3..4ca931b 100644
--- a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp
+++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp
@@ -29,6 +29,9 @@ using namespace NFind;
29extern bool g_IsNT; 29extern bool g_IsNT;
30#endif 30#endif
31 31
32#define MY_CAST_FUNC (void(*)())
33// #define MY_CAST_FUNC
34
32namespace NFsFolder { 35namespace NFsFolder {
33 36
34HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib) 37HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib)
@@ -245,7 +248,9 @@ void CCopyState::Prepare()
245 my_CopyFileExA = NULL; 248 my_CopyFileExA = NULL;
246 if (!g_IsNT) 249 if (!g_IsNT)
247 { 250 {
248 my_CopyFileExA = (Func_CopyFileExA)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); 251 my_CopyFileExA = (Func_CopyFileExA)
252 MY_CAST_FUNC
253 ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA");
249 } 254 }
250 else 255 else
251 #endif 256 #endif
diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h
index c45c215..5fe1ef7 100644
--- a/CPP/7zip/UI/FileManager/MyCom2.h
+++ b/CPP/7zip/UI/FileManager/MyCom2.h
@@ -7,8 +7,9 @@
7 7
8#define MY_ADDREF_RELEASE_MT \ 8#define MY_ADDREF_RELEASE_MT \
9STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement((LONG *)&__m_RefCount); return __m_RefCount; } \ 9STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement((LONG *)&__m_RefCount); return __m_RefCount; } \
10STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); if (__m_RefCount != 0) \ 10STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); \
11 return __m_RefCount; delete this; return 0; } 11 if (__m_RefCount != 0) return __m_RefCount; \
12 delete this; return 0; }
12 13
13#define MY_UNKNOWN_IMP_SPEC_MT2(i1, i) \ 14#define MY_UNKNOWN_IMP_SPEC_MT2(i1, i) \
14 MY_QUERYINTERFACE_BEGIN \ 15 MY_QUERYINTERFACE_BEGIN \
diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp
index e34e74f..a683b5e 100644
--- a/CPP/7zip/UI/FileManager/PanelOperations.cpp
+++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp
@@ -24,6 +24,9 @@ using namespace NWindows;
24using namespace NFile; 24using namespace NFile;
25using namespace NName; 25using namespace NName;
26 26
27#define MY_CAST_FUNC (void(*)())
28// #define MY_CAST_FUNC
29
27#ifndef _UNICODE 30#ifndef _UNICODE
28extern bool g_IsNT; 31extern bool g_IsNT;
29#endif 32#endif
@@ -96,7 +99,7 @@ HRESULT CThreadFolderOperations::DoOperation(CPanel &panel, const UString &progr
96} 99}
97 100
98#ifndef _UNICODE 101#ifndef _UNICODE
99typedef int (WINAPI * SHFileOperationWP)(LPSHFILEOPSTRUCTW lpFileOp); 102typedef int (WINAPI * Func_SHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp);
100#endif 103#endif
101 104
102/* 105/*
@@ -192,9 +195,10 @@ void CPanel::DeleteItems(bool NON_CE_VAR(toRecycleBin))
192 #ifdef _UNICODE 195 #ifdef _UNICODE
193 /* res = */ ::SHFileOperationW(&fo); 196 /* res = */ ::SHFileOperationW(&fo);
194 #else 197 #else
195 SHFileOperationWP shFileOperationW = (SHFileOperationWP) 198 Func_SHFileOperationW shFileOperationW = (Func_SHFileOperationW)
199 MY_CAST_FUNC
196 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW"); 200 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW");
197 if (shFileOperationW == 0) 201 if (!shFileOperationW)
198 return; 202 return;
199 /* res = */ shFileOperationW(&fo); 203 /* res = */ shFileOperationW(&fo);
200 #endif 204 #endif
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
index b756dfc..d8e0f8b 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
@@ -12,6 +12,9 @@
12 12
13#include <ShlObj.h> 13#include <ShlObj.h>
14 14
15#define MY_CAST_FUNC (void(*)())
16// #define MY_CAST_FUNC
17
15#ifndef _UNICODE 18#ifndef _UNICODE
16extern bool g_IsNT; 19extern bool g_IsNT;
17#endif 20#endif
@@ -39,15 +42,16 @@ int GetIconIndexForCSIDL(int csidl)
39} 42}
40 43
41#ifndef _UNICODE 44#ifndef _UNICODE
42typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); 45typedef int (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
43 46
44static struct CSHGetFileInfoInit 47static struct CSHGetFileInfoInit
45{ 48{
46 SHGetFileInfoWP shGetFileInfoW; 49 Func_SHGetFileInfoW shGetFileInfoW;
47 CSHGetFileInfoInit() 50 CSHGetFileInfoInit()
48 { 51 {
49 shGetFileInfoW = (SHGetFileInfoWP) 52 shGetFileInfoW = (Func_SHGetFileInfoW)
50 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW"); 53 MY_CAST_FUNC
54 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");
51 } 55 }
52} g_SHGetFileInfoInit; 56} g_SHGetFileInfoInit;
53#endif 57#endif
diff --git a/CPP/7zip/UI/FileManager/TextPairs.cpp b/CPP/7zip/UI/FileManager/TextPairs.cpp
index 6a989fc..4edf025 100644
--- a/CPP/7zip/UI/FileManager/TextPairs.cpp
+++ b/CPP/7zip/UI/FileManager/TextPairs.cpp
@@ -104,13 +104,16 @@ void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, 0); }
104 104
105int CPairsStorage::FindID(const UString &id, int &insertPos) const 105int CPairsStorage::FindID(const UString &id, int &insertPos) const
106{ 106{
107 int left = 0, right = Pairs.Size(); 107 unsigned left = 0, right = Pairs.Size();
108 while (left != right) 108 while (left != right)
109 { 109 {
110 int mid = (left + right) / 2; 110 const unsigned mid = (left + right) / 2;
111 int compResult = ComparePairIDs(id, Pairs[mid].ID); 111 const int compResult = ComparePairIDs(id, Pairs[mid].ID);
112 if (compResult == 0) 112 if (compResult == 0)
113 {
114 insertPos = mid; // to disable GCC warning
113 return mid; 115 return mid;
116 }
114 if (compResult < 0) 117 if (compResult < 0)
115 right = mid; 118 right = mid;
116 else 119 else
@@ -129,7 +132,7 @@ int CPairsStorage::FindID(const UString &id) const
129void CPairsStorage::AddPair(const CTextPair &pair) 132void CPairsStorage::AddPair(const CTextPair &pair)
130{ 133{
131 int insertPos; 134 int insertPos;
132 int pos = FindID(pair.ID, insertPos); 135 const int pos = FindID(pair.ID, insertPos);
133 if (pos >= 0) 136 if (pos >= 0)
134 Pairs[pos] = pair; 137 Pairs[pos] = pair;
135 else 138 else
@@ -138,7 +141,7 @@ void CPairsStorage::AddPair(const CTextPair &pair)
138 141
139void CPairsStorage::DeletePair(const UString &id) 142void CPairsStorage::DeletePair(const UString &id)
140{ 143{
141 int pos = FindID(id); 144 const int pos = FindID(id);
142 if (pos >= 0) 145 if (pos >= 0)
143 Pairs.Delete(pos); 146 Pairs.Delete(pos);
144} 147}
@@ -146,7 +149,7 @@ void CPairsStorage::DeletePair(const UString &id)
146bool CPairsStorage::GetValue(const UString &id, UString &value) const 149bool CPairsStorage::GetValue(const UString &id, UString &value) const
147{ 150{
148 value.Empty(); 151 value.Empty();
149 int pos = FindID(id); 152 const int pos = FindID(id);
150 if (pos < 0) 153 if (pos < 0)
151 return false; 154 return false;
152 value = Pairs[pos].Value; 155 value = Pairs[pos].Value;
@@ -155,7 +158,7 @@ bool CPairsStorage::GetValue(const UString &id, UString &value) const
155 158
156UString CPairsStorage::GetValue(const UString &id) const 159UString CPairsStorage::GetValue(const UString &id) const
157{ 160{
158 int pos = FindID(id); 161 const int pos = FindID(id);
159 if (pos < 0) 162 if (pos < 0)
160 return UString(); 163 return UString();
161 return Pairs[pos].Value; 164 return Pairs[pos].Value;
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp
index 25b9219..b85ae1e 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.cpp
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -292,6 +292,7 @@ static const CFormatInfo g_Formats[] =
292 "Tar", 292 "Tar",
293 (1 << 0), 293 (1 << 0),
294 METHODS_PAIR(g_TarMethods), 294 METHODS_PAIR(g_TarMethods),
295 0
295 // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns 296 // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns
296 }, 297 },
297 { 298 {
@@ -596,7 +597,6 @@ void CCompressDialog::EnableMultiCombo(unsigned id)
596} 597}
597 598
598static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s); 599static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s);
599static void FormatOptions_To_String(const NCompression::CFormatOptions &fo, AString &s);
600 600
601static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res) 601static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res)
602{ 602{
@@ -607,7 +607,7 @@ static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBoo
607} 607}
608 608
609#define SET_GUI_BOOL(name) \ 609#define SET_GUI_BOOL(name) \
610 Combine_Two_BoolPairs(Info. ## name, m_RegistryInfo. ## name, name) 610 Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name)
611 611
612 612
613static void Set_Final_BoolPairs( 613static void Set_Final_BoolPairs(
@@ -630,7 +630,7 @@ static void Set_Final_BoolPairs(
630} 630}
631 631
632#define SET_FINAL_BOOL_PAIRS(name) \ 632#define SET_FINAL_BOOL_PAIRS(name) \
633 Set_Final_BoolPairs(name, Info. ## name, m_RegistryInfo. ## name) 633 Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name)
634 634
635void CCompressDialog::FormatChanged(bool isChanged) 635void CCompressDialog::FormatChanged(bool isChanged)
636{ 636{
@@ -2711,7 +2711,7 @@ void CCompressDialog::ShowOptionsString()
2711 NCompression::CFormatOptions &fo = Get_FormatOptions(); 2711 NCompression::CFormatOptions &fo = Get_FormatOptions();
2712 2712
2713 AString s; 2713 AString s;
2714 if (fo.TimePrec != -1) 2714 if (fo.IsSet_TimePrec())
2715 { 2715 {
2716 s.Add_OptSpaced("tp"); 2716 s.Add_OptSpaced("tp");
2717 s.Add_UInt32(fo.TimePrec); 2717 s.Add_UInt32(fo.TimePrec);
diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp
index fdfbeb9..24866b1 100644
--- a/CPP/Windows/MemoryLock.cpp
+++ b/CPP/Windows/MemoryLock.cpp
@@ -21,7 +21,7 @@ typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR
21typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges, 21typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges,
22 PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); 22 PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);
23} 23}
24#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff)GetProcAddress(hModule, name) 24#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff) (void(*)()) GetProcAddress(hModule, name)
25#endif 25#endif
26 26
27bool EnablePrivilege(LPCTSTR privilegeName, bool enable) 27bool EnablePrivilege(LPCTSTR privilegeName, bool enable)
diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp
index 8a7f45c..ede83fa 100644
--- a/CPP/Windows/SecurityUtils.cpp
+++ b/CPP/Windows/SecurityUtils.cpp
@@ -4,6 +4,9 @@
4 4
5#include "SecurityUtils.h" 5#include "SecurityUtils.h"
6 6
7#define MY_CAST_FUNC (void(*)())
8// #define MY_CAST_FUNC
9
7namespace NWindows { 10namespace NWindows {
8namespace NSecurity { 11namespace NSecurity {
9 12
@@ -50,8 +53,10 @@ static void MyLookupSids(CPolicy &policy, PSID ps)
50} 53}
51*/ 54*/
52 55
56extern "C" {
57
53#ifndef _UNICODE 58#ifndef _UNICODE
54typedef BOOL (WINAPI * LookupAccountNameWP)( 59typedef BOOL (WINAPI * Func_LookupAccountNameW)(
55 LPCWSTR lpSystemName, 60 LPCWSTR lpSystemName,
56 LPCWSTR lpAccountName, 61 LPCWSTR lpAccountName,
57 PSID Sid, 62 PSID Sid,
@@ -62,13 +67,17 @@ typedef BOOL (WINAPI * LookupAccountNameWP)(
62 ); 67 );
63#endif 68#endif
64 69
70}
71
65static PSID GetSid(LPWSTR accountName) 72static PSID GetSid(LPWSTR accountName)
66{ 73{
67 #ifndef _UNICODE 74 #ifndef _UNICODE
68 HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll")); 75 HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll"));
69 if (hModule == NULL) 76 if (hModule == NULL)
70 return NULL; 77 return NULL;
71 LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW"); 78 Func_LookupAccountNameW lookupAccountNameW = (Func_LookupAccountNameW)
79 MY_CAST_FUNC
80 GetProcAddress(hModule, "LookupAccountNameW");
72 if (lookupAccountNameW == NULL) 81 if (lookupAccountNameW == NULL)
73 return NULL; 82 return NULL;
74 #endif 83 #endif
diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h
index 8966dfd..c0d7b12 100644
--- a/CPP/Windows/SecurityUtils.h
+++ b/CPP/Windows/SecurityUtils.h
@@ -7,6 +7,31 @@
7 7
8#include "Defs.h" 8#include "Defs.h"
9 9
10#ifndef _UNICODE
11
12extern "C" {
13typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName,
14 PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);
15typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle);
16typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle,
17 PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );
18#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
19}
20
21#define POLICY_FUNC_CALL(fff, str) \
22 if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \
23 Func_ ## fff v = (Func_ ## fff) (void(*)()) GetProcAddress(hModule, str); \
24 if (!v) return MY_STATUS_NOT_IMPLEMENTED; \
25 const NTSTATUS res = v
26
27#else
28
29#define POLICY_FUNC_CALL(fff, str) \
30 const NTSTATUS res = ::fff
31
32#endif
33
34
10namespace NWindows { 35namespace NWindows {
11namespace NSecurity { 36namespace NSecurity {
12 37
@@ -53,15 +78,9 @@ public:
53 78
54}; 79};
55 80
56#ifndef _UNICODE
57typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName,
58 PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);
59typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle);
60typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle,
61 PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );
62#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
63#endif
64 81
82
83
65struct CPolicy 84struct CPolicy
66{ 85{
67protected: 86protected:
@@ -82,43 +101,17 @@ public:
82 NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, 101 NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes,
83 ACCESS_MASK desiredAccess) 102 ACCESS_MASK desiredAccess)
84 { 103 {
85 #ifndef _UNICODE
86 if (hModule == NULL)
87 return MY_STATUS_NOT_IMPLEMENTED;
88 LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy");
89 if (lsaOpenPolicy == NULL)
90 return MY_STATUS_NOT_IMPLEMENTED;
91 #endif
92
93 Close(); 104 Close();
94 return 105 POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy")
95 #ifdef _UNICODE
96 ::LsaOpenPolicy
97 #else
98 lsaOpenPolicy
99 #endif
100 (systemName, objectAttributes, desiredAccess, &_handle); 106 (systemName, objectAttributes, desiredAccess, &_handle);
107 return res;
101 } 108 }
102 109
103 NTSTATUS Close() 110 NTSTATUS Close()
104 { 111 {
105 if (_handle == NULL) 112 if (_handle == NULL)
106 return 0; 113 return 0;
107 114 POLICY_FUNC_CALL (LsaClose, "LsaClose")
108 #ifndef _UNICODE
109 if (hModule == NULL)
110 return MY_STATUS_NOT_IMPLEMENTED;
111 LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose");
112 if (lsaClose == NULL)
113 return MY_STATUS_NOT_IMPLEMENTED;
114 #endif
115
116 NTSTATUS res =
117 #ifdef _UNICODE
118 ::LsaClose
119 #else
120 lsaClose
121 #endif
122 (_handle); 115 (_handle);
123 _handle = NULL; 116 _handle = NULL;
124 return res; 117 return res;
@@ -137,21 +130,9 @@ public:
137 130
138 NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) 131 NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
139 { 132 {
140 #ifndef _UNICODE 133 POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights")
141 if (hModule == NULL)
142 return MY_STATUS_NOT_IMPLEMENTED;
143 LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights");
144 if (lsaAddAccountRights == NULL)
145 return MY_STATUS_NOT_IMPLEMENTED;
146 #endif
147
148 return
149 #ifdef _UNICODE
150 ::LsaAddAccountRights
151 #else
152 lsaAddAccountRights
153 #endif
154 (_handle, accountSid, userRights, countOfRights); 134 (_handle, accountSid, userRights, countOfRights);
135 return res;
155 } 136 }
156 NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) 137 NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights)
157 { return AddAccountRights(accountSid, userRights, 1); } 138 { return AddAccountRights(accountSid, userRights, 1); }
diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp
index d0f9032..071833c 100644
--- a/CPP/Windows/Shell.cpp
+++ b/CPP/Windows/Shell.cpp
@@ -258,14 +258,21 @@ bool BrowseForFolder(HWND owner, LPCTSTR title,
258 258
259#ifndef _UNICODE 259#ifndef _UNICODE
260 260
261typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath); 261extern "C" {
262typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath);
263typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi);
264}
265
266#define MY_CAST_FUNC (void(*)())
267// #define MY_CAST_FUNC
262 268
263bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) 269bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
264{ 270{
265 path.Empty(); 271 path.Empty();
266 SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP) 272 Func_SHGetPathFromIDListW shGetPathFromIDListW = (Func_SHGetPathFromIDListW)
273 MY_CAST_FUNC
267 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW"); 274 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW");
268 if (shGetPathFromIDListW == 0) 275 if (!shGetPathFromIDListW)
269 return false; 276 return false;
270 const unsigned len = MAX_PATH * 2; 277 const unsigned len = MAX_PATH * 2;
271 bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); 278 bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len)));
@@ -273,14 +280,14 @@ bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
273 return result; 280 return result;
274} 281}
275 282
276typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi);
277 283
278static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) 284static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)
279{ 285{
280 NWindows::NCOM::CComInitializer comInitializer; 286 NWindows::NCOM::CComInitializer comInitializer;
281 SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP) 287 Func_SHBrowseForFolderW shBrowseForFolderW = (Func_SHBrowseForFolderW)
288 MY_CAST_FUNC
282 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW"); 289 ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW");
283 if (shBrowseForFolderW == 0) 290 if (!shBrowseForFolderW)
284 return false; 291 return false;
285 LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo); 292 LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo);
286 if (itemIDList == NULL) 293 if (itemIDList == NULL)
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs
index c7a61b4..123182e 100644
--- a/DOC/7zip.wxs
+++ b/DOC/7zip.wxs
@@ -1,7 +1,7 @@
1<?xml version="1.0"?> 1<?xml version="1.0"?>
2 2
3<?define VerMajor = "22" ?> 3<?define VerMajor = "22" ?>
4<?define VerMinor = "00" ?> 4<?define VerMinor = "01" ?>
5<?define VerBuild = "00" ?> 5<?define VerBuild = "00" ?>
6<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> 6<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
7<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> 7<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>
diff --git a/DOC/readme.txt b/DOC/readme.txt
index 0f6c77b..faec8dc 100644
--- a/DOC/readme.txt
+++ b/DOC/readme.txt
@@ -1,9 +1,9 @@
17-Zip 21.07 Sources 17-Zip 22.01 Sources
2------------------- 2-------------------
3 3
47-Zip is a file archiver for Windows. 47-Zip is a file archiver for Windows.
5 5
67-Zip Copyright (C) 1999-2021 Igor Pavlov. 67-Zip Copyright (C) 1999-2022 Igor Pavlov.
7 7
8 8
9License Info 9License Info