mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-09 02:07:06 -06:00
Initialer Commit
This commit is contained in:
248
CPP/7zip/7zip.mak
Normal file
248
CPP/7zip/7zip.mak
Normal file
@@ -0,0 +1,248 @@
|
||||
OBJS = \
|
||||
$O\StdAfx.obj \
|
||||
$(CURRENT_OBJS) \
|
||||
$(COMMON_OBJS) \
|
||||
$(WIN_OBJS) \
|
||||
$(WIN_CTRL_OBJS) \
|
||||
$(7ZIP_COMMON_OBJS) \
|
||||
$(AR_OBJS) \
|
||||
$(AR_COMMON_OBJS) \
|
||||
$(UI_COMMON_OBJS) \
|
||||
$(AGENT_OBJS) \
|
||||
$(CONSOLE_OBJS) \
|
||||
$(EXPLORER_OBJS) \
|
||||
$(FM_OBJS) \
|
||||
$(GUI_OBJS) \
|
||||
$(7Z_OBJS) \
|
||||
$(CAB_OBJS) \
|
||||
$(CHM_OBJS) \
|
||||
$(COM_OBJS) \
|
||||
$(ISO_OBJS) \
|
||||
$(NSIS_OBJS) \
|
||||
$(RAR_OBJS) \
|
||||
$(TAR_OBJS) \
|
||||
$(UDF_OBJS) \
|
||||
$(WIM_OBJS) \
|
||||
$(ZIP_OBJS) \
|
||||
$(COMPRESS_OBJS) \
|
||||
$(CRYPTO_OBJS) \
|
||||
$(C_OBJS) \
|
||||
$(ZSTD_OBJS) \
|
||||
$(ASM_OBJS) \
|
||||
$O\resource.res \
|
||||
|
||||
!include "../../../Build.mak"
|
||||
|
||||
# MAK_SINGLE_FILE = 1
|
||||
|
||||
!IFDEF MAK_SINGLE_FILE
|
||||
|
||||
!IFDEF CURRENT_OBJS
|
||||
$(CURRENT_OBJS): ./$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
|
||||
!IFDEF COMMON_OBJS
|
||||
$(COMMON_OBJS): ../../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF WIN_OBJS
|
||||
$(WIN_OBJS): ../../../Windows/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF WIN_CTRL_OBJS
|
||||
$(WIN_CTRL_OBJS): ../../../Windows/Control/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF 7ZIP_COMMON_OBJS
|
||||
$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF AR_OBJS
|
||||
$(AR_OBJS): ../../Archive/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF AR_COMMON_OBJS
|
||||
$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF 7Z_OBJS
|
||||
$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF CAB_OBJS
|
||||
$(CAB_OBJS): ../../Archive/Cab/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF CHM_OBJS
|
||||
$(CHM_OBJS): ../../Archive/Chm/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF COM_OBJS
|
||||
$(COM_OBJS): ../../Archive/Com/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF ISO_OBJS
|
||||
$(ISO_OBJS): ../../Archive/Iso/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF NSIS_OBJS
|
||||
$(NSIS_OBJS): ../../Archive/Nsis/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF RAR_OBJS
|
||||
$(RAR_OBJS): ../../Archive/Rar/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF TAR_OBJS
|
||||
$(TAR_OBJS): ../../Archive/Tar/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF UDF_OBJS
|
||||
$(UDF_OBJS): ../../Archive/Udf/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF WIM_OBJS
|
||||
$(WIM_OBJS): ../../Archive/Wim/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF ZIP_OBJS
|
||||
$(ZIP_OBJS): ../../Archive/Zip/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF COMPRESS_OBJS
|
||||
$(COMPRESS_OBJS): ../../Compress/$(*B).cpp
|
||||
$(COMPL_O2)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF CRYPTO_OBJS
|
||||
$(CRYPTO_OBJS): ../../Crypto/$(*B).cpp
|
||||
$(COMPL_O2)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF UI_COMMON_OBJS
|
||||
$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF AGENT_OBJS
|
||||
$(AGENT_OBJS): ../../UI/Agent/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF CONSOLE_OBJS
|
||||
$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF EXPLORER_OBJS
|
||||
$(EXPLORER_OBJS): ../../UI/Explorer/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF FM_OBJS
|
||||
$(FM_OBJS): ../../UI/FileManager/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF GUI_OBJS
|
||||
$(GUI_OBJS): ../../UI/GUI/$(*B).cpp
|
||||
$(COMPL)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF C_OBJS
|
||||
$(C_OBJS): ../../../../C/$(*B).c
|
||||
$(COMPL_O2)
|
||||
!ENDIF
|
||||
|
||||
!IFDEF ZSTD_OBJS
|
||||
$(ZSTD_OBJS): ../../../../C/ZStd/$(*B).c
|
||||
$(COMPL_O2)
|
||||
!ENDIF
|
||||
|
||||
|
||||
!ELSE
|
||||
|
||||
{.}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../../Common}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../../Windows}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../../Windows/Control}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Common}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
|
||||
{../../UI/Common}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../UI/Agent}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../UI/Console}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../UI/Explorer}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../UI/FileManager}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../UI/GUI}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
|
||||
|
||||
{../../Archive}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Common}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
|
||||
{../../Archive/7z}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Cab}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Chm}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Com}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Iso}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Nsis}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Rar}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Tar}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Udf}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Wim}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
{../../Archive/Zip}.cpp{$O}.obj::
|
||||
$(COMPLB)
|
||||
|
||||
{../../Compress}.cpp{$O}.obj::
|
||||
$(COMPLB_O2)
|
||||
{../../Crypto}.cpp{$O}.obj::
|
||||
$(COMPLB_O2)
|
||||
{../../../../C}.c{$O}.obj::
|
||||
$(CCOMPLB)
|
||||
{../../../../C/ZStd}.c{$O}.obj::
|
||||
$(CCOMPLB)
|
||||
|
||||
!ENDIF
|
||||
|
||||
!include "Asm.mak"
|
||||
7
CPP/7zip/Aes.mak
Normal file
7
CPP/7zip/Aes.mak
Normal file
@@ -0,0 +1,7 @@
|
||||
C_OBJS = $(C_OBJS) \
|
||||
$O\Aes.obj
|
||||
|
||||
!IF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS" && "$(CPU)" != "ARM"
|
||||
ASM_OBJS = $(ASM_OBJS) \
|
||||
$O\AesOpt.obj
|
||||
!ENDIF
|
||||
642
CPP/7zip/Archive/7z/7z.dsp
Normal file
642
CPP/7zip/Archive/7z/7z.dsp
Normal file
@@ -0,0 +1,642 @@
|
||||
# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=7z - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "7z.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "7z - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x419 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-zip\Formats\7z.dll" /opt:NOWIN98
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "7z - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x419 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-zip\Formats\7z.dll" /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "7z - Win32 Release"
|
||||
# Name "7z - Win32 Debug"
|
||||
# Begin Group "Spec"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Archive.def
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ArchiveExports.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\DllExports.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resource.rc
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\StdAfx.cpp
|
||||
# ADD CPP /Yc"StdAfx.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\StdAfx.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Engine"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zCompressionMode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zCompressionMode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zDecode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zDecode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zEncode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zEncode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zExtract.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zFolderInStream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zFolderInStream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHandler.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHandler.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHandlerOut.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHeader.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHeader.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zIn.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zIn.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zItem.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zOut.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zOut.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zProperties.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zProperties.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zRegister.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zSpecStream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zSpecStream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zUpdate.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zUpdate.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Interface"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\IArchive.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\ICoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\IMyUnknown.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\IPassword.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\IProgress.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\IStream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\PropID.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Buffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\CRC.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\DynamicBuffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\IntToString.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\IntToString.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\MyString.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\MyString.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\MyVector.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\MyVector.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\NewHandler.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\NewHandler.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\StringConvert.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\StringConvert.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\StringToInt.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\StringToInt.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Wildcard.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Wildcard.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Archive Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\CoderMixer2.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\CoderMixer2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\HandlerOut.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\HandlerOut.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\InStreamWithCRC.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\InStreamWithCRC.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\ItemNameUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\ItemNameUtils.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\MultiStream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\MultiStream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\OutStreamWithCRC.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\OutStreamWithCRC.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\ParseProperties.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\ParseProperties.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "7-Zip Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\CreateCoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\CreateCoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\FilterCoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\FilterCoder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\InOutTempBuffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\InOutTempBuffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\LimitedStreams.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\LimitedStreams.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\LockedStream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\LockedStream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\MethodId.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\MethodId.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\MethodProps.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\MethodProps.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\OutBuffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\OutBuffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\ProgressUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\ProgressUtils.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\PropId.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\RegisterArc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\RegisterCodec.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamBinder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamBinder.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamObjects.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamObjects.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamUtils.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\VirtThread.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\VirtThread.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Windows"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\DLL.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\DLL.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileDir.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileDir.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileFind.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileFind.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileIO.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileIO.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileName.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\FileName.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Handle.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\PropVariant.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\PropVariant.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Synchronization.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Synchronization.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\System.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\System.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\Thread.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Compress"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\CopyCoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\CopyCoder.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "C"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\7zCrc.c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\7zCrc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\7zCrcOpt.c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\Alloc.c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\Alloc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\CpuArch.c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\Threads.c
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\..\C\Threads.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
29
CPP/7zip/Archive/7z/7z.dsw
Normal file
29
CPP/7zip/Archive/7z/7z.dsw
Normal file
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "7z"=".\7z.dsp" - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
3
CPP/7zip/Archive/7z/7zCompressionMode.cpp
Normal file
3
CPP/7zip/Archive/7z/7zCompressionMode.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// CompressionMethod.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
74
CPP/7zip/Archive/7z/7zCompressionMode.h
Normal file
74
CPP/7zip/Archive/7z/7zCompressionMode.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// 7zCompressionMode.h
|
||||
|
||||
#ifndef __7Z_COMPRESSION_MODE_H
|
||||
#define __7Z_COMPRESSION_MODE_H
|
||||
|
||||
#include "../../Common/MethodId.h"
|
||||
#include "../../Common/MethodProps.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
struct CMethodFull: public CMethodProps
|
||||
{
|
||||
CMethodId Id;
|
||||
UInt32 NumStreams;
|
||||
|
||||
bool IsSimpleCoder() const { return NumStreams == 1; }
|
||||
};
|
||||
|
||||
struct CBond2
|
||||
{
|
||||
UInt32 OutCoder;
|
||||
UInt32 OutStream;
|
||||
UInt32 InCoder;
|
||||
};
|
||||
|
||||
struct CCompressionMethodMode
|
||||
{
|
||||
/*
|
||||
if (Bonds.Empty()), then default bonds must be created
|
||||
if (Filter_was_Inserted)
|
||||
{
|
||||
Methods[0] is filter method
|
||||
Bonds don't contain bonds for filter (these bonds must be created)
|
||||
}
|
||||
*/
|
||||
|
||||
CObjectVector<CMethodFull> Methods;
|
||||
CRecordVector<CBond2> Bonds;
|
||||
|
||||
bool IsThereBond_to_Coder(unsigned coderIndex) const
|
||||
{
|
||||
FOR_VECTOR(i, Bonds)
|
||||
if (Bonds[i].InCoder == coderIndex)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DefaultMethod_was_Inserted;
|
||||
bool Filter_was_Inserted;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
UInt32 NumThreads;
|
||||
bool MultiThreadMixer;
|
||||
#endif
|
||||
|
||||
bool PasswordIsDefined;
|
||||
UString Password;
|
||||
|
||||
bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
|
||||
CCompressionMethodMode():
|
||||
DefaultMethod_was_Inserted(false),
|
||||
Filter_was_Inserted(false),
|
||||
PasswordIsDefined(false)
|
||||
#ifndef _7ZIP_ST
|
||||
, NumThreads(1)
|
||||
, MultiThreadMixer(true)
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
543
CPP/7zip/Archive/7z/7zDecode.cpp
Normal file
543
CPP/7zip/Archive/7z/7zDecode.cpp
Normal file
@@ -0,0 +1,543 @@
|
||||
// 7zDecode.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zDecode.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CDecProgress:
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ICompressProgressInfo> _progress;
|
||||
public:
|
||||
CDecProgress(ICompressProgressInfo *progress): _progress(progress) {}
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressProgressInfo)
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize)
|
||||
{
|
||||
return _progress->SetRatioInfo(NULL, outSize);
|
||||
}
|
||||
|
||||
static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi)
|
||||
{
|
||||
bi.Clear();
|
||||
|
||||
bi.Bonds.ClearAndSetSize(folder.Bonds.Size());
|
||||
unsigned i;
|
||||
for (i = 0; i < folder.Bonds.Size(); i++)
|
||||
{
|
||||
NCoderMixer2::CBond &bond = bi.Bonds[i];
|
||||
const N7z::CBond &folderBond = folder.Bonds[i];
|
||||
bond.PackIndex = folderBond.PackIndex;
|
||||
bond.UnpackIndex = folderBond.UnpackIndex;
|
||||
}
|
||||
|
||||
bi.Coders.ClearAndSetSize(folder.Coders.Size());
|
||||
bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size());
|
||||
for (i = 0; i < folder.Coders.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folder.Coders[i];
|
||||
bi.Coders[i].NumStreams = coderInfo.NumStreams;
|
||||
bi.CoderMethodIDs[i] = coderInfo.MethodID;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!bi.SetUnpackCoder())
|
||||
throw 1112;
|
||||
*/
|
||||
bi.UnpackCoder = folder.UnpackCoder;
|
||||
bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size());
|
||||
for (i = 0; i < folder.PackStreams.Size(); i++)
|
||||
bi.PackStreams[i] = folder.PackStreams[i];
|
||||
}
|
||||
|
||||
static inline bool AreCodersEqual(
|
||||
const NCoderMixer2::CCoderStreamsInfo &a1,
|
||||
const NCoderMixer2::CCoderStreamsInfo &a2)
|
||||
{
|
||||
return (a1.NumStreams == a2.NumStreams);
|
||||
}
|
||||
|
||||
static inline bool AreBondsEqual(
|
||||
const NCoderMixer2::CBond &a1,
|
||||
const NCoderMixer2::CBond &a2)
|
||||
{
|
||||
return
|
||||
(a1.PackIndex == a2.PackIndex) &&
|
||||
(a1.UnpackIndex == a2.UnpackIndex);
|
||||
}
|
||||
|
||||
static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
|
||||
{
|
||||
if (a1.Coders.Size() != a2.Coders.Size())
|
||||
return false;
|
||||
unsigned i;
|
||||
for (i = 0; i < a1.Coders.Size(); i++)
|
||||
if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
|
||||
return false;
|
||||
|
||||
if (a1.Bonds.Size() != a2.Bonds.Size())
|
||||
return false;
|
||||
for (i = 0; i < a1.Bonds.Size(); i++)
|
||||
if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i]))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
|
||||
if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
|
||||
return false;
|
||||
|
||||
if (a1.PackStreams.Size() != a2.PackStreams.Size())
|
||||
return false;
|
||||
for (i = 0; i < a1.PackStreams.Size(); i++)
|
||||
if (a1.PackStreams[i] != a2.PackStreams[i])
|
||||
return false;
|
||||
|
||||
/*
|
||||
if (a1.UnpackCoder != a2.UnpackCoder)
|
||||
return false;
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
CDecoder::CDecoder(bool useMixerMT):
|
||||
_bindInfoPrev_Defined(false),
|
||||
_useMixerMT(useMixerMT)
|
||||
{}
|
||||
|
||||
|
||||
struct CLockedInStream:
|
||||
public IUnknown,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Pos;
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
NWindows::NSynchronization::CCriticalSection CriticalSection;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
|
||||
class CLockedSequentialInStreamMT:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLockedInStream *_glob;
|
||||
UInt64 _pos;
|
||||
CMyComPtr<IUnknown> _globRef;
|
||||
public:
|
||||
void Init(CLockedInStream *lockedInStream, UInt64 startPos)
|
||||
{
|
||||
_globRef = lockedInStream;
|
||||
_glob = lockedInStream;
|
||||
_pos = startPos;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(ISequentialInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection);
|
||||
|
||||
if (_pos != _glob->Pos)
|
||||
{
|
||||
RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));
|
||||
_glob->Pos = _pos;
|
||||
}
|
||||
|
||||
UInt32 realProcessedSize = 0;
|
||||
HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
|
||||
_pos += realProcessedSize;
|
||||
_glob->Pos = _pos;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
|
||||
class CLockedSequentialInStreamST:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLockedInStream *_glob;
|
||||
UInt64 _pos;
|
||||
CMyComPtr<IUnknown> _globRef;
|
||||
public:
|
||||
void Init(CLockedInStream *lockedInStream, UInt64 startPos)
|
||||
{
|
||||
_globRef = lockedInStream;
|
||||
_glob = lockedInStream;
|
||||
_pos = startPos;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(ISequentialInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (_pos != _glob->Pos)
|
||||
{
|
||||
RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));
|
||||
_glob->Pos = _pos;
|
||||
}
|
||||
|
||||
UInt32 realProcessedSize = 0;
|
||||
HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
|
||||
_pos += realProcessedSize;
|
||||
_glob->Pos = _pos;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::Decode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream *inStream,
|
||||
UInt64 startPos,
|
||||
const CFolders &folders, unsigned folderIndex,
|
||||
const UInt64 *unpackSize
|
||||
|
||||
, ISequentialOutStream *outStream
|
||||
, ICompressProgressInfo *compressProgress
|
||||
, ISequentialInStream **
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
inStreamMainRes
|
||||
#endif
|
||||
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
, bool mtMode, UInt32 numThreads
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]];
|
||||
CFolderEx folderInfo;
|
||||
folders.ParseFolderEx(folderIndex, folderInfo);
|
||||
|
||||
if (!folderInfo.IsDecodingSupported())
|
||||
return E_NOTIMPL;
|
||||
|
||||
CBindInfoEx bindInfo;
|
||||
Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo);
|
||||
if (!bindInfo.CalcMapsAndCheck())
|
||||
return E_NOTIMPL;
|
||||
|
||||
UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex);
|
||||
bool fullUnpack = true;
|
||||
if (unpackSize)
|
||||
{
|
||||
if (*unpackSize > folderUnpackSize)
|
||||
return E_FAIL;
|
||||
fullUnpack = (*unpackSize == folderUnpackSize);
|
||||
}
|
||||
|
||||
/*
|
||||
We don't need to init isEncrypted and passwordIsDefined
|
||||
We must upgrade them only
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
isEncrypted = false;
|
||||
passwordIsDefined = false;
|
||||
#endif
|
||||
*/
|
||||
|
||||
if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev))
|
||||
{
|
||||
_mixerRef.Release();
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_useMixerMT)
|
||||
#endif
|
||||
{
|
||||
_mixerMT = new NCoderMixer2::CMixerMT(false);
|
||||
_mixerRef = _mixerMT;
|
||||
_mixer = _mixerMT;
|
||||
}
|
||||
#ifdef USE_MIXER_ST
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
_mixerST = new NCoderMixer2::CMixerST(false);
|
||||
_mixerRef = _mixerST;
|
||||
_mixer = _mixerST;
|
||||
#endif
|
||||
}
|
||||
|
||||
RINOK(_mixer->SetBindInfo(bindInfo));
|
||||
|
||||
FOR_VECTOR(i, folderInfo.Coders)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folderInfo.Coders[i];
|
||||
|
||||
#ifndef _SFX
|
||||
// we don't support RAR codecs here
|
||||
if ((coderInfo.MethodID >> 8) == 0x403)
|
||||
return E_NOTIMPL;
|
||||
#endif
|
||||
|
||||
CCreatedCoder cod;
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
coderInfo.MethodID, false, cod));
|
||||
|
||||
if (coderInfo.IsSimpleCoder())
|
||||
{
|
||||
if (!cod.Coder)
|
||||
return E_NOTIMPL;
|
||||
// CMethodId m = coderInfo.MethodID;
|
||||
// isFilter = (IsFilterMethod(m) || m == k_AES);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
_mixer->AddCoder(cod);
|
||||
|
||||
// now there is no codec that uses another external codec
|
||||
/*
|
||||
#ifdef EXTERNAL_CODECS
|
||||
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
|
||||
decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
|
||||
if (setCompressCodecsInfo)
|
||||
{
|
||||
// we must use g_ExternalCodecs also
|
||||
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
_bindInfoPrev = bindInfo;
|
||||
_bindInfoPrev_Defined = true;
|
||||
}
|
||||
|
||||
_mixer->ReInit();
|
||||
|
||||
UInt32 packStreamIndex = 0;
|
||||
UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < folderInfo.Coders.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folderInfo.Coders[i];
|
||||
IUnknown *decoder = _mixer->GetCoder(i).GetUnknown();
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
|
||||
decoder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
|
||||
if (setDecoderProperties)
|
||||
{
|
||||
const CByteBuffer &props = coderInfo.Props;
|
||||
size_t size = props.Size();
|
||||
if (size > 0xFFFFFFFF)
|
||||
return E_NOTIMPL;
|
||||
HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size);
|
||||
if (res == E_INVALIDARG)
|
||||
res = E_NOTIMPL;
|
||||
RINOK(res);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
if (mtMode)
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderMt> setCoderMt;
|
||||
decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
|
||||
if (setCoderMt)
|
||||
{
|
||||
RINOK(setCoderMt->SetNumberOfThreads(numThreads));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
{
|
||||
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
|
||||
decoder->QueryInterface(IID_ICryptoSetPassword, (void **)&cryptoSetPassword);
|
||||
if (cryptoSetPassword)
|
||||
{
|
||||
isEncrypted = true;
|
||||
if (!getTextPassword)
|
||||
return E_NOTIMPL;
|
||||
CMyComBSTR passwordBSTR;
|
||||
RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
|
||||
passwordIsDefined = true;
|
||||
password.Empty();
|
||||
size_t len = 0;
|
||||
if (passwordBSTR)
|
||||
{
|
||||
password = passwordBSTR;
|
||||
len = password.Len();
|
||||
}
|
||||
CByteBuffer buffer(len * 2);
|
||||
for (size_t k = 0; k < len; k++)
|
||||
{
|
||||
wchar_t c = passwordBSTR[k];
|
||||
((Byte *)buffer)[k * 2] = (Byte)c;
|
||||
((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
|
||||
}
|
||||
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetFinishMode> setFinishMode;
|
||||
decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
|
||||
if (setFinishMode)
|
||||
{
|
||||
RINOK(setFinishMode->SetFinishMode(BoolToInt(fullUnpack)));
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 numStreams = (UInt32)coderInfo.NumStreams;
|
||||
|
||||
CObjArray<UInt64> packSizes(numStreams);
|
||||
CObjArray<const UInt64 *> packSizesPointers(numStreams);
|
||||
|
||||
for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++)
|
||||
{
|
||||
int bond = folderInfo.FindBond_for_PackStream(packStreamIndex);
|
||||
|
||||
if (bond >= 0)
|
||||
packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex];
|
||||
else
|
||||
{
|
||||
int index = folderInfo.Find_in_PackStreams(packStreamIndex);
|
||||
if (index < 0)
|
||||
return E_NOTIMPL;
|
||||
packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index];
|
||||
packSizesPointers[j] = &packSizes[j];
|
||||
}
|
||||
}
|
||||
|
||||
const UInt64 *unpackSizesPointer =
|
||||
(unpackSize && i == bindInfo.UnpackCoder) ?
|
||||
unpackSize :
|
||||
&folders.CoderUnpackSizes[unpackStreamIndexStart + i];
|
||||
|
||||
_mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers);
|
||||
}
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
_mixer->SelectMainCoder(!fullUnpack);
|
||||
}
|
||||
|
||||
CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
|
||||
|
||||
CLockedInStream *lockedInStreamSpec = new CLockedInStream;
|
||||
CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec;
|
||||
|
||||
bool needMtLock = false;
|
||||
|
||||
if (folderInfo.PackStreams.Size() > 1)
|
||||
{
|
||||
// lockedInStream.Pos = (UInt64)(Int64)-1;
|
||||
// RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &lockedInStream.Pos));
|
||||
RINOK(inStream->Seek(startPos + packPositions[0], STREAM_SEEK_SET, &lockedInStreamSpec->Pos));
|
||||
lockedInStreamSpec->Stream = inStream;
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex))
|
||||
#endif
|
||||
needMtLock = true;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
UInt64 packPos = startPos + packPositions[j];
|
||||
|
||||
if (folderInfo.PackStreams.Size() == 1)
|
||||
{
|
||||
RINOK(inStream->Seek(packPos, STREAM_SEEK_SET, NULL));
|
||||
packStream = inStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USE_MIXER_MT
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_useMixerMT || needMtLock)
|
||||
#endif
|
||||
{
|
||||
CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT;
|
||||
packStream = lockedStreamImpSpec;
|
||||
lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
|
||||
}
|
||||
#ifdef USE_MIXER_ST
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST;
|
||||
packStream = lockedStreamImpSpec;
|
||||
lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
inStreams.AddNew() = streamSpec;
|
||||
streamSpec->SetStream(packStream);
|
||||
streamSpec->Init(packPositions[j + 1] - packPositions[j]);
|
||||
}
|
||||
|
||||
unsigned num = inStreams.Size();
|
||||
CObjArray<ISequentialInStream *> inStreamPointers(num);
|
||||
for (i = 0; i < num; i++)
|
||||
inStreamPointers[i] = inStreams[i];
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
CMyComPtr<ICompressProgressInfo> progress2;
|
||||
if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex))
|
||||
progress2 = new CDecProgress(compressProgress);
|
||||
|
||||
ISequentialOutStream *outStreamPointer = outStream;
|
||||
return _mixer->Code(inStreamPointers, &outStreamPointer, progress2 ? (ICompressProgressInfo *)progress2 : compressProgress);
|
||||
}
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes);
|
||||
#else
|
||||
return E_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
}}
|
||||
68
CPP/7zip/Archive/7z/7zDecode.h
Normal file
68
CPP/7zip/Archive/7z/7zDecode.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// 7zDecode.h
|
||||
|
||||
#ifndef __7Z_DECODE_H
|
||||
#define __7Z_DECODE_H
|
||||
|
||||
#include "../Common/CoderMixer2.h"
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
struct CBindInfoEx: public NCoderMixer2::CBindInfo
|
||||
{
|
||||
CRecordVector<CMethodId> CoderMethodIDs;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
CBindInfo::Clear();
|
||||
CoderMethodIDs.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
bool _bindInfoPrev_Defined;
|
||||
CBindInfoEx _bindInfoPrev;
|
||||
|
||||
bool _useMixerMT;
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
NCoderMixer2::CMixerST *_mixerST;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
NCoderMixer2::CMixerMT *_mixerMT;
|
||||
#endif
|
||||
|
||||
NCoderMixer2::CMixer *_mixer;
|
||||
CMyComPtr<IUnknown> _mixerRef;
|
||||
|
||||
public:
|
||||
|
||||
CDecoder(bool useMixerMT);
|
||||
|
||||
HRESULT Decode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream *inStream,
|
||||
UInt64 startPos,
|
||||
const CFolders &folders, unsigned folderIndex,
|
||||
const UInt64 *unpackSize // if (!unpackSize), then full folder is required
|
||||
// if (unpackSize), then only *unpackSize bytes from folder are required
|
||||
|
||||
, ISequentialOutStream *outStream
|
||||
, ICompressProgressInfo *compressProgress
|
||||
, ISequentialInStream **inStreamMainRes
|
||||
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
, bool mtMode, UInt32 numThreads
|
||||
#endif
|
||||
);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
656
CPP/7zip/Archive/7z/7zEncode.cpp
Normal file
656
CPP/7zip/Archive/7z/7zEncode.cpp
Normal file
@@ -0,0 +1,656 @@
|
||||
// 7zEncode.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/FilterCoder.h"
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/InOutTempBuffer.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zEncode.h"
|
||||
#include "7zSpecStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
void CEncoder::InitBindConv()
|
||||
{
|
||||
unsigned numIn = _bindInfo.Coders.Size();
|
||||
|
||||
_SrcIn_to_DestOut.ClearAndSetSize(numIn);
|
||||
_DestOut_to_SrcIn.ClearAndSetSize(numIn);
|
||||
|
||||
unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams();
|
||||
_SrcOut_to_DestIn.ClearAndSetSize(numOut);
|
||||
// _DestIn_to_SrcOut.ClearAndSetSize(numOut);
|
||||
|
||||
UInt32 destIn = 0;
|
||||
UInt32 destOut = 0;
|
||||
|
||||
for (unsigned i = _bindInfo.Coders.Size(); i != 0;)
|
||||
{
|
||||
i--;
|
||||
|
||||
const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i];
|
||||
|
||||
numIn--;
|
||||
numOut -= coder.NumStreams;
|
||||
|
||||
_SrcIn_to_DestOut[numIn] = destOut;
|
||||
_DestOut_to_SrcIn[destOut] = numIn;
|
||||
|
||||
destOut++;
|
||||
|
||||
for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++)
|
||||
{
|
||||
UInt32 index = numOut + j;
|
||||
_SrcOut_to_DestIn[index] = destIn;
|
||||
// _DestIn_to_SrcOut[destIn] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEncoder::SetFolder(CFolder &folder)
|
||||
{
|
||||
folder.Bonds.SetSize(_bindInfo.Bonds.Size());
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < _bindInfo.Bonds.Size(); i++)
|
||||
{
|
||||
CBond &fb = folder.Bonds[i];
|
||||
const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i];
|
||||
fb.PackIndex = _SrcOut_to_DestIn[mixerBond.PackIndex];
|
||||
fb.UnpackIndex = _SrcIn_to_DestOut[mixerBond.UnpackIndex];
|
||||
}
|
||||
|
||||
folder.Coders.SetSize(_bindInfo.Coders.Size());
|
||||
|
||||
for (i = 0; i < _bindInfo.Coders.Size(); i++)
|
||||
{
|
||||
CCoderInfo &coderInfo = folder.Coders[i];
|
||||
const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i];
|
||||
|
||||
coderInfo.NumStreams = coderStreamsInfo.NumStreams;
|
||||
coderInfo.MethodID = _decompressionMethods[i];
|
||||
// we don't free coderInfo.Props here. So coderInfo.Props can be non-empty.
|
||||
}
|
||||
|
||||
folder.PackStreams.SetSize(_bindInfo.PackStreams.Size());
|
||||
|
||||
for (i = 0; i < _bindInfo.PackStreams.Size(); i++)
|
||||
folder.PackStreams[i] = _SrcOut_to_DestIn[_bindInfo.PackStreams[i]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder)
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
|
||||
coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
|
||||
if (setCoderProperties)
|
||||
return props.SetCoderProps(setCoderProperties, dataSizeReduce);
|
||||
return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)
|
||||
{
|
||||
_progress = progress;
|
||||
OutSize = 0;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
|
||||
{
|
||||
UInt64 outSize2;
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
|
||||
#endif
|
||||
outSize2 = OutSize;
|
||||
}
|
||||
|
||||
if (_progress)
|
||||
return _progress->SetRatioInfo(inSize, &outSize2);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CEncoder::CreateMixerCoder(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const UInt64 *inSizeForReduce)
|
||||
{
|
||||
#ifdef USE_MIXER_MT
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_options.MultiThreadMixer)
|
||||
#endif
|
||||
{
|
||||
_mixerMT = new NCoderMixer2::CMixerMT(true);
|
||||
_mixerRef = _mixerMT;
|
||||
_mixer = _mixerMT;
|
||||
}
|
||||
#ifdef USE_MIXER_ST
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
_mixerST = new NCoderMixer2::CMixerST(true);
|
||||
_mixerRef = _mixerST;
|
||||
_mixer = _mixerST;
|
||||
#endif
|
||||
}
|
||||
|
||||
RINOK(_mixer->SetBindInfo(_bindInfo));
|
||||
|
||||
FOR_VECTOR (m, _options.Methods)
|
||||
{
|
||||
const CMethodFull &methodFull = _options.Methods[m];
|
||||
|
||||
CCreatedCoder cod;
|
||||
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
methodFull.Id, true, cod));
|
||||
|
||||
if (cod.NumStreams != methodFull.NumStreams)
|
||||
return E_FAIL;
|
||||
if (!cod.Coder && !cod.Coder2)
|
||||
return E_FAIL;
|
||||
|
||||
CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderMt> setCoderMt;
|
||||
encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
|
||||
if (setCoderMt)
|
||||
{
|
||||
RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon));
|
||||
|
||||
/*
|
||||
CMyComPtr<ICryptoResetSalt> resetSalt;
|
||||
encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
|
||||
if (resetSalt)
|
||||
{
|
||||
resetSalt->ResetSalt();
|
||||
}
|
||||
*/
|
||||
|
||||
// now there is no codec that uses another external codec
|
||||
/*
|
||||
#ifdef EXTERNAL_CODECS
|
||||
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
|
||||
encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
|
||||
if (setCompressCodecsInfo)
|
||||
{
|
||||
// we must use g_ExternalCodecs also
|
||||
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
|
||||
encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
|
||||
|
||||
if (cryptoSetPassword)
|
||||
{
|
||||
const unsigned sizeInBytes = _options.Password.Len() * 2;
|
||||
CByteBuffer buffer(sizeInBytes);
|
||||
for (unsigned i = 0; i < _options.Password.Len(); i++)
|
||||
{
|
||||
wchar_t c = _options.Password[i];
|
||||
((Byte *)buffer)[i * 2] = (Byte)c;
|
||||
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
|
||||
}
|
||||
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)sizeInBytes));
|
||||
}
|
||||
|
||||
_mixer->AddCoder(cod);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CSequentialOutTempBufferImp2:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CInOutTempBuffer *_buf;
|
||||
public:
|
||||
CMtEncMultiProgress *_mtProgresSpec;
|
||||
|
||||
CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}
|
||||
void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
|
||||
MY_UNKNOWN_IMP1(ISequentialOutStream)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)
|
||||
{
|
||||
if (!_buf->Write(data, size))
|
||||
{
|
||||
if (processed)
|
||||
*processed = 0;
|
||||
return E_FAIL;
|
||||
}
|
||||
if (processed)
|
||||
*processed = size;
|
||||
if (_mtProgresSpec)
|
||||
_mtProgresSpec->AddOutSize(size);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
class CSequentialOutMtNotify:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
CMtEncMultiProgress *_mtProgresSpec;
|
||||
|
||||
CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}
|
||||
MY_UNKNOWN_IMP1(ISequentialOutStream)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)
|
||||
{
|
||||
UInt32 realProcessed = 0;
|
||||
HRESULT res = _stream->Write(data, size, &realProcessed);
|
||||
if (processed)
|
||||
*processed = realProcessed;
|
||||
if (_mtProgresSpec)
|
||||
_mtProgresSpec->AddOutSize(size);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CEncoder::Encode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream,
|
||||
// const UInt64 *inStreamSize,
|
||||
const UInt64 *inSizeForReduce,
|
||||
CFolder &folderItem,
|
||||
CRecordVector<UInt64> &coderUnpackSizes,
|
||||
UInt64 &unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
CRecordVector<UInt64> &packSizes,
|
||||
ICompressProgressInfo *compressProgress)
|
||||
{
|
||||
RINOK(EncoderConstr());
|
||||
|
||||
if (!_mixerRef)
|
||||
{
|
||||
RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
|
||||
}
|
||||
|
||||
_mixer->ReInit();
|
||||
|
||||
CMtEncMultiProgress *mtProgressSpec = NULL;
|
||||
CMyComPtr<ICompressProgressInfo> mtProgress;
|
||||
|
||||
CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
|
||||
CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
|
||||
|
||||
CObjectVector<CInOutTempBuffer> inOutTempBuffers;
|
||||
CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
|
||||
CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
|
||||
|
||||
unsigned numMethods = _bindInfo.Coders.Size();
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
{
|
||||
CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
|
||||
iotb.Create();
|
||||
iotb.InitWriting();
|
||||
}
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
{
|
||||
CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2;
|
||||
CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
|
||||
tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
|
||||
tempBuffers.Add(tempBuffer);
|
||||
tempBufferSpecs.Add(tempBufferSpec);
|
||||
}
|
||||
|
||||
for (i = 0; i < numMethods; i++)
|
||||
_mixer->SetCoderInfo(i, NULL, NULL);
|
||||
|
||||
|
||||
/* inStreamSize can be used by BCJ2 to set optimal range of conversion.
|
||||
But current BCJ2 encoder uses also another way to check exact size of current file.
|
||||
So inStreamSize is not required. */
|
||||
|
||||
/*
|
||||
if (inStreamSize)
|
||||
_mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
|
||||
*/
|
||||
|
||||
|
||||
CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
|
||||
CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
|
||||
|
||||
CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
|
||||
CMyComPtr<ISequentialOutStream> outStreamSizeCount;
|
||||
|
||||
inStreamSizeCountSpec->Init(inStream);
|
||||
|
||||
ISequentialInStream *inStreamPointer = inStreamSizeCount;
|
||||
CRecordVector<ISequentialOutStream *> outStreamPointers;
|
||||
|
||||
SetFolder(folderItem);
|
||||
|
||||
for (i = 0; i < numMethods; i++)
|
||||
{
|
||||
IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
|
||||
|
||||
CMyComPtr<ICryptoResetInitVector> resetInitVector;
|
||||
coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
|
||||
if (resetInitVector)
|
||||
{
|
||||
resetInitVector->ResetInitVector();
|
||||
}
|
||||
|
||||
CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
|
||||
coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
|
||||
|
||||
CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props;
|
||||
|
||||
if (writeCoderProperties)
|
||||
{
|
||||
CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
|
||||
CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
|
||||
outStreamSpec->Init();
|
||||
writeCoderProperties->WriteCoderProperties(dynOutStream);
|
||||
outStreamSpec->CopyToBuffer(props);
|
||||
}
|
||||
else
|
||||
props.Free();
|
||||
}
|
||||
|
||||
_mixer->SelectMainCoder(false);
|
||||
UInt32 mainCoder = _mixer->MainCoderIndex;
|
||||
|
||||
bool useMtProgress = false;
|
||||
if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
|
||||
{
|
||||
#ifdef _7ZIP_ST
|
||||
if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
|
||||
#endif
|
||||
useMtProgress = true;
|
||||
}
|
||||
|
||||
if (useMtProgress)
|
||||
{
|
||||
mtProgressSpec = new CMtEncMultiProgress;
|
||||
mtProgress = mtProgressSpec;
|
||||
mtProgressSpec->Init(compressProgress);
|
||||
|
||||
mtOutStreamNotifySpec = new CSequentialOutMtNotify;
|
||||
mtOutStreamNotify = mtOutStreamNotifySpec;
|
||||
mtOutStreamNotifySpec->_stream = outStream;
|
||||
mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec;
|
||||
|
||||
FOR_VECTOR(t, tempBufferSpecs)
|
||||
{
|
||||
tempBufferSpecs[t]->_mtProgresSpec = mtProgressSpec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_bindInfo.PackStreams.Size() != 0)
|
||||
{
|
||||
outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
|
||||
outStreamSizeCount = outStreamSizeCountSpec;
|
||||
outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
|
||||
outStreamSizeCountSpec->Init();
|
||||
outStreamPointers.Add(outStreamSizeCount);
|
||||
}
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
outStreamPointers.Add(tempBuffers[i - 1]);
|
||||
|
||||
RINOK(_mixer->Code(
|
||||
&inStreamPointer,
|
||||
&outStreamPointers.Front(),
|
||||
mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress));
|
||||
|
||||
if (_bindInfo.PackStreams.Size() != 0)
|
||||
packSizes.Add(outStreamSizeCountSpec->GetSize());
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
{
|
||||
CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
|
||||
RINOK(inOutTempBuffer.WriteToStream(outStream));
|
||||
packSizes.Add(inOutTempBuffer.GetDataSize());
|
||||
}
|
||||
|
||||
unpackSize = 0;
|
||||
|
||||
for (i = 0; i < _bindInfo.Coders.Size(); i++)
|
||||
{
|
||||
int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]);
|
||||
UInt64 streamSize;
|
||||
if (bond < 0)
|
||||
{
|
||||
streamSize = inStreamSizeCountSpec->GetSize();
|
||||
unpackSize = streamSize;
|
||||
}
|
||||
else
|
||||
streamSize = _mixer->GetBondStreamSize(bond);
|
||||
coderUnpackSizes.Add(streamSize);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
CEncoder::CEncoder(const CCompressionMethodMode &options):
|
||||
_constructed(false)
|
||||
{
|
||||
if (options.IsEmpty())
|
||||
throw 1;
|
||||
|
||||
_options = options;
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
_mixerST = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
_mixerMT = NULL;
|
||||
#endif
|
||||
|
||||
_mixer = NULL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::EncoderConstr()
|
||||
{
|
||||
if (_constructed)
|
||||
return S_OK;
|
||||
if (_options.Methods.IsEmpty())
|
||||
{
|
||||
// it has only password method;
|
||||
if (!_options.PasswordIsDefined)
|
||||
throw 1;
|
||||
if (!_options.Bonds.IsEmpty())
|
||||
throw 1;
|
||||
|
||||
CMethodFull method;
|
||||
method.Id = k_AES;
|
||||
method.NumStreams = 1;
|
||||
_options.Methods.Add(method);
|
||||
|
||||
NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
|
||||
coderStreamsInfo.NumStreams = 1;
|
||||
_bindInfo.Coders.Add(coderStreamsInfo);
|
||||
|
||||
_bindInfo.PackStreams.Add(0);
|
||||
_bindInfo.UnpackCoder = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
UInt32 numOutStreams = 0;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < _options.Methods.Size(); i++)
|
||||
{
|
||||
const CMethodFull &methodFull = _options.Methods[i];
|
||||
NCoderMixer2::CCoderStreamsInfo cod;
|
||||
|
||||
cod.NumStreams = methodFull.NumStreams;
|
||||
|
||||
if (_options.Bonds.IsEmpty())
|
||||
{
|
||||
// if there are no bonds in options, we create bonds via first streams of coders
|
||||
if (i != _options.Methods.Size() - 1)
|
||||
{
|
||||
NCoderMixer2::CBond bond;
|
||||
bond.PackIndex = numOutStreams;
|
||||
bond.UnpackIndex = i + 1; // it's next coder
|
||||
_bindInfo.Bonds.Add(bond);
|
||||
}
|
||||
else if (cod.NumStreams != 0)
|
||||
_bindInfo.PackStreams.Insert(0, numOutStreams);
|
||||
|
||||
for (UInt32 j = 1; j < cod.NumStreams; j++)
|
||||
_bindInfo.PackStreams.Add(numOutStreams + j);
|
||||
}
|
||||
|
||||
numOutStreams += cod.NumStreams;
|
||||
|
||||
_bindInfo.Coders.Add(cod);
|
||||
}
|
||||
|
||||
if (!_options.Bonds.IsEmpty())
|
||||
{
|
||||
for (i = 0; i < _options.Bonds.Size(); i++)
|
||||
{
|
||||
NCoderMixer2::CBond mixerBond;
|
||||
const CBond2 &bond = _options.Bonds[i];
|
||||
if (bond.InCoder >= _bindInfo.Coders.Size()
|
||||
|| bond.OutCoder >= _bindInfo.Coders.Size()
|
||||
|| bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
|
||||
return E_INVALIDARG;
|
||||
mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
|
||||
mixerBond.UnpackIndex = bond.InCoder;
|
||||
_bindInfo.Bonds.Add(mixerBond);
|
||||
}
|
||||
|
||||
for (i = 0; i < numOutStreams; i++)
|
||||
if (_bindInfo.FindBond_for_PackStream(i) == -1)
|
||||
_bindInfo.PackStreams.Add(i);
|
||||
}
|
||||
|
||||
if (!_bindInfo.SetUnpackCoder())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_bindInfo.CalcMapsAndCheck())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (_bindInfo.PackStreams.Size() != 1)
|
||||
{
|
||||
/* main_PackStream is pack stream of main path of coders tree.
|
||||
We find main_PackStream, and place to start of list of out streams.
|
||||
It allows to use more optimal memory usage for temp buffers,
|
||||
if main_PackStream is largest stream. */
|
||||
|
||||
UInt32 ci = _bindInfo.UnpackCoder;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (_bindInfo.Coders[ci].NumStreams == 0)
|
||||
break;
|
||||
|
||||
UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
|
||||
int bond = _bindInfo.FindBond_for_PackStream(outIndex);
|
||||
if (bond >= 0)
|
||||
{
|
||||
ci = _bindInfo.Bonds[bond].UnpackIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
int si = _bindInfo.FindStream_in_PackStreams(outIndex);
|
||||
if (si >= 0)
|
||||
_bindInfo.PackStreams.MoveToFront(si);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
|
||||
|
||||
unsigned numInStreams = _bindInfo.Coders.Size();
|
||||
|
||||
for (i = 0; i < numCryptoStreams; i++)
|
||||
{
|
||||
NCoderMixer2::CBond bond;
|
||||
bond.UnpackIndex = numInStreams + i;
|
||||
bond.PackIndex = _bindInfo.PackStreams[i];
|
||||
_bindInfo.Bonds.Add(bond);
|
||||
}
|
||||
_bindInfo.PackStreams.Clear();
|
||||
|
||||
/*
|
||||
if (numCryptoStreams == 0)
|
||||
numCryptoStreams = 1;
|
||||
*/
|
||||
|
||||
for (i = 0; i < numCryptoStreams; i++)
|
||||
{
|
||||
CMethodFull method;
|
||||
method.NumStreams = 1;
|
||||
method.Id = k_AES;
|
||||
_options.Methods.Add(method);
|
||||
|
||||
NCoderMixer2::CCoderStreamsInfo cod;
|
||||
cod.NumStreams = 1;
|
||||
_bindInfo.Coders.Add(cod);
|
||||
|
||||
_bindInfo.PackStreams.Add(numOutStreams++);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (unsigned i = _options.Methods.Size(); i != 0;)
|
||||
_decompressionMethods.Add(_options.Methods[--i].Id);
|
||||
|
||||
if (_bindInfo.Coders.Size() > 16)
|
||||
return E_INVALIDARG;
|
||||
if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_bindInfo.CalcMapsAndCheck())
|
||||
return E_INVALIDARG;
|
||||
|
||||
InitBindConv();
|
||||
_constructed = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder() {}
|
||||
|
||||
}}
|
||||
92
CPP/7zip/Archive/7z/7zEncode.h
Normal file
92
CPP/7zip/Archive/7z/7zEncode.h
Normal file
@@ -0,0 +1,92 @@
|
||||
// 7zEncode.h
|
||||
|
||||
#ifndef __7Z_ENCODE_H
|
||||
#define __7Z_ENCODE_H
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
|
||||
#include "../Common/CoderMixer2.h"
|
||||
|
||||
#include "7zItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CMtEncMultiProgress:
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ICompressProgressInfo> _progress;
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::NSynchronization::CCriticalSection CriticalSection;
|
||||
#endif
|
||||
|
||||
public:
|
||||
UInt64 OutSize;
|
||||
|
||||
CMtEncMultiProgress(): OutSize(0) {}
|
||||
|
||||
void Init(ICompressProgressInfo *progress);
|
||||
|
||||
void AddOutSize(UInt64 addOutSize)
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
|
||||
#endif
|
||||
OutSize += addOutSize;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressProgressInfo)
|
||||
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
};
|
||||
|
||||
class CEncoder
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
NCoderMixer2::CMixerST *_mixerST;
|
||||
#endif
|
||||
#ifdef USE_MIXER_MT
|
||||
NCoderMixer2::CMixerMT *_mixerMT;
|
||||
#endif
|
||||
|
||||
NCoderMixer2::CMixer *_mixer;
|
||||
CMyComPtr<IUnknown> _mixerRef;
|
||||
|
||||
CCompressionMethodMode _options;
|
||||
NCoderMixer2::CBindInfo _bindInfo;
|
||||
CRecordVector<CMethodId> _decompressionMethods;
|
||||
|
||||
CRecordVector<UInt32> _SrcIn_to_DestOut;
|
||||
CRecordVector<UInt32> _SrcOut_to_DestIn;
|
||||
// CRecordVector<UInt32> _DestIn_to_SrcOut;
|
||||
CRecordVector<UInt32> _DestOut_to_SrcIn;
|
||||
|
||||
void InitBindConv();
|
||||
void SetFolder(CFolder &folder);
|
||||
|
||||
HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const UInt64 *inSizeForReduce);
|
||||
|
||||
bool _constructed;
|
||||
public:
|
||||
|
||||
CEncoder(const CCompressionMethodMode &options);
|
||||
~CEncoder();
|
||||
HRESULT EncoderConstr();
|
||||
HRESULT Encode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream,
|
||||
// const UInt64 *inStreamSize,
|
||||
const UInt64 *inSizeForReduce,
|
||||
CFolder &folderItem,
|
||||
CRecordVector<UInt64> &coderUnpackSizes,
|
||||
UInt64 &unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
CRecordVector<UInt64> &packSizes,
|
||||
ICompressProgressInfo *compressProgress);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
408
CPP/7zip/Archive/7z/7zExtract.cpp
Normal file
408
CPP/7zip/Archive/7z/7zExtract.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
// 7zExtract.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "7zDecode.h"
|
||||
#include "7zHandler.h"
|
||||
|
||||
// EXTERN_g_ExternalCodecs
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CFolderOutStream:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
public:
|
||||
bool TestMode;
|
||||
bool CheckCrc;
|
||||
private:
|
||||
bool _fileIsOpen;
|
||||
bool _calcCrc;
|
||||
UInt32 _crc;
|
||||
UInt64 _rem;
|
||||
|
||||
const UInt32 *_indexes;
|
||||
unsigned _numFiles;
|
||||
unsigned _fileIndex;
|
||||
|
||||
HRESULT OpenFile(bool isCorrupted = false);
|
||||
HRESULT CloseFile_and_SetResult(Int32 res);
|
||||
HRESULT CloseFile();
|
||||
HRESULT ProcessEmptyFiles();
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ISequentialOutStream)
|
||||
|
||||
const CDbEx *_db;
|
||||
CMyComPtr<IArchiveExtractCallback> ExtractCallback;
|
||||
|
||||
bool ExtraWriteWasCut;
|
||||
|
||||
CFolderOutStream():
|
||||
TestMode(false),
|
||||
CheckCrc(true)
|
||||
{}
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles);
|
||||
HRESULT FlushCorrupted(Int32 callbackOperationResult);
|
||||
|
||||
bool WasWritingFinished() const { return _numFiles == 0; }
|
||||
};
|
||||
|
||||
|
||||
HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles)
|
||||
{
|
||||
_fileIndex = startIndex;
|
||||
_indexes = indexes;
|
||||
_numFiles = numFiles;
|
||||
|
||||
_fileIsOpen = false;
|
||||
ExtraWriteWasCut = false;
|
||||
|
||||
return ProcessEmptyFiles();
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::OpenFile(bool isCorrupted)
|
||||
{
|
||||
const CFileItem &fi = _db->Files[_fileIndex];
|
||||
UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex);
|
||||
Int32 askMode = (_fileIndex == nextFileIndex) ?
|
||||
(TestMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract) :
|
||||
NExtract::NAskMode::kSkip;
|
||||
|
||||
if (isCorrupted
|
||||
&& askMode == NExtract::NAskMode::kExtract
|
||||
&& !_db->IsItemAnti(_fileIndex)
|
||||
&& !fi.IsDir)
|
||||
askMode = NExtract::NAskMode::kTest;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode));
|
||||
|
||||
_stream = realOutStream;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir);
|
||||
|
||||
_fileIsOpen = true;
|
||||
_rem = fi.Size;
|
||||
|
||||
if (askMode == NExtract::NAskMode::kExtract
|
||||
&& !realOutStream
|
||||
&& !_db->IsItemAnti(_fileIndex)
|
||||
&& !fi.IsDir)
|
||||
askMode = NExtract::NAskMode::kSkip;
|
||||
return ExtractCallback->PrepareOperation(askMode);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res)
|
||||
{
|
||||
_stream.Release();
|
||||
_fileIsOpen = false;
|
||||
|
||||
if (!_indexes)
|
||||
_numFiles--;
|
||||
else if (*_indexes == _fileIndex)
|
||||
{
|
||||
_indexes++;
|
||||
_numFiles--;
|
||||
}
|
||||
|
||||
_fileIndex++;
|
||||
return ExtractCallback->SetOperationResult(res);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::CloseFile()
|
||||
{
|
||||
const CFileItem &fi = _db->Files[_fileIndex];
|
||||
return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ?
|
||||
NExtract::NOperationResult::kOK :
|
||||
NExtract::NOperationResult::kCRCError);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::ProcessEmptyFiles()
|
||||
{
|
||||
while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0)
|
||||
{
|
||||
RINOK(OpenFile());
|
||||
RINOK(CloseFile());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
UInt32 cur = (size < _rem ? size : (UInt32)_rem);
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, cur, &cur);
|
||||
if (_calcCrc)
|
||||
_crc = CrcUpdate(_crc, data, cur);
|
||||
if (processedSize)
|
||||
*processedSize += cur;
|
||||
data = (const Byte *)data + cur;
|
||||
size -= cur;
|
||||
_rem -= cur;
|
||||
if (_rem == 0)
|
||||
{
|
||||
RINOK(CloseFile());
|
||||
RINOK(ProcessEmptyFiles());
|
||||
}
|
||||
RINOK(result);
|
||||
if (cur == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
RINOK(ProcessEmptyFiles());
|
||||
if (_numFiles == 0)
|
||||
{
|
||||
// we support partial extracting
|
||||
/*
|
||||
if (processedSize)
|
||||
*processedSize += size;
|
||||
break;
|
||||
*/
|
||||
ExtraWriteWasCut = true;
|
||||
// return S_FALSE;
|
||||
return k_My_HRESULT_WritingWasCut;
|
||||
}
|
||||
RINOK(OpenFile());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult)
|
||||
{
|
||||
while (_numFiles != 0)
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
RINOK(CloseFile_and_SetResult(callbackOperationResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(OpenFile(true));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
|
||||
|
||||
UInt64 importantTotalUnpacked = 0;
|
||||
|
||||
// numItems = (UInt32)(Int32)-1;
|
||||
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _db.Files.Size();
|
||||
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
|
||||
{
|
||||
CNum prevFolder = kNumNoIndex;
|
||||
UInt32 nextFile = 0;
|
||||
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 fileIndex = allFilesMode ? i : indices[i];
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
|
||||
if (folderIndex == kNumNoIndex)
|
||||
continue;
|
||||
if (folderIndex != prevFolder || fileIndex < nextFile)
|
||||
nextFile = _db.FolderStartFileIndex[folderIndex];
|
||||
for (CNum index = nextFile; index <= fileIndex; index++)
|
||||
importantTotalUnpacked += _db.Files[index].Size;
|
||||
nextFile = fileIndex + 1;
|
||||
prevFolder = folderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(extractCallback->SetTotal(importantTotalUnpacked));
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CDecoder decoder(
|
||||
#if !defined(USE_MIXER_MT)
|
||||
false
|
||||
#elif !defined(USE_MIXER_ST)
|
||||
true
|
||||
#elif !defined(__7Z_SET_PROPERTIES)
|
||||
#ifdef _7ZIP_ST
|
||||
false
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
#else
|
||||
_useMultiThreadMixer
|
||||
#endif
|
||||
);
|
||||
|
||||
UInt64 curPacked, curUnpacked;
|
||||
|
||||
CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage;
|
||||
extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage);
|
||||
|
||||
CFolderOutStream *folderOutStream = new CFolderOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
|
||||
|
||||
folderOutStream->_db = &_db;
|
||||
folderOutStream->ExtractCallback = extractCallback;
|
||||
folderOutStream->TestMode = (testModeSpec != 0);
|
||||
folderOutStream->CheckCrc = (_crcSize != 0);
|
||||
|
||||
for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked)
|
||||
{
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
if (i >= numItems)
|
||||
break;
|
||||
|
||||
curUnpacked = 0;
|
||||
curPacked = 0;
|
||||
|
||||
UInt32 fileIndex = allFilesMode ? i : indices[i];
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
|
||||
|
||||
UInt32 numSolidFiles = 1;
|
||||
|
||||
if (folderIndex != kNumNoIndex)
|
||||
{
|
||||
curPacked = _db.GetFolderFullPackSize(folderIndex);
|
||||
UInt32 nextFile = fileIndex + 1;
|
||||
fileIndex = _db.FolderStartFileIndex[folderIndex];
|
||||
UInt32 k;
|
||||
|
||||
for (k = i + 1; k < numItems; k++)
|
||||
{
|
||||
UInt32 fileIndex2 = allFilesMode ? k : indices[k];
|
||||
if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex
|
||||
|| fileIndex2 < nextFile)
|
||||
break;
|
||||
nextFile = fileIndex2 + 1;
|
||||
}
|
||||
|
||||
numSolidFiles = k - i;
|
||||
|
||||
for (k = fileIndex; k < nextFile; k++)
|
||||
curUnpacked += _db.Files[k].Size;
|
||||
}
|
||||
|
||||
{
|
||||
HRESULT result = folderOutStream->Init(fileIndex,
|
||||
allFilesMode ? NULL : indices + i,
|
||||
numSolidFiles);
|
||||
|
||||
i += numSolidFiles;
|
||||
|
||||
RINOK(result);
|
||||
}
|
||||
|
||||
// to test solid block with zero unpacked size we disable that code
|
||||
if (folderOutStream->WasWritingFinished())
|
||||
continue;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
||||
if (extractCallback)
|
||||
extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
#ifndef _NO_CRYPTO
|
||||
bool isEncrypted = false;
|
||||
bool passwordIsDefined = false;
|
||||
UString password;
|
||||
#endif
|
||||
|
||||
|
||||
HRESULT result = decoder.Decode(
|
||||
EXTERNAL_CODECS_VARS
|
||||
_inStream,
|
||||
_db.ArcInfo.DataStartPosition,
|
||||
_db, folderIndex,
|
||||
&curUnpacked,
|
||||
|
||||
outStream,
|
||||
progress,
|
||||
NULL // *inStreamMainRes
|
||||
|
||||
_7Z_DECODER_CRYPRO_VARS
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
, true, _numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
if (result == S_FALSE || result == E_NOTIMPL)
|
||||
{
|
||||
bool wasFinished = folderOutStream->WasWritingFinished();
|
||||
|
||||
int resOp = (result == S_FALSE ?
|
||||
NExtract::NOperationResult::kDataError :
|
||||
NExtract::NOperationResult::kUnsupportedMethod);
|
||||
|
||||
RINOK(folderOutStream->FlushCorrupted(resOp));
|
||||
|
||||
if (wasFinished)
|
||||
{
|
||||
// we don't show error, if it's after required files
|
||||
if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage)
|
||||
{
|
||||
RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (result != S_OK)
|
||||
return result;
|
||||
|
||||
RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
|
||||
continue;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
|
||||
// continue;
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
136
CPP/7zip/Archive/7z/7zFolderInStream.cpp
Normal file
136
CPP/7zip/Archive/7z/7zFolderInStream.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// 7zFolderInStream.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zFolderInStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
|
||||
const UInt32 *indexes, unsigned numFiles)
|
||||
{
|
||||
_updateCallback = updateCallback;
|
||||
_indexes = indexes;
|
||||
_numFiles = numFiles;
|
||||
_index = 0;
|
||||
|
||||
Processed.ClearAndReserve(numFiles);
|
||||
CRCs.ClearAndReserve(numFiles);
|
||||
Sizes.ClearAndReserve(numFiles);
|
||||
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
|
||||
_stream.Release();
|
||||
}
|
||||
|
||||
HRESULT CFolderInStream::OpenStream()
|
||||
{
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
|
||||
while (_index < _numFiles)
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> stream;
|
||||
HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (result != S_FALSE)
|
||||
return result;
|
||||
}
|
||||
|
||||
_stream = stream;
|
||||
|
||||
if (stream)
|
||||
{
|
||||
CMyComPtr<IStreamGetSize> streamGetSize;
|
||||
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
|
||||
if (streamGetSize)
|
||||
{
|
||||
if (streamGetSize->GetSize(&_size) == S_OK)
|
||||
_size_Defined = true;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_index++;
|
||||
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
AddFileInfo(result == S_OK);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CFolderInStream::AddFileInfo(bool isProcessed)
|
||||
{
|
||||
Processed.Add(isProcessed);
|
||||
Sizes.Add(_pos);
|
||||
CRCs.Add(CRC_GET_DIGEST(_crc));
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
while (size != 0)
|
||||
{
|
||||
if (_stream)
|
||||
{
|
||||
UInt32 processed2;
|
||||
RINOK(_stream->Read(data, size, &processed2));
|
||||
if (processed2 != 0)
|
||||
{
|
||||
_crc = CrcUpdate(_crc, data, processed2);
|
||||
_pos += processed2;
|
||||
if (processedSize)
|
||||
*processedSize = processed2;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_stream.Release();
|
||||
_index++;
|
||||
AddFileInfo(true);
|
||||
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
|
||||
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
}
|
||||
|
||||
if (_index >= _numFiles)
|
||||
break;
|
||||
RINOK(OpenStream());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
|
||||
{
|
||||
*value = 0;
|
||||
if (subStream > Sizes.Size())
|
||||
return S_FALSE; // E_FAIL;
|
||||
|
||||
unsigned index = (unsigned)subStream;
|
||||
if (index < Sizes.Size())
|
||||
{
|
||||
*value = Sizes[index];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!_size_Defined)
|
||||
{
|
||||
*value = _pos;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
*value = (_pos > _size ? _pos : _size);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
61
CPP/7zip/Archive/7z/7zFolderInStream.h
Normal file
61
CPP/7zip/Archive/7z/7zFolderInStream.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// 7zFolderInStream.h
|
||||
|
||||
#ifndef __7Z_FOLDER_IN_STREAM_H
|
||||
#define __7Z_FOLDER_IN_STREAM_H
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../../Common/MyVector.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CFolderInStream:
|
||||
public ISequentialInStream,
|
||||
public ICompressGetSubStreamSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> _stream;
|
||||
UInt64 _pos;
|
||||
UInt32 _crc;
|
||||
bool _size_Defined;
|
||||
UInt64 _size;
|
||||
|
||||
const UInt32 *_indexes;
|
||||
unsigned _numFiles;
|
||||
unsigned _index;
|
||||
|
||||
CMyComPtr<IArchiveUpdateCallback> _updateCallback;
|
||||
|
||||
HRESULT OpenStream();
|
||||
void AddFileInfo(bool isProcessed);
|
||||
|
||||
public:
|
||||
CRecordVector<bool> Processed;
|
||||
CRecordVector<UInt32> CRCs;
|
||||
CRecordVector<UInt64> Sizes;
|
||||
|
||||
MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
|
||||
|
||||
void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);
|
||||
|
||||
bool WasFinished() const { return _index == _numFiles; }
|
||||
|
||||
UInt64 GetFullSize() const
|
||||
{
|
||||
UInt64 size = 0;
|
||||
FOR_VECTOR (i, Sizes)
|
||||
size += Sizes[i];
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
755
CPP/7zip/Archive/7z/7zHandler.cpp
Normal file
755
CPP/7zip/Archive/7z/7zHandler.cpp
Normal file
@@ -0,0 +1,755 @@
|
||||
// 7zHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/IntToString.h"
|
||||
|
||||
#ifndef __7Z_SET_PROPERTIES
|
||||
#include "../../../Windows/System.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "7zHandler.h"
|
||||
#include "7zProperties.h"
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
#ifdef EXTRACT_ONLY
|
||||
#include "../Common/ParseProperties.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NCOM;
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
CHandler::CHandler()
|
||||
{
|
||||
#ifndef _NO_CRYPTO
|
||||
_isEncrypted = false;
|
||||
_passwordIsDefined = false;
|
||||
#endif
|
||||
|
||||
#ifdef EXTRACT_ONLY
|
||||
|
||||
_crcSize = 4;
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
_numThreads = NSystem::GetNumberOfProcessors();
|
||||
_useMultiThreadMixer = true;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _db.Files.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef _SFX
|
||||
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
|
||||
{
|
||||
*numProps = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
|
||||
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidHeadersSize,
|
||||
kpidMethod,
|
||||
kpidSolid,
|
||||
kpidNumBlocks
|
||||
// , kpidIsTree
|
||||
};
|
||||
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
static inline char GetHex(unsigned value)
|
||||
{
|
||||
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
|
||||
}
|
||||
|
||||
static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id)
|
||||
{
|
||||
int len = 0;
|
||||
do
|
||||
{
|
||||
s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
|
||||
s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
|
||||
}
|
||||
while (id != 0);
|
||||
return (unsigned)-len;
|
||||
}
|
||||
|
||||
static void ConvertMethodIdToString(AString &res, UInt64 id)
|
||||
{
|
||||
const unsigned kLen = 32;
|
||||
char s[kLen];
|
||||
unsigned len = kLen - 1;
|
||||
s[len] = 0;
|
||||
res += s + len - ConvertMethodIdToString_Back(s + len, id);
|
||||
}
|
||||
|
||||
static unsigned GetStringForSizeValue(char *s, UInt32 val)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i <= 31; i++)
|
||||
if (((UInt32)1 << i) == val)
|
||||
{
|
||||
if (i < 10)
|
||||
{
|
||||
s[0] = (char)('0' + i);
|
||||
s[1] = 0;
|
||||
return 1;
|
||||
}
|
||||
if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); }
|
||||
else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); }
|
||||
else { s[0] = '3'; s[1] = (char)('0' + i - 30); }
|
||||
s[2] = 0;
|
||||
return 2;
|
||||
}
|
||||
char c = 'b';
|
||||
if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
|
||||
else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
|
||||
::ConvertUInt32ToString(val, s);
|
||||
unsigned pos = MyStringLen(s);
|
||||
s[pos++] = c;
|
||||
s[pos] = 0;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
static inline void AddHexToString(UString &res, Byte value)
|
||||
{
|
||||
res += GetHex((Byte)(value >> 4));
|
||||
res += GetHex((Byte)(value & 0xF));
|
||||
}
|
||||
*/
|
||||
|
||||
static char *AddProp32(char *s, const char *name, UInt32 v)
|
||||
{
|
||||
*s++ = ':';
|
||||
s = MyStpCpy(s, name);
|
||||
::ConvertUInt32ToString(v, s);
|
||||
return s + MyStringLen(s);
|
||||
}
|
||||
|
||||
void CHandler::AddMethodName(AString &s, UInt64 id)
|
||||
{
|
||||
AString name;
|
||||
FindMethod(EXTERNAL_CODECS_VARS id, name);
|
||||
if (name.IsEmpty())
|
||||
ConvertMethodIdToString(s, id);
|
||||
else
|
||||
s += name;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
#ifndef _SFX
|
||||
COM_TRY_BEGIN
|
||||
#endif
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
#ifndef _SFX
|
||||
case kpidMethod:
|
||||
{
|
||||
AString s;
|
||||
const CParsedMethods &pm = _db.ParsedMethods;
|
||||
FOR_VECTOR (i, pm.IDs)
|
||||
{
|
||||
UInt64 id = pm.IDs[i];
|
||||
s.Add_Space_if_NotEmpty();
|
||||
char temp[16];
|
||||
if (id == k_LZMA2)
|
||||
{
|
||||
s += "LZMA2:";
|
||||
if ((pm.Lzma2Prop & 1) == 0)
|
||||
ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp);
|
||||
else
|
||||
GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11));
|
||||
s += temp;
|
||||
}
|
||||
else if (id == k_LZMA)
|
||||
{
|
||||
s += "LZMA:";
|
||||
GetStringForSizeValue(temp, pm.LzmaDic);
|
||||
s += temp;
|
||||
}
|
||||
else
|
||||
AddMethodName(s, id);
|
||||
}
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
case kpidSolid: prop = _db.IsSolid(); break;
|
||||
case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break;
|
||||
case kpidHeadersSize: prop = _db.HeadersSize; break;
|
||||
case kpidPhySize: prop = _db.PhySize; break;
|
||||
case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break;
|
||||
/*
|
||||
case kpidIsTree: if (_db.IsTree) prop = true; break;
|
||||
case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break;
|
||||
case kpidIsAux: if (_db.IsTree) prop = true; break;
|
||||
*/
|
||||
// case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break;
|
||||
#endif
|
||||
|
||||
case kpidWarningFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError;
|
||||
if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature;
|
||||
if (v != 0)
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc;
|
||||
if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError;
|
||||
if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
|
||||
// if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported;
|
||||
if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature;
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
#ifndef _SFX
|
||||
COM_TRY_END
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index)
|
||||
{
|
||||
UInt64 value;
|
||||
if (v.GetItem(index, value))
|
||||
PropVarEm_Set_FileTime64(prop, value);
|
||||
}
|
||||
|
||||
bool CHandler::IsFolderEncrypted(CNum folderIndex) const
|
||||
{
|
||||
if (folderIndex == kNumNoIndex)
|
||||
return false;
|
||||
size_t startPos = _db.FoCodersDataOffset[folderIndex];
|
||||
const Byte *p = _db.CodersData + startPos;
|
||||
size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
|
||||
CInByte2 inByte;
|
||||
inByte.Init(p, size);
|
||||
|
||||
CNum numCoders = inByte.ReadNum();
|
||||
for (; numCoders != 0; numCoders--)
|
||||
{
|
||||
Byte mainByte = inByte.ReadByte();
|
||||
unsigned idSize = (mainByte & 0xF);
|
||||
const Byte *longID = inByte.GetPtr();
|
||||
UInt64 id64 = 0;
|
||||
for (unsigned j = 0; j < idSize; j++)
|
||||
id64 = ((id64 << 8) | longID[j]);
|
||||
inByte.SkipDataNoCheck(idSize);
|
||||
if (id64 == k_AES)
|
||||
return true;
|
||||
if ((mainByte & 0x20) != 0)
|
||||
inByte.SkipDataNoCheck(inByte.ReadNum());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
|
||||
{
|
||||
*numProps = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
|
||||
{
|
||||
*name = NULL;
|
||||
*propID = kpidNtSecure;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
|
||||
{
|
||||
/*
|
||||
const CFileItem &file = _db.Files[index];
|
||||
*parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir);
|
||||
*parent = (UInt32)(Int32)file.Parent;
|
||||
*/
|
||||
*parentType = NParentType::kDir;
|
||||
*parent = (UInt32)(Int32)-1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
|
||||
{
|
||||
*data = NULL;
|
||||
*dataSize = 0;
|
||||
*propType = 0;
|
||||
|
||||
if (/* _db.IsTree && propID == kpidName ||
|
||||
!_db.IsTree && */ propID == kpidPath)
|
||||
{
|
||||
if (_db.NameOffsets && _db.NamesBuf)
|
||||
{
|
||||
size_t offset = _db.NameOffsets[index];
|
||||
size_t size = (_db.NameOffsets[index + 1] - offset) * 2;
|
||||
if (size < ((UInt32)1 << 31))
|
||||
{
|
||||
*data = (const void *)(_db.NamesBuf + offset * 2);
|
||||
*dataSize = (UInt32)size;
|
||||
*propType = NPropDataType::kUtf16z;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
/*
|
||||
if (propID == kpidNtSecure)
|
||||
{
|
||||
if (index < (UInt32)_db.SecureIDs.Size())
|
||||
{
|
||||
int id = _db.SecureIDs[index];
|
||||
size_t offs = _db.SecureOffsets[id];
|
||||
size_t size = _db.SecureOffsets[id + 1] - offs;
|
||||
if (size >= 0)
|
||||
{
|
||||
*data = _db.SecureBuf + offs;
|
||||
*dataSize = (UInt32)size;
|
||||
*propType = NPropDataType::kRaw;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef _SFX
|
||||
|
||||
HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
|
||||
{
|
||||
PropVariant_Clear(prop);
|
||||
if (folderIndex == kNumNoIndex)
|
||||
return S_OK;
|
||||
// for (int ttt = 0; ttt < 1; ttt++) {
|
||||
const unsigned kTempSize = 256;
|
||||
char temp[kTempSize];
|
||||
unsigned pos = kTempSize;
|
||||
temp[--pos] = 0;
|
||||
|
||||
size_t startPos = _db.FoCodersDataOffset[folderIndex];
|
||||
const Byte *p = _db.CodersData + startPos;
|
||||
size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
|
||||
CInByte2 inByte;
|
||||
inByte.Init(p, size);
|
||||
|
||||
// numCoders == 0 ???
|
||||
CNum numCoders = inByte.ReadNum();
|
||||
bool needSpace = false;
|
||||
|
||||
for (; numCoders != 0; numCoders--, needSpace = true)
|
||||
{
|
||||
if (pos < 32) // max size of property
|
||||
break;
|
||||
Byte mainByte = inByte.ReadByte();
|
||||
unsigned idSize = (mainByte & 0xF);
|
||||
const Byte *longID = inByte.GetPtr();
|
||||
UInt64 id64 = 0;
|
||||
for (unsigned j = 0; j < idSize; j++)
|
||||
id64 = ((id64 << 8) | longID[j]);
|
||||
inByte.SkipDataNoCheck(idSize);
|
||||
|
||||
if ((mainByte & 0x10) != 0)
|
||||
{
|
||||
inByte.ReadNum(); // NumInStreams
|
||||
inByte.ReadNum(); // NumOutStreams
|
||||
}
|
||||
|
||||
CNum propsSize = 0;
|
||||
const Byte *props = NULL;
|
||||
if ((mainByte & 0x20) != 0)
|
||||
{
|
||||
propsSize = inByte.ReadNum();
|
||||
props = inByte.GetPtr();
|
||||
inByte.SkipDataNoCheck(propsSize);
|
||||
}
|
||||
|
||||
const char *name = NULL;
|
||||
char s[32];
|
||||
s[0] = 0;
|
||||
|
||||
if (id64 <= (UInt32)0xFFFFFFFF)
|
||||
{
|
||||
UInt32 id = (UInt32)id64;
|
||||
if (id == k_LZMA)
|
||||
{
|
||||
name = "LZMA";
|
||||
if (propsSize == 5)
|
||||
{
|
||||
UInt32 dicSize = GetUi32((const Byte *)props + 1);
|
||||
char *dest = s + GetStringForSizeValue(s, dicSize);
|
||||
UInt32 d = props[0];
|
||||
if (d != 0x5D)
|
||||
{
|
||||
UInt32 lc = d % 9;
|
||||
d /= 9;
|
||||
UInt32 pb = d / 5;
|
||||
UInt32 lp = d % 5;
|
||||
if (lc != 3) dest = AddProp32(dest, "lc", lc);
|
||||
if (lp != 0) dest = AddProp32(dest, "lp", lp);
|
||||
if (pb != 2) dest = AddProp32(dest, "pb", pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (id == k_LZMA2)
|
||||
{
|
||||
name = "LZMA2";
|
||||
if (propsSize == 1)
|
||||
{
|
||||
Byte d = props[0];
|
||||
if ((d & 1) == 0)
|
||||
ConvertUInt32ToString((UInt32)((d >> 1) + 12), s);
|
||||
else
|
||||
GetStringForSizeValue(s, 3 << ((d >> 1) + 11));
|
||||
}
|
||||
}
|
||||
else if (id == k_PPMD)
|
||||
{
|
||||
name = "PPMD";
|
||||
if (propsSize == 5)
|
||||
{
|
||||
Byte order = *props;
|
||||
char *dest = s;
|
||||
*dest++ = 'o';
|
||||
ConvertUInt32ToString(order, dest);
|
||||
dest += MyStringLen(dest);
|
||||
dest = MyStpCpy(dest, ":mem");
|
||||
GetStringForSizeValue(dest, GetUi32(props + 1));
|
||||
}
|
||||
}
|
||||
else if (id == k_Delta)
|
||||
{
|
||||
name = "Delta";
|
||||
if (propsSize == 1)
|
||||
ConvertUInt32ToString((UInt32)props[0] + 1, s);
|
||||
}
|
||||
else if (id == k_BCJ2) name = "BCJ2";
|
||||
else if (id == k_BCJ) name = "BCJ";
|
||||
else if (id == k_AES)
|
||||
{
|
||||
name = "7zAES";
|
||||
if (propsSize >= 1)
|
||||
{
|
||||
Byte firstByte = props[0];
|
||||
UInt32 numCyclesPower = firstByte & 0x3F;
|
||||
ConvertUInt32ToString(numCyclesPower, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
unsigned nameLen = MyStringLen(name);
|
||||
unsigned propsLen = MyStringLen(s);
|
||||
unsigned totalLen = nameLen + propsLen;
|
||||
if (propsLen != 0)
|
||||
totalLen++;
|
||||
if (needSpace)
|
||||
totalLen++;
|
||||
if (totalLen + 5 >= pos)
|
||||
break;
|
||||
pos -= totalLen;
|
||||
MyStringCopy(temp + pos, name);
|
||||
if (propsLen != 0)
|
||||
{
|
||||
char *dest = temp + pos + nameLen;
|
||||
*dest++ = ':';
|
||||
MyStringCopy(dest, s);
|
||||
}
|
||||
if (needSpace)
|
||||
temp[pos + totalLen - 1] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
AString methodName;
|
||||
FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
|
||||
if (needSpace)
|
||||
temp[--pos] = ' ';
|
||||
if (methodName.IsEmpty())
|
||||
pos -= ConvertMethodIdToString_Back(temp + pos, id64);
|
||||
else
|
||||
{
|
||||
unsigned len = methodName.Len();
|
||||
if (len + 5 > pos)
|
||||
break;
|
||||
pos -= len;
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
temp[pos + i] = methodName[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numCoders != 0 && pos >= 4)
|
||||
{
|
||||
temp[--pos] = ' ';
|
||||
temp[--pos] = '.';
|
||||
temp[--pos] = '.';
|
||||
temp[--pos] = '.';
|
||||
}
|
||||
|
||||
return PropVarEm_Set_Str(prop, temp + pos);
|
||||
// }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
PropVariant_Clear(value);
|
||||
// COM_TRY_BEGIN
|
||||
// NCOM::CPropVariant prop;
|
||||
|
||||
/*
|
||||
const CRef2 &ref2 = _refs[index];
|
||||
if (ref2.Refs.IsEmpty())
|
||||
return E_FAIL;
|
||||
const CRef &ref = ref2.Refs.Front();
|
||||
*/
|
||||
|
||||
const CFileItem &item = _db.Files[index];
|
||||
UInt32 index2 = index;
|
||||
|
||||
switch (propID)
|
||||
{
|
||||
case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break;
|
||||
case kpidSize:
|
||||
{
|
||||
PropVarEm_Set_UInt64(value, item.Size);
|
||||
// prop = ref2.Size;
|
||||
break;
|
||||
}
|
||||
case kpidPackSize:
|
||||
{
|
||||
// prop = ref2.PackSize;
|
||||
{
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
|
||||
if (folderIndex != kNumNoIndex)
|
||||
{
|
||||
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
|
||||
PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex));
|
||||
/*
|
||||
else
|
||||
PropVarEm_Set_UInt64(value, 0);
|
||||
*/
|
||||
}
|
||||
else
|
||||
PropVarEm_Set_UInt64(value, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// case kpidIsAux: prop = _db.IsItemAux(index2); break;
|
||||
case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; }
|
||||
case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break;
|
||||
case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break;
|
||||
case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break;
|
||||
case kpidAttrib: if (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); break;
|
||||
case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break;
|
||||
case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break;
|
||||
case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break;
|
||||
/*
|
||||
case kpidIsAltStream: prop = item.IsAltStream; break;
|
||||
case kpidNtSecure:
|
||||
{
|
||||
int id = _db.SecureIDs[index];
|
||||
size_t offs = _db.SecureOffsets[id];
|
||||
size_t size = _db.SecureOffsets[id + 1] - offs;
|
||||
if (size >= 0)
|
||||
{
|
||||
prop.SetBlob(_db.SecureBuf + offs, (ULONG)size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
case kpidPath: return _db.GetPath_Prop(index, value);
|
||||
|
||||
#ifndef _SFX
|
||||
|
||||
case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value);
|
||||
case kpidBlock:
|
||||
{
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
|
||||
if (folderIndex != kNumNoIndex)
|
||||
PropVarEm_Set_UInt32(value, (UInt32)folderIndex);
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case kpidPackedSize0:
|
||||
case kpidPackedSize1:
|
||||
case kpidPackedSize2:
|
||||
case kpidPackedSize3:
|
||||
case kpidPackedSize4:
|
||||
{
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
|
||||
if (folderIndex != kNumNoIndex)
|
||||
{
|
||||
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
|
||||
_db.FoStartPackStreamIndex[folderIndex + 1] -
|
||||
_db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0))
|
||||
{
|
||||
PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0));
|
||||
}
|
||||
}
|
||||
else
|
||||
PropVarEm_Set_UInt64(value, 0);
|
||||
}
|
||||
break;
|
||||
*/
|
||||
|
||||
#endif
|
||||
}
|
||||
// prop.Detach(value);
|
||||
return S_OK;
|
||||
// COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
#ifndef _SFX
|
||||
_fileInfoPopIDs.Clear();
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
||||
if (openArchiveCallback)
|
||||
openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
|
||||
#endif
|
||||
|
||||
CInArchive archive(
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
_useMultiThreadMixer
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
);
|
||||
_db.IsArc = false;
|
||||
RINOK(archive.Open(stream, maxCheckStartPosition));
|
||||
_db.IsArc = true;
|
||||
|
||||
HRESULT result = archive.ReadDatabase(
|
||||
EXTERNAL_CODECS_VARS
|
||||
_db
|
||||
#ifndef _NO_CRYPTO
|
||||
, getTextPassword, _isEncrypted, _passwordIsDefined, _password
|
||||
#endif
|
||||
);
|
||||
RINOK(result);
|
||||
|
||||
_inStream = stream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Close();
|
||||
// return E_INVALIDARG;
|
||||
// return S_FALSE;
|
||||
// we must return out_of_memory here
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
// _inStream = stream;
|
||||
#ifndef _SFX
|
||||
FillPopIDs();
|
||||
#endif
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
_inStream.Release();
|
||||
_db.Clear();
|
||||
#ifndef _NO_CRYPTO
|
||||
_isEncrypted = false;
|
||||
_passwordIsDefined = false;
|
||||
_password.Empty();
|
||||
#endif
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
#ifdef EXTRACT_ONLY
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
|
||||
_numThreads = numProcessors;
|
||||
_useMultiThreadMixer = true;
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
const PROPVARIANT &value = values[i];
|
||||
UInt32 number;
|
||||
unsigned index = ParseStringToUInt32(name, number);
|
||||
if (index == 0)
|
||||
{
|
||||
if (name.IsEqualTo("mtf"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer));
|
||||
continue;
|
||||
}
|
||||
if (name.IsPrefixedBy_Ascii_NoCase("mt"))
|
||||
{
|
||||
RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
IMPL_ISetCompressCodecsInfo
|
||||
|
||||
}}
|
||||
173
CPP/7zip/Archive/7z/7zHandler.h
Normal file
173
CPP/7zip/Archive/7z/7zHandler.h
Normal file
@@ -0,0 +1,173 @@
|
||||
// 7z/Handler.h
|
||||
|
||||
#ifndef __7Z_HANDLER_H
|
||||
#define __7Z_HANDLER_H
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
#include "../Common/HandlerOut.h"
|
||||
#endif
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
#ifndef __7Z_SET_PROPERTIES
|
||||
|
||||
#ifdef EXTRACT_ONLY
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
#define __7Z_SET_PROPERTIES
|
||||
#endif
|
||||
#else
|
||||
#define __7Z_SET_PROPERTIES
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
|
||||
class COutHandler: public CMultiMethodProps
|
||||
{
|
||||
HRESULT SetSolidFromString(const UString &s);
|
||||
HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value);
|
||||
public:
|
||||
bool _removeSfxBlock;
|
||||
|
||||
UInt64 _numSolidFiles;
|
||||
UInt64 _numSolidBytes;
|
||||
bool _numSolidBytesDefined;
|
||||
bool _solidExtension;
|
||||
bool _useTypeSorting;
|
||||
|
||||
bool _compressHeaders;
|
||||
bool _encryptHeadersSpecified;
|
||||
bool _encryptHeaders;
|
||||
// bool _useParents; 9.26
|
||||
|
||||
CBoolPair Write_CTime;
|
||||
CBoolPair Write_ATime;
|
||||
CBoolPair Write_MTime;
|
||||
|
||||
bool _useMultiThreadMixer;
|
||||
|
||||
// bool _volumeMode;
|
||||
|
||||
void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
|
||||
void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); }
|
||||
void InitSolid()
|
||||
{
|
||||
InitSolidFiles();
|
||||
InitSolidSize();
|
||||
_solidExtension = false;
|
||||
_numSolidBytesDefined = false;
|
||||
}
|
||||
|
||||
void InitProps();
|
||||
|
||||
COutHandler() { InitProps(); }
|
||||
|
||||
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveGetRawProps,
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
public ISetProperties,
|
||||
#endif
|
||||
#ifndef EXTRACT_ONLY
|
||||
public IOutArchive,
|
||||
#endif
|
||||
PUBLIC_ISetCompressCodecsInfo
|
||||
public CMyUnknownImp
|
||||
#ifndef EXTRACT_ONLY
|
||||
, public COutHandler
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(IInArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
MY_QUERYINTERFACE_ENTRY(ISetProperties)
|
||||
#endif
|
||||
#ifndef EXTRACT_ONLY
|
||||
MY_QUERYINTERFACE_ENTRY(IOutArchive)
|
||||
#endif
|
||||
QUERY_ENTRY_ISetCompressCodecsInfo
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IArchiveGetRawProps(;)
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
#endif
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
INTERFACE_IOutArchive(;)
|
||||
#endif
|
||||
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
CHandler();
|
||||
|
||||
private:
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
NArchive::N7z::CDbEx _db;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
bool _isEncrypted;
|
||||
bool _passwordIsDefined;
|
||||
UString _password;
|
||||
#endif
|
||||
|
||||
#ifdef EXTRACT_ONLY
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
UInt32 _numThreads;
|
||||
bool _useMultiThreadMixer;
|
||||
#endif
|
||||
|
||||
UInt32 _crcSize;
|
||||
|
||||
#else
|
||||
|
||||
CRecordVector<CBond2> _bonds;
|
||||
|
||||
HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m);
|
||||
HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod);
|
||||
HRESULT SetMainMethod(CCompressionMethodMode &method
|
||||
#ifndef _7ZIP_ST
|
||||
, UInt32 numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
bool IsFolderEncrypted(CNum folderIndex) const;
|
||||
#ifndef _SFX
|
||||
|
||||
CRecordVector<UInt64> _fileInfoPopIDs;
|
||||
void FillPopIDs();
|
||||
void AddMethodName(AString &s, UInt64 id);
|
||||
HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const;
|
||||
|
||||
#endif
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
914
CPP/7zip/Archive/7z/7zHandlerOut.cpp
Normal file
914
CPP/7zip/Archive/7z/7zHandlerOut.cpp
Normal file
@@ -0,0 +1,914 @@
|
||||
// 7zHandlerOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/StringToInt.h"
|
||||
#include "../../../Common/Wildcard.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
#include "../Common/ParseProperties.h"
|
||||
|
||||
#include "7zHandler.h"
|
||||
#include "7zOut.h"
|
||||
#include "7zUpdate.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
static const char *k_LZMA_Name = "LZMA";
|
||||
static const char *kDefaultMethodName = "LZMA2";
|
||||
static const char *k_Copy_Name = "Copy";
|
||||
|
||||
static const char *k_MatchFinder_ForHeaders = "BT2";
|
||||
static const UInt32 k_NumFastBytes_ForHeaders = 273;
|
||||
static const UInt32 k_Level_ForHeaders = 5;
|
||||
static const UInt32 k_Dictionary_ForHeaders =
|
||||
#ifdef UNDER_CE
|
||||
1 << 18;
|
||||
#else
|
||||
1 << 20;
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
{
|
||||
*type = NFileTimeType::kWindows;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
|
||||
{
|
||||
if (!FindMethod(
|
||||
EXTERNAL_CODECS_VARS
|
||||
m.MethodName, dest.Id, dest.NumStreams))
|
||||
return E_INVALIDARG;
|
||||
(CProps &)dest = (CProps &)m;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
|
||||
{
|
||||
if (!_compressHeaders)
|
||||
return S_OK;
|
||||
COneMethodInfo m;
|
||||
m.MethodName = k_LZMA_Name;
|
||||
m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
|
||||
m.AddProp_Level(k_Level_ForHeaders);
|
||||
m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
|
||||
m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
|
||||
m.AddProp_NumThreads(1);
|
||||
|
||||
CMethodFull &methodFull = headerMethod.Methods.AddNew();
|
||||
return PropsMethod_To_FullMethod(methodFull, m);
|
||||
}
|
||||
|
||||
HRESULT CHandler::SetMainMethod(
|
||||
CCompressionMethodMode &methodMode
|
||||
#ifndef _7ZIP_ST
|
||||
, UInt32 numThreads
|
||||
#endif
|
||||
)
|
||||
{
|
||||
methodMode.Bonds = _bonds;
|
||||
|
||||
CObjectVector<COneMethodInfo> methods = _methods;
|
||||
|
||||
{
|
||||
FOR_VECTOR (i, methods)
|
||||
{
|
||||
AString &methodName = methods[i].MethodName;
|
||||
if (methodName.IsEmpty())
|
||||
methodName = kDefaultMethodName;
|
||||
}
|
||||
if (methods.IsEmpty())
|
||||
{
|
||||
COneMethodInfo &m = methods.AddNew();
|
||||
m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
|
||||
methodMode.DefaultMethod_was_Inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_filterMethod.MethodName.IsEmpty())
|
||||
{
|
||||
// if (methodMode.Bonds.IsEmpty())
|
||||
{
|
||||
FOR_VECTOR (k, methodMode.Bonds)
|
||||
{
|
||||
CBond2 &bond = methodMode.Bonds[k];
|
||||
bond.InCoder++;
|
||||
bond.OutCoder++;
|
||||
}
|
||||
methods.Insert(0, _filterMethod);
|
||||
methodMode.Filter_was_Inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
const UInt64 kSolidBytes_Min = (1 << 24);
|
||||
const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
|
||||
|
||||
bool needSolid = false;
|
||||
|
||||
FOR_VECTOR (i, methods)
|
||||
{
|
||||
COneMethodInfo &oneMethodInfo = methods[i];
|
||||
SetGlobalLevelAndThreads(oneMethodInfo
|
||||
#ifndef _7ZIP_ST
|
||||
, numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
CMethodFull &methodFull = methodMode.Methods.AddNew();
|
||||
RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
|
||||
|
||||
if (methodFull.Id != k_Copy)
|
||||
needSolid = true;
|
||||
|
||||
if (_numSolidBytesDefined)
|
||||
continue;
|
||||
|
||||
UInt32 dicSize;
|
||||
switch (methodFull.Id)
|
||||
{
|
||||
case k_LZMA:
|
||||
case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
|
||||
case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
|
||||
case k_Deflate: dicSize = (UInt32)1 << 15; break;
|
||||
case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
_numSolidBytes = (UInt64)dicSize << 7;
|
||||
if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;
|
||||
if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;
|
||||
_numSolidBytesDefined = true;
|
||||
}
|
||||
|
||||
if (!_numSolidBytesDefined)
|
||||
if (needSolid)
|
||||
_numSolidBytes = kSolidBytes_Max;
|
||||
else
|
||||
_numSolidBytes = 0;
|
||||
_numSolidBytesDefined = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
|
||||
{
|
||||
// ft = 0;
|
||||
// ftDefined = false;
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(index, propID, &prop));
|
||||
if (prop.vt == VT_FILETIME)
|
||||
{
|
||||
ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
|
||||
ftDefined = true;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
ft = 0;
|
||||
ftDefined = false;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
#ifdef _WIN32
|
||||
static const wchar_t kDirDelimiter1 = L'\\';
|
||||
#endif
|
||||
static const wchar_t kDirDelimiter2 = L'/';
|
||||
|
||||
static inline bool IsCharDirLimiter(wchar_t c)
|
||||
{
|
||||
return (
|
||||
#ifdef _WIN32
|
||||
c == kDirDelimiter1 ||
|
||||
#endif
|
||||
c == kDirDelimiter2);
|
||||
}
|
||||
|
||||
static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
|
||||
{
|
||||
CTreeFolder &tf = treeFolders[cur];
|
||||
tf.SortIndex = curSortIndex++;
|
||||
for (int i = 0; i < tf.SubFolders.Size(); i++)
|
||||
curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
|
||||
tf.SortIndexEnd = curSortIndex;
|
||||
return curSortIndex;
|
||||
}
|
||||
|
||||
static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
|
||||
{
|
||||
const CIntVector &subFolders = treeFolders[cur].SubFolders;
|
||||
int left = 0, right = subFolders.Size();
|
||||
insertPos = -1;
|
||||
for (;;)
|
||||
{
|
||||
if (left == right)
|
||||
{
|
||||
insertPos = left;
|
||||
return -1;
|
||||
}
|
||||
int mid = (left + right) / 2;
|
||||
int midFolder = subFolders[mid];
|
||||
int compare = CompareFileNames(name, treeFolders[midFolder].Name);
|
||||
if (compare == 0)
|
||||
return midFolder;
|
||||
if (compare < 0)
|
||||
right = mid;
|
||||
else
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
|
||||
{
|
||||
int insertPos;
|
||||
int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
|
||||
if (folderIndex < 0)
|
||||
{
|
||||
folderIndex = treeFolders.Size();
|
||||
CTreeFolder &newFolder = treeFolders.AddNew();
|
||||
newFolder.Parent = cur;
|
||||
newFolder.Name = name;
|
||||
treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
|
||||
}
|
||||
// else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
|
||||
return folderIndex;
|
||||
}
|
||||
*/
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
const CDbEx *db = 0;
|
||||
#ifdef _7Z_VOL
|
||||
if (_volumes.Size() > 1)
|
||||
return E_FAIL;
|
||||
const CVolume *volume = 0;
|
||||
if (_volumes.Size() == 1)
|
||||
{
|
||||
volume = &_volumes.Front();
|
||||
db = &volume->Database;
|
||||
}
|
||||
#else
|
||||
if (_inStream != 0)
|
||||
db = &_db;
|
||||
#endif
|
||||
|
||||
/*
|
||||
CMyComPtr<IArchiveGetRawProps> getRawProps;
|
||||
updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
|
||||
|
||||
CUniqBlocks secureBlocks;
|
||||
secureBlocks.AddUniq(NULL, 0);
|
||||
|
||||
CObjectVector<CTreeFolder> treeFolders;
|
||||
{
|
||||
CTreeFolder folder;
|
||||
folder.Parent = -1;
|
||||
treeFolders.Add(folder);
|
||||
}
|
||||
*/
|
||||
|
||||
CObjectVector<CUpdateItem> updateItems;
|
||||
|
||||
bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
|
||||
bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
|
||||
bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
|
||||
|
||||
if (db && !db->Files.IsEmpty())
|
||||
{
|
||||
if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
|
||||
if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
|
||||
if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
|
||||
}
|
||||
|
||||
UString s;
|
||||
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
Int32 newData, newProps;
|
||||
UInt32 indexInArchive;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
|
||||
CUpdateItem ui;
|
||||
ui.NewProps = IntToBool(newProps);
|
||||
ui.NewData = IntToBool(newData);
|
||||
ui.IndexInArchive = indexInArchive;
|
||||
ui.IndexInClient = i;
|
||||
ui.IsAnti = false;
|
||||
ui.Size = 0;
|
||||
|
||||
UString name;
|
||||
// bool isAltStream = false;
|
||||
if (ui.IndexInArchive != -1)
|
||||
{
|
||||
if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())
|
||||
return E_INVALIDARG;
|
||||
const CFileItem &fi = db->Files[ui.IndexInArchive];
|
||||
if (!ui.NewProps)
|
||||
{
|
||||
_db.GetPath(ui.IndexInArchive, name);
|
||||
}
|
||||
ui.IsDir = fi.IsDir;
|
||||
ui.Size = fi.Size;
|
||||
// isAltStream = fi.IsAltStream;
|
||||
ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
|
||||
|
||||
if (!ui.NewProps)
|
||||
{
|
||||
ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
|
||||
ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
|
||||
ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (ui.NewProps)
|
||||
{
|
||||
bool folderStatusIsDefined;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
ui.AttribDefined = false;
|
||||
else if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
ui.Attrib = prop.ulVal;
|
||||
ui.AttribDefined = true;
|
||||
}
|
||||
}
|
||||
|
||||
// we need MTime to sort files.
|
||||
if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined));
|
||||
if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined));
|
||||
if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined));
|
||||
|
||||
/*
|
||||
if (getRawProps)
|
||||
{
|
||||
const void *data;
|
||||
UInt32 dataSize;
|
||||
UInt32 propType;
|
||||
|
||||
getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
|
||||
if (dataSize != 0 && propType != NPropDataType::kRaw)
|
||||
return E_FAIL;
|
||||
ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
{
|
||||
}
|
||||
else if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
name = NItemName::MakeLegalName(prop.bstrVal);
|
||||
}
|
||||
}
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
folderStatusIsDefined = false;
|
||||
else if (prop.vt != VT_BOOL)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
ui.IsDir = (prop.boolVal != VARIANT_FALSE);
|
||||
folderStatusIsDefined = true;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
ui.IsAnti = false;
|
||||
else if (prop.vt != VT_BOOL)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
isAltStream = false;
|
||||
else if (prop.vt != VT_BOOL)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
isAltStream = (prop.boolVal != VARIANT_FALSE);
|
||||
}
|
||||
*/
|
||||
|
||||
if (ui.IsAnti)
|
||||
{
|
||||
ui.AttribDefined = false;
|
||||
|
||||
ui.CTimeDefined = false;
|
||||
ui.ATimeDefined = false;
|
||||
ui.MTimeDefined = false;
|
||||
|
||||
ui.Size = 0;
|
||||
}
|
||||
|
||||
if (!folderStatusIsDefined && ui.AttribDefined)
|
||||
ui.SetDirStatusFromAttrib();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
if (_db.SecureIDs.IsEmpty())
|
||||
ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
|
||||
else
|
||||
{
|
||||
int id = _db.SecureIDs[ui.IndexInArchive];
|
||||
size_t offs = _db.SecureOffsets[id];
|
||||
size_t size = _db.SecureOffsets[id + 1] - offs;
|
||||
ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
int folderIndex = 0;
|
||||
if (_useParents)
|
||||
{
|
||||
int j;
|
||||
s.Empty();
|
||||
for (j = 0; j < name.Len(); j++)
|
||||
{
|
||||
wchar_t c = name[j];
|
||||
if (IsCharDirLimiter(c))
|
||||
{
|
||||
folderIndex = AddFolder(treeFolders, folderIndex, s);
|
||||
s.Empty();
|
||||
continue;
|
||||
}
|
||||
s += c;
|
||||
}
|
||||
if (isAltStream)
|
||||
{
|
||||
int colonPos = s.Find(':');
|
||||
if (colonPos < 0)
|
||||
{
|
||||
// isAltStream = false;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
UString mainName = s.Left(colonPos);
|
||||
int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
|
||||
if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
|
||||
{
|
||||
for (int j = updateItems.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
CUpdateItem &ui2 = updateItems[j];
|
||||
if (ui2.ParentFolderIndex == folderIndex
|
||||
&& ui2.Name == mainName)
|
||||
{
|
||||
ui2.TreeFolderIndex = newFolderIndex;
|
||||
treeFolders[newFolderIndex].UpdateItemIndex = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
folderIndex = newFolderIndex;
|
||||
s.Delete(0, colonPos + 1);
|
||||
}
|
||||
ui.Name = s;
|
||||
}
|
||||
else
|
||||
ui.Name = name;
|
||||
ui.IsAltStream = isAltStream;
|
||||
ui.ParentFolderIndex = folderIndex;
|
||||
ui.TreeFolderIndex = -1;
|
||||
if (ui.IsDir && !s.IsEmpty())
|
||||
{
|
||||
ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
|
||||
treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
|
||||
}
|
||||
}
|
||||
*/
|
||||
ui.Name = name;
|
||||
|
||||
if (ui.NewData)
|
||||
{
|
||||
ui.Size = 0;
|
||||
if (!ui.IsDir)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
ui.Size = (UInt64)prop.uhVal.QuadPart;
|
||||
if (ui.Size != 0 && ui.IsAnti)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
updateItems.Add(ui);
|
||||
}
|
||||
|
||||
/*
|
||||
FillSortIndex(treeFolders, 0, 0);
|
||||
for (i = 0; i < (UInt32)updateItems.Size(); i++)
|
||||
{
|
||||
CUpdateItem &ui = updateItems[i];
|
||||
ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
|
||||
ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
|
||||
}
|
||||
*/
|
||||
|
||||
CCompressionMethodMode methodMode, headerMethod;
|
||||
|
||||
HRESULT res = SetMainMethod(methodMode
|
||||
#ifndef _7ZIP_ST
|
||||
, _numThreads
|
||||
#endif
|
||||
);
|
||||
RINOK(res);
|
||||
|
||||
RINOK(SetHeaderMethod(headerMethod));
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
methodMode.NumThreads = _numThreads;
|
||||
methodMode.MultiThreadMixer = _useMultiThreadMixer;
|
||||
headerMethod.NumThreads = 1;
|
||||
headerMethod.MultiThreadMixer = _useMultiThreadMixer;
|
||||
#endif
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword2> getPassword2;
|
||||
updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
|
||||
|
||||
methodMode.PasswordIsDefined = false;
|
||||
methodMode.Password.Empty();
|
||||
if (getPassword2)
|
||||
{
|
||||
CMyComBSTR password;
|
||||
Int32 passwordIsDefined;
|
||||
RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
|
||||
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
|
||||
if (methodMode.PasswordIsDefined && password)
|
||||
methodMode.Password = password;
|
||||
}
|
||||
|
||||
bool compressMainHeader = _compressHeaders; // check it
|
||||
|
||||
bool encryptHeaders = false;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
if (!methodMode.PasswordIsDefined && _passwordIsDefined)
|
||||
{
|
||||
// if header is compressed, we use that password for updated archive
|
||||
methodMode.PasswordIsDefined = true;
|
||||
methodMode.Password = _password;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (methodMode.PasswordIsDefined)
|
||||
{
|
||||
if (_encryptHeadersSpecified)
|
||||
encryptHeaders = _encryptHeaders;
|
||||
#ifndef _NO_CRYPTO
|
||||
else
|
||||
encryptHeaders = _passwordIsDefined;
|
||||
#endif
|
||||
compressMainHeader = true;
|
||||
if (encryptHeaders)
|
||||
{
|
||||
headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
|
||||
headerMethod.Password = methodMode.Password;
|
||||
}
|
||||
}
|
||||
|
||||
if (numItems < 2)
|
||||
compressMainHeader = false;
|
||||
|
||||
int level = GetLevel();
|
||||
|
||||
CUpdateOptions options;
|
||||
options.Method = &methodMode;
|
||||
options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
|
||||
options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
|
||||
// use BCJ for all levels, BCJ2 uses LZMA2! /TR 2016-03-03
|
||||
// options.MaxFilter = (level >= 8);
|
||||
options.AnalysisLevel = GetAnalysisLevel();
|
||||
|
||||
options.HeaderOptions.CompressMainHeader = compressMainHeader;
|
||||
/*
|
||||
options.HeaderOptions.WriteCTime = Write_CTime;
|
||||
options.HeaderOptions.WriteATime = Write_ATime;
|
||||
options.HeaderOptions.WriteMTime = Write_MTime;
|
||||
*/
|
||||
|
||||
options.NumSolidFiles = _numSolidFiles;
|
||||
options.NumSolidBytes = _numSolidBytes;
|
||||
options.SolidExtension = _solidExtension;
|
||||
options.UseTypeSorting = _useTypeSorting;
|
||||
|
||||
options.RemoveSfxBlock = _removeSfxBlock;
|
||||
// options.VolumeMode = _volumeMode;
|
||||
|
||||
options.MultiThreadMixer = _useMultiThreadMixer;
|
||||
|
||||
COutArchive archive;
|
||||
CArchiveDatabaseOut newDatabase;
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword> getPassword;
|
||||
updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
|
||||
|
||||
/*
|
||||
if (secureBlocks.Sorted.Size() > 1)
|
||||
{
|
||||
secureBlocks.GetReverseMap();
|
||||
for (int i = 0; i < updateItems.Size(); i++)
|
||||
{
|
||||
int &secureIndex = updateItems[i].SecureIndex;
|
||||
secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
res = Update(
|
||||
EXTERNAL_CODECS_VARS
|
||||
#ifdef _7Z_VOL
|
||||
volume ? volume->Stream: 0,
|
||||
volume ? db : 0,
|
||||
#else
|
||||
_inStream,
|
||||
db,
|
||||
#endif
|
||||
updateItems,
|
||||
// treeFolders,
|
||||
// secureBlocks,
|
||||
archive, newDatabase, outStream, updateCallback, options
|
||||
#ifndef _NO_CRYPTO
|
||||
, getPassword
|
||||
#endif
|
||||
);
|
||||
|
||||
RINOK(res);
|
||||
|
||||
updateItems.ClearAndFree();
|
||||
|
||||
return archive.WriteDatabase(EXTERNAL_CODECS_VARS
|
||||
newDatabase, options.HeaderMethod, options.HeaderOptions);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
|
||||
{
|
||||
stream = 0;
|
||||
{
|
||||
unsigned index = ParseStringToUInt32(srcString, coder);
|
||||
if (index == 0)
|
||||
return E_INVALIDARG;
|
||||
srcString.DeleteFrontal(index);
|
||||
}
|
||||
if (srcString[0] == 's')
|
||||
{
|
||||
srcString.Delete(0);
|
||||
unsigned index = ParseStringToUInt32(srcString, stream);
|
||||
if (index == 0)
|
||||
return E_INVALIDARG;
|
||||
srcString.DeleteFrontal(index);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COutHandler::InitProps()
|
||||
{
|
||||
CMultiMethodProps::Init();
|
||||
|
||||
_removeSfxBlock = false;
|
||||
_compressHeaders = true;
|
||||
_encryptHeadersSpecified = false;
|
||||
_encryptHeaders = false;
|
||||
// _useParents = false;
|
||||
|
||||
Write_CTime.Init();
|
||||
Write_ATime.Init();
|
||||
Write_MTime.Init();
|
||||
|
||||
_useMultiThreadMixer = true;
|
||||
|
||||
// _volumeMode = false;
|
||||
|
||||
InitSolid();
|
||||
_useTypeSorting = false;
|
||||
}
|
||||
|
||||
HRESULT COutHandler::SetSolidFromString(const UString &s)
|
||||
{
|
||||
UString s2 = s;
|
||||
s2.MakeLower_Ascii();
|
||||
for (unsigned i = 0; i < s2.Len();)
|
||||
{
|
||||
const wchar_t *start = ((const wchar_t *)s2) + i;
|
||||
const wchar_t *end;
|
||||
UInt64 v = ConvertStringToUInt64(start, &end);
|
||||
if (start == end)
|
||||
{
|
||||
if (s2[i++] != 'e')
|
||||
return E_INVALIDARG;
|
||||
_solidExtension = true;
|
||||
continue;
|
||||
}
|
||||
i += (int)(end - start);
|
||||
if (i == s2.Len())
|
||||
return E_INVALIDARG;
|
||||
wchar_t c = s2[i++];
|
||||
if (c == 'f')
|
||||
{
|
||||
if (v < 1)
|
||||
v = 1;
|
||||
_numSolidFiles = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned numBits;
|
||||
switch (c)
|
||||
{
|
||||
case 'b': numBits = 0; break;
|
||||
case 'k': numBits = 10; break;
|
||||
case 'm': numBits = 20; break;
|
||||
case 'g': numBits = 30; break;
|
||||
case 't': numBits = 40; break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
_numSolidBytes = (v << numBits);
|
||||
_numSolidBytesDefined = true;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
|
||||
{
|
||||
bool isSolid;
|
||||
switch (value.vt)
|
||||
{
|
||||
case VT_EMPTY: isSolid = true; break;
|
||||
case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
|
||||
case VT_BSTR:
|
||||
if (StringToBool(value.bstrVal, isSolid))
|
||||
break;
|
||||
return SetSolidFromString(value.bstrVal);
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
if (isSolid)
|
||||
InitSolid();
|
||||
else
|
||||
_numSolidFiles = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(prop, dest.Val));
|
||||
dest.Def = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
|
||||
{
|
||||
UString name = nameSpec;
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (name[0] == L's')
|
||||
{
|
||||
name.Delete(0);
|
||||
if (name.IsEmpty())
|
||||
return SetSolidFromPROPVARIANT(value);
|
||||
if (value.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
return SetSolidFromString(name);
|
||||
}
|
||||
|
||||
UInt32 number;
|
||||
int index = ParseStringToUInt32(name, number);
|
||||
// UString realName = name.Ptr(index);
|
||||
if (index == 0)
|
||||
{
|
||||
if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
|
||||
if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
|
||||
// if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
|
||||
|
||||
if (name.IsEqualTo("hcf"))
|
||||
{
|
||||
bool compressHeadersFull = true;
|
||||
RINOK(PROPVARIANT_to_bool(value, compressHeadersFull));
|
||||
return compressHeadersFull ? S_OK: E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (name.IsEqualTo("he"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
|
||||
_encryptHeadersSpecified = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);
|
||||
if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);
|
||||
if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);
|
||||
|
||||
if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
|
||||
|
||||
if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
|
||||
|
||||
// if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
|
||||
}
|
||||
return CMultiMethodProps::SetProperty(name, value);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
_bonds.Clear();
|
||||
InitProps();
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
const PROPVARIANT &value = values[i];
|
||||
|
||||
if (name[0] == 'b')
|
||||
{
|
||||
if (value.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
name.Delete(0);
|
||||
|
||||
CBond2 bond;
|
||||
RINOK(ParseBond(name, bond.OutCoder, bond.OutStream));
|
||||
if (name[0] != ':')
|
||||
return E_INVALIDARG;
|
||||
name.Delete(0);
|
||||
UInt32 inStream = 0;
|
||||
RINOK(ParseBond(name, bond.InCoder, inStream));
|
||||
if (inStream != 0)
|
||||
return E_INVALIDARG;
|
||||
if (!name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
_bonds.Add(bond);
|
||||
continue;
|
||||
}
|
||||
|
||||
RINOK(SetProperty(name, value));
|
||||
}
|
||||
|
||||
unsigned numEmptyMethods = GetNumEmptyMethods();
|
||||
if (numEmptyMethods > 0)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < _bonds.Size(); k++)
|
||||
{
|
||||
const CBond2 &bond = _bonds[k];
|
||||
if (bond.InCoder < (UInt32)numEmptyMethods ||
|
||||
bond.OutCoder < (UInt32)numEmptyMethods)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
for (k = 0; k < _bonds.Size(); k++)
|
||||
{
|
||||
CBond2 &bond = _bonds[k];
|
||||
bond.InCoder -= (UInt32)numEmptyMethods;
|
||||
bond.OutCoder -= (UInt32)numEmptyMethods;
|
||||
}
|
||||
_methods.DeleteFrontal(numEmptyMethods);
|
||||
}
|
||||
|
||||
FOR_VECTOR (k, _bonds)
|
||||
{
|
||||
const CBond2 &bond = _bonds[k];
|
||||
if (bond.InCoder >= (UInt32)_methods.Size() ||
|
||||
bond.OutCoder >= (UInt32)_methods.Size())
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
19
CPP/7zip/Archive/7z/7zHeader.cpp
Normal file
19
CPP/7zip/Archive/7z/7zHeader.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// 7zHeader.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
#ifdef _7Z_VOL
|
||||
Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1};
|
||||
#endif
|
||||
|
||||
// We can change signature. So file doesn't contain correct signature.
|
||||
// struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } };
|
||||
// static SignatureInitializer g_SignatureInitializer;
|
||||
|
||||
}}
|
||||
150
CPP/7zip/Archive/7z/7zHeader.h
Normal file
150
CPP/7zip/Archive/7z/7zHeader.h
Normal file
@@ -0,0 +1,150 @@
|
||||
// 7z/7zHeader.h
|
||||
|
||||
#ifndef __7Z_HEADER_H
|
||||
#define __7Z_HEADER_H
|
||||
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
const unsigned kSignatureSize = 6;
|
||||
extern Byte kSignature[kSignatureSize];
|
||||
|
||||
// #define _7Z_VOL
|
||||
// 7z-MultiVolume is not finished yet.
|
||||
// It can work already, but I still do not like some
|
||||
// things of that new multivolume format.
|
||||
// So please keep it commented.
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
extern Byte kFinishSignature[kSignatureSize];
|
||||
#endif
|
||||
|
||||
struct CArchiveVersion
|
||||
{
|
||||
Byte Major;
|
||||
Byte Minor;
|
||||
};
|
||||
|
||||
const Byte kMajorVersion = 0;
|
||||
|
||||
struct CStartHeader
|
||||
{
|
||||
UInt64 NextHeaderOffset;
|
||||
UInt64 NextHeaderSize;
|
||||
UInt32 NextHeaderCRC;
|
||||
};
|
||||
|
||||
const UInt32 kStartHeaderSize = 20;
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
struct CFinishHeader: public CStartHeader
|
||||
{
|
||||
UInt64 ArchiveStartOffset; // data offset from end if that struct
|
||||
UInt64 AdditionalStartBlockSize; // start signature & start header size
|
||||
};
|
||||
|
||||
const UInt32 kFinishHeaderSize = kStartHeaderSize + 16;
|
||||
#endif
|
||||
|
||||
namespace NID
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kEnd,
|
||||
|
||||
kHeader,
|
||||
|
||||
kArchiveProperties,
|
||||
|
||||
kAdditionalStreamsInfo,
|
||||
kMainStreamsInfo,
|
||||
kFilesInfo,
|
||||
|
||||
kPackInfo,
|
||||
kUnpackInfo,
|
||||
kSubStreamsInfo,
|
||||
|
||||
kSize,
|
||||
kCRC,
|
||||
|
||||
kFolder,
|
||||
|
||||
kCodersUnpackSize,
|
||||
kNumUnpackStream,
|
||||
|
||||
kEmptyStream,
|
||||
kEmptyFile,
|
||||
kAnti,
|
||||
|
||||
kName,
|
||||
kCTime,
|
||||
kATime,
|
||||
kMTime,
|
||||
kWinAttrib,
|
||||
kComment,
|
||||
|
||||
kEncodedHeader,
|
||||
|
||||
kStartPos,
|
||||
kDummy
|
||||
|
||||
// kNtSecure,
|
||||
// kParent,
|
||||
// kIsAux
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const UInt32 k_Copy = 0;
|
||||
const UInt32 k_Delta = 3;
|
||||
|
||||
const UInt32 k_LZMA2 = 0x21;
|
||||
|
||||
const UInt32 k_SWAP2 = 0x20302;
|
||||
const UInt32 k_SWAP4 = 0x20304;
|
||||
|
||||
const UInt32 k_LZMA = 0x30101;
|
||||
const UInt32 k_PPMD = 0x30401;
|
||||
|
||||
const UInt32 k_Deflate = 0x40108;
|
||||
const UInt32 k_BZip2 = 0x40202;
|
||||
|
||||
const UInt32 k_BCJ = 0x3030103;
|
||||
const UInt32 k_BCJ2 = 0x303011B;
|
||||
const UInt32 k_PPC = 0x3030205;
|
||||
const UInt32 k_IA64 = 0x3030401;
|
||||
const UInt32 k_ARM = 0x3030501;
|
||||
const UInt32 k_ARMT = 0x3030701;
|
||||
const UInt32 k_SPARC = 0x3030805;
|
||||
|
||||
const UInt32 k_ZStd = 0x4F71101;
|
||||
|
||||
const UInt32 k_AES = 0x6F10701;
|
||||
|
||||
|
||||
static inline bool IsFilterMethod(UInt64 m)
|
||||
{
|
||||
if (m > (UInt64)0xFFFFFFFF)
|
||||
return false;
|
||||
switch ((UInt32)m)
|
||||
{
|
||||
case k_Delta:
|
||||
case k_BCJ:
|
||||
case k_BCJ2:
|
||||
case k_PPC:
|
||||
case k_IA64:
|
||||
case k_ARM:
|
||||
case k_ARMT:
|
||||
case k_SPARC:
|
||||
case k_SWAP2:
|
||||
case k_SWAP4:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
1640
CPP/7zip/Archive/7z/7zIn.cpp
Normal file
1640
CPP/7zip/Archive/7z/7zIn.cpp
Normal file
File diff suppressed because it is too large
Load Diff
431
CPP/7zip/Archive/7z/7zIn.h
Normal file
431
CPP/7zip/Archive/7z/7zIn.h
Normal file
@@ -0,0 +1,431 @@
|
||||
// 7zIn.h
|
||||
|
||||
#ifndef __7Z_IN_H
|
||||
#define __7Z_IN_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/InBuffer.h"
|
||||
|
||||
#include "7zItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
/*
|
||||
We don't need to init isEncrypted and passwordIsDefined
|
||||
We must upgrade them only */
|
||||
|
||||
#ifdef _NO_CRYPTO
|
||||
#define _7Z_DECODER_CRYPRO_VARS_DECL
|
||||
#define _7Z_DECODER_CRYPRO_VARS
|
||||
#else
|
||||
#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password
|
||||
#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password
|
||||
#endif
|
||||
|
||||
struct CParsedMethods
|
||||
{
|
||||
Byte Lzma2Prop;
|
||||
UInt32 LzmaDic;
|
||||
CRecordVector<UInt64> IDs;
|
||||
|
||||
CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
|
||||
};
|
||||
|
||||
struct CFolderEx: public CFolder
|
||||
{
|
||||
unsigned UnpackCoder;
|
||||
};
|
||||
|
||||
struct CFolders
|
||||
{
|
||||
CNum NumPackStreams;
|
||||
CNum NumFolders;
|
||||
|
||||
CObjArray<UInt64> PackPositions; // NumPackStreams + 1
|
||||
// CUInt32DefVector PackCRCs; // we don't use PackCRCs now
|
||||
|
||||
CUInt32DefVector FolderCRCs; // NumFolders
|
||||
CObjArray<CNum> NumUnpackStreamsVector; // NumFolders
|
||||
|
||||
CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
|
||||
CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1
|
||||
CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1
|
||||
CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
|
||||
|
||||
CObjArray<size_t> FoCodersDataOffset; // NumFolders + 1
|
||||
CByteBuffer CodersData;
|
||||
|
||||
CParsedMethods ParsedMethods;
|
||||
|
||||
void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const;
|
||||
void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const
|
||||
{
|
||||
ParseFolderInfo(folderIndex, folder);
|
||||
folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex];
|
||||
}
|
||||
|
||||
unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
|
||||
{
|
||||
return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]);
|
||||
}
|
||||
|
||||
UInt64 GetFolderUnpackSize(unsigned folderIndex) const
|
||||
{
|
||||
return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]];
|
||||
}
|
||||
|
||||
UInt64 GetStreamPackSize(unsigned index) const
|
||||
{
|
||||
return PackPositions[index + 1] - PackPositions[index];
|
||||
}
|
||||
|
||||
CFolders(): NumPackStreams(0), NumFolders(0) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
NumPackStreams = 0;
|
||||
PackPositions.Free();
|
||||
// PackCRCs.Clear();
|
||||
|
||||
NumFolders = 0;
|
||||
FolderCRCs.Clear();
|
||||
NumUnpackStreamsVector.Free();
|
||||
CoderUnpackSizes.Free();
|
||||
FoToCoderUnpackSizes.Free();
|
||||
FoStartPackStreamIndex.Free();
|
||||
FoToMainUnpackSizeIndex.Free();
|
||||
FoCodersDataOffset.Free();
|
||||
CodersData.Free();
|
||||
}
|
||||
};
|
||||
|
||||
struct CDatabase: public CFolders
|
||||
{
|
||||
CRecordVector<CFileItem> Files;
|
||||
|
||||
CUInt64DefVector CTime;
|
||||
CUInt64DefVector ATime;
|
||||
CUInt64DefVector MTime;
|
||||
CUInt64DefVector StartPos;
|
||||
CBoolVector IsAnti;
|
||||
/*
|
||||
CBoolVector IsAux;
|
||||
CByteBuffer SecureBuf;
|
||||
CRecordVector<UInt32> SecureIDs;
|
||||
*/
|
||||
|
||||
CByteBuffer NamesBuf;
|
||||
CObjArray<size_t> NameOffsets; // numFiles + 1, offsets of utf-16 symbols
|
||||
|
||||
/*
|
||||
void ClearSecure()
|
||||
{
|
||||
SecureBuf.Free();
|
||||
SecureIDs.Clear();
|
||||
}
|
||||
*/
|
||||
|
||||
void Clear()
|
||||
{
|
||||
CFolders::Clear();
|
||||
// ClearSecure();
|
||||
|
||||
NamesBuf.Free();
|
||||
NameOffsets.Free();
|
||||
|
||||
Files.Clear();
|
||||
CTime.Clear();
|
||||
ATime.Clear();
|
||||
MTime.Clear();
|
||||
StartPos.Clear();
|
||||
IsAnti.Clear();
|
||||
// IsAux.Clear();
|
||||
}
|
||||
|
||||
bool IsSolid() const
|
||||
{
|
||||
for (CNum i = 0; i < NumFolders; i++)
|
||||
if (NumUnpackStreamsVector[i] > 1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
|
||||
// bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
|
||||
|
||||
/*
|
||||
const void* GetName(unsigned index) const
|
||||
{
|
||||
if (!NameOffsets || !NamesBuf)
|
||||
return NULL;
|
||||
return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2);
|
||||
};
|
||||
*/
|
||||
void GetPath(unsigned index, UString &path) const;
|
||||
HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw();
|
||||
};
|
||||
|
||||
struct CInArchiveInfo
|
||||
{
|
||||
CArchiveVersion Version;
|
||||
UInt64 StartPosition;
|
||||
UInt64 StartPositionAfterHeader;
|
||||
UInt64 DataStartPosition;
|
||||
UInt64 DataStartPosition2;
|
||||
CRecordVector<UInt64> FileInfoPopIDs;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
StartPosition = 0;
|
||||
StartPositionAfterHeader = 0;
|
||||
DataStartPosition = 0;
|
||||
DataStartPosition2 = 0;
|
||||
FileInfoPopIDs.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct CDbEx: public CDatabase
|
||||
{
|
||||
CInArchiveInfo ArcInfo;
|
||||
|
||||
CObjArray<CNum> FolderStartFileIndex;
|
||||
CObjArray<CNum> FileIndexToFolderIndexMap;
|
||||
|
||||
UInt64 HeadersSize;
|
||||
UInt64 PhySize;
|
||||
|
||||
/*
|
||||
CRecordVector<size_t> SecureOffsets;
|
||||
bool IsTree;
|
||||
bool ThereAreAltStreams;
|
||||
*/
|
||||
|
||||
bool IsArc;
|
||||
bool PhySizeWasConfirmed;
|
||||
|
||||
bool ThereIsHeaderError;
|
||||
bool UnexpectedEnd;
|
||||
// bool UnsupportedVersion;
|
||||
|
||||
bool StartHeaderWasRecovered;
|
||||
bool UnsupportedFeatureWarning;
|
||||
bool UnsupportedFeatureError;
|
||||
|
||||
/*
|
||||
void ClearSecureEx()
|
||||
{
|
||||
ClearSecure();
|
||||
SecureOffsets.Clear();
|
||||
}
|
||||
*/
|
||||
|
||||
void Clear()
|
||||
{
|
||||
IsArc = false;
|
||||
PhySizeWasConfirmed = false;
|
||||
|
||||
ThereIsHeaderError = false;
|
||||
UnexpectedEnd = false;
|
||||
// UnsupportedVersion = false;
|
||||
|
||||
StartHeaderWasRecovered = false;
|
||||
UnsupportedFeatureError = false;
|
||||
UnsupportedFeatureWarning = false;
|
||||
|
||||
/*
|
||||
IsTree = false;
|
||||
ThereAreAltStreams = false;
|
||||
*/
|
||||
|
||||
CDatabase::Clear();
|
||||
|
||||
// SecureOffsets.Clear();
|
||||
ArcInfo.Clear();
|
||||
FolderStartFileIndex.Free();
|
||||
FileIndexToFolderIndexMap.Free();
|
||||
|
||||
HeadersSize = 0;
|
||||
PhySize = 0;
|
||||
}
|
||||
|
||||
void FillLinks();
|
||||
|
||||
UInt64 GetFolderStreamPos(CNum folderIndex, unsigned indexInFolder) const
|
||||
{
|
||||
return ArcInfo.DataStartPosition +
|
||||
PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
|
||||
}
|
||||
|
||||
UInt64 GetFolderFullPackSize(CNum folderIndex) const
|
||||
{
|
||||
return
|
||||
PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
|
||||
PackPositions[FoStartPackStreamIndex[folderIndex]];
|
||||
}
|
||||
|
||||
UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const
|
||||
{
|
||||
size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex;
|
||||
return PackPositions[i + 1] - PackPositions[i];
|
||||
}
|
||||
|
||||
UInt64 GetFilePackSize(CNum fileIndex) const
|
||||
{
|
||||
CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
|
||||
if (folderIndex != kNumNoIndex)
|
||||
if (FolderStartFileIndex[folderIndex] == fileIndex)
|
||||
return GetFolderFullPackSize(folderIndex);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const unsigned kNumBufLevelsMax = 4;
|
||||
|
||||
struct CInByte2
|
||||
{
|
||||
const Byte *_buffer;
|
||||
public:
|
||||
size_t _size;
|
||||
size_t _pos;
|
||||
|
||||
size_t GetRem() const { return _size - _pos; }
|
||||
const Byte *GetPtr() const { return _buffer + _pos; }
|
||||
void Init(const Byte *buffer, size_t size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_pos = 0;
|
||||
}
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, size_t size);
|
||||
void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; }
|
||||
void SkipData(UInt64 size);
|
||||
|
||||
void SkipData();
|
||||
void SkipRem() { _pos = _size; }
|
||||
UInt64 ReadNumber();
|
||||
CNum ReadNum();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
|
||||
void ParseFolder(CFolder &folder);
|
||||
};
|
||||
|
||||
class CStreamSwitch;
|
||||
|
||||
const UInt32 kHeaderSize = 32;
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
friend class CStreamSwitch;
|
||||
|
||||
CMyComPtr<IInStream> _stream;
|
||||
|
||||
unsigned _numInByteBufs;
|
||||
CInByte2 _inByteVector[kNumBufLevelsMax];
|
||||
|
||||
CInByte2 *_inByteBack;
|
||||
bool ThereIsHeaderError;
|
||||
|
||||
UInt64 _arhiveBeginStreamPosition;
|
||||
UInt64 _fileEndPosition;
|
||||
|
||||
Byte _header[kHeaderSize];
|
||||
|
||||
UInt64 HeadersSize;
|
||||
|
||||
bool _useMixerMT;
|
||||
|
||||
void AddByteStream(const Byte *buffer, size_t size);
|
||||
|
||||
void DeleteByteStream(bool needUpdatePos)
|
||||
{
|
||||
_numInByteBufs--;
|
||||
if (_numInByteBufs > 0)
|
||||
{
|
||||
_inByteBack = &_inByteVector[_numInByteBufs - 1];
|
||||
if (needUpdatePos)
|
||||
_inByteBack->_pos += _inByteVector[_numInByteBufs]._pos;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
|
||||
|
||||
void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
|
||||
Byte ReadByte() { return _inByteBack->ReadByte(); }
|
||||
UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
|
||||
CNum ReadNum() { return _inByteBack->ReadNum(); }
|
||||
UInt64 ReadID() { return _inByteBack->ReadNumber(); }
|
||||
UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
|
||||
UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
|
||||
void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
|
||||
void SkipData() { _inByteBack->SkipData(); }
|
||||
void WaitId(UInt64 id);
|
||||
|
||||
void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
|
||||
void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs);
|
||||
|
||||
void ReadPackInfo(CFolders &f);
|
||||
|
||||
void ReadUnpackInfo(
|
||||
const CObjectVector<CByteBuffer> *dataVector,
|
||||
CFolders &folders);
|
||||
|
||||
void ReadSubStreamsInfo(
|
||||
CFolders &folders,
|
||||
CRecordVector<UInt64> &unpackSizes,
|
||||
CUInt32DefVector &digests);
|
||||
|
||||
void ReadStreamsInfo(
|
||||
const CObjectVector<CByteBuffer> *dataVector,
|
||||
UInt64 &dataOffset,
|
||||
CFolders &folders,
|
||||
CRecordVector<UInt64> &unpackSizes,
|
||||
CUInt32DefVector &digests);
|
||||
|
||||
void ReadBoolVector(unsigned numItems, CBoolVector &v);
|
||||
void ReadBoolVector2(unsigned numItems, CBoolVector &v);
|
||||
void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
|
||||
CUInt64DefVector &v, unsigned numItems);
|
||||
HRESULT ReadAndDecodePackedStreams(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
UInt64 baseOffset, UInt64 &dataOffset,
|
||||
CObjectVector<CByteBuffer> &dataVector
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
HRESULT ReadHeader(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CDbEx &db
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
HRESULT ReadDatabase2(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CDbEx &db
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
public:
|
||||
CInArchive(bool useMixerMT):
|
||||
_numInByteBufs(0),
|
||||
_useMixerMT(useMixerMT)
|
||||
{}
|
||||
|
||||
HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
|
||||
void Close();
|
||||
|
||||
HRESULT ReadDatabase(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CDbEx &db
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
183
CPP/7zip/Archive/7z/7zItem.h
Normal file
183
CPP/7zip/Archive/7z/7zItem.h
Normal file
@@ -0,0 +1,183 @@
|
||||
// 7zItem.h
|
||||
|
||||
#ifndef __7Z_ITEM_H
|
||||
#define __7Z_ITEM_H
|
||||
|
||||
#include "../../../Common/MyBuffer.h"
|
||||
#include "../../../Common/MyString.h"
|
||||
|
||||
#include "../../Common/MethodId.h"
|
||||
|
||||
#include "7zHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
typedef UInt32 CNum;
|
||||
const CNum kNumMax = 0x7FFFFFFF;
|
||||
const CNum kNumNoIndex = 0xFFFFFFFF;
|
||||
|
||||
struct CCoderInfo
|
||||
{
|
||||
CMethodId MethodID;
|
||||
CByteBuffer Props;
|
||||
UInt32 NumStreams;
|
||||
|
||||
bool IsSimpleCoder() const { return NumStreams == 1; }
|
||||
};
|
||||
|
||||
struct CBond
|
||||
{
|
||||
UInt32 PackIndex;
|
||||
UInt32 UnpackIndex;
|
||||
};
|
||||
|
||||
struct CFolder
|
||||
{
|
||||
CLASS_NO_COPY(CFolder)
|
||||
public:
|
||||
CObjArray2<CCoderInfo> Coders;
|
||||
CObjArray2<CBond> Bonds;
|
||||
CObjArray2<UInt32> PackStreams;
|
||||
|
||||
CFolder() {}
|
||||
|
||||
bool IsDecodingSupported() const { return Coders.Size() <= 32; }
|
||||
|
||||
int Find_in_PackStreams(UInt32 packStream) const
|
||||
{
|
||||
FOR_VECTOR(i, PackStreams)
|
||||
if (PackStreams[i] == packStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindBond_for_PackStream(UInt32 packStream) const
|
||||
{
|
||||
FOR_VECTOR(i, Bonds)
|
||||
if (Bonds[i].PackIndex == packStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
int FindBond_for_UnpackStream(UInt32 unpackStream) const
|
||||
{
|
||||
FOR_VECTOR(i, Bonds)
|
||||
if (Bonds[i].UnpackIndex == unpackStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindOutCoder() const
|
||||
{
|
||||
for (int i = (int)Coders.Size() - 1; i >= 0; i--)
|
||||
if (FindBond_for_UnpackStream(i) < 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
bool IsEncrypted() const
|
||||
{
|
||||
FOR_VECTOR(i, Coders)
|
||||
if (Coders[i].MethodID == k_AES)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct CUInt32DefVector
|
||||
{
|
||||
CBoolVector Defs;
|
||||
CRecordVector<UInt32> Vals;
|
||||
|
||||
void ClearAndSetSize(unsigned newSize)
|
||||
{
|
||||
Defs.ClearAndSetSize(newSize);
|
||||
Vals.ClearAndSetSize(newSize);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Defs.Clear();
|
||||
Vals.Clear();
|
||||
}
|
||||
|
||||
void ReserveDown()
|
||||
{
|
||||
Defs.ReserveDown();
|
||||
Vals.ReserveDown();
|
||||
}
|
||||
|
||||
bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; }
|
||||
};
|
||||
|
||||
struct CUInt64DefVector
|
||||
{
|
||||
CBoolVector Defs;
|
||||
CRecordVector<UInt64> Vals;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Defs.Clear();
|
||||
Vals.Clear();
|
||||
}
|
||||
|
||||
void ReserveDown()
|
||||
{
|
||||
Defs.ReserveDown();
|
||||
Vals.ReserveDown();
|
||||
}
|
||||
|
||||
bool GetItem(unsigned index, UInt64 &value) const
|
||||
{
|
||||
if (index < Defs.Size() && Defs[index])
|
||||
{
|
||||
value = Vals[index];
|
||||
return true;
|
||||
}
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetItem(unsigned index, bool defined, UInt64 value);
|
||||
|
||||
bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
|
||||
};
|
||||
|
||||
struct CFileItem
|
||||
{
|
||||
UInt64 Size;
|
||||
UInt32 Attrib;
|
||||
UInt32 Crc;
|
||||
/*
|
||||
int Parent;
|
||||
bool IsAltStream;
|
||||
*/
|
||||
bool HasStream; // Test it !!! it means that there is
|
||||
// stream in some folder. It can be empty stream
|
||||
bool IsDir;
|
||||
bool CrcDefined;
|
||||
bool AttribDefined;
|
||||
|
||||
CFileItem():
|
||||
/*
|
||||
Parent(-1),
|
||||
IsAltStream(false),
|
||||
*/
|
||||
HasStream(true),
|
||||
IsDir(false),
|
||||
CrcDefined(false),
|
||||
AttribDefined(false)
|
||||
{}
|
||||
void SetAttrib(UInt32 attrib)
|
||||
{
|
||||
AttribDefined = true;
|
||||
Attrib = attrib;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
916
CPP/7zip/Archive/7z/7zOut.cpp
Normal file
916
CPP/7zip/Archive/7z/7zOut.cpp
Normal file
@@ -0,0 +1,916 @@
|
||||
// 7zOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/AutoPtr.h"
|
||||
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
HRESULT COutArchive::WriteSignature()
|
||||
{
|
||||
Byte buf[8];
|
||||
memcpy(buf, kSignature, kSignatureSize);
|
||||
buf[kSignatureSize] = kMajorVersion;
|
||||
buf[kSignatureSize + 1] = 4;
|
||||
return WriteDirect(buf, 8);
|
||||
}
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
HRESULT COutArchive::WriteFinishSignature()
|
||||
{
|
||||
RINOK(WriteDirect(kFinishSignature, kSignatureSize));
|
||||
CArchiveVersion av;
|
||||
av.Major = kMajorVersion;
|
||||
av.Minor = 2;
|
||||
RINOK(WriteDirectByte(av.Major));
|
||||
return WriteDirectByte(av.Minor);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SetUInt32(Byte *p, UInt32 d)
|
||||
{
|
||||
for (int i = 0; i < 4; i++, d >>= 8)
|
||||
p[i] = (Byte)d;
|
||||
}
|
||||
|
||||
static void SetUInt64(Byte *p, UInt64 d)
|
||||
{
|
||||
for (int i = 0; i < 8; i++, d >>= 8)
|
||||
p[i] = (Byte)d;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
|
||||
{
|
||||
Byte buf[24];
|
||||
SetUInt64(buf + 4, h.NextHeaderOffset);
|
||||
SetUInt64(buf + 12, h.NextHeaderSize);
|
||||
SetUInt32(buf + 20, h.NextHeaderCRC);
|
||||
SetUInt32(buf, CrcCalc(buf + 4, 20));
|
||||
return WriteDirect(buf, 24);
|
||||
}
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
|
||||
{
|
||||
CCRC crc;
|
||||
crc.UpdateUInt64(h.NextHeaderOffset);
|
||||
crc.UpdateUInt64(h.NextHeaderSize);
|
||||
crc.UpdateUInt32(h.NextHeaderCRC);
|
||||
crc.UpdateUInt64(h.ArchiveStartOffset);
|
||||
crc.UpdateUInt64(h.AdditionalStartBlockSize);
|
||||
RINOK(WriteDirectUInt32(crc.GetDigest()));
|
||||
RINOK(WriteDirectUInt64(h.NextHeaderOffset));
|
||||
RINOK(WriteDirectUInt64(h.NextHeaderSize));
|
||||
RINOK(WriteDirectUInt32(h.NextHeaderCRC));
|
||||
RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
|
||||
return WriteDirectUInt64(h.AdditionalStartBlockSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
|
||||
{
|
||||
Close();
|
||||
#ifdef _7Z_VOL
|
||||
// endMarker = false;
|
||||
_endMarker = endMarker;
|
||||
#endif
|
||||
SeqStream = stream;
|
||||
if (!endMarker)
|
||||
{
|
||||
SeqStream.QueryInterface(IID_IOutStream, &Stream);
|
||||
if (!Stream)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
// endMarker = true;
|
||||
}
|
||||
}
|
||||
#ifdef _7Z_VOL
|
||||
if (endMarker)
|
||||
{
|
||||
/*
|
||||
CStartHeader sh;
|
||||
sh.NextHeaderOffset = (UInt32)(Int32)-1;
|
||||
sh.NextHeaderSize = (UInt32)(Int32)-1;
|
||||
sh.NextHeaderCRC = 0;
|
||||
WriteStartHeader(sh);
|
||||
*/
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!Stream)
|
||||
return E_FAIL;
|
||||
RINOK(WriteSignature());
|
||||
RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COutArchive::Close()
|
||||
{
|
||||
SeqStream.Release();
|
||||
Stream.Release();
|
||||
}
|
||||
|
||||
HRESULT COutArchive::SkipPrefixArchiveHeader()
|
||||
{
|
||||
#ifdef _7Z_VOL
|
||||
if (_endMarker)
|
||||
return S_OK;
|
||||
#endif
|
||||
Byte buf[24];
|
||||
memset(buf, 0, 24);
|
||||
return WriteDirect(buf, 24);
|
||||
}
|
||||
|
||||
UInt64 COutArchive::GetPos() const
|
||||
{
|
||||
if (_countMode)
|
||||
return _countSize;
|
||||
if (_writeToStream)
|
||||
return _outByte.GetProcessedSize();
|
||||
return _outByte2.GetPos();
|
||||
}
|
||||
|
||||
void COutArchive::WriteBytes(const void *data, size_t size)
|
||||
{
|
||||
if (_countMode)
|
||||
_countSize += size;
|
||||
else if (_writeToStream)
|
||||
{
|
||||
_outByte.WriteBytes(data, size);
|
||||
_crc = CrcUpdate(_crc, data, size);
|
||||
}
|
||||
else
|
||||
_outByte2.WriteBytes(data, size);
|
||||
}
|
||||
|
||||
void COutArchive::WriteByte(Byte b)
|
||||
{
|
||||
if (_countMode)
|
||||
_countSize++;
|
||||
else if (_writeToStream)
|
||||
{
|
||||
_outByte.WriteByte(b);
|
||||
_crc = CRC_UPDATE_BYTE(_crc, b);
|
||||
}
|
||||
else
|
||||
_outByte2.WriteByte(b);
|
||||
}
|
||||
|
||||
void COutArchive::WriteUInt32(UInt32 value)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
WriteByte((Byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void COutArchive::WriteUInt64(UInt64 value)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
WriteByte((Byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void COutArchive::WriteNumber(UInt64 value)
|
||||
{
|
||||
Byte firstByte = 0;
|
||||
Byte mask = 0x80;
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (value < ((UInt64(1) << ( 7 * (i + 1)))))
|
||||
{
|
||||
firstByte |= Byte(value >> (8 * i));
|
||||
break;
|
||||
}
|
||||
firstByte |= mask;
|
||||
mask >>= 1;
|
||||
}
|
||||
WriteByte(firstByte);
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
WriteByte((Byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static UInt32 GetBigNumberSize(UInt64 value)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < 9; i++)
|
||||
if (value < (((UInt64)1 << (i * 7))))
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
|
||||
{
|
||||
UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
|
||||
if (nameLength != 0)
|
||||
{
|
||||
nameLength = (nameLength + 1) * 2;
|
||||
result += nameLength + GetBigNumberSize(nameLength) + 2;
|
||||
}
|
||||
if (props)
|
||||
{
|
||||
result += 20;
|
||||
}
|
||||
if (result >= 128)
|
||||
result++;
|
||||
result += kSignatureSize + 2 + kFinishHeaderSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
|
||||
{
|
||||
UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
|
||||
int testSize;
|
||||
if (volSize > headersSizeBase)
|
||||
testSize = volSize - headersSizeBase;
|
||||
else
|
||||
testSize = 1;
|
||||
UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
|
||||
UInt64 pureSize = 1;
|
||||
if (volSize > headersSize)
|
||||
pureSize = volSize - headersSize;
|
||||
return pureSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
void COutArchive::WriteFolder(const CFolder &folder)
|
||||
{
|
||||
WriteNumber(folder.Coders.Size());
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < folder.Coders.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &coder = folder.Coders[i];
|
||||
{
|
||||
UInt64 id = coder.MethodID;
|
||||
unsigned idSize;
|
||||
for (idSize = 1; idSize < sizeof(id); idSize++)
|
||||
if ((id >> (8 * idSize)) == 0)
|
||||
break;
|
||||
idSize &= 0xF;
|
||||
Byte temp[16];
|
||||
for (unsigned t = idSize; t != 0; t--, id >>= 8)
|
||||
temp[t] = (Byte)(id & 0xFF);
|
||||
|
||||
Byte b = (Byte)(idSize);
|
||||
bool isComplex = !coder.IsSimpleCoder();
|
||||
b |= (isComplex ? 0x10 : 0);
|
||||
|
||||
size_t propsSize = coder.Props.Size();
|
||||
b |= ((propsSize != 0) ? 0x20 : 0);
|
||||
temp[0] = b;
|
||||
WriteBytes(temp, idSize + 1);
|
||||
if (isComplex)
|
||||
{
|
||||
WriteNumber(coder.NumStreams);
|
||||
WriteNumber(1); // NumOutStreams;
|
||||
}
|
||||
if (propsSize == 0)
|
||||
continue;
|
||||
WriteNumber(propsSize);
|
||||
WriteBytes(coder.Props, propsSize);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < folder.Bonds.Size(); i++)
|
||||
{
|
||||
const CBond &bond = folder.Bonds[i];
|
||||
WriteNumber(bond.PackIndex);
|
||||
WriteNumber(bond.UnpackIndex);
|
||||
}
|
||||
|
||||
if (folder.PackStreams.Size() > 1)
|
||||
for (i = 0; i < folder.PackStreams.Size(); i++)
|
||||
WriteNumber(folder.PackStreams[i]);
|
||||
}
|
||||
|
||||
void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
|
||||
{
|
||||
Byte b = 0;
|
||||
Byte mask = 0x80;
|
||||
FOR_VECTOR (i, boolVector)
|
||||
{
|
||||
if (boolVector[i])
|
||||
b |= mask;
|
||||
mask >>= 1;
|
||||
if (mask == 0)
|
||||
{
|
||||
WriteByte(b);
|
||||
mask = 0x80;
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
if (mask != 0x80)
|
||||
WriteByte(b);
|
||||
}
|
||||
|
||||
static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
|
||||
|
||||
void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector)
|
||||
{
|
||||
WriteByte(id);
|
||||
WriteNumber(Bv_GetSizeInBytes(boolVector));
|
||||
WriteBoolVector(boolVector);
|
||||
}
|
||||
|
||||
void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
|
||||
{
|
||||
unsigned numDefined = 0;
|
||||
unsigned i;
|
||||
for (i = 0; i < digests.Defs.Size(); i++)
|
||||
if (digests.Defs[i])
|
||||
numDefined++;
|
||||
if (numDefined == 0)
|
||||
return;
|
||||
|
||||
WriteByte(NID::kCRC);
|
||||
if (numDefined == digests.Defs.Size())
|
||||
WriteByte(1);
|
||||
else
|
||||
{
|
||||
WriteByte(0);
|
||||
WriteBoolVector(digests.Defs);
|
||||
}
|
||||
for (i = 0; i < digests.Defs.Size(); i++)
|
||||
if (digests.Defs[i])
|
||||
WriteUInt32(digests.Vals[i]);
|
||||
}
|
||||
|
||||
void COutArchive::WritePackInfo(
|
||||
UInt64 dataOffset,
|
||||
const CRecordVector<UInt64> &packSizes,
|
||||
const CUInt32DefVector &packCRCs)
|
||||
{
|
||||
if (packSizes.IsEmpty())
|
||||
return;
|
||||
WriteByte(NID::kPackInfo);
|
||||
WriteNumber(dataOffset);
|
||||
WriteNumber(packSizes.Size());
|
||||
WriteByte(NID::kSize);
|
||||
FOR_VECTOR (i, packSizes)
|
||||
WriteNumber(packSizes[i]);
|
||||
|
||||
WriteHashDigests(packCRCs);
|
||||
|
||||
WriteByte(NID::kEnd);
|
||||
}
|
||||
|
||||
void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders, const COutFolders &outFolders)
|
||||
{
|
||||
if (folders.IsEmpty())
|
||||
return;
|
||||
|
||||
WriteByte(NID::kUnpackInfo);
|
||||
|
||||
WriteByte(NID::kFolder);
|
||||
WriteNumber(folders.Size());
|
||||
{
|
||||
WriteByte(0);
|
||||
FOR_VECTOR (i, folders)
|
||||
WriteFolder(folders[i]);
|
||||
}
|
||||
|
||||
WriteByte(NID::kCodersUnpackSize);
|
||||
FOR_VECTOR (i, outFolders.CoderUnpackSizes)
|
||||
WriteNumber(outFolders.CoderUnpackSizes[i]);
|
||||
|
||||
WriteHashDigests(outFolders.FolderUnpackCRCs);
|
||||
|
||||
WriteByte(NID::kEnd);
|
||||
}
|
||||
|
||||
void COutArchive::WriteSubStreamsInfo(const CObjectVector<CFolder> &folders,
|
||||
const COutFolders &outFolders,
|
||||
const CRecordVector<UInt64> &unpackSizes,
|
||||
const CUInt32DefVector &digests)
|
||||
{
|
||||
const CRecordVector<CNum> &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector;
|
||||
WriteByte(NID::kSubStreamsInfo);
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
|
||||
if (numUnpackStreamsInFolders[i] != 1)
|
||||
{
|
||||
WriteByte(NID::kNumUnpackStream);
|
||||
for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
|
||||
WriteNumber(numUnpackStreamsInFolders[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
|
||||
if (numUnpackStreamsInFolders[i] > 1)
|
||||
{
|
||||
WriteByte(NID::kSize);
|
||||
CNum index = 0;
|
||||
for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
|
||||
{
|
||||
CNum num = numUnpackStreamsInFolders[i];
|
||||
for (CNum j = 0; j < num; j++)
|
||||
{
|
||||
if (j + 1 != num)
|
||||
WriteNumber(unpackSizes[index]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
CUInt32DefVector digests2;
|
||||
|
||||
unsigned digestIndex = 0;
|
||||
for (i = 0; i < folders.Size(); i++)
|
||||
{
|
||||
unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i];
|
||||
if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i))
|
||||
digestIndex++;
|
||||
else
|
||||
for (unsigned j = 0; j < numSubStreams; j++, digestIndex++)
|
||||
{
|
||||
digests2.Defs.Add(digests.Defs[digestIndex]);
|
||||
digests2.Vals.Add(digests.Vals[digestIndex]);
|
||||
}
|
||||
}
|
||||
WriteHashDigests(digests2);
|
||||
WriteByte(NID::kEnd);
|
||||
}
|
||||
|
||||
// 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
|
||||
|
||||
void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
|
||||
{
|
||||
if (!_useAlign)
|
||||
return;
|
||||
pos += (unsigned)GetPos();
|
||||
pos &= (alignSize - 1);
|
||||
if (pos == 0)
|
||||
return;
|
||||
unsigned skip = alignSize - pos;
|
||||
if (skip < 2)
|
||||
skip += alignSize;
|
||||
skip -= 2;
|
||||
WriteByte(NID::kDummy);
|
||||
WriteByte((Byte)skip);
|
||||
for (unsigned i = 0; i < skip; i++)
|
||||
WriteByte(0);
|
||||
}
|
||||
|
||||
void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize)
|
||||
{
|
||||
const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
|
||||
const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
|
||||
SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
|
||||
|
||||
WriteByte(type);
|
||||
WriteNumber(dataSize);
|
||||
if (numDefined == v.Size())
|
||||
WriteByte(1);
|
||||
else
|
||||
{
|
||||
WriteByte(0);
|
||||
WriteBoolVector(v);
|
||||
}
|
||||
WriteByte(0);
|
||||
}
|
||||
|
||||
void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
|
||||
{
|
||||
unsigned numDefined = 0;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < v.Defs.Size(); i++)
|
||||
if (v.Defs[i])
|
||||
numDefined++;
|
||||
|
||||
if (numDefined == 0)
|
||||
return;
|
||||
|
||||
WriteAlignedBoolHeader(v.Defs, numDefined, type, 8);
|
||||
|
||||
for (i = 0; i < v.Defs.Size(); i++)
|
||||
if (v.Defs[i])
|
||||
WriteUInt64(v.Vals[i]);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::EncodeStream(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CEncoder &encoder, const CByteBuffer &data,
|
||||
CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)
|
||||
{
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CMyComPtr<ISequentialInStream> stream = streamSpec;
|
||||
streamSpec->Init(data, data.Size());
|
||||
outFolders.FolderUnpackCRCs.Defs.Add(true);
|
||||
outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size()));
|
||||
// outFolders.NumUnpackStreamsVector.Add(1);
|
||||
UInt64 dataSize64 = data.Size();
|
||||
UInt64 unpackSize;
|
||||
RINOK(encoder.Encode(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
stream,
|
||||
// NULL,
|
||||
&dataSize64,
|
||||
folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL))
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COutArchive::WriteHeader(
|
||||
const CArchiveDatabaseOut &db,
|
||||
// const CHeaderOptions &headerOptions,
|
||||
UInt64 &headerOffset)
|
||||
{
|
||||
/*
|
||||
bool thereIsSecure = (db.SecureBuf.Size() != 0);
|
||||
*/
|
||||
_useAlign = true;
|
||||
|
||||
{
|
||||
UInt64 packSize = 0;
|
||||
FOR_VECTOR (i, db.PackSizes)
|
||||
packSize += db.PackSizes[i];
|
||||
headerOffset = packSize;
|
||||
}
|
||||
|
||||
|
||||
WriteByte(NID::kHeader);
|
||||
|
||||
// Archive Properties
|
||||
|
||||
if (db.Folders.Size() > 0)
|
||||
{
|
||||
WriteByte(NID::kMainStreamsInfo);
|
||||
WritePackInfo(0, db.PackSizes, db.PackCRCs);
|
||||
WriteUnpackInfo(db.Folders, (const COutFolders &)db);
|
||||
|
||||
CRecordVector<UInt64> unpackSizes;
|
||||
CUInt32DefVector digests;
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
if (!file.HasStream)
|
||||
continue;
|
||||
unpackSizes.Add(file.Size);
|
||||
digests.Defs.Add(file.CrcDefined);
|
||||
digests.Vals.Add(file.Crc);
|
||||
}
|
||||
|
||||
WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests);
|
||||
WriteByte(NID::kEnd);
|
||||
}
|
||||
|
||||
if (db.Files.IsEmpty())
|
||||
{
|
||||
WriteByte(NID::kEnd);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteByte(NID::kFilesInfo);
|
||||
WriteNumber(db.Files.Size());
|
||||
|
||||
{
|
||||
/* ---------- Empty Streams ---------- */
|
||||
CBoolVector emptyStreamVector;
|
||||
emptyStreamVector.ClearAndSetSize(db.Files.Size());
|
||||
unsigned numEmptyStreams = 0;
|
||||
{
|
||||
FOR_VECTOR (i, db.Files)
|
||||
if (db.Files[i].HasStream)
|
||||
emptyStreamVector[i] = false;
|
||||
else
|
||||
{
|
||||
emptyStreamVector[i] = true;
|
||||
numEmptyStreams++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numEmptyStreams != 0)
|
||||
{
|
||||
WritePropBoolVector(NID::kEmptyStream, emptyStreamVector);
|
||||
|
||||
CBoolVector emptyFileVector, antiVector;
|
||||
emptyFileVector.ClearAndSetSize(numEmptyStreams);
|
||||
antiVector.ClearAndSetSize(numEmptyStreams);
|
||||
bool thereAreEmptyFiles = false, thereAreAntiItems = false;
|
||||
unsigned cur = 0;
|
||||
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
if (file.HasStream)
|
||||
continue;
|
||||
emptyFileVector[cur] = !file.IsDir;
|
||||
if (!file.IsDir)
|
||||
thereAreEmptyFiles = true;
|
||||
bool isAnti = db.IsItemAnti(i);
|
||||
antiVector[cur] = isAnti;
|
||||
if (isAnti)
|
||||
thereAreAntiItems = true;
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (thereAreEmptyFiles)
|
||||
WritePropBoolVector(NID::kEmptyFile, emptyFileVector);
|
||||
if (thereAreAntiItems)
|
||||
WritePropBoolVector(NID::kAnti, antiVector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/* ---------- Names ---------- */
|
||||
|
||||
unsigned numDefined = 0;
|
||||
size_t namesDataSize = 0;
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const UString &name = db.Names[i];
|
||||
if (!name.IsEmpty())
|
||||
numDefined++;
|
||||
namesDataSize += (name.Len() + 1) * 2;
|
||||
}
|
||||
|
||||
if (numDefined > 0)
|
||||
{
|
||||
namesDataSize++;
|
||||
SkipAlign(2 + GetBigNumberSize(namesDataSize), 16);
|
||||
|
||||
WriteByte(NID::kName);
|
||||
WriteNumber(namesDataSize);
|
||||
WriteByte(0);
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const UString &name = db.Names[i];
|
||||
for (unsigned t = 0; t <= name.Len(); t++)
|
||||
{
|
||||
wchar_t c = name[t];
|
||||
WriteByte((Byte)c);
|
||||
WriteByte((Byte)(c >> 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime);
|
||||
/* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime);
|
||||
/* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime);
|
||||
WriteUInt64DefVector(db.StartPos, NID::kStartPos);
|
||||
|
||||
{
|
||||
/* ---------- Write Attrib ---------- */
|
||||
CBoolVector boolVector;
|
||||
boolVector.ClearAndSetSize(db.Files.Size());
|
||||
unsigned numDefined = 0;
|
||||
|
||||
{
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
bool defined = db.Files[i].AttribDefined;
|
||||
boolVector[i] = defined;
|
||||
if (defined)
|
||||
numDefined++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numDefined != 0)
|
||||
{
|
||||
WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4);
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
if (file.AttribDefined)
|
||||
WriteUInt32(file.Attrib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
// ---------- Write IsAux ----------
|
||||
unsigned numAux = 0;
|
||||
const CBoolVector &isAux = db.IsAux;
|
||||
for (i = 0; i < isAux.Size(); i++)
|
||||
if (isAux[i])
|
||||
numAux++;
|
||||
if (numAux > 0)
|
||||
{
|
||||
const unsigned bvSize = Bv_GetSizeInBytes(isAux);
|
||||
WriteByte(NID::kIsAux);
|
||||
WriteNumber(bvSize);
|
||||
WriteBoolVector(isAux);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// ---------- Write Parent ----------
|
||||
CBoolVector boolVector;
|
||||
boolVector.Reserve(db.Files.Size());
|
||||
unsigned numIsDir = 0;
|
||||
unsigned numParentLinks = 0;
|
||||
for (i = 0; i < db.Files.Size(); i++)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
bool defined = !file.IsAltStream;
|
||||
boolVector.Add(defined);
|
||||
if (defined)
|
||||
numIsDir++;
|
||||
if (file.Parent >= 0)
|
||||
numParentLinks++;
|
||||
}
|
||||
if (numParentLinks > 0)
|
||||
{
|
||||
// WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4);
|
||||
const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector);
|
||||
const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1;
|
||||
SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4);
|
||||
|
||||
WriteByte(NID::kParent);
|
||||
WriteNumber(dataSize);
|
||||
if (numIsDir == boolVector.Size())
|
||||
WriteByte(1);
|
||||
else
|
||||
{
|
||||
WriteByte(0);
|
||||
WriteBoolVector(boolVector);
|
||||
}
|
||||
for (i = 0; i < db.Files.Size(); i++)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
// if (file.Parent >= 0)
|
||||
WriteUInt32(file.Parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thereIsSecure)
|
||||
{
|
||||
UInt64 secureDataSize = 1 + 4 +
|
||||
db.SecureBuf.Size() +
|
||||
db.SecureSizes.Size() * 4;
|
||||
// secureDataSize += db.SecureIDs.Size() * 4;
|
||||
for (i = 0; i < db.SecureIDs.Size(); i++)
|
||||
secureDataSize += GetBigNumberSize(db.SecureIDs[i]);
|
||||
SkipAlign(2 + GetBigNumberSize(secureDataSize), 4);
|
||||
WriteByte(NID::kNtSecure);
|
||||
WriteNumber(secureDataSize);
|
||||
WriteByte(0);
|
||||
WriteUInt32(db.SecureSizes.Size());
|
||||
for (i = 0; i < db.SecureSizes.Size(); i++)
|
||||
WriteUInt32(db.SecureSizes[i]);
|
||||
WriteBytes(db.SecureBuf, db.SecureBuf.Size());
|
||||
for (i = 0; i < db.SecureIDs.Size(); i++)
|
||||
{
|
||||
WriteNumber(db.SecureIDs[i]);
|
||||
// WriteUInt32(db.SecureIDs[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
WriteByte(NID::kEnd); // for files
|
||||
WriteByte(NID::kEnd); // for headers
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteDatabase(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CArchiveDatabaseOut &db,
|
||||
const CCompressionMethodMode *options,
|
||||
const CHeaderOptions &headerOptions)
|
||||
{
|
||||
if (!db.CheckNumFiles())
|
||||
return E_FAIL;
|
||||
|
||||
UInt64 headerOffset;
|
||||
UInt32 headerCRC;
|
||||
UInt64 headerSize;
|
||||
if (db.IsEmpty())
|
||||
{
|
||||
headerSize = 0;
|
||||
headerOffset = 0;
|
||||
headerCRC = CrcCalc(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool encodeHeaders = false;
|
||||
if (options != 0)
|
||||
if (options->IsEmpty())
|
||||
options = 0;
|
||||
if (options != 0)
|
||||
if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
|
||||
encodeHeaders = true;
|
||||
|
||||
_outByte.SetStream(SeqStream);
|
||||
_outByte.Init();
|
||||
_crc = CRC_INIT_VAL;
|
||||
_countMode = encodeHeaders;
|
||||
_writeToStream = true;
|
||||
_countSize = 0;
|
||||
WriteHeader(db, /* headerOptions, */ headerOffset);
|
||||
|
||||
if (encodeHeaders)
|
||||
{
|
||||
CByteBuffer buf(_countSize);
|
||||
_outByte2.Init((Byte *)buf, _countSize);
|
||||
|
||||
_countMode = false;
|
||||
_writeToStream = false;
|
||||
WriteHeader(db, /* headerOptions, */ headerOffset);
|
||||
|
||||
if (_countSize != _outByte2.GetPos())
|
||||
return E_FAIL;
|
||||
|
||||
CCompressionMethodMode encryptOptions;
|
||||
encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
|
||||
encryptOptions.Password = options->Password;
|
||||
CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
|
||||
CRecordVector<UInt64> packSizes;
|
||||
CObjectVector<CFolder> folders;
|
||||
COutFolders outFolders;
|
||||
|
||||
RINOK(EncodeStream(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
encoder, buf,
|
||||
packSizes, folders, outFolders));
|
||||
|
||||
_writeToStream = true;
|
||||
|
||||
if (folders.Size() == 0)
|
||||
throw 1;
|
||||
|
||||
WriteID(NID::kEncodedHeader);
|
||||
WritePackInfo(headerOffset, packSizes, CUInt32DefVector());
|
||||
WriteUnpackInfo(folders, outFolders);
|
||||
WriteByte(NID::kEnd);
|
||||
FOR_VECTOR (i, packSizes)
|
||||
headerOffset += packSizes[i];
|
||||
}
|
||||
RINOK(_outByte.Flush());
|
||||
headerCRC = CRC_GET_DIGEST(_crc);
|
||||
headerSize = _outByte.GetProcessedSize();
|
||||
}
|
||||
#ifdef _7Z_VOL
|
||||
if (_endMarker)
|
||||
{
|
||||
CFinishHeader h;
|
||||
h.NextHeaderSize = headerSize;
|
||||
h.NextHeaderCRC = headerCRC;
|
||||
h.NextHeaderOffset =
|
||||
UInt64(0) - (headerSize +
|
||||
4 + kFinishHeaderSize);
|
||||
h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
|
||||
h.AdditionalStartBlockSize = 0;
|
||||
RINOK(WriteFinishHeader(h));
|
||||
return WriteFinishSignature();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
CStartHeader h;
|
||||
h.NextHeaderSize = headerSize;
|
||||
h.NextHeaderCRC = headerCRC;
|
||||
h.NextHeaderOffset = headerOffset;
|
||||
RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
|
||||
return WriteStartHeader(h);
|
||||
}
|
||||
}
|
||||
|
||||
void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value)
|
||||
{
|
||||
while (index >= Defs.Size())
|
||||
Defs.Add(false);
|
||||
Defs[index] = defined;
|
||||
if (!defined)
|
||||
return;
|
||||
while (index >= Vals.Size())
|
||||
Vals.Add(0);
|
||||
Vals[index] = value;
|
||||
}
|
||||
|
||||
void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name)
|
||||
{
|
||||
unsigned index = Files.Size();
|
||||
CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
|
||||
ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
|
||||
MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
|
||||
StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
|
||||
SetItem_Anti(index, file2.IsAnti);
|
||||
// SetItem_Aux(index, file2.IsAux);
|
||||
Names.Add(name);
|
||||
Files.Add(file);
|
||||
}
|
||||
|
||||
}}
|
||||
321
CPP/7zip/Archive/7z/7zOut.h
Normal file
321
CPP/7zip/Archive/7z/7zOut.h
Normal file
@@ -0,0 +1,321 @@
|
||||
// 7zOut.h
|
||||
|
||||
#ifndef __7Z_OUT_H
|
||||
#define __7Z_OUT_H
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zEncode.h"
|
||||
#include "7zHeader.h"
|
||||
#include "7zItem.h"
|
||||
|
||||
#include "../../Common/OutBuffer.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CWriteBufferLoc
|
||||
{
|
||||
Byte *_data;
|
||||
size_t _size;
|
||||
size_t _pos;
|
||||
public:
|
||||
CWriteBufferLoc(): _size(0), _pos(0) {}
|
||||
void Init(Byte *data, size_t size)
|
||||
{
|
||||
_data = data;
|
||||
_size = size;
|
||||
_pos = 0;
|
||||
}
|
||||
void WriteBytes(const void *data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
if (size > _size - _pos)
|
||||
throw 1;
|
||||
memcpy(_data + _pos, data, size);
|
||||
_pos += size;
|
||||
}
|
||||
void WriteByte(Byte b)
|
||||
{
|
||||
if (_size == _pos)
|
||||
throw 1;
|
||||
_data[_pos++] = b;
|
||||
}
|
||||
size_t GetPos() const { return _pos; }
|
||||
};
|
||||
|
||||
struct CHeaderOptions
|
||||
{
|
||||
bool CompressMainHeader;
|
||||
/*
|
||||
bool WriteCTime;
|
||||
bool WriteATime;
|
||||
bool WriteMTime;
|
||||
*/
|
||||
|
||||
CHeaderOptions():
|
||||
CompressMainHeader(true)
|
||||
/*
|
||||
, WriteCTime(false)
|
||||
, WriteATime(false)
|
||||
, WriteMTime(true)
|
||||
*/
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct CFileItem2
|
||||
{
|
||||
UInt64 CTime;
|
||||
UInt64 ATime;
|
||||
UInt64 MTime;
|
||||
UInt64 StartPos;
|
||||
bool CTimeDefined;
|
||||
bool ATimeDefined;
|
||||
bool MTimeDefined;
|
||||
bool StartPosDefined;
|
||||
bool IsAnti;
|
||||
// bool IsAux;
|
||||
|
||||
void Init()
|
||||
{
|
||||
CTimeDefined = false;
|
||||
ATimeDefined = false;
|
||||
MTimeDefined = false;
|
||||
StartPosDefined = false;
|
||||
IsAnti = false;
|
||||
// IsAux = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct COutFolders
|
||||
{
|
||||
CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only.
|
||||
|
||||
CRecordVector<CNum> NumUnpackStreamsVector;
|
||||
CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
|
||||
|
||||
void OutFoldersClear()
|
||||
{
|
||||
FolderUnpackCRCs.Clear();
|
||||
NumUnpackStreamsVector.Clear();
|
||||
CoderUnpackSizes.Clear();
|
||||
}
|
||||
|
||||
void OutFoldersReserveDown()
|
||||
{
|
||||
FolderUnpackCRCs.ReserveDown();
|
||||
NumUnpackStreamsVector.ReserveDown();
|
||||
CoderUnpackSizes.ReserveDown();
|
||||
}
|
||||
};
|
||||
|
||||
struct CArchiveDatabaseOut: public COutFolders
|
||||
{
|
||||
CRecordVector<UInt64> PackSizes;
|
||||
CUInt32DefVector PackCRCs;
|
||||
CObjectVector<CFolder> Folders;
|
||||
|
||||
CRecordVector<CFileItem> Files;
|
||||
UStringVector Names;
|
||||
CUInt64DefVector CTime;
|
||||
CUInt64DefVector ATime;
|
||||
CUInt64DefVector MTime;
|
||||
CUInt64DefVector StartPos;
|
||||
CRecordVector<bool> IsAnti;
|
||||
|
||||
/*
|
||||
CRecordVector<bool> IsAux;
|
||||
|
||||
CByteBuffer SecureBuf;
|
||||
CRecordVector<UInt32> SecureSizes;
|
||||
CRecordVector<UInt32> SecureIDs;
|
||||
|
||||
void ClearSecure()
|
||||
{
|
||||
SecureBuf.Free();
|
||||
SecureSizes.Clear();
|
||||
SecureIDs.Clear();
|
||||
}
|
||||
*/
|
||||
|
||||
void Clear()
|
||||
{
|
||||
OutFoldersClear();
|
||||
|
||||
PackSizes.Clear();
|
||||
PackCRCs.Clear();
|
||||
Folders.Clear();
|
||||
|
||||
Files.Clear();
|
||||
Names.Clear();
|
||||
CTime.Clear();
|
||||
ATime.Clear();
|
||||
MTime.Clear();
|
||||
StartPos.Clear();
|
||||
IsAnti.Clear();
|
||||
|
||||
/*
|
||||
IsAux.Clear();
|
||||
ClearSecure();
|
||||
*/
|
||||
}
|
||||
|
||||
void ReserveDown()
|
||||
{
|
||||
OutFoldersReserveDown();
|
||||
|
||||
PackSizes.ReserveDown();
|
||||
PackCRCs.ReserveDown();
|
||||
Folders.ReserveDown();
|
||||
|
||||
Files.ReserveDown();
|
||||
Names.ReserveDown();
|
||||
CTime.ReserveDown();
|
||||
ATime.ReserveDown();
|
||||
MTime.ReserveDown();
|
||||
StartPos.ReserveDown();
|
||||
IsAnti.ReserveDown();
|
||||
|
||||
/*
|
||||
IsAux.ReserveDown();
|
||||
*/
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return (
|
||||
PackSizes.IsEmpty() &&
|
||||
NumUnpackStreamsVector.IsEmpty() &&
|
||||
Folders.IsEmpty() &&
|
||||
Files.IsEmpty());
|
||||
}
|
||||
|
||||
bool CheckNumFiles() const
|
||||
{
|
||||
unsigned size = Files.Size();
|
||||
return (
|
||||
CTime.CheckSize(size) &&
|
||||
ATime.CheckSize(size) &&
|
||||
MTime.CheckSize(size) &&
|
||||
StartPos.CheckSize(size) &&
|
||||
(size == IsAnti.Size() || IsAnti.Size() == 0));
|
||||
}
|
||||
|
||||
bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
|
||||
// bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
|
||||
|
||||
void SetItem_Anti(unsigned index, bool isAnti)
|
||||
{
|
||||
while (index >= IsAnti.Size())
|
||||
IsAnti.Add(false);
|
||||
IsAnti[index] = isAnti;
|
||||
}
|
||||
/*
|
||||
void SetItem_Aux(unsigned index, bool isAux)
|
||||
{
|
||||
while (index >= IsAux.Size())
|
||||
IsAux.Add(false);
|
||||
IsAux[index] = isAux;
|
||||
}
|
||||
*/
|
||||
|
||||
void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name);
|
||||
};
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
UInt64 _prefixHeaderPos;
|
||||
|
||||
HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); }
|
||||
|
||||
UInt64 GetPos() const;
|
||||
void WriteBytes(const void *data, size_t size);
|
||||
void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); }
|
||||
void WriteByte(Byte b);
|
||||
void WriteUInt32(UInt32 value);
|
||||
void WriteUInt64(UInt64 value);
|
||||
void WriteNumber(UInt64 value);
|
||||
void WriteID(UInt64 value) { WriteNumber(value); }
|
||||
|
||||
void WriteFolder(const CFolder &folder);
|
||||
HRESULT WriteFileHeader(const CFileItem &itemInfo);
|
||||
void WriteBoolVector(const CBoolVector &boolVector);
|
||||
void WritePropBoolVector(Byte id, const CBoolVector &boolVector);
|
||||
|
||||
void WriteHashDigests(const CUInt32DefVector &digests);
|
||||
|
||||
void WritePackInfo(
|
||||
UInt64 dataOffset,
|
||||
const CRecordVector<UInt64> &packSizes,
|
||||
const CUInt32DefVector &packCRCs);
|
||||
|
||||
void WriteUnpackInfo(
|
||||
const CObjectVector<CFolder> &folders,
|
||||
const COutFolders &outFolders);
|
||||
|
||||
void WriteSubStreamsInfo(
|
||||
const CObjectVector<CFolder> &folders,
|
||||
const COutFolders &outFolders,
|
||||
const CRecordVector<UInt64> &unpackSizes,
|
||||
const CUInt32DefVector &digests);
|
||||
|
||||
void SkipAlign(unsigned pos, unsigned alignSize);
|
||||
void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize);
|
||||
void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type);
|
||||
|
||||
HRESULT EncodeStream(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CEncoder &encoder, const CByteBuffer &data,
|
||||
CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders);
|
||||
void WriteHeader(
|
||||
const CArchiveDatabaseOut &db,
|
||||
// const CHeaderOptions &headerOptions,
|
||||
UInt64 &headerOffset);
|
||||
|
||||
bool _countMode;
|
||||
bool _writeToStream;
|
||||
size_t _countSize;
|
||||
UInt32 _crc;
|
||||
COutBuffer _outByte;
|
||||
CWriteBufferLoc _outByte2;
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
bool _endMarker;
|
||||
#endif
|
||||
|
||||
bool _useAlign;
|
||||
|
||||
HRESULT WriteSignature();
|
||||
#ifdef _7Z_VOL
|
||||
HRESULT WriteFinishSignature();
|
||||
#endif
|
||||
HRESULT WriteStartHeader(const CStartHeader &h);
|
||||
#ifdef _7Z_VOL
|
||||
HRESULT WriteFinishHeader(const CFinishHeader &h);
|
||||
#endif
|
||||
CMyComPtr<IOutStream> Stream;
|
||||
public:
|
||||
|
||||
COutArchive() { _outByte.Create(1 << 16); }
|
||||
CMyComPtr<ISequentialOutStream> SeqStream;
|
||||
HRESULT Create(ISequentialOutStream *stream, bool endMarker);
|
||||
void Close();
|
||||
HRESULT SkipPrefixArchiveHeader();
|
||||
HRESULT WriteDatabase(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CArchiveDatabaseOut &db,
|
||||
const CCompressionMethodMode *options,
|
||||
const CHeaderOptions &headerOptions);
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false);
|
||||
static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
174
CPP/7zip/Archive/7z/7zProperties.cpp
Normal file
174
CPP/7zip/Archive/7z/7zProperties.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
// 7zProperties.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zProperties.h"
|
||||
#include "7zHeader.h"
|
||||
#include "7zHandler.h"
|
||||
|
||||
// #define _MULTI_PACK
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
struct CPropMap
|
||||
{
|
||||
UInt32 FilePropID;
|
||||
CStatProp StatProp;
|
||||
};
|
||||
|
||||
static const CPropMap kPropMap[] =
|
||||
{
|
||||
{ NID::kName, { NULL, kpidPath, VT_BSTR } },
|
||||
{ NID::kSize, { NULL, kpidSize, VT_UI8 } },
|
||||
{ NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
|
||||
|
||||
#ifdef _MULTI_PACK
|
||||
{ 100, { "Pack0", kpidPackedSize0, VT_UI8 } },
|
||||
{ 101, { "Pack1", kpidPackedSize1, VT_UI8 } },
|
||||
{ 102, { "Pack2", kpidPackedSize2, VT_UI8 } },
|
||||
{ 103, { "Pack3", kpidPackedSize3, VT_UI8 } },
|
||||
{ 104, { "Pack4", kpidPackedSize4, VT_UI8 } },
|
||||
#endif
|
||||
|
||||
{ NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
|
||||
{ NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
|
||||
{ NID::kATime, { NULL, kpidATime, VT_FILETIME } },
|
||||
{ NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } },
|
||||
{ NID::kStartPos, { NULL, kpidPosition, VT_UI8 } },
|
||||
|
||||
{ NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
|
||||
|
||||
// { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } },
|
||||
{ NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }
|
||||
|
||||
#ifndef _SFX
|
||||
,
|
||||
{ 97, { NULL, kpidEncrypted, VT_BOOL } },
|
||||
{ 98, { NULL, kpidMethod, VT_BSTR } },
|
||||
{ 99, { NULL, kpidBlock, VT_UI4 } }
|
||||
#endif
|
||||
};
|
||||
|
||||
static void CopyOneItem(CRecordVector<UInt64> &src,
|
||||
CRecordVector<UInt64> &dest, UInt32 item)
|
||||
{
|
||||
FOR_VECTOR (i, src)
|
||||
if (src[i] == item)
|
||||
{
|
||||
dest.Add(item);
|
||||
src.Delete(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
|
||||
{
|
||||
FOR_VECTOR (i, src)
|
||||
if (src[i] == item)
|
||||
{
|
||||
src.Delete(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
|
||||
{
|
||||
FOR_VECTOR (i, dest)
|
||||
if (dest[i] == item)
|
||||
{
|
||||
dest.Delete(i);
|
||||
break;
|
||||
}
|
||||
dest.Insert(0, item);
|
||||
}
|
||||
|
||||
#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id);
|
||||
|
||||
void CHandler::FillPopIDs()
|
||||
{
|
||||
_fileInfoPopIDs.Clear();
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
if (_volumes.Size() < 1)
|
||||
return;
|
||||
const CVolume &volume = _volumes.Front();
|
||||
const CArchiveDatabaseEx &_db = volume.Database;
|
||||
#endif
|
||||
|
||||
CRecordVector<UInt64> fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs;
|
||||
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
|
||||
/*
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kParent);
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kNtSecure);
|
||||
*/
|
||||
|
||||
COPY_ONE_ITEM(kName);
|
||||
COPY_ONE_ITEM(kAnti);
|
||||
COPY_ONE_ITEM(kSize);
|
||||
COPY_ONE_ITEM(kPackInfo);
|
||||
COPY_ONE_ITEM(kCTime);
|
||||
COPY_ONE_ITEM(kMTime);
|
||||
COPY_ONE_ITEM(kATime);
|
||||
COPY_ONE_ITEM(kWinAttrib);
|
||||
COPY_ONE_ITEM(kCRC);
|
||||
COPY_ONE_ITEM(kComment);
|
||||
|
||||
_fileInfoPopIDs += fileInfoPopIDs;
|
||||
|
||||
#ifndef _SFX
|
||||
_fileInfoPopIDs.Add(97);
|
||||
_fileInfoPopIDs.Add(98);
|
||||
_fileInfoPopIDs.Add(99);
|
||||
#endif
|
||||
|
||||
#ifdef _MULTI_PACK
|
||||
_fileInfoPopIDs.Add(100);
|
||||
_fileInfoPopIDs.Add(101);
|
||||
_fileInfoPopIDs.Add(102);
|
||||
_fileInfoPopIDs.Add(103);
|
||||
_fileInfoPopIDs.Add(104);
|
||||
#endif
|
||||
|
||||
#ifndef _SFX
|
||||
InsertToHead(_fileInfoPopIDs, NID::kMTime);
|
||||
InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
|
||||
InsertToHead(_fileInfoPopIDs, NID::kSize);
|
||||
InsertToHead(_fileInfoPopIDs, NID::kName);
|
||||
#endif
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
|
||||
{
|
||||
*numProps = _fileInfoPopIDs.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
|
||||
{
|
||||
if (index >= _fileInfoPopIDs.Size())
|
||||
return E_INVALIDARG;
|
||||
UInt64 id = _fileInfoPopIDs[index];
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(kPropMap); i++)
|
||||
{
|
||||
const CPropMap &pr = kPropMap[i];
|
||||
if (pr.FilePropID == id)
|
||||
{
|
||||
const CStatProp &st = pr.StatProp;
|
||||
*propID = st.PropID;
|
||||
*varType = st.vt;
|
||||
/*
|
||||
if (st.lpwstrName)
|
||||
*name = ::SysAllocString(st.lpwstrName);
|
||||
else
|
||||
*/
|
||||
*name = NULL;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
}}
|
||||
22
CPP/7zip/Archive/7z/7zProperties.h
Normal file
22
CPP/7zip/Archive/7z/7zProperties.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// 7zProperties.h
|
||||
|
||||
#ifndef __7Z_PROPERTIES_H
|
||||
#define __7Z_PROPERTIES_H
|
||||
|
||||
#include "../../PropID.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
enum
|
||||
{
|
||||
kpidPackedSize0 = kpidUserDefined,
|
||||
kpidPackedSize1,
|
||||
kpidPackedSize2,
|
||||
kpidPackedSize3,
|
||||
kpidPackedSize4
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
21
CPP/7zip/Archive/7z/7zRegister.cpp
Normal file
21
CPP/7zip/Archive/7z/7zRegister.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// 7zRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "7zHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
static Byte k_Signature_Dec[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
|
||||
REGISTER_ARC_IO_DECREMENT_SIG(
|
||||
"7z", "7z", NULL, 7,
|
||||
k_Signature_Dec,
|
||||
0,
|
||||
NArcInfoFlags::kFindSignature,
|
||||
NULL);
|
||||
|
||||
}}
|
||||
22
CPP/7zip/Archive/7z/7zSpecStream.cpp
Normal file
22
CPP/7zip/Archive/7z/7zSpecStream.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// 7zSpecStream.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zSpecStream.h"
|
||||
|
||||
STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result = _stream->Read(data, size, &realProcessedSize);
|
||||
_size += realProcessedSize;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value)
|
||||
{
|
||||
if (!_getSubStreamSize)
|
||||
return E_NOTIMPL;
|
||||
return _getSubStreamSize->GetSubStreamSize(subStream, value);
|
||||
}
|
||||
35
CPP/7zip/Archive/7z/7zSpecStream.h
Normal file
35
CPP/7zip/Archive/7z/7zSpecStream.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// 7zSpecStream.h
|
||||
|
||||
#ifndef __7Z_SPEC_STREAM_H
|
||||
#define __7Z_SPEC_STREAM_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
|
||||
class CSequentialInStreamSizeCount2:
|
||||
public ISequentialInStream,
|
||||
public ICompressGetSubStreamSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> _stream;
|
||||
CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
|
||||
UInt64 _size;
|
||||
public:
|
||||
void Init(ISequentialInStream *stream)
|
||||
{
|
||||
_size = 0;
|
||||
_getSubStreamSize.Release();
|
||||
_stream = stream;
|
||||
_stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
|
||||
}
|
||||
UInt64 GetSize() const { return _size; }
|
||||
|
||||
MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
|
||||
};
|
||||
|
||||
#endif
|
||||
2469
CPP/7zip/Archive/7z/7zUpdate.cpp
Normal file
2469
CPP/7zip/Archive/7z/7zUpdate.cpp
Normal file
File diff suppressed because it is too large
Load Diff
139
CPP/7zip/Archive/7z/7zUpdate.h
Normal file
139
CPP/7zip/Archive/7z/7zUpdate.h
Normal file
@@ -0,0 +1,139 @@
|
||||
// 7zUpdate.h
|
||||
|
||||
#ifndef __7Z_UPDATE_H
|
||||
#define __7Z_UPDATE_H
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
// #include "../../Common/UniqBlocks.h"
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zIn.h"
|
||||
#include "7zOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
/*
|
||||
struct CTreeFolder
|
||||
{
|
||||
UString Name;
|
||||
int Parent;
|
||||
CIntVector SubFolders;
|
||||
int UpdateItemIndex;
|
||||
int SortIndex;
|
||||
int SortIndexEnd;
|
||||
|
||||
CTreeFolder(): UpdateItemIndex(-1) {}
|
||||
};
|
||||
*/
|
||||
|
||||
struct CUpdateItem
|
||||
{
|
||||
int IndexInArchive;
|
||||
int IndexInClient;
|
||||
|
||||
UInt64 CTime;
|
||||
UInt64 ATime;
|
||||
UInt64 MTime;
|
||||
|
||||
UInt64 Size;
|
||||
UString Name;
|
||||
/*
|
||||
bool IsAltStream;
|
||||
int ParentFolderIndex;
|
||||
int TreeFolderIndex;
|
||||
*/
|
||||
|
||||
// that code is not used in 9.26
|
||||
// int ParentSortIndex;
|
||||
// int ParentSortIndexEnd;
|
||||
|
||||
UInt32 Attrib;
|
||||
|
||||
bool NewData;
|
||||
bool NewProps;
|
||||
|
||||
bool IsAnti;
|
||||
bool IsDir;
|
||||
|
||||
bool AttribDefined;
|
||||
bool CTimeDefined;
|
||||
bool ATimeDefined;
|
||||
bool MTimeDefined;
|
||||
|
||||
// int SecureIndex; // 0 means (no_security)
|
||||
|
||||
bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
|
||||
// bool HasStream() const { return !IsDir && !IsAnti /* && Size != 0 */; } // for test purposes
|
||||
|
||||
CUpdateItem():
|
||||
// ParentSortIndex(-1),
|
||||
// IsAltStream(false),
|
||||
IsAnti(false),
|
||||
IsDir(false),
|
||||
AttribDefined(false),
|
||||
CTimeDefined(false),
|
||||
ATimeDefined(false),
|
||||
MTimeDefined(false)
|
||||
// SecureIndex(0)
|
||||
{}
|
||||
void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
|
||||
|
||||
// unsigned GetExtensionPos() const;
|
||||
// UString GetExtension() const;
|
||||
};
|
||||
|
||||
struct CUpdateOptions
|
||||
{
|
||||
const CCompressionMethodMode *Method;
|
||||
const CCompressionMethodMode *HeaderMethod;
|
||||
bool UseFilters; // use additional filters for some files
|
||||
bool MaxFilter; // use BCJ2 filter instead of BCJ
|
||||
int AnalysisLevel;
|
||||
|
||||
CHeaderOptions HeaderOptions;
|
||||
|
||||
UInt64 NumSolidFiles;
|
||||
UInt64 NumSolidBytes;
|
||||
bool SolidExtension;
|
||||
|
||||
bool UseTypeSorting;
|
||||
|
||||
bool RemoveSfxBlock;
|
||||
bool MultiThreadMixer;
|
||||
|
||||
CUpdateOptions():
|
||||
Method(NULL),
|
||||
HeaderMethod(NULL),
|
||||
UseFilters(false),
|
||||
MaxFilter(false),
|
||||
AnalysisLevel(-1),
|
||||
NumSolidFiles((UInt64)(Int64)(-1)),
|
||||
NumSolidBytes((UInt64)(Int64)(-1)),
|
||||
SolidExtension(false),
|
||||
UseTypeSorting(true),
|
||||
RemoveSfxBlock(false),
|
||||
MultiThreadMixer(true)
|
||||
{}
|
||||
};
|
||||
|
||||
HRESULT Update(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream *inStream,
|
||||
const CDbEx *db,
|
||||
const CObjectVector<CUpdateItem> &updateItems,
|
||||
// const CObjectVector<CTreeFolder> &treeFolders, // treeFolders[0] is root
|
||||
// const CUniqBlocks &secureBlocks,
|
||||
COutArchive &archive,
|
||||
CArchiveDatabaseOut &newDatabase,
|
||||
ISequentialOutStream *seqOutStream,
|
||||
IArchiveUpdateCallback *updateCallback,
|
||||
const CUpdateOptions &options
|
||||
#ifndef _NO_CRYPTO
|
||||
, ICryptoGetTextPassword *getDecoderPassword
|
||||
#endif
|
||||
);
|
||||
}}
|
||||
|
||||
#endif
|
||||
3
CPP/7zip/Archive/7z/StdAfx.cpp
Normal file
3
CPP/7zip/Archive/7z/StdAfx.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// StdAfx.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
8
CPP/7zip/Archive/7z/StdAfx.h
Normal file
8
CPP/7zip/Archive/7z/StdAfx.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
81
CPP/7zip/Archive/7z/makefile
Normal file
81
CPP/7zip/Archive/7z/makefile
Normal file
@@ -0,0 +1,81 @@
|
||||
PROG = 7z.dll
|
||||
DEF_FILE = ../Archive.def
|
||||
CFLAGS = $(CFLAGS) \
|
||||
-DEXTERNAL_CODECS \
|
||||
|
||||
AR_OBJS = \
|
||||
$O\ArchiveExports.obj \
|
||||
$O\DllExports.obj \
|
||||
|
||||
7Z_OBJS = \
|
||||
$O\7zCompressionMode.obj \
|
||||
$O\7zDecode.obj \
|
||||
$O\7zEncode.obj \
|
||||
$O\7zExtract.obj \
|
||||
$O\7zFolderInStream.obj \
|
||||
$O\7zHandler.obj \
|
||||
$O\7zHandlerOut.obj \
|
||||
$O\7zHeader.obj \
|
||||
$O\7zIn.obj \
|
||||
$O\7zOut.obj \
|
||||
$O\7zProperties.obj \
|
||||
$O\7zSpecStream.obj \
|
||||
$O\7zUpdate.obj \
|
||||
$O\7zRegister.obj \
|
||||
|
||||
COMMON_OBJS = \
|
||||
$O\CRC.obj \
|
||||
$O\IntToString.obj \
|
||||
$O\NewHandler.obj \
|
||||
$O\MyString.obj \
|
||||
$O\StringConvert.obj \
|
||||
$O\StringToInt.obj \
|
||||
$O\MyVector.obj \
|
||||
$O\Wildcard.obj \
|
||||
|
||||
WIN_OBJS = \
|
||||
$O\DLL.obj \
|
||||
$O\FileDir.obj \
|
||||
$O\FileFind.obj \
|
||||
$O\FileIO.obj \
|
||||
$O\FileName.obj \
|
||||
$O\PropVariant.obj \
|
||||
$O\Synchronization.obj \
|
||||
$O\System.obj \
|
||||
|
||||
7ZIP_COMMON_OBJS = \
|
||||
$O\CreateCoder.obj \
|
||||
$O\InOutTempBuffer.obj \
|
||||
$O\FilterCoder.obj \
|
||||
$O\LimitedStreams.obj \
|
||||
$O\LockedStream.obj \
|
||||
$O\MethodId.obj \
|
||||
$O\MethodProps.obj \
|
||||
$O\OutBuffer.obj \
|
||||
$O\ProgressUtils.obj \
|
||||
$O\PropId.obj \
|
||||
$O\StreamBinder.obj \
|
||||
$O\StreamObjects.obj \
|
||||
$O\StreamUtils.obj \
|
||||
$O\VirtThread.obj \
|
||||
|
||||
COMPRESS_OBJS = \
|
||||
$O\CopyCoder.obj \
|
||||
|
||||
AR_COMMON_OBJS = \
|
||||
$O\CoderMixer2.obj \
|
||||
$O\HandlerOut.obj \
|
||||
$O\InStreamWithCRC.obj \
|
||||
$O\ItemNameUtils.obj \
|
||||
$O\MultiStream.obj \
|
||||
$O\OutStreamWithCRC.obj \
|
||||
$O\ParseProperties.obj \
|
||||
|
||||
C_OBJS = \
|
||||
$O\Alloc.obj \
|
||||
$O\CpuArch.obj \
|
||||
$O\Threads.obj \
|
||||
|
||||
!include "../../Crc.mak"
|
||||
|
||||
!include "../../7zip.mak"
|
||||
11
CPP/7zip/Archive/7z/resource.rc
Normal file
11
CPP/7zip/Archive/7z/resource.rc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../../MyVersionInfo.rc"
|
||||
|
||||
MY_VERSION_INFO_DLL("7z Plugin", "7z")
|
||||
|
||||
0 ICON "../Icons/7z.ico"
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
100 "7z:0"
|
||||
END
|
||||
|
||||
320
CPP/7zip/Archive/ApmHandler.cpp
Normal file
320
CPP/7zip/Archive/ApmHandler.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
// ApmHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/Defs.h"
|
||||
#include "../../Common/IntToString.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "HandlerCont.h"
|
||||
|
||||
#define Get16(p) GetBe16(p)
|
||||
#define Get32(p) GetBe32(p)
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NApm {
|
||||
|
||||
static const Byte kSig0 = 'E';
|
||||
static const Byte kSig1 = 'R';
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UInt32 StartBlock;
|
||||
UInt32 NumBlocks;
|
||||
char Name[32];
|
||||
char Type[32];
|
||||
/*
|
||||
UInt32 DataStartBlock;
|
||||
UInt32 NumDataBlocks;
|
||||
UInt32 Status;
|
||||
UInt32 BootStartBlock;
|
||||
UInt32 BootSize;
|
||||
UInt32 BootAddr;
|
||||
UInt32 BootEntry;
|
||||
UInt32 BootChecksum;
|
||||
char Processor[16];
|
||||
*/
|
||||
|
||||
bool Parse(const Byte *p, UInt32 &numBlocksInMap)
|
||||
{
|
||||
numBlocksInMap = Get32(p + 4);
|
||||
StartBlock = Get32(p + 8);
|
||||
NumBlocks = Get32(p + 0xC);
|
||||
memcpy(Name, p + 0x10, 32);
|
||||
memcpy(Type, p + 0x30, 32);
|
||||
if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
|
||||
return false;
|
||||
/*
|
||||
DataStartBlock = Get32(p + 0x50);
|
||||
NumDataBlocks = Get32(p + 0x54);
|
||||
Status = Get32(p + 0x58);
|
||||
BootStartBlock = Get32(p + 0x5C);
|
||||
BootSize = Get32(p + 0x60);
|
||||
BootAddr = Get32(p + 0x64);
|
||||
if (Get32(p + 0x68) != 0)
|
||||
return false;
|
||||
BootEntry = Get32(p + 0x6C);
|
||||
if (Get32(p + 0x70) != 0)
|
||||
return false;
|
||||
BootChecksum = Get32(p + 0x74);
|
||||
memcpy(Processor, p + 0x78, 16);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class CHandler: public CHandlerCont
|
||||
{
|
||||
CRecordVector<CItem> _items;
|
||||
unsigned _blockSizeLog;
|
||||
UInt32 _numBlocks;
|
||||
UInt64 _phySize;
|
||||
bool _isArc;
|
||||
|
||||
HRESULT ReadTables(IInStream *stream);
|
||||
UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
|
||||
|
||||
virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
|
||||
{
|
||||
const CItem &item = _items[index];
|
||||
pos = BlocksToBytes(item.StartBlock);
|
||||
size = BlocksToBytes(item.NumBlocks);
|
||||
return NExtract::NOperationResult::kOK;
|
||||
}
|
||||
|
||||
public:
|
||||
INTERFACE_IInArchive_Cont(;)
|
||||
};
|
||||
|
||||
static const UInt32 kSectorSize = 512;
|
||||
|
||||
API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size)
|
||||
{
|
||||
if (size < kSectorSize)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
if (p[0] != kSig0 || p[1] != kSig1)
|
||||
return k_IsArc_Res_NO;
|
||||
unsigned i;
|
||||
for (i = 8; i < 16; i++)
|
||||
if (p[i] != 0)
|
||||
return k_IsArc_Res_NO;
|
||||
UInt32 blockSize = Get16(p + 2);
|
||||
for (i = 9; ((UInt32)1 << i) != blockSize; i++)
|
||||
if (i >= 12)
|
||||
return k_IsArc_Res_NO;
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CHandler::ReadTables(IInStream *stream)
|
||||
{
|
||||
Byte buf[kSectorSize];
|
||||
{
|
||||
RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
|
||||
if (buf[0] != kSig0 || buf[1] != kSig1)
|
||||
return S_FALSE;
|
||||
UInt32 blockSize = Get16(buf + 2);
|
||||
unsigned i;
|
||||
for (i = 9; ((UInt32)1 << i) != blockSize; i++)
|
||||
if (i >= 12)
|
||||
return S_FALSE;
|
||||
_blockSizeLog = i;
|
||||
_numBlocks = Get32(buf + 4);
|
||||
for (i = 8; i < 16; i++)
|
||||
if (buf[i] != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
unsigned numSkips = (unsigned)1 << (_blockSizeLog - 9);
|
||||
for (unsigned j = 1; j < numSkips; j++)
|
||||
{
|
||||
RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
|
||||
}
|
||||
|
||||
UInt32 numBlocksInMap = 0;
|
||||
|
||||
for (unsigned i = 0;;)
|
||||
{
|
||||
RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
|
||||
|
||||
CItem item;
|
||||
|
||||
UInt32 numBlocksInMap2 = 0;
|
||||
if (!item.Parse(buf, numBlocksInMap2))
|
||||
return S_FALSE;
|
||||
if (i == 0)
|
||||
{
|
||||
numBlocksInMap = numBlocksInMap2;
|
||||
if (numBlocksInMap > (1 << 8))
|
||||
return S_FALSE;
|
||||
}
|
||||
else if (numBlocksInMap2 != numBlocksInMap)
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 finish = item.StartBlock + item.NumBlocks;
|
||||
if (finish < item.StartBlock)
|
||||
return S_FALSE;
|
||||
_numBlocks = MyMax(_numBlocks, finish);
|
||||
|
||||
_items.Add(item);
|
||||
for (unsigned j = 1; j < numSkips; j++)
|
||||
{
|
||||
RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
|
||||
}
|
||||
if (++i == numBlocksInMap)
|
||||
break;
|
||||
}
|
||||
|
||||
_phySize = BlocksToBytes(_numBlocks);
|
||||
_isArc = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
RINOK(ReadTables(stream));
|
||||
_stream = stream;
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_isArc = false;
|
||||
_phySize = 0;
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidSize,
|
||||
kpidOffset
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidClusterSize
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
static AString GetString(const char *s)
|
||||
{
|
||||
AString res;
|
||||
for (unsigned i = 0; i < 32 && s[i] != 0; i++)
|
||||
res += s[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidMainSubfile:
|
||||
{
|
||||
int mainIndex = -1;
|
||||
FOR_VECTOR (i, _items)
|
||||
{
|
||||
AString s = GetString(_items[i].Type);
|
||||
if (s != "Apple_Free" &&
|
||||
s != "Apple_partition_map")
|
||||
{
|
||||
if (mainIndex >= 0)
|
||||
{
|
||||
mainIndex = -1;
|
||||
break;
|
||||
}
|
||||
mainIndex = i;
|
||||
}
|
||||
}
|
||||
if (mainIndex >= 0)
|
||||
prop = (UInt32)mainIndex;
|
||||
break;
|
||||
}
|
||||
case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
|
||||
case kpidPhySize: prop = _phySize; break;
|
||||
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
const CItem &item = _items[index];
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
AString s = GetString(item.Name);
|
||||
if (s.IsEmpty())
|
||||
{
|
||||
char s2[32];
|
||||
ConvertUInt32ToString(index, s2);
|
||||
s = s2;
|
||||
}
|
||||
AString type = GetString(item.Type);
|
||||
if (type == "Apple_HFS")
|
||||
type = "hfs";
|
||||
if (!type.IsEmpty())
|
||||
{
|
||||
s += '.';
|
||||
s += type;
|
||||
}
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
prop = BlocksToBytes(item.NumBlocks);
|
||||
break;
|
||||
case kpidOffset: prop = BlocksToBytes(item.StartBlock); break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static const Byte k_Signature[] = { kSig0, kSig1 };
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"APM", "apm", 0, 0xD4,
|
||||
k_Signature,
|
||||
0,
|
||||
0,
|
||||
IsArc_Apm)
|
||||
|
||||
}}
|
||||
854
CPP/7zip/Archive/ArHandler.cpp
Normal file
854
CPP/7zip/Archive/ArHandler.cpp
Normal file
@@ -0,0 +1,854 @@
|
||||
// ArHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/IntToString.h"
|
||||
#include "../../Common/StringConvert.h"
|
||||
#include "../../Common/StringToInt.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
#include "../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/ItemNameUtils.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NAr {
|
||||
|
||||
/*
|
||||
The end of each file member (including last file in archive) is 2-bytes aligned.
|
||||
It uses 0xA padding if required.
|
||||
|
||||
File Names:
|
||||
|
||||
GNU/SVR4 variant (.a static library):
|
||||
/ - archive symbol table
|
||||
// - the list of the long filenames, separated by one or more LF characters.
|
||||
/N - the reference to name string in long filenames list
|
||||
name/ - the name
|
||||
|
||||
Microsoft variant (.lib static library):
|
||||
/ - First linker file (archive symbol table)
|
||||
/ - Second linker file
|
||||
// - the list of the long filenames, null-terminated. Each string begins
|
||||
immediately after the null byte in the previous string.
|
||||
/N - the reference to name string in long filenames list
|
||||
name/ - the name
|
||||
|
||||
BSD (Mac OS X) variant:
|
||||
"__.SYMDEF" - archive symbol table
|
||||
or
|
||||
"__.SYMDEF SORTED" - archive symbol table
|
||||
#1/N - the real filename of length N is appended to the file header.
|
||||
*/
|
||||
|
||||
static const unsigned kSignatureLen = 8;
|
||||
|
||||
#define SIGNATURE { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A }
|
||||
|
||||
static const Byte kSignature[kSignatureLen] = SIGNATURE;
|
||||
|
||||
static const unsigned kNameSize = 16;
|
||||
static const unsigned kTimeSize = 12;
|
||||
static const unsigned kUserSize = 6;
|
||||
static const unsigned kModeSize = 8;
|
||||
static const unsigned kSizeSize = 10;
|
||||
|
||||
static const unsigned kHeaderSize = kNameSize + kTimeSize + kUserSize * 2 + kModeSize + kSizeSize + 1 + 1;
|
||||
|
||||
enum EType
|
||||
{
|
||||
kType_Ar,
|
||||
kType_ALib,
|
||||
kType_Deb,
|
||||
kType_Lib
|
||||
};
|
||||
|
||||
static const char * const k_TypeExtionsions[] =
|
||||
{
|
||||
"ar"
|
||||
, "a"
|
||||
, "deb"
|
||||
, "lib"
|
||||
};
|
||||
|
||||
enum ESubType
|
||||
{
|
||||
kSubType_None,
|
||||
kSubType_BSD
|
||||
};
|
||||
|
||||
/*
|
||||
struct CHeader
|
||||
{
|
||||
char Name[kNameSize];
|
||||
char MTime[kTimeSize];
|
||||
char User[kUserSize];
|
||||
char Group[kUserSize];
|
||||
char Mode[kModeSize];
|
||||
char Size[kSizeSize];
|
||||
char Quote;
|
||||
char NewLine;
|
||||
};
|
||||
*/
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt64 Size;
|
||||
UInt32 MTime;
|
||||
UInt32 User;
|
||||
UInt32 Group;
|
||||
UInt32 Mode;
|
||||
|
||||
UInt64 HeaderPos;
|
||||
UInt64 HeaderSize;
|
||||
|
||||
int TextFileIndex;
|
||||
int SameNameIndex;
|
||||
|
||||
CItem(): TextFileIndex(-1), SameNameIndex(-1) {}
|
||||
UInt64 GetDataPos() const { return HeaderPos + HeaderSize; }
|
||||
};
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
|
||||
public:
|
||||
UInt64 Position;
|
||||
ESubType SubType;
|
||||
|
||||
HRESULT GetNextItem(CItem &itemInfo, bool &filled);
|
||||
HRESULT Open(IInStream *inStream);
|
||||
HRESULT SkipData(UInt64 dataSize)
|
||||
{
|
||||
return m_Stream->Seek(dataSize + (dataSize & 1), STREAM_SEEK_CUR, &Position);
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream)
|
||||
{
|
||||
SubType = kSubType_None;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &Position));
|
||||
char signature[kSignatureLen];
|
||||
RINOK(ReadStream_FALSE(inStream, signature, kSignatureLen));
|
||||
Position += kSignatureLen;
|
||||
if (memcmp(signature, kSignature, kSignatureLen) != 0)
|
||||
return S_FALSE;
|
||||
m_Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static unsigned RemoveTailSpaces(char *dest, const char *s, unsigned size)
|
||||
{
|
||||
memcpy(dest, s, size);
|
||||
for (; size != 0; size--)
|
||||
{
|
||||
if (dest[size - 1] != ' ')
|
||||
break;
|
||||
}
|
||||
dest[size] = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
static bool OctalToNumber32(const char *s, unsigned size, UInt32 &res)
|
||||
{
|
||||
res = 0;
|
||||
char sz[32];
|
||||
size = RemoveTailSpaces(sz, s, size);
|
||||
if (size == 0)
|
||||
return true; // some items doesn't contaion any numbers
|
||||
const char *end;
|
||||
UInt64 res64 = ConvertOctStringToUInt64(sz, &end);
|
||||
if ((unsigned)(end - sz) != size)
|
||||
return false;
|
||||
res = (UInt32)res64;
|
||||
return (res64 <= 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static bool DecimalToNumber(const char *s, unsigned size, UInt64 &res)
|
||||
{
|
||||
res = 0;
|
||||
char sz[32];
|
||||
size = RemoveTailSpaces(sz, s, size);
|
||||
if (size == 0)
|
||||
return true; // some items doesn't contaion any numbers
|
||||
const char *end;
|
||||
res = ConvertStringToUInt64(sz, &end);
|
||||
return ((unsigned)(end - sz) == size);
|
||||
}
|
||||
|
||||
static bool DecimalToNumber32(const char *s, unsigned size, UInt32 &res)
|
||||
{
|
||||
UInt64 res64;
|
||||
if (!DecimalToNumber(s, size, res64))
|
||||
return false;
|
||||
res = (UInt32)res64;
|
||||
return (res64 <= 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
|
||||
|
||||
HRESULT CInArchive::GetNextItem(CItem &item, bool &filled)
|
||||
{
|
||||
filled = false;
|
||||
|
||||
char header[kHeaderSize];
|
||||
const char *cur = header;
|
||||
|
||||
{
|
||||
size_t processedSize = sizeof(header);
|
||||
item.HeaderPos = Position;
|
||||
item.HeaderSize = kHeaderSize;
|
||||
RINOK(ReadStream(m_Stream, header, &processedSize));
|
||||
if (processedSize != sizeof(header))
|
||||
return S_OK;
|
||||
if (header[kHeaderSize - 2] != 0x60 ||
|
||||
header[kHeaderSize - 1] != 0x0A)
|
||||
return S_OK;
|
||||
for (unsigned i = 0; i < kHeaderSize - 2; i++)
|
||||
// if (header[i] < 0x20)
|
||||
if (header[i] == 0)
|
||||
return S_OK;
|
||||
Position += processedSize;
|
||||
}
|
||||
|
||||
UInt32 longNameLen = 0;
|
||||
if (cur[0] == '#' &&
|
||||
cur[1] == '1' &&
|
||||
cur[2] == '/' &&
|
||||
cur[3] != 0)
|
||||
{
|
||||
// BSD variant
|
||||
RIF(DecimalToNumber32(cur + 3, kNameSize - 3 , longNameLen));
|
||||
if (longNameLen >= (1 << 12))
|
||||
longNameLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char tempString[kNameSize + 1];
|
||||
RemoveTailSpaces(tempString, cur, kNameSize);
|
||||
item.Name = tempString;
|
||||
}
|
||||
cur += kNameSize;
|
||||
|
||||
RIF(DecimalToNumber32(cur, kTimeSize, item.MTime)); cur += kTimeSize;
|
||||
RIF(DecimalToNumber32(cur, kUserSize, item.User)); cur += kUserSize;
|
||||
RIF(DecimalToNumber32(cur, kUserSize, item.Group)); cur += kUserSize;
|
||||
RIF(OctalToNumber32(cur, kModeSize, item.Mode)); cur += kModeSize;
|
||||
RIF(DecimalToNumber(cur, kSizeSize, item.Size)); cur += kSizeSize;
|
||||
|
||||
if (longNameLen != 0 && longNameLen <= item.Size)
|
||||
{
|
||||
SubType = kSubType_BSD;
|
||||
size_t processedSize = longNameLen;
|
||||
char *s = item.Name.GetBuf(longNameLen);
|
||||
HRESULT res = ReadStream(m_Stream, s, &processedSize);
|
||||
item.Name.ReleaseBuf_CalcLen(longNameLen);
|
||||
RINOK(res);
|
||||
if (processedSize != longNameLen)
|
||||
return S_OK;
|
||||
item.Size -= longNameLen;
|
||||
item.HeaderSize += longNameLen;
|
||||
Position += processedSize;
|
||||
}
|
||||
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CItem> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
Int32 _mainSubfile;
|
||||
UInt64 _phySize;
|
||||
|
||||
EType _type;
|
||||
ESubType _subType;
|
||||
int _longNames_FileIndex;
|
||||
AString _libFiles[2];
|
||||
unsigned _numLibFiles;
|
||||
AString _errorMessage;
|
||||
bool _isArc;
|
||||
|
||||
|
||||
void UpdateErrorMessage(const char *s);
|
||||
|
||||
HRESULT ParseLongNames(IInStream *stream);
|
||||
void ChangeDuplicateNames();
|
||||
int FindItem(UInt32 offset) const;
|
||||
HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos);
|
||||
HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex);
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
void CHandler::UpdateErrorMessage(const char *s)
|
||||
{
|
||||
if (!_errorMessage.IsEmpty())
|
||||
_errorMessage += '\n';
|
||||
_errorMessage += s;
|
||||
}
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidSubType
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidSize,
|
||||
kpidMTime,
|
||||
kpidPosixAttrib,
|
||||
kpidUser,
|
||||
kpidGroup
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
HRESULT CHandler::ParseLongNames(IInStream *stream)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < _items.Size(); i++)
|
||||
if (_items[i].Name == "//")
|
||||
break;
|
||||
if (i == _items.Size())
|
||||
return S_OK;
|
||||
|
||||
unsigned fileIndex = i;
|
||||
const CItem &item = _items[fileIndex];
|
||||
if (item.Size > ((UInt32)1 << 30))
|
||||
return S_FALSE;
|
||||
RINOK(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
|
||||
const size_t size = (size_t)item.Size;
|
||||
|
||||
CByteArr p(size);
|
||||
RINOK(ReadStream_FALSE(stream, p, size));
|
||||
|
||||
for (i = 0; i < _items.Size(); i++)
|
||||
{
|
||||
CItem &item2 = _items[i];
|
||||
if (item2.Name[0] != '/')
|
||||
continue;
|
||||
const char *ptr = item2.Name.Ptr(1);
|
||||
const char *end;
|
||||
UInt32 pos = ConvertStringToUInt32(ptr, &end);
|
||||
if (*end != 0 || end == ptr)
|
||||
continue;
|
||||
if (pos >= size)
|
||||
continue;
|
||||
UInt32 start = pos;
|
||||
for (;;)
|
||||
{
|
||||
if (pos >= size)
|
||||
return S_FALSE;
|
||||
char c = p[pos];
|
||||
if (c == 0 || c == 0x0A)
|
||||
break;
|
||||
pos++;
|
||||
}
|
||||
item2.Name.SetFrom((const char *)(p + start), pos - start);
|
||||
}
|
||||
|
||||
_longNames_FileIndex = fileIndex;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CHandler::ChangeDuplicateNames()
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 1; i < _items.Size(); i++)
|
||||
{
|
||||
CItem &item = _items[i];
|
||||
if (item.Name[0] == '/')
|
||||
continue;
|
||||
CItem &prev = _items[i - 1];
|
||||
if (item.Name == prev.Name)
|
||||
{
|
||||
if (prev.SameNameIndex < 0)
|
||||
prev.SameNameIndex = 0;
|
||||
item.SameNameIndex = prev.SameNameIndex + 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < _items.Size(); i++)
|
||||
{
|
||||
CItem &item = _items[i];
|
||||
if (item.SameNameIndex < 0)
|
||||
continue;
|
||||
char sz[32];
|
||||
ConvertUInt32ToString(item.SameNameIndex + 1, sz);
|
||||
unsigned len = MyStringLen(sz);
|
||||
sz[len++] = '.';
|
||||
sz[len] = 0;
|
||||
item.Name.Insert(0, sz);
|
||||
}
|
||||
}
|
||||
|
||||
int CHandler::FindItem(UInt32 offset) const
|
||||
{
|
||||
unsigned left = 0, right = _items.Size();
|
||||
while (left != right)
|
||||
{
|
||||
unsigned mid = (left + right) / 2;
|
||||
UInt64 midVal = _items[mid].HeaderPos;
|
||||
if (offset == midVal)
|
||||
return mid;
|
||||
if (offset < midVal)
|
||||
right = mid;
|
||||
else
|
||||
left = mid + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
HRESULT CHandler::AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos)
|
||||
{
|
||||
int fileIndex = FindItem(offset);
|
||||
if (fileIndex < (int)0)
|
||||
return S_FALSE;
|
||||
|
||||
size_t i = pos;
|
||||
do
|
||||
{
|
||||
if (i >= size)
|
||||
return S_FALSE;
|
||||
}
|
||||
while (data[i++] != 0);
|
||||
|
||||
AString &s = _libFiles[_numLibFiles];
|
||||
const AString &name = _items[fileIndex].Name;
|
||||
s += name;
|
||||
if (!name.IsEmpty() && name.Back() == '/')
|
||||
s.DeleteBack();
|
||||
s += " ";
|
||||
s += (const char *)(data + pos);
|
||||
s += (char)0xD;
|
||||
s += (char)0xA;
|
||||
pos = i;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); return GetUi32(p); }
|
||||
|
||||
HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex)
|
||||
{
|
||||
CItem &item = _items[fileIndex];
|
||||
if (item.Name != "/" &&
|
||||
item.Name != "__.SYMDEF" &&
|
||||
item.Name != "__.SYMDEF SORTED")
|
||||
return S_OK;
|
||||
if (item.Size > ((UInt32)1 << 30) ||
|
||||
item.Size < 4)
|
||||
return S_OK;
|
||||
RINOK(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
|
||||
size_t size = (size_t)item.Size;
|
||||
CByteArr p(size);
|
||||
RINOK(ReadStream_FALSE(stream, p, size));
|
||||
|
||||
size_t pos = 0;
|
||||
|
||||
if (item.Name != "/")
|
||||
{
|
||||
// __.SYMDEF parsing (BSD)
|
||||
unsigned be;
|
||||
for (be = 0; be < 2; be++)
|
||||
{
|
||||
UInt32 tableSize = Get32(p, be);
|
||||
pos = 4;
|
||||
if (size - pos < tableSize || (tableSize & 7) != 0)
|
||||
continue;
|
||||
size_t namesStart = pos + tableSize;
|
||||
UInt32 namesSize = Get32(p + namesStart, be);
|
||||
namesStart += 4;
|
||||
if (namesStart > size || namesStart + namesSize != size)
|
||||
continue;
|
||||
|
||||
UInt32 numSymbols = tableSize >> 3;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numSymbols; i++, pos += 8)
|
||||
{
|
||||
size_t namePos = Get32(p + pos, be);
|
||||
UInt32 offset = Get32(p + pos + 4, be);
|
||||
if (AddFunc(offset, p + namesStart, namesSize, namePos) != S_OK)
|
||||
break;
|
||||
}
|
||||
if (i == numSymbols)
|
||||
{
|
||||
pos = size;
|
||||
_type = kType_ALib;
|
||||
_subType = kSubType_BSD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (be == 2)
|
||||
return S_FALSE;
|
||||
}
|
||||
else if (_numLibFiles == 0)
|
||||
{
|
||||
// archive symbol table (GNU)
|
||||
UInt32 numSymbols = GetBe32(p);
|
||||
pos = 4;
|
||||
if (numSymbols > (size - pos) / 4)
|
||||
return S_FALSE;
|
||||
pos += 4 * numSymbols;
|
||||
|
||||
for (UInt32 i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 offset = GetBe32(p + 4 + i * 4);
|
||||
RINOK(AddFunc(offset, p, size, pos));
|
||||
}
|
||||
_type = kType_ALib;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Second linker file (Microsoft .lib)
|
||||
UInt32 numMembers = GetUi32(p);
|
||||
pos = 4;
|
||||
if (numMembers > (size - pos) / 4)
|
||||
return S_FALSE;
|
||||
pos += 4 * numMembers;
|
||||
|
||||
if (size - pos < 4)
|
||||
return S_FALSE;
|
||||
UInt32 numSymbols = GetUi32(p + pos);
|
||||
pos += 4;
|
||||
if (numSymbols > (size - pos) / 2)
|
||||
return S_FALSE;
|
||||
size_t indexStart = pos;
|
||||
pos += 2 * numSymbols;
|
||||
|
||||
for (UInt32 i = 0; i < numSymbols; i++)
|
||||
{
|
||||
// index is 1-based. So 32-bit numSymbols field works as item[0]
|
||||
UInt32 index = GetUi16(p + indexStart + i * 2);
|
||||
if (index == 0 || index > numMembers)
|
||||
return S_FALSE;
|
||||
UInt32 offset = GetUi32(p + index * 4);
|
||||
RINOK(AddFunc(offset, p, size, pos));
|
||||
}
|
||||
_type = kType_Lib;
|
||||
}
|
||||
// size can be 2-byte aligned in linux files
|
||||
if (pos != size && pos + (pos & 1) != size)
|
||||
return S_FALSE;
|
||||
item.TextFileIndex = _numLibFiles++;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
{
|
||||
Close();
|
||||
|
||||
UInt64 fileSize = 0;
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
|
||||
CInArchive arc;
|
||||
RINOK(arc.Open(stream));
|
||||
|
||||
if (callback)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &fileSize));
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &arc.Position));
|
||||
}
|
||||
|
||||
CItem item;
|
||||
for (;;)
|
||||
{
|
||||
bool filled;
|
||||
RINOK(arc.GetNextItem(item, filled));
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
arc.SkipData(item.Size);
|
||||
if (callback && (_items.Size() & 0xFF) == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &arc.Position));
|
||||
}
|
||||
}
|
||||
|
||||
if (_items.IsEmpty())
|
||||
{
|
||||
// we don't need false empty archives (8-bytes signature only)
|
||||
if (arc.Position != fileSize)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
_isArc = true;
|
||||
|
||||
_subType = arc.SubType;
|
||||
|
||||
if (ParseLongNames(stream) != S_OK)
|
||||
UpdateErrorMessage("Long file names parsing error");
|
||||
if (_longNames_FileIndex >= 0)
|
||||
_items.Delete(_longNames_FileIndex);
|
||||
|
||||
if (!_items.IsEmpty() && _items[0].Name == "debian-binary")
|
||||
{
|
||||
_type = kType_Deb;
|
||||
_items.DeleteFrontal(1);
|
||||
for (unsigned i = 0; i < _items.Size(); i++)
|
||||
if (_items[i].Name.IsPrefixedBy("data.tar."))
|
||||
if (_mainSubfile < 0)
|
||||
_mainSubfile = i;
|
||||
else
|
||||
{
|
||||
_mainSubfile = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeDuplicateNames();
|
||||
bool error = false;
|
||||
for (unsigned li = 0; li < 2 && li < _items.Size(); li++)
|
||||
if (ParseLibSymbols(stream, li) != S_OK)
|
||||
error = true;
|
||||
if (error)
|
||||
UpdateErrorMessage("Library symbols information error");
|
||||
}
|
||||
|
||||
_stream = stream;
|
||||
_phySize = arc.Position;
|
||||
|
||||
/*
|
||||
if (fileSize < _phySize)
|
||||
UpdateErrorMessage("Unexpected end of archive");
|
||||
*/
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_isArc = false;
|
||||
_phySize = 0;
|
||||
|
||||
_errorMessage.Empty();
|
||||
_stream.Release();
|
||||
_items.Clear();
|
||||
|
||||
_type = kType_Ar;
|
||||
_subType = kSubType_None;
|
||||
_mainSubfile = -1;
|
||||
_longNames_FileIndex = -1;
|
||||
|
||||
_numLibFiles = 0;
|
||||
_libFiles[0].Empty();
|
||||
_libFiles[1].Empty();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: prop = _phySize; break;
|
||||
case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
|
||||
case kpidExtension: prop = k_TypeExtionsions[(unsigned)_type]; break;
|
||||
case kpidShortComment:
|
||||
case kpidSubType:
|
||||
{
|
||||
AString s = k_TypeExtionsions[(unsigned)_type];
|
||||
if (_subType == kSubType_BSD)
|
||||
s += ":BSD";
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
case kpidWarning: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
|
||||
case kpidIsNotArcType: if (_type != kType_Deb) prop = true; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
const CItem &item = _items[index];
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath:
|
||||
if (item.TextFileIndex >= 0)
|
||||
prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt";
|
||||
else
|
||||
prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP));
|
||||
break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
if (item.TextFileIndex >= 0)
|
||||
prop = (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len();
|
||||
else
|
||||
prop = item.Size;
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
if (item.MTime != 0)
|
||||
{
|
||||
FILETIME fileTime;
|
||||
NTime::UnixTimeToFileTime(item.MTime, fileTime);
|
||||
prop = fileTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidUser: if (item.User != 0) prop = item.User; break;
|
||||
case kpidGroup: if (item.Group != 0) prop = item.Group; break;
|
||||
case kpidPosixAttrib:
|
||||
if (item.TextFileIndex < 0)
|
||||
prop = item.Mode;
|
||||
break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
const CItem &item = _items[allFilesMode ? i : indices[i]];
|
||||
totalSize +=
|
||||
(item.TextFileIndex >= 0) ?
|
||||
(UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size;
|
||||
}
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
currentTotalSize += (item.TextFileIndex >= 0) ?
|
||||
(UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size;
|
||||
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (testMode)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
bool isOk = true;
|
||||
if (item.TextFileIndex >= 0)
|
||||
{
|
||||
const AString &f = _libFiles[(unsigned)item.TextFileIndex];
|
||||
if (realOutStream)
|
||||
RINOK(WriteStream(realOutStream, f, f.Len()));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
isOk = (copyCoderSpec->TotalSize == item.Size);
|
||||
}
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(isOk ?
|
||||
NExtract::NOperationResult::kOK:
|
||||
NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CItem &item = _items[index];
|
||||
if (item.TextFileIndex >= 0)
|
||||
{
|
||||
const AString &f = _libFiles[(unsigned)item.TextFileIndex];
|
||||
Create_BufInStream_WithNewBuffer((const void *)(const char *)f, f.Len(), stream);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"Ar", "ar a deb lib", 0, 0xEC,
|
||||
kSignature,
|
||||
0,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
12
CPP/7zip/Archive/Archive.def
Normal file
12
CPP/7zip/Archive/Archive.def
Normal file
@@ -0,0 +1,12 @@
|
||||
EXPORTS
|
||||
CreateObject PRIVATE
|
||||
|
||||
GetHandlerProperty PRIVATE
|
||||
GetNumberOfFormats PRIVATE
|
||||
GetHandlerProperty2 PRIVATE
|
||||
GetIsArc PRIVATE
|
||||
|
||||
SetCodecs PRIVATE
|
||||
|
||||
SetLargePageMode PRIVATE
|
||||
SetCaseSensitive PRIVATE
|
||||
19
CPP/7zip/Archive/Archive2.def
Normal file
19
CPP/7zip/Archive/Archive2.def
Normal file
@@ -0,0 +1,19 @@
|
||||
EXPORTS
|
||||
CreateObject PRIVATE
|
||||
|
||||
GetHandlerProperty PRIVATE
|
||||
GetNumberOfFormats PRIVATE
|
||||
GetHandlerProperty2 PRIVATE
|
||||
GetIsArc PRIVATE
|
||||
|
||||
GetNumberOfMethods PRIVATE
|
||||
GetMethodProperty PRIVATE
|
||||
CreateDecoder PRIVATE
|
||||
CreateEncoder PRIVATE
|
||||
|
||||
GetHashers PRIVATE
|
||||
|
||||
SetCodecs PRIVATE
|
||||
|
||||
SetLargePageMode PRIVATE
|
||||
SetCaseSensitive PRIVATE
|
||||
151
CPP/7zip/Archive/ArchiveExports.cpp
Normal file
151
CPP/7zip/Archive/ArchiveExports.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// ArchiveExports.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/7zVersion.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../Common/RegisterArc.h"
|
||||
|
||||
static const unsigned kNumArcsMax = 64;
|
||||
static unsigned g_NumArcs = 0;
|
||||
static unsigned g_DefaultArcIndex = 0;
|
||||
static const CArcInfo *g_Arcs[kNumArcsMax];
|
||||
|
||||
void RegisterArc(const CArcInfo *arcInfo) throw()
|
||||
{
|
||||
if (g_NumArcs < kNumArcsMax)
|
||||
{
|
||||
const char *p = arcInfo->Name;
|
||||
if (p[0] == '7' && p[1] == 'z' && p[2] == 0)
|
||||
g_DefaultArcIndex = g_NumArcs;
|
||||
g_Arcs[g_NumArcs++] = arcInfo;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_GUID(CLSID_CArchiveHandler,
|
||||
k_7zip_GUID_Data1,
|
||||
k_7zip_GUID_Data2,
|
||||
k_7zip_GUID_Data3_Common,
|
||||
0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
|
||||
|
||||
#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
|
||||
|
||||
static inline HRESULT SetPropStrFromBin(const char *s, unsigned size, PROPVARIANT *value)
|
||||
{
|
||||
if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
|
||||
value->vt = VT_BSTR;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
|
||||
{
|
||||
return SetPropStrFromBin((const char *)&guid, sizeof(guid), value);
|
||||
}
|
||||
|
||||
int FindFormatCalssId(const GUID *clsid)
|
||||
{
|
||||
GUID cls = *clsid;
|
||||
CLS_ARC_ID_ITEM(cls) = 0;
|
||||
if (cls != CLSID_CArchiveHandler)
|
||||
return -1;
|
||||
Byte id = CLS_ARC_ID_ITEM(*clsid);
|
||||
for (unsigned i = 0; i < g_NumArcs; i++)
|
||||
if (g_Arcs[i]->Id == id)
|
||||
return (int)i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
{
|
||||
int needIn = (*iid == IID_IInArchive);
|
||||
int needOut = (*iid == IID_IOutArchive);
|
||||
if (!needIn && !needOut)
|
||||
return E_NOINTERFACE;
|
||||
int formatIndex = FindFormatCalssId(clsid);
|
||||
if (formatIndex < 0)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
|
||||
const CArcInfo &arc = *g_Arcs[formatIndex];
|
||||
if (needIn)
|
||||
{
|
||||
*outObject = arc.CreateInArchive();
|
||||
((IInArchive *)*outObject)->AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!arc.CreateOutArchive)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
*outObject = arc.CreateOutArchive();
|
||||
((IOutArchive *)*outObject)->AddRef();
|
||||
}
|
||||
}
|
||||
COM_TRY_END
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::PropVariant_Clear(value);
|
||||
if (formatIndex >= g_NumArcs)
|
||||
return E_INVALIDARG;
|
||||
const CArcInfo &arc = *g_Arcs[formatIndex];
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case NArchive::NHandlerPropID::kName: prop = arc.Name; break;
|
||||
case NArchive::NHandlerPropID::kClassID:
|
||||
{
|
||||
GUID clsId = CLSID_CArchiveHandler;
|
||||
CLS_ARC_ID_ITEM(clsId) = arc.Id;
|
||||
return SetPropGUID(clsId, value);
|
||||
}
|
||||
case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break;
|
||||
case NArchive::NHandlerPropID::kAddExtension: if (arc.AddExt) prop = arc.AddExt; break;
|
||||
case NArchive::NHandlerPropID::kUpdate: prop = (bool)(arc.CreateOutArchive != NULL); break;
|
||||
case NArchive::NHandlerPropID::kKeepName: prop = ((arc.Flags & NArcInfoFlags::kKeepName) != 0); break;
|
||||
case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break;
|
||||
case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break;
|
||||
case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break;
|
||||
case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break;
|
||||
// case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break;
|
||||
|
||||
case NArchive::NHandlerPropID::kSignature:
|
||||
if (arc.SignatureSize != 0 && !arc.IsMultiSignature())
|
||||
return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value);
|
||||
break;
|
||||
case NArchive::NHandlerPropID::kMultiSignature:
|
||||
if (arc.SignatureSize != 0 && arc.IsMultiSignature())
|
||||
return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value);
|
||||
break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
return GetHandlerProperty2(g_DefaultArcIndex, propID, value);
|
||||
}
|
||||
|
||||
STDAPI GetNumberOfFormats(UINT32 *numFormats)
|
||||
{
|
||||
*numFormats = g_NumArcs;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc)
|
||||
{
|
||||
*isArc = NULL;
|
||||
if (formatIndex >= g_NumArcs)
|
||||
return E_INVALIDARG;
|
||||
*isArc = g_Arcs[formatIndex]->IsArc;
|
||||
return S_OK;
|
||||
}
|
||||
977
CPP/7zip/Archive/ArjHandler.cpp
Normal file
977
CPP/7zip/Archive/ArjHandler.cpp
Normal file
@@ -0,0 +1,977 @@
|
||||
// ArjHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/IntToString.h"
|
||||
#include "../../Common/StringConvert.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
#include "../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
#include "../Compress/LzhDecoder.h"
|
||||
|
||||
#include "Common/ItemNameUtils.h"
|
||||
#include "Common/OutStreamWithCRC.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NArj {
|
||||
namespace NDecoder {
|
||||
|
||||
static const unsigned kMatchMinLen = 3;
|
||||
|
||||
static const UInt32 kWindowSize = 1 << 15; // must be >= (1 << 14)
|
||||
|
||||
class CCoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow _outWindow;
|
||||
NBitm::CDecoder<CInBuffer> _inBitStream;
|
||||
|
||||
class CCoderReleaser
|
||||
{
|
||||
CCoder *_coder;
|
||||
public:
|
||||
CCoderReleaser(CCoder *coder): _coder(coder) {}
|
||||
void Disable() { _coder = NULL; }
|
||||
~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); }
|
||||
};
|
||||
friend class CCoderReleaser;
|
||||
|
||||
HRESULT CodeReal(UInt64 outSize, ICompressProgressInfo *progress);
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
bool FinishMode;
|
||||
CCoder(): FinishMode(false) {}
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
|
||||
};
|
||||
|
||||
HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
|
||||
{
|
||||
const UInt32 kStep = 1 << 20;
|
||||
UInt64 next = 0;
|
||||
if (rem > kStep && progress)
|
||||
next = rem - kStep;
|
||||
|
||||
while (rem != 0)
|
||||
{
|
||||
if (rem <= next)
|
||||
{
|
||||
if (_inBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 packSize = _inBitStream.GetProcessedSize();
|
||||
UInt64 pos = _outWindow.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &pos));
|
||||
next = 0;
|
||||
if (rem > kStep)
|
||||
next = rem - kStep;
|
||||
}
|
||||
|
||||
UInt32 len;
|
||||
|
||||
{
|
||||
const unsigned kNumBits = 7 + 7;
|
||||
UInt32 val = _inBitStream.GetValue(kNumBits);
|
||||
|
||||
if ((val & (1 << (kNumBits - 1))) == 0)
|
||||
{
|
||||
_outWindow.PutByte((Byte)(val >> 5));
|
||||
_inBitStream.MovePos(1 + 8);
|
||||
rem--;
|
||||
continue;
|
||||
}
|
||||
|
||||
UInt32 mask = 1 << (kNumBits - 2);
|
||||
unsigned w;
|
||||
|
||||
for (w = 1; w < 7; w++, mask >>= 1)
|
||||
if ((val & mask) == 0)
|
||||
break;
|
||||
|
||||
unsigned readBits = (w != 7 ? 1 : 0);
|
||||
readBits += w + w;
|
||||
len = (1 << w) - 1 + kMatchMinLen - 1 +
|
||||
(((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
|
||||
_inBitStream.MovePos(readBits);
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned kNumBits = 4 + 13;
|
||||
UInt32 val = _inBitStream.GetValue(kNumBits);
|
||||
|
||||
unsigned readBits = 1;
|
||||
unsigned w;
|
||||
|
||||
if ((val & ((UInt32)1 << 16)) == 0) w = 9;
|
||||
else if ((val & ((UInt32)1 << 15)) == 0) w = 10;
|
||||
else if ((val & ((UInt32)1 << 14)) == 0) w = 11;
|
||||
else if ((val & ((UInt32)1 << 13)) == 0) w = 12;
|
||||
else { w = 13; readBits = 0; }
|
||||
|
||||
readBits += w + w - 9;
|
||||
|
||||
UInt32 dist = ((UInt32)1 << w) - (1 << 9) +
|
||||
(((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
|
||||
_inBitStream.MovePos(readBits);
|
||||
|
||||
if (len > rem)
|
||||
len = (UInt32)rem;
|
||||
|
||||
if (!_outWindow.CopyBlock(dist, len))
|
||||
return S_FALSE;
|
||||
rem -= len;
|
||||
}
|
||||
}
|
||||
|
||||
if (FinishMode)
|
||||
{
|
||||
if (_inBitStream.ReadAlignBits() != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (_inBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!outSize)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_outWindow.Create(kWindowSize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_inBitStream.Create(1 << 17))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_outWindow.SetStream(outStream);
|
||||
_outWindow.Init(false);
|
||||
_inBitStream.SetStream(inStream);
|
||||
_inBitStream.Init();
|
||||
|
||||
CCoderReleaser coderReleaser(this);
|
||||
HRESULT res;
|
||||
{
|
||||
res = CodeReal(*outSize, progress);
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
coderReleaser.Disable();
|
||||
return _outWindow.Flush();
|
||||
}
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NArj {
|
||||
|
||||
static const unsigned kBlockSizeMin = 30;
|
||||
static const unsigned kBlockSizeMax = 2600;
|
||||
|
||||
static const Byte kSig0 = 0x60;
|
||||
static const Byte kSig1 = 0xEA;
|
||||
|
||||
namespace NCompressionMethod
|
||||
{
|
||||
enum
|
||||
{
|
||||
kStored = 0,
|
||||
kCompressed1a = 1,
|
||||
kCompressed1b = 2,
|
||||
kCompressed1c = 3,
|
||||
kCompressed2 = 4,
|
||||
kNoDataNoCRC = 8,
|
||||
kNoData = 9
|
||||
};
|
||||
}
|
||||
|
||||
namespace NFileType
|
||||
{
|
||||
enum
|
||||
{
|
||||
kBinary = 0,
|
||||
k7BitText,
|
||||
kArchiveHeader,
|
||||
kDirectory,
|
||||
kVolumeLablel,
|
||||
kChapterLabel
|
||||
};
|
||||
}
|
||||
|
||||
namespace NFlags
|
||||
{
|
||||
const Byte kGarbled = 1 << 0;
|
||||
const Byte kAnsiPage = 1 << 1; // or (OLD_SECURED_FLAG) obsolete
|
||||
const Byte kVolume = 1 << 2;
|
||||
const Byte kExtFile = 1 << 3;
|
||||
const Byte kPathSym = 1 << 4;
|
||||
const Byte kBackup = 1 << 5; // obsolete
|
||||
const Byte kSecured = 1 << 6;
|
||||
const Byte kDualName = 1 << 7;
|
||||
}
|
||||
|
||||
namespace NHostOS
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kMSDOS = 0, // MS-DOS, OS/2, Win32, pkarj 2.50 (FAT / VFAT / FAT32)
|
||||
kPRIMOS,
|
||||
kUnix,
|
||||
kAMIGA,
|
||||
kMac,
|
||||
kOS_2,
|
||||
kAPPLE_GS,
|
||||
kAtari_ST,
|
||||
kNext,
|
||||
kVAX_VMS,
|
||||
kWIN95
|
||||
};
|
||||
}
|
||||
|
||||
static const char * const kHostOS[] =
|
||||
{
|
||||
"MSDOS"
|
||||
, "PRIMOS"
|
||||
, "UNIX"
|
||||
, "AMIGA"
|
||||
, "MAC"
|
||||
, "OS/2"
|
||||
, "APPLE GS"
|
||||
, "ATARI ST"
|
||||
, "NEXT"
|
||||
, "VAX VMS"
|
||||
, "WIN95"
|
||||
};
|
||||
|
||||
struct CArcHeader
|
||||
{
|
||||
// Byte ArchiverVersion;
|
||||
// Byte ExtractVersion;
|
||||
Byte HostOS;
|
||||
// Byte Flags;
|
||||
// Byte SecuryVersion;
|
||||
// Byte FileType;
|
||||
// Byte Reserved;
|
||||
UInt32 CTime;
|
||||
UInt32 MTime;
|
||||
UInt32 ArchiveSize;
|
||||
// UInt32 SecurPos;
|
||||
// UInt16 FilespecPosInFilename;
|
||||
UInt16 SecurSize;
|
||||
// Byte EncryptionVersion;
|
||||
// Byte LastChapter;
|
||||
AString Name;
|
||||
AString Comment;
|
||||
|
||||
HRESULT Parse(const Byte *p, unsigned size);
|
||||
};
|
||||
|
||||
API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size)
|
||||
{
|
||||
if (size < kBlockSizeMin + 4)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
if (p[0] != kSig0 || p[1] != kSig1)
|
||||
return k_IsArc_Res_NO;
|
||||
UInt32 blockSize = Get16(p + 2);
|
||||
if (blockSize < kBlockSizeMin ||
|
||||
blockSize > kBlockSizeMax)
|
||||
return k_IsArc_Res_NO;
|
||||
|
||||
p += 4;
|
||||
size -= 4;
|
||||
|
||||
Byte headerSize = p[0];
|
||||
if (headerSize < kBlockSizeMin ||
|
||||
headerSize > blockSize ||
|
||||
p[6] != NFileType::kArchiveHeader ||
|
||||
p[28] > 8) // EncryptionVersion
|
||||
return k_IsArc_Res_NO;
|
||||
|
||||
if (blockSize + 4 <= size)
|
||||
if (Get32(p + blockSize) != CrcCalc(p, blockSize))
|
||||
return k_IsArc_Res_NO;
|
||||
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ReadString(const Byte *p, unsigned &size, AString &res)
|
||||
{
|
||||
unsigned num = size;
|
||||
for (unsigned i = 0; i < num;)
|
||||
{
|
||||
if (p[i++] == 0)
|
||||
{
|
||||
size = i;
|
||||
res = (const char *)p;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CArcHeader::Parse(const Byte *p, unsigned size)
|
||||
{
|
||||
Byte headerSize = p[0];
|
||||
if (headerSize < kBlockSizeMin || headerSize > size)
|
||||
return S_FALSE;
|
||||
// ArchiverVersion = p[1];
|
||||
// ExtractVersion = p[2];
|
||||
HostOS = p[3];
|
||||
// Flags = p[4];
|
||||
// SecuryVersion = p[5];
|
||||
if (p[6] != NFileType::kArchiveHeader)
|
||||
return S_FALSE;
|
||||
// Reserved = p[7];
|
||||
CTime = Get32(p + 8);
|
||||
MTime = Get32(p + 12);
|
||||
ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives)
|
||||
// SecurPos = Get32(p + 20);
|
||||
// UInt16 filespecPositionInFilename = Get16(p + 24);
|
||||
SecurSize = Get16(p + 26);
|
||||
// EncryptionVersion = p[28];
|
||||
// LastChapter = p[29];
|
||||
unsigned pos = headerSize;
|
||||
unsigned size1 = size - pos;
|
||||
RINOK(ReadString(p + pos, size1, Name));
|
||||
pos += size1;
|
||||
size1 = size - pos;
|
||||
RINOK(ReadString(p + pos, size1, Comment));
|
||||
pos += size1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
AString Comment;
|
||||
|
||||
UInt32 MTime;
|
||||
UInt32 PackSize;
|
||||
UInt32 Size;
|
||||
UInt32 FileCRC;
|
||||
UInt32 SplitPos;
|
||||
|
||||
Byte Version;
|
||||
Byte ExtractVersion;
|
||||
Byte HostOS;
|
||||
Byte Flags;
|
||||
Byte Method;
|
||||
Byte FileType;
|
||||
|
||||
// UInt16 FilespecPosInFilename;
|
||||
UInt16 FileAccessMode;
|
||||
// Byte FirstChapter;
|
||||
// Byte LastChapter;
|
||||
|
||||
UInt64 DataPosition;
|
||||
|
||||
bool IsEncrypted() const { return (Flags & NFlags::kGarbled) != 0; }
|
||||
bool IsDir() const { return (FileType == NFileType::kDirectory); }
|
||||
bool IsSplitAfter() const { return (Flags & NFlags::kVolume) != 0; }
|
||||
bool IsSplitBefore() const { return (Flags & NFlags::kExtFile) != 0; }
|
||||
UInt32 GetWinAttrib() const
|
||||
{
|
||||
UInt32 atrrib = 0;
|
||||
switch (HostOS)
|
||||
{
|
||||
case NHostOS::kMSDOS:
|
||||
case NHostOS::kWIN95:
|
||||
atrrib = FileAccessMode;
|
||||
break;
|
||||
}
|
||||
if (IsDir())
|
||||
atrrib |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
return atrrib;
|
||||
}
|
||||
|
||||
HRESULT Parse(const Byte *p, unsigned size);
|
||||
};
|
||||
|
||||
HRESULT CItem::Parse(const Byte *p, unsigned size)
|
||||
{
|
||||
Byte headerSize = p[0];
|
||||
if (headerSize < kBlockSizeMin || headerSize > size)
|
||||
return S_FALSE;
|
||||
Version = p[1];
|
||||
ExtractVersion = p[2];
|
||||
HostOS = p[3];
|
||||
Flags = p[4];
|
||||
Method = p[5];
|
||||
FileType = p[6];
|
||||
// Reserved = p[7];
|
||||
MTime = Get32(p + 8);
|
||||
PackSize = Get32(p + 12);
|
||||
Size = Get32(p + 16);
|
||||
FileCRC = Get32(p + 20);
|
||||
// FilespecPosInFilename = Get16(p + 24);
|
||||
FileAccessMode = Get16(p + 26);
|
||||
// FirstChapter = p[28];
|
||||
// FirstChapter = p[29];
|
||||
|
||||
SplitPos = 0;
|
||||
if (IsSplitBefore() && headerSize >= 34)
|
||||
SplitPos = Get32(p + 30);
|
||||
|
||||
unsigned pos = headerSize;
|
||||
unsigned size1 = size - pos;
|
||||
RINOK(ReadString(p + pos, size1, Name));
|
||||
pos += size1;
|
||||
size1 = size - pos;
|
||||
RINOK(ReadString(p + pos, size1, Comment));
|
||||
pos += size1;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
enum EErrorType
|
||||
{
|
||||
k_ErrorType_OK,
|
||||
k_ErrorType_Corrupted,
|
||||
k_ErrorType_UnexpectedEnd,
|
||||
};
|
||||
|
||||
class CArc
|
||||
{
|
||||
public:
|
||||
UInt64 Processed;
|
||||
EErrorType Error;
|
||||
bool IsArc;
|
||||
IInStream *Stream;
|
||||
IArchiveOpenCallback *Callback;
|
||||
UInt64 NumFiles;
|
||||
CArcHeader Header;
|
||||
|
||||
HRESULT Open();
|
||||
HRESULT GetNextItem(CItem &item, bool &filled);
|
||||
void Close()
|
||||
{
|
||||
IsArc = false;
|
||||
Error = k_ErrorType_OK;
|
||||
}
|
||||
private:
|
||||
UInt32 _blockSize;
|
||||
Byte _block[kBlockSizeMax + 4];
|
||||
|
||||
HRESULT ReadBlock(bool &filled, bool readSignature);
|
||||
HRESULT SkipExtendedHeaders();
|
||||
HRESULT Read(void *data, size_t *size);
|
||||
};
|
||||
|
||||
HRESULT CArc::Read(void *data, size_t *size)
|
||||
{
|
||||
HRESULT res = ReadStream(Stream, data, size);
|
||||
Processed += *size;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define READ_STREAM(_dest_, _size_) \
|
||||
{ size_t _processed_ = (_size_); RINOK(Read(_dest_, &_processed_)); \
|
||||
if (_processed_ != (_size_)) { Error = k_ErrorType_UnexpectedEnd; return S_OK; } }
|
||||
|
||||
HRESULT CArc::ReadBlock(bool &filled, bool readSignature)
|
||||
{
|
||||
Error = k_ErrorType_OK;
|
||||
filled = false;
|
||||
Byte buf[4];
|
||||
unsigned signSize = readSignature ? 2 : 0;
|
||||
READ_STREAM(buf, signSize + 2)
|
||||
if (readSignature)
|
||||
if (buf[0] != kSig0 || buf[1] != kSig1)
|
||||
{
|
||||
Error = k_ErrorType_Corrupted;
|
||||
return S_OK;
|
||||
}
|
||||
_blockSize = Get16(buf + signSize);
|
||||
if (_blockSize == 0) // end of archive
|
||||
return S_OK;
|
||||
if (_blockSize < kBlockSizeMin ||
|
||||
_blockSize > kBlockSizeMax)
|
||||
{
|
||||
Error = k_ErrorType_Corrupted;
|
||||
return S_OK;
|
||||
}
|
||||
READ_STREAM(_block, _blockSize + 4);
|
||||
if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
|
||||
{
|
||||
Error = k_ErrorType_Corrupted;
|
||||
return S_OK;
|
||||
}
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CArc::SkipExtendedHeaders()
|
||||
{
|
||||
for (UInt32 i = 0;; i++)
|
||||
{
|
||||
bool filled;
|
||||
RINOK(ReadBlock(filled, false));
|
||||
if (!filled)
|
||||
return S_OK;
|
||||
if (Callback && (i & 0xFF) == 0)
|
||||
RINOK(Callback->SetCompleted(&NumFiles, &Processed));
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CArc::Open()
|
||||
{
|
||||
bool filled;
|
||||
RINOK(ReadBlock(filled, true));
|
||||
if (!filled)
|
||||
return S_FALSE;
|
||||
RINOK(Header.Parse(_block, _blockSize));
|
||||
IsArc = true;
|
||||
return SkipExtendedHeaders();
|
||||
}
|
||||
|
||||
HRESULT CArc::GetNextItem(CItem &item, bool &filled)
|
||||
{
|
||||
RINOK(ReadBlock(filled, true));
|
||||
if (!filled)
|
||||
return S_OK;
|
||||
filled = false;
|
||||
if (item.Parse(_block, _blockSize) != S_OK)
|
||||
{
|
||||
Error = k_ErrorType_Corrupted;
|
||||
return S_OK;
|
||||
}
|
||||
/*
|
||||
UInt32 extraData;
|
||||
if ((header.Flags & NFlags::kExtFile) != 0)
|
||||
extraData = GetUi32(_block + pos);
|
||||
*/
|
||||
|
||||
RINOK(SkipExtendedHeaders());
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CItem> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
UInt64 _phySize;
|
||||
CArc _arc;
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidName,
|
||||
kpidCTime,
|
||||
kpidMTime,
|
||||
kpidHostOS,
|
||||
kpidComment
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidIsDir,
|
||||
kpidSize,
|
||||
kpidPosition,
|
||||
kpidPackSize,
|
||||
kpidMTime,
|
||||
kpidAttrib,
|
||||
kpidEncrypted,
|
||||
kpidCRC,
|
||||
kpidMethod,
|
||||
kpidHostOS,
|
||||
kpidComment
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
|
||||
{
|
||||
if (dosTime == 0)
|
||||
return;
|
||||
FILETIME localFileTime, utc;
|
||||
if (NTime::DosTimeToFileTime(dosTime, localFileTime))
|
||||
{
|
||||
if (!LocalFileTimeToFileTime(&localFileTime, &utc))
|
||||
utc.dwHighDateTime = utc.dwLowDateTime = 0;
|
||||
}
|
||||
else
|
||||
utc.dwHighDateTime = utc.dwLowDateTime = 0;
|
||||
prop = utc;
|
||||
}
|
||||
|
||||
static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)
|
||||
{
|
||||
char temp[16];
|
||||
const char *s = NULL;
|
||||
if (hostOS < ARRAY_SIZE(kHostOS))
|
||||
s = kHostOS[hostOS];
|
||||
else
|
||||
{
|
||||
ConvertUInt32ToString(hostOS, temp);
|
||||
s = temp;
|
||||
}
|
||||
prop = s;
|
||||
}
|
||||
|
||||
static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop)
|
||||
{
|
||||
if (!s.IsEmpty())
|
||||
prop = MultiByteToUnicodeString(s, CP_OEMCP);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: prop = _phySize; break;
|
||||
case kpidName: SetUnicodeString(_arc.Header.Name, prop); break;
|
||||
case kpidCTime: SetTime(_arc.Header.CTime, prop); break;
|
||||
case kpidMTime: SetTime(_arc.Header.MTime, prop); break;
|
||||
case kpidHostOS: SetHostOS(_arc.Header.HostOS, prop); break;
|
||||
case kpidComment: SetUnicodeString(_arc.Header.Comment, prop); break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_arc.IsArc) v |= kpv_ErrorFlags_IsNotArc;
|
||||
switch (_arc.Error)
|
||||
{
|
||||
case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
|
||||
case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break;
|
||||
}
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
const CItem &item = _items[index];
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize: prop = item.Size; break;
|
||||
case kpidPackSize: prop = item.PackSize; break;
|
||||
case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break;
|
||||
case kpidAttrib: prop = item.GetWinAttrib(); break;
|
||||
case kpidEncrypted: prop = item.IsEncrypted(); break;
|
||||
case kpidCRC: prop = item.FileCRC; break;
|
||||
case kpidMethod: prop = item.Method; break;
|
||||
case kpidHostOS: SetHostOS(item.HostOS, prop); break;
|
||||
case kpidMTime: SetTime(item.MTime, prop); break;
|
||||
case kpidComment: SetUnicodeString(item.Comment, prop); break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
|
||||
{
|
||||
Close();
|
||||
|
||||
UInt64 endPos = 0;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
|
||||
_arc.Stream = inStream;
|
||||
_arc.Callback = callback;
|
||||
_arc.NumFiles = 0;
|
||||
_arc.Processed = 0;
|
||||
|
||||
RINOK(_arc.Open());
|
||||
|
||||
_phySize = _arc.Processed;
|
||||
if (_arc.Header.ArchiveSize != 0)
|
||||
_phySize = (UInt64)_arc.Header.ArchiveSize + _arc.Header.SecurSize;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItem item;
|
||||
bool filled;
|
||||
|
||||
_arc.Error = k_ErrorType_OK;
|
||||
RINOK(_arc.GetNextItem(item, filled));
|
||||
|
||||
if (_arc.Error != k_ErrorType_OK)
|
||||
break;
|
||||
|
||||
if (!filled)
|
||||
{
|
||||
if (_arc.Error == k_ErrorType_OK)
|
||||
if (_arc.Header.ArchiveSize == 0)
|
||||
_phySize = _arc.Processed;
|
||||
break;
|
||||
}
|
||||
item.DataPosition = _arc.Processed;
|
||||
_items.Add(item);
|
||||
|
||||
UInt64 pos = item.DataPosition + item.PackSize;
|
||||
if (_arc.Header.ArchiveSize == 0)
|
||||
_phySize = pos;
|
||||
if (pos > endPos)
|
||||
{
|
||||
_arc.Error = k_ErrorType_UnexpectedEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL));
|
||||
_arc.NumFiles = _items.Size();
|
||||
_arc.Processed = pos;
|
||||
|
||||
if (callback && (_items.Size() & 0xFF) == 0)
|
||||
{
|
||||
RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
HRESULT res;
|
||||
{
|
||||
res = Open2(inStream, callback);
|
||||
if (res == S_OK)
|
||||
{
|
||||
_stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_arc.Close();
|
||||
_phySize = 0;
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
UInt64 totalUnpacked = 0, totalPacked = 0;
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
const CItem &item = _items[allFilesMode ? i : indices[i]];
|
||||
totalUnpacked += item.Size;
|
||||
// totalPacked += item.PackSize;
|
||||
}
|
||||
extractCallback->SetTotal(totalUnpacked);
|
||||
|
||||
totalUnpacked = totalPacked = 0;
|
||||
UInt64 curUnpacked, curPacked;
|
||||
|
||||
NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
|
||||
CMyComPtr<ICompressCoder> lzhDecoder;
|
||||
|
||||
NCompress::NArj::NDecoder::CCoder *arjDecoderSpec = NULL;
|
||||
CMyComPtr<ICompressCoder> arjDecoder;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
|
||||
inStreamSpec->SetStream(_stream);
|
||||
|
||||
for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
|
||||
{
|
||||
lps->InSize = totalPacked;
|
||||
lps->OutSize = totalUnpacked;
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
curUnpacked = curPacked = 0;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
|
||||
if (item.IsDir())
|
||||
{
|
||||
// if (!testMode)
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
curUnpacked = item.Size;
|
||||
curPacked = item.PackSize;
|
||||
|
||||
{
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
realOutStream.Release();
|
||||
outStreamSpec->Init();
|
||||
|
||||
inStreamSpec->Init(item.PackSize);
|
||||
|
||||
UInt64 pos;
|
||||
_stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
|
||||
|
||||
HRESULT result = S_OK;
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
|
||||
if (item.IsEncrypted())
|
||||
opRes = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
else
|
||||
{
|
||||
switch (item.Method)
|
||||
{
|
||||
case NCompressionMethod::kStored:
|
||||
{
|
||||
result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
|
||||
if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
case NCompressionMethod::kCompressed1a:
|
||||
case NCompressionMethod::kCompressed1b:
|
||||
case NCompressionMethod::kCompressed1c:
|
||||
{
|
||||
if (!lzhDecoder)
|
||||
{
|
||||
lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
|
||||
lzhDecoder = lzhDecoderSpec;
|
||||
}
|
||||
lzhDecoderSpec->FinishMode = true;
|
||||
const UInt32 kHistorySize = 26624;
|
||||
lzhDecoderSpec->SetDictSize(kHistorySize);
|
||||
result = lzhDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
|
||||
if (result == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize)
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
case NCompressionMethod::kCompressed2:
|
||||
{
|
||||
if (!arjDecoder)
|
||||
{
|
||||
arjDecoderSpec = new NCompress::NArj::NDecoder::CCoder;
|
||||
arjDecoder = arjDecoderSpec;
|
||||
}
|
||||
arjDecoderSpec->FinishMode = true;
|
||||
result = arjDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
|
||||
if (result == S_OK && arjDecoderSpec->GetInputProcessedSize() != item.PackSize)
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
opRes = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (opRes == NExtract::NOperationResult::kOK)
|
||||
{
|
||||
if (result == S_FALSE)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
else
|
||||
{
|
||||
RINOK(result);
|
||||
opRes = (outStreamSpec->GetCRC() == item.FileCRC) ?
|
||||
NExtract::NOperationResult::kOK:
|
||||
NExtract::NOperationResult::kCRCError;
|
||||
}
|
||||
}
|
||||
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(opRes));
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static const Byte k_Signature[] = { kSig0, kSig1 };
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"Arj", "arj", 0, 4,
|
||||
k_Signature,
|
||||
0,
|
||||
0,
|
||||
IsArc_Arj)
|
||||
|
||||
}}
|
||||
443
CPP/7zip/Archive/Bz2Handler.cpp
Normal file
443
CPP/7zip/Archive/Bz2Handler.cpp
Normal file
@@ -0,0 +1,443 @@
|
||||
// Bz2Handler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/BZip2Decoder.h"
|
||||
#include "../Compress/BZip2Encoder.h"
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/DummyOutStream.h"
|
||||
#include "Common/HandlerOut.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBz2 {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
|
||||
bool _isArc;
|
||||
bool _needSeekToStart;
|
||||
bool _dataAfterEnd;
|
||||
bool _needMoreInput;
|
||||
|
||||
bool _packSize_Defined;
|
||||
bool _unpackSize_Defined;
|
||||
bool _numStreams_Defined;
|
||||
bool _numBlocks_Defined;
|
||||
|
||||
UInt64 _packSize;
|
||||
UInt64 _unpackSize;
|
||||
UInt64 _numStreams;
|
||||
UInt64 _numBlocks;
|
||||
|
||||
CSingleMethodProps _props;
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(
|
||||
IInArchive,
|
||||
IArchiveOpenSeq,
|
||||
IOutArchive,
|
||||
ISetProperties)
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
|
||||
CHandler() { }
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidSize,
|
||||
kpidPackSize
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidNumStreams,
|
||||
kpidNumBlocks
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
|
||||
case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
|
||||
case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
|
||||
case kpidNumBlocks: if (_numBlocks_Defined) prop = _numBlocks; break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
|
||||
if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
|
||||
if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
|
||||
prop = v;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
|
||||
case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const unsigned kSignatureCheckSize = 10;
|
||||
|
||||
API_FUNC_static_IsArc IsArc_BZip2(const Byte *p, size_t size)
|
||||
{
|
||||
if (size < kSignatureCheckSize)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
if (p[0] != 'B' || p[1] != 'Z' || p[2] != 'h' || p[3] < '1' || p[3] > '9')
|
||||
return k_IsArc_Res_NO;
|
||||
p += 4;
|
||||
if (NCompress::NBZip2::IsBlockSig(p))
|
||||
return k_IsArc_Res_YES;
|
||||
if (NCompress::NBZip2::IsEndSig(p))
|
||||
return k_IsArc_Res_YES;
|
||||
return k_IsArc_Res_NO;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
{
|
||||
Byte buf[kSignatureCheckSize];
|
||||
RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize));
|
||||
if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO)
|
||||
return S_FALSE;
|
||||
_isArc = true;
|
||||
_stream = stream;
|
||||
_seqStream = stream;
|
||||
_needSeekToStart = true;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
||||
{
|
||||
Close();
|
||||
_isArc = true;
|
||||
_seqStream = stream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_isArc = false;
|
||||
_needSeekToStart = false;
|
||||
_dataAfterEnd = false;
|
||||
_needMoreInput = false;
|
||||
|
||||
_packSize_Defined = false;
|
||||
_unpackSize_Defined = false;
|
||||
_numStreams_Defined = false;
|
||||
_numBlocks_Defined = false;
|
||||
|
||||
_packSize = 0;
|
||||
|
||||
_seqStream.Release();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (_packSize_Defined)
|
||||
extractCallback->SetTotal(_packSize);
|
||||
|
||||
// RINOK(extractCallback->SetCompleted(&packSize));
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
|
||||
if (!testMode && !realOutStream)
|
||||
return S_OK;
|
||||
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
|
||||
|
||||
if (_needSeekToStart)
|
||||
{
|
||||
if (!_stream)
|
||||
return E_FAIL;
|
||||
RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
else
|
||||
_needSeekToStart = true;
|
||||
|
||||
Int32 opRes;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
|
||||
CMyComPtr<ICompressCoder> decoder = decoderSpec;
|
||||
decoderSpec->SetInStream(_seqStream);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
RINOK(decoderSpec->SetNumberOfThreads(_props._numThreads));
|
||||
#endif
|
||||
|
||||
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
|
||||
realOutStream.Release();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, true);
|
||||
|
||||
UInt64 packSize = 0;
|
||||
UInt64 unpackedSize = 0;
|
||||
UInt64 numStreams = 0;
|
||||
|
||||
decoderSpec->InitNumBlocks();
|
||||
|
||||
HRESULT result = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
lps->InSize = packSize;
|
||||
lps->OutSize = unpackedSize;
|
||||
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
result = decoderSpec->CodeResume(outStream, progress);
|
||||
|
||||
if (result != S_FALSE && result != S_OK)
|
||||
return result;
|
||||
|
||||
if (decoderSpec->IsBz)
|
||||
numStreams++;
|
||||
else if (numStreams == 0)
|
||||
{
|
||||
_isArc = false;
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
unpackedSize = outStreamSpec->GetSize();
|
||||
UInt64 streamSize = decoderSpec->GetStreamSize();
|
||||
|
||||
if (streamSize == packSize)
|
||||
{
|
||||
// no new bytes in input stream, So it's good end of archive.
|
||||
result = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!decoderSpec->IsBz)
|
||||
{
|
||||
_dataAfterEnd = true;
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (decoderSpec->Base.BitDecoder.ExtraBitsWereRead())
|
||||
{
|
||||
_needMoreInput = true;
|
||||
packSize = streamSize;
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
packSize = decoderSpec->GetInputProcessedSize();
|
||||
|
||||
if (packSize > streamSize)
|
||||
return E_FAIL;
|
||||
|
||||
if (result != S_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (numStreams != 0)
|
||||
{
|
||||
_packSize = packSize;
|
||||
_unpackSize = unpackedSize;
|
||||
_numStreams = numStreams;
|
||||
_numBlocks = decoderSpec->GetNumBlocks();
|
||||
|
||||
_packSize_Defined = true;
|
||||
_unpackSize_Defined = true;
|
||||
_numStreams_Defined = true;
|
||||
_numBlocks_Defined = true;
|
||||
}
|
||||
|
||||
decoderSpec->ReleaseInStream();
|
||||
outStream.Release();
|
||||
|
||||
if (!_isArc)
|
||||
opRes = NExtract::NOperationResult::kIsNotArc;
|
||||
else if (_needMoreInput)
|
||||
opRes = NExtract::NOperationResult::kUnexpectedEnd;
|
||||
else if (decoderSpec->CrcError)
|
||||
opRes = NExtract::NOperationResult::kCRCError;
|
||||
else if (_dataAfterEnd)
|
||||
opRes = NExtract::NOperationResult::kDataAfterEnd;
|
||||
else if (result == S_FALSE)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
else if (result == S_OK)
|
||||
opRes = NExtract::NOperationResult::kOK;
|
||||
else
|
||||
return result;
|
||||
|
||||
}
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
|
||||
return extractCallback->SetOperationResult(opRes);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static HRESULT UpdateArchive(
|
||||
UInt64 unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
const CProps &props,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
RINOK(updateCallback->SetTotal(unpackSize));
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
|
||||
localProgressSpec->Init(updateCallback, true);
|
||||
NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
|
||||
CMyComPtr<ICompressCoder> encoder = encoderSpec;
|
||||
RINOK(props.SetCoderProps(encoderSpec, NULL));
|
||||
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
|
||||
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
{
|
||||
*type = NFileTimeType::kUnix;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
Int32 newData, newProps;
|
||||
UInt32 indexInArchive;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
|
||||
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
|
||||
if (prop.vt != VT_EMPTY)
|
||||
if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
UInt64 size;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
size = prop.uhVal.QuadPart;
|
||||
}
|
||||
return UpdateArchive(size, outStream, _props, updateCallback);
|
||||
}
|
||||
|
||||
if (indexInArchive != 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(updateCallback, true);
|
||||
|
||||
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
|
||||
if (opCallback)
|
||||
{
|
||||
RINOK(opCallback->ReportOperation(
|
||||
NEventIndexType::kInArcIndex, 0,
|
||||
NUpdateNotifyOp::kReplicate))
|
||||
}
|
||||
|
||||
if (_stream)
|
||||
RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
|
||||
return NCompress::CopyStream(_stream, outStream, progress);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
return _props.SetProperties(names, values, numProps);
|
||||
}
|
||||
|
||||
static const Byte k_Signature[] = { 'B', 'Z', 'h' };
|
||||
|
||||
REGISTER_ARC_IO(
|
||||
"bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kKeepName,
|
||||
IsArc_BZip2)
|
||||
|
||||
}}
|
||||
100
CPP/7zip/Archive/Cab/CabBlockInStream.cpp
Normal file
100
CPP/7zip/Archive/Cab/CabBlockInStream.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// CabBlockInStream.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/Alloc.h"
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "CabBlockInStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
static const UInt32 kBlockSize = (1 << 16);
|
||||
|
||||
bool CCabBlockInStream::Create()
|
||||
{
|
||||
if (!_buf)
|
||||
_buf = (Byte *)::MyAlloc(kBlockSize);
|
||||
return _buf != 0;
|
||||
}
|
||||
|
||||
CCabBlockInStream::~CCabBlockInStream()
|
||||
{
|
||||
::MyFree(_buf);
|
||||
}
|
||||
|
||||
static UInt32 CheckSum(const Byte *p, UInt32 size)
|
||||
{
|
||||
UInt32 sum = 0;
|
||||
|
||||
for (; size >= 8; size -= 8)
|
||||
{
|
||||
sum ^= GetUi32(p) ^ GetUi32(p + 4);
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (size >= 4)
|
||||
{
|
||||
sum ^= GetUi32(p);
|
||||
p += 4;
|
||||
}
|
||||
|
||||
size &= 3;
|
||||
if (size > 2) sum ^= (UInt32)(*p++) << 16;
|
||||
if (size > 1) sum ^= (UInt32)(*p++) << 8;
|
||||
if (size > 0) sum ^= (UInt32)(*p++);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize)
|
||||
{
|
||||
const UInt32 kHeaderSize = 8;
|
||||
const UInt32 kReservedMax = 256;
|
||||
Byte header[kHeaderSize + kReservedMax];
|
||||
RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize))
|
||||
packSize = GetUi16(header + 4);
|
||||
unpackSize = GetUi16(header + 6);
|
||||
if (packSize > kBlockSize - _size)
|
||||
return S_FALSE;
|
||||
RINOK(ReadStream_FALSE(stream, _buf + _size, packSize));
|
||||
|
||||
if (MsZip)
|
||||
{
|
||||
if (_size == 0)
|
||||
{
|
||||
if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B)
|
||||
return S_FALSE;
|
||||
_pos = 2;
|
||||
}
|
||||
if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (GetUi32(header) != 0) // checkSum
|
||||
if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize))
|
||||
return S_FALSE;
|
||||
|
||||
_size += packSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
UInt32 rem = _size - _pos;
|
||||
if (size > rem)
|
||||
size = rem;
|
||||
memcpy(data, _buf + _pos, size);
|
||||
_pos += size;
|
||||
}
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
43
CPP/7zip/Archive/Cab/CabBlockInStream.h
Normal file
43
CPP/7zip/Archive/Cab/CabBlockInStream.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// CabBlockInStream.h
|
||||
|
||||
#ifndef __CAB_BLOCK_IN_STREAM_H
|
||||
#define __CAB_BLOCK_IN_STREAM_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
class CCabBlockInStream:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Byte *_buf;
|
||||
UInt32 _size;
|
||||
UInt32 _pos;
|
||||
|
||||
public:
|
||||
UInt32 ReservedSize; // < 256
|
||||
bool MsZip;
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {}
|
||||
~CCabBlockInStream();
|
||||
|
||||
bool Create();
|
||||
|
||||
void InitForNewBlock() { _size = 0; _pos = 0; }
|
||||
|
||||
HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize);
|
||||
|
||||
UInt32 GetPackSizeAvail() const { return _size - _pos; }
|
||||
const Byte *GetData() const { return _buf + _pos; }
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
1261
CPP/7zip/Archive/Cab/CabHandler.cpp
Normal file
1261
CPP/7zip/Archive/Cab/CabHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
37
CPP/7zip/Archive/Cab/CabHandler.h
Normal file
37
CPP/7zip/Archive/Cab/CabHandler.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// CabHandler.h
|
||||
|
||||
#ifndef __CAB_HANDLER_H
|
||||
#define __CAB_HANDLER_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "CabIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
private:
|
||||
CMvDatabaseEx m_Database;
|
||||
UString _errorMessage;
|
||||
bool _isArc;
|
||||
bool _errorInHeaders;
|
||||
bool _unexpectedEnd;
|
||||
// int _mainVolIndex;
|
||||
UInt32 _phySize;
|
||||
UInt64 _offset;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
15
CPP/7zip/Archive/Cab/CabHeader.cpp
Normal file
15
CPP/7zip/Archive/Cab/CabHeader.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// CabHeader.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "CabHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
namespace NHeader {
|
||||
|
||||
const Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 };
|
||||
|
||||
// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; } } g_SignatureInitializer;
|
||||
|
||||
}}}
|
||||
41
CPP/7zip/Archive/Cab/CabHeader.h
Normal file
41
CPP/7zip/Archive/Cab/CabHeader.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Archive/CabHeader.h
|
||||
|
||||
#ifndef __ARCHIVE_CAB_HEADER_H
|
||||
#define __ARCHIVE_CAB_HEADER_H
|
||||
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
namespace NHeader {
|
||||
|
||||
const unsigned kMarkerSize = 8;
|
||||
extern const Byte kMarker[kMarkerSize];
|
||||
|
||||
namespace NArcFlags
|
||||
{
|
||||
const unsigned kPrevCabinet = 1;
|
||||
const unsigned kNextCabinet = 2;
|
||||
const unsigned kReservePresent = 4;
|
||||
}
|
||||
|
||||
namespace NMethod
|
||||
{
|
||||
const Byte kNone = 0;
|
||||
const Byte kMSZip = 1;
|
||||
const Byte kQuantum = 2;
|
||||
const Byte kLZX = 3;
|
||||
}
|
||||
|
||||
const unsigned kFileNameIsUtf8_Mask = 0x80;
|
||||
|
||||
namespace NFolderIndex
|
||||
{
|
||||
const unsigned kContinuedFromPrev = 0xFFFD;
|
||||
const unsigned kContinuedToNext = 0xFFFE;
|
||||
const unsigned kContinuedPrevAndNext = 0xFFFF;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
491
CPP/7zip/Archive/Cab/CabIn.cpp
Normal file
491
CPP/7zip/Archive/Cab/CabIn.cpp
Normal file
@@ -0,0 +1,491 @@
|
||||
// Archive/CabIn.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "CabIn.h"
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
struct CUnexpectedEndException {};
|
||||
|
||||
void CInArchive::Skip(unsigned size)
|
||||
{
|
||||
if (_inBuffer.Skip(size) != size)
|
||||
throw CUnexpectedEndException();
|
||||
}
|
||||
|
||||
void CInArchive::Read(Byte *data, unsigned size)
|
||||
{
|
||||
if (_inBuffer.ReadBytes(data, size) != size)
|
||||
throw CUnexpectedEndException();
|
||||
}
|
||||
|
||||
void CInArchive::ReadName(AString &s)
|
||||
{
|
||||
for (size_t i = 0; i < ((size_t)1 << 13); i++)
|
||||
{
|
||||
Byte b;
|
||||
if (!_inBuffer.ReadByte(b))
|
||||
throw CUnexpectedEndException();
|
||||
if (b == 0)
|
||||
{
|
||||
s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i);
|
||||
return;
|
||||
}
|
||||
if (_tempBuf.Size() == i)
|
||||
_tempBuf.ChangeSize_KeepData(i * 2, i);
|
||||
_tempBuf[i] = b;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
if (!_inBuffer.ReadByte(b))
|
||||
throw CUnexpectedEndException();
|
||||
if (b == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
ErrorInNames = true;
|
||||
s = "[ERROR-LONG-PATH]";
|
||||
}
|
||||
|
||||
void CInArchive::ReadOtherArc(COtherArc &oa)
|
||||
{
|
||||
ReadName(oa.FileName);
|
||||
ReadName(oa.DiskName);
|
||||
}
|
||||
|
||||
|
||||
struct CSignatureFinder
|
||||
{
|
||||
Byte *Buf;
|
||||
UInt32 Pos;
|
||||
UInt32 End;
|
||||
const Byte *Signature;
|
||||
UInt32 SignatureSize;
|
||||
|
||||
UInt32 _HeaderSize;
|
||||
UInt32 _AlignSize;
|
||||
UInt32 _BufUseCapacity;
|
||||
|
||||
ISequentialInStream *Stream;
|
||||
UInt64 Processed; // Global offset of start of Buf
|
||||
|
||||
const UInt64 *SearchLimit;
|
||||
|
||||
UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize)
|
||||
{
|
||||
_HeaderSize = headerSize;
|
||||
for (_AlignSize = (1 << 5); _AlignSize < _HeaderSize; _AlignSize <<= 1);
|
||||
_BufUseCapacity = basicSize + _AlignSize;
|
||||
return _BufUseCapacity + 16;
|
||||
}
|
||||
|
||||
/*
|
||||
returns:
|
||||
S_OK - signature found (at Pos)
|
||||
S_FALSE - signature not found
|
||||
*/
|
||||
HRESULT Find();
|
||||
};
|
||||
|
||||
|
||||
HRESULT CSignatureFinder::Find()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
Buf[End] = Signature[0]; // it's for fast search;
|
||||
|
||||
while (End - Pos >= _HeaderSize)
|
||||
{
|
||||
const Byte *p = Buf + Pos;
|
||||
Byte b = Signature[0];
|
||||
for (;;)
|
||||
{
|
||||
if (*p == b) break; p++;
|
||||
if (*p == b) break; p++;
|
||||
}
|
||||
Pos = (UInt32)(p - Buf);
|
||||
if (End - Pos < _HeaderSize)
|
||||
{
|
||||
Pos = End - _HeaderSize + 1;
|
||||
break;
|
||||
}
|
||||
UInt32 i;
|
||||
for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++);
|
||||
if (i == SignatureSize)
|
||||
return S_OK;
|
||||
Pos++;
|
||||
}
|
||||
|
||||
if (Pos >= _AlignSize)
|
||||
{
|
||||
UInt32 num = (Pos & ~(_AlignSize - 1));
|
||||
Processed += num;
|
||||
Pos -= num;
|
||||
End -= num;
|
||||
memmove(Buf, Buf + num, End);
|
||||
}
|
||||
UInt32 rem = _BufUseCapacity - End;
|
||||
if (SearchLimit)
|
||||
{
|
||||
if (Processed + Pos > *SearchLimit)
|
||||
return S_FALSE;
|
||||
UInt64 rem2 = *SearchLimit - (Processed + End) + _HeaderSize;
|
||||
if (rem > rem2)
|
||||
rem = (UInt32)rem2;
|
||||
}
|
||||
|
||||
UInt32 processedSize;
|
||||
if (Processed == 0 && rem == _BufUseCapacity - _HeaderSize)
|
||||
rem -= _AlignSize; // to make reads more aligned.
|
||||
RINOK(Stream->Read(Buf + End, rem, &processedSize));
|
||||
if (processedSize == 0)
|
||||
return S_FALSE;
|
||||
End += processedSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CInArcInfo::Parse(const Byte *p)
|
||||
{
|
||||
if (Get32(p + 0x0C) != 0 ||
|
||||
Get32(p + 0x14) != 0)
|
||||
return false;
|
||||
Size = Get32(p + 8);
|
||||
if (Size < 36)
|
||||
return false;
|
||||
Flags = Get16(p + 0x1E);
|
||||
if (Flags > 7)
|
||||
return false;
|
||||
FileHeadersOffset = Get32(p + 0x10);
|
||||
if (FileHeadersOffset != 0 && FileHeadersOffset > Size)
|
||||
return false;
|
||||
VersionMinor = p[0x18];
|
||||
VersionMajor = p[0x19];
|
||||
NumFolders = Get16(p + 0x1A);
|
||||
NumFiles = Get16(p + 0x1C);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
|
||||
{
|
||||
IsArc = false;
|
||||
ErrorInNames = false;
|
||||
UnexpectedEnd = false;
|
||||
HeaderError = false;
|
||||
|
||||
db.Clear();
|
||||
RINOK(db.Stream->Seek(0, STREAM_SEEK_CUR, &db.StartPosition));
|
||||
// UInt64 temp = db.StartPosition;
|
||||
|
||||
CByteBuffer buffer;
|
||||
CInArcInfo &ai = db.ArcInfo;
|
||||
UInt64 startInBuf = 0;
|
||||
|
||||
CLimitedSequentialInStream *limitedStreamSpec = NULL;
|
||||
CMyComPtr<ISequentialInStream> limitedStream;
|
||||
|
||||
// for (int iii = 0; iii < 10000; iii++)
|
||||
{
|
||||
// db.StartPosition = temp; RINOK(db.Stream->Seek(db.StartPosition, STREAM_SEEK_SET, NULL));
|
||||
|
||||
const UInt32 kMainHeaderSize = 32;
|
||||
Byte header[kMainHeaderSize];
|
||||
const UInt32 kBufSize = 1 << 15;
|
||||
RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize));
|
||||
if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header))
|
||||
{
|
||||
limitedStreamSpec = new CLimitedSequentialInStream;
|
||||
limitedStream = limitedStreamSpec;
|
||||
limitedStreamSpec->SetStream(db.Stream);
|
||||
limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize);
|
||||
buffer.Alloc(kBufSize);
|
||||
memcpy(buffer, header, kMainHeaderSize);
|
||||
UInt32 numProcessedBytes;
|
||||
RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes));
|
||||
_inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
|
||||
return S_FALSE;
|
||||
|
||||
CSignatureFinder finder;
|
||||
|
||||
finder.Stream = db.Stream;
|
||||
finder.Signature = NHeader::kMarker;
|
||||
finder.SignatureSize = NHeader::kMarkerSize;
|
||||
finder.SearchLimit = searchHeaderSizeLimit;
|
||||
|
||||
buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize));
|
||||
finder.Buf = buffer;
|
||||
|
||||
memcpy(buffer, header, kMainHeaderSize);
|
||||
finder.Processed = db.StartPosition;
|
||||
finder.End = kMainHeaderSize;
|
||||
finder.Pos = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
RINOK(finder.Find());
|
||||
if (ai.Parse(finder.Buf + finder.Pos))
|
||||
{
|
||||
db.StartPosition = finder.Processed + finder.Pos;
|
||||
limitedStreamSpec = new CLimitedSequentialInStream;
|
||||
limitedStreamSpec->SetStream(db.Stream);
|
||||
limitedStream = limitedStreamSpec;
|
||||
UInt32 remInFinder = finder.End - finder.Pos;
|
||||
if (ai.Size <= remInFinder)
|
||||
{
|
||||
limitedStreamSpec->Init(0);
|
||||
finder.End = finder.Pos + ai.Size;
|
||||
}
|
||||
else
|
||||
limitedStreamSpec->Init(ai.Size - remInFinder);
|
||||
|
||||
startInBuf = finder.Pos;
|
||||
_inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize);
|
||||
break;
|
||||
}
|
||||
finder.Pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IsArc = true;
|
||||
|
||||
_inBuffer.SetStream(limitedStream);
|
||||
if (_tempBuf.Size() == 0)
|
||||
_tempBuf.Alloc(1 << 12);
|
||||
|
||||
Byte p[16];
|
||||
unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0);
|
||||
Read(p, nextSize);
|
||||
ai.SetID = Get16(p);
|
||||
ai.CabinetNumber = Get16(p + 2);
|
||||
|
||||
if (ai.ReserveBlockPresent())
|
||||
{
|
||||
ai.PerCabinet_AreaSize = Get16(p + 4);
|
||||
ai.PerFolder_AreaSize = p[6];
|
||||
ai.PerDataBlock_AreaSize = p[7];
|
||||
Skip(ai.PerCabinet_AreaSize);
|
||||
}
|
||||
|
||||
if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc);
|
||||
if (ai.IsThereNext()) ReadOtherArc(ai.NextArc);
|
||||
|
||||
UInt32 i;
|
||||
|
||||
db.Folders.ClearAndReserve(ai.NumFolders);
|
||||
|
||||
for (i = 0; i < ai.NumFolders; i++)
|
||||
{
|
||||
Read(p, 8);
|
||||
CFolder folder;
|
||||
folder.DataStart = Get32(p);
|
||||
folder.NumDataBlocks = Get16(p + 4);
|
||||
folder.MethodMajor = p[6];
|
||||
folder.MethodMinor = p[7];
|
||||
Skip(ai.PerFolder_AreaSize);
|
||||
db.Folders.AddInReserved(folder);
|
||||
}
|
||||
|
||||
// for (int iii = 0; iii < 10000; iii++) {
|
||||
|
||||
if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset)
|
||||
{
|
||||
// printf("\n!!! Seek Error !!!!\n");
|
||||
// fflush(stdout);
|
||||
RINOK(db.Stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL));
|
||||
limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset);
|
||||
_inBuffer.Init();
|
||||
}
|
||||
|
||||
db.Items.ClearAndReserve(ai.NumFiles);
|
||||
|
||||
for (i = 0; i < ai.NumFiles; i++)
|
||||
{
|
||||
Read(p, 16);
|
||||
CItem &item = db.Items.AddNewInReserved();
|
||||
item.Size = Get32(p);
|
||||
item.Offset = Get32(p + 4);
|
||||
item.FolderIndex = Get16(p + 8);
|
||||
UInt16 pureDate = Get16(p + 10);
|
||||
UInt16 pureTime = Get16(p + 12);
|
||||
item.Time = (((UInt32)pureDate << 16)) | pureTime;
|
||||
item.Attributes = Get16(p + 14);
|
||||
|
||||
ReadName(item.Name);
|
||||
|
||||
if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size())
|
||||
{
|
||||
HeaderError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// }
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Open2(db, searchHeaderSizeLimit);
|
||||
}
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
|
||||
|
||||
static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
|
||||
{
|
||||
const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param;
|
||||
const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex];
|
||||
const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
|
||||
const CItem &item1 = db1.Items[p1->ItemIndex];
|
||||
const CItem &item2 = db2.Items[p2->ItemIndex];;
|
||||
bool isDir1 = item1.IsDir();
|
||||
bool isDir2 = item2.IsDir();
|
||||
if (isDir1 && !isDir2) return -1;
|
||||
if (isDir2 && !isDir1) return 1;
|
||||
int f1 = mvDb.GetFolderIndex(p1);
|
||||
int f2 = mvDb.GetFolderIndex(p2);
|
||||
RINOZ(MyCompare(f1, f2));
|
||||
RINOZ(MyCompare(item1.Offset, item2.Offset));
|
||||
RINOZ(MyCompare(item1.Size, item2.Size));
|
||||
RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex));
|
||||
return MyCompare(p1->ItemIndex, p2->ItemIndex);
|
||||
}
|
||||
|
||||
|
||||
bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2)
|
||||
{
|
||||
const CMvItem *p1 = &Items[i1];
|
||||
const CMvItem *p2 = &Items[i2];
|
||||
const CDatabaseEx &db1 = Volumes[p1->VolumeIndex];
|
||||
const CDatabaseEx &db2 = Volumes[p2->VolumeIndex];
|
||||
const CItem &item1 = db1.Items[p1->ItemIndex];
|
||||
const CItem &item2 = db2.Items[p2->ItemIndex];;
|
||||
return GetFolderIndex(p1) == GetFolderIndex(p2)
|
||||
&& item1.Offset == item2.Offset
|
||||
&& item1.Size == item2.Size
|
||||
&& item1.Name == item2.Name;
|
||||
}
|
||||
|
||||
|
||||
void CMvDatabaseEx::FillSortAndShrink()
|
||||
{
|
||||
Items.Clear();
|
||||
StartFolderOfVol.Clear();
|
||||
FolderStartFileIndex.Clear();
|
||||
|
||||
int offset = 0;
|
||||
|
||||
FOR_VECTOR (v, Volumes)
|
||||
{
|
||||
const CDatabaseEx &db = Volumes[v];
|
||||
int curOffset = offset;
|
||||
if (db.IsTherePrevFolder())
|
||||
curOffset--;
|
||||
StartFolderOfVol.Add(curOffset);
|
||||
offset += db.GetNumberOfNewFolders();
|
||||
|
||||
CMvItem mvItem;
|
||||
mvItem.VolumeIndex = v;
|
||||
FOR_VECTOR (i, db.Items)
|
||||
{
|
||||
mvItem.ItemIndex = i;
|
||||
Items.Add(mvItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (Items.Size() > 1)
|
||||
{
|
||||
Items.Sort(CompareMvItems, (void *)this);
|
||||
unsigned j = 1;
|
||||
unsigned i = 1;
|
||||
for (; i < Items.Size(); i++)
|
||||
if (!AreItemsEqual(i, i - 1))
|
||||
Items[j++] = Items[i];
|
||||
Items.DeleteFrom(j);
|
||||
}
|
||||
|
||||
FOR_VECTOR (i, Items)
|
||||
{
|
||||
int folderIndex = GetFolderIndex(&Items[i]);
|
||||
while (folderIndex >= (int)FolderStartFileIndex.Size())
|
||||
FolderStartFileIndex.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CMvDatabaseEx::Check()
|
||||
{
|
||||
for (unsigned v = 1; v < Volumes.Size(); v++)
|
||||
{
|
||||
const CDatabaseEx &db1 = Volumes[v];
|
||||
if (db1.IsTherePrevFolder())
|
||||
{
|
||||
const CDatabaseEx &db0 = Volumes[v - 1];
|
||||
if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty())
|
||||
return false;
|
||||
const CFolder &f0 = db0.Folders.Back();
|
||||
const CFolder &f1 = db1.Folders.Front();
|
||||
if (f0.MethodMajor != f1.MethodMajor ||
|
||||
f0.MethodMinor != f1.MethodMinor)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 beginPos = 0;
|
||||
UInt64 endPos = 0;
|
||||
int prevFolder = -2;
|
||||
|
||||
FOR_VECTOR (i, Items)
|
||||
{
|
||||
const CMvItem &mvItem = Items[i];
|
||||
int fIndex = GetFolderIndex(&mvItem);
|
||||
if (fIndex >= (int)FolderStartFileIndex.Size())
|
||||
return false;
|
||||
const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
|
||||
if (item.IsDir())
|
||||
continue;
|
||||
|
||||
int folderIndex = GetFolderIndex(&mvItem);
|
||||
|
||||
if (folderIndex != prevFolder)
|
||||
prevFolder = folderIndex;
|
||||
else if (item.Offset < endPos &&
|
||||
(item.Offset != beginPos || item.GetEndOffset() != endPos))
|
||||
return false;
|
||||
|
||||
beginPos = item.Offset;
|
||||
endPos = item.GetEndOffset();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
||||
176
CPP/7zip/Archive/Cab/CabIn.h
Normal file
176
CPP/7zip/Archive/Cab/CabIn.h
Normal file
@@ -0,0 +1,176 @@
|
||||
// Archive/CabIn.h
|
||||
|
||||
#ifndef __ARCHIVE_CAB_IN_H
|
||||
#define __ARCHIVE_CAB_IN_H
|
||||
|
||||
#include "../../../Common/MyBuffer.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../Common/InBuffer.h"
|
||||
|
||||
#include "CabItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
struct COtherArc
|
||||
{
|
||||
AString FileName;
|
||||
AString DiskName;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
FileName.Empty();
|
||||
DiskName.Empty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CArchInfo
|
||||
{
|
||||
Byte VersionMinor; // cabinet file format version, minor
|
||||
Byte VersionMajor; // cabinet file format version, major
|
||||
UInt32 NumFolders; // number of CFFOLDER entries in this cabinet
|
||||
UInt32 NumFiles; // number of CFFILE entries in this cabinet
|
||||
UInt32 Flags; // cabinet file option indicators
|
||||
UInt32 SetID; // must be the same for all cabinets in a set
|
||||
UInt32 CabinetNumber; // number of this cabinet file in a set
|
||||
|
||||
UInt16 PerCabinet_AreaSize; // (optional) size of per-cabinet reserved area
|
||||
Byte PerFolder_AreaSize; // (optional) size of per-folder reserved area
|
||||
Byte PerDataBlock_AreaSize; // (optional) size of per-datablock reserved area
|
||||
|
||||
COtherArc PrevArc; // prev link can skip some volumes !!!
|
||||
COtherArc NextArc;
|
||||
|
||||
bool ReserveBlockPresent() const { return (Flags & NHeader::NArcFlags::kReservePresent) != 0; }
|
||||
bool IsTherePrev() const { return (Flags & NHeader::NArcFlags::kPrevCabinet) != 0; }
|
||||
bool IsThereNext() const { return (Flags & NHeader::NArcFlags::kNextCabinet) != 0; }
|
||||
Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlock_AreaSize : 0); }
|
||||
|
||||
CArchInfo()
|
||||
{
|
||||
PerCabinet_AreaSize = 0;
|
||||
PerFolder_AreaSize = 0;
|
||||
PerDataBlock_AreaSize = 0;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
PerCabinet_AreaSize = 0;
|
||||
PerFolder_AreaSize = 0;
|
||||
PerDataBlock_AreaSize = 0;
|
||||
|
||||
PrevArc.Clear();
|
||||
NextArc.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CInArcInfo: public CArchInfo
|
||||
{
|
||||
UInt32 Size; // size of this cabinet file in bytes
|
||||
UInt32 FileHeadersOffset; // offset of the first CFFILE entry
|
||||
|
||||
bool Parse(const Byte *p);
|
||||
};
|
||||
|
||||
|
||||
struct CDatabase
|
||||
{
|
||||
CRecordVector<CFolder> Folders;
|
||||
CObjectVector<CItem> Items;
|
||||
UInt64 StartPosition;
|
||||
CInArcInfo ArcInfo;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
ArcInfo.Clear();
|
||||
Folders.Clear();
|
||||
Items.Clear();
|
||||
}
|
||||
|
||||
bool IsTherePrevFolder() const
|
||||
{
|
||||
FOR_VECTOR (i, Items)
|
||||
if (Items[i].ContinuedFromPrev())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetNumberOfNewFolders() const
|
||||
{
|
||||
int res = Folders.Size();
|
||||
if (IsTherePrevFolder())
|
||||
res--;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CDatabaseEx: public CDatabase
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
};
|
||||
|
||||
|
||||
struct CMvItem
|
||||
{
|
||||
unsigned VolumeIndex;
|
||||
unsigned ItemIndex;
|
||||
};
|
||||
|
||||
|
||||
class CMvDatabaseEx
|
||||
{
|
||||
bool AreItemsEqual(unsigned i1, unsigned i2);
|
||||
|
||||
public:
|
||||
CObjectVector<CDatabaseEx> Volumes;
|
||||
CRecordVector<CMvItem> Items;
|
||||
CRecordVector<int> StartFolderOfVol; // can be negative
|
||||
CRecordVector<unsigned> FolderStartFileIndex;
|
||||
|
||||
int GetFolderIndex(const CMvItem *mvi) const
|
||||
{
|
||||
const CDatabaseEx &db = Volumes[mvi->VolumeIndex];
|
||||
return StartFolderOfVol[mvi->VolumeIndex] +
|
||||
db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size());
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Volumes.Clear();
|
||||
Items.Clear();
|
||||
StartFolderOfVol.Clear();
|
||||
FolderStartFileIndex.Clear();
|
||||
}
|
||||
|
||||
void FillSortAndShrink();
|
||||
bool Check();
|
||||
};
|
||||
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CInBufferBase _inBuffer;
|
||||
CByteBuffer _tempBuf;
|
||||
|
||||
void Skip(unsigned size);
|
||||
void Read(Byte *data, unsigned size);
|
||||
void ReadName(AString &s);
|
||||
void ReadOtherArc(COtherArc &oa);
|
||||
HRESULT Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit);
|
||||
|
||||
public:
|
||||
bool IsArc;
|
||||
bool ErrorInNames;
|
||||
bool UnexpectedEnd;
|
||||
bool HeaderError;
|
||||
|
||||
HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
66
CPP/7zip/Archive/Cab/CabItem.h
Normal file
66
CPP/7zip/Archive/Cab/CabItem.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// Archive/CabItem.h
|
||||
|
||||
#ifndef __ARCHIVE_CAB_ITEM_H
|
||||
#define __ARCHIVE_CAB_ITEM_H
|
||||
|
||||
#include "../../../Common/MyString.h"
|
||||
|
||||
#include "CabHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
const unsigned kNumMethodsMax = 16;
|
||||
|
||||
struct CFolder
|
||||
{
|
||||
UInt32 DataStart; // offset of the first CFDATA block in this folder
|
||||
UInt16 NumDataBlocks; // number of CFDATA blocks in this folder
|
||||
Byte MethodMajor;
|
||||
Byte MethodMinor;
|
||||
|
||||
Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); }
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt32 Offset;
|
||||
UInt32 Size;
|
||||
UInt32 Time;
|
||||
UInt32 FolderIndex;
|
||||
UInt16 Flags;
|
||||
UInt16 Attributes;
|
||||
|
||||
UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
|
||||
UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; }
|
||||
bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; }
|
||||
bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; }
|
||||
|
||||
bool ContinuedFromPrev() const
|
||||
{
|
||||
return
|
||||
FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev ||
|
||||
FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext;
|
||||
}
|
||||
|
||||
bool ContinuedToNext() const
|
||||
{
|
||||
return
|
||||
FolderIndex == NHeader::NFolderIndex::kContinuedToNext ||
|
||||
FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext;
|
||||
}
|
||||
|
||||
int GetFolderIndex(unsigned numFolders) const
|
||||
{
|
||||
if (ContinuedFromPrev())
|
||||
return 0;
|
||||
if (ContinuedToNext())
|
||||
return numFolders - 1;
|
||||
return FolderIndex;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
19
CPP/7zip/Archive/Cab/CabRegister.cpp
Normal file
19
CPP/7zip/Archive/Cab/CabRegister.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// CabRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "CabHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCab {
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"Cab", "cab", 0, 8,
|
||||
NHeader::kMarker,
|
||||
0,
|
||||
NArcInfoFlags::kFindSignature,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
8
CPP/7zip/Archive/Cab/StdAfx.h
Normal file
8
CPP/7zip/Archive/Cab/StdAfx.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
828
CPP/7zip/Archive/Chm/ChmHandler.cpp
Normal file
828
CPP/7zip/Archive/Chm/ChmHandler.cpp
Normal file
@@ -0,0 +1,828 @@
|
||||
// ChmHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
#include "../../../Common/UTFConvert.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
#include "../../Compress/LzxDecoder.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "ChmHandler.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NChm {
|
||||
|
||||
// #define _CHM_DETAILS
|
||||
|
||||
#ifdef _CHM_DETAILS
|
||||
|
||||
enum
|
||||
{
|
||||
kpidSection = kpidUserDefined
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidSize,
|
||||
kpidMethod,
|
||||
kpidBlock
|
||||
|
||||
#ifdef _CHM_DETAILS
|
||||
,
|
||||
L"Section", kpidSection,
|
||||
kpidOffset
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
// kpidNumBlocks,
|
||||
};
|
||||
*/
|
||||
|
||||
IMP_IInArchive_Props
|
||||
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
// COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
/*
|
||||
case kpidNumBlocks:
|
||||
{
|
||||
UInt64 numBlocks = 0;
|
||||
FOR_VECTOR(i, m_Database.Sections)
|
||||
{
|
||||
const CSectionInfo &s = m_Database.Sections[i];
|
||||
FOR_VECTOR(j, s.Methods)
|
||||
{
|
||||
const CMethodInfo &m = s.Methods[j];
|
||||
if (m.IsLzx())
|
||||
numBlocks += m.LzxInfo.ResetTable.GetNumBlocks();
|
||||
}
|
||||
}
|
||||
prop = numBlocks;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case kpidOffset: prop = m_Database.StartPosition; break;
|
||||
case kpidPhySize: prop = m_Database.PhySize; break;
|
||||
|
||||
case kpidErrorFlags: prop = m_ErrorFlags; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
// COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
|
||||
if (m_Database.NewFormat)
|
||||
{
|
||||
switch (propID)
|
||||
{
|
||||
case kpidSize:
|
||||
prop = (UInt64)m_Database.NewFormatString.Len();
|
||||
break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
unsigned entryIndex;
|
||||
if (m_Database.LowLevel)
|
||||
entryIndex = index;
|
||||
else
|
||||
entryIndex = m_Database.Indices[index];
|
||||
|
||||
const CItem &item = m_Database.Items[entryIndex];
|
||||
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
UString us;
|
||||
// if (
|
||||
ConvertUTF8ToUnicode(item.Name, us);
|
||||
{
|
||||
if (!m_Database.LowLevel)
|
||||
{
|
||||
if (us.Len() > 1 && us[0] == L'/')
|
||||
us.Delete(0);
|
||||
}
|
||||
NItemName::ConvertToOSName2(us);
|
||||
prop = us;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize: prop = item.Size; break;
|
||||
case kpidMethod:
|
||||
{
|
||||
if (!item.IsDir())
|
||||
if (item.Section == 0)
|
||||
prop = "Copy";
|
||||
else if (item.Section < m_Database.Sections.Size())
|
||||
prop = m_Database.Sections[(unsigned)item.Section].GetMethodName();
|
||||
break;
|
||||
}
|
||||
case kpidBlock:
|
||||
if (m_Database.LowLevel)
|
||||
prop = item.Section;
|
||||
else if (item.Section != 0 && item.Section < m_Database.Sections.Size())
|
||||
prop = m_Database.GetFolder(index);
|
||||
break;
|
||||
|
||||
#ifdef _CHM_DETAILS
|
||||
|
||||
case kpidSection: prop = (UInt32)item.Section; break;
|
||||
case kpidOffset: prop = (UInt32)item.Offset; break;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
/*
|
||||
class CProgressImp: public CProgressVirt
|
||||
{
|
||||
CMyComPtr<IArchiveOpenCallback> _callback;
|
||||
public:
|
||||
STDMETHOD(SetTotal)(const UInt64 *numFiles);
|
||||
STDMETHOD(SetCompleted)(const UInt64 *numFiles);
|
||||
CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {};
|
||||
};
|
||||
|
||||
STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
|
||||
{
|
||||
if (_callback)
|
||||
return _callback->SetCompleted(numFiles, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
|
||||
{
|
||||
if (_callback)
|
||||
return _callback->SetCompleted(numFiles, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
try
|
||||
{
|
||||
CInArchive archive(_help2);
|
||||
// CProgressImp progressImp(openArchiveCallback);
|
||||
HRESULT res = archive.Open(inStream, maxCheckStartPosition, m_Database);
|
||||
if (!archive.IsArc) m_ErrorFlags |= kpv_ErrorFlags_IsNotArc;
|
||||
if (archive.HeadersError) m_ErrorFlags |= kpv_ErrorFlags_HeadersError;
|
||||
if (archive.UnexpectedEnd) m_ErrorFlags |= kpv_ErrorFlags_UnexpectedEnd;
|
||||
if (archive.UnsupportedFeature) m_ErrorFlags |= kpv_ErrorFlags_UnsupportedFeature;
|
||||
|
||||
RINOK(res);
|
||||
/*
|
||||
if (m_Database.LowLevel)
|
||||
return S_FALSE;
|
||||
*/
|
||||
m_Stream = inStream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
m_ErrorFlags = 0;
|
||||
m_Database.Clear();
|
||||
m_Stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CChmFolderOutStream:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
UInt64 m_FolderSize;
|
||||
UInt64 m_PosInFolder;
|
||||
UInt64 m_PosInSection;
|
||||
const CRecordVector<bool> *m_ExtractStatuses;
|
||||
unsigned m_StartIndex;
|
||||
unsigned m_CurrentIndex;
|
||||
unsigned m_NumFiles;
|
||||
|
||||
private:
|
||||
const CFilesDatabase *m_Database;
|
||||
CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
|
||||
bool m_TestMode;
|
||||
|
||||
bool m_IsOk;
|
||||
bool m_FileIsOpen;
|
||||
UInt64 m_RemainFileSize;
|
||||
CMyComPtr<ISequentialOutStream> m_RealOutStream;
|
||||
|
||||
HRESULT OpenFile();
|
||||
HRESULT WriteEmptyFiles();
|
||||
public:
|
||||
void Init(
|
||||
const CFilesDatabase *database,
|
||||
IArchiveExtractCallback *extractCallback,
|
||||
bool testMode);
|
||||
HRESULT FlushCorrupted(UInt64 maxSize);
|
||||
};
|
||||
|
||||
void CChmFolderOutStream::Init(
|
||||
const CFilesDatabase *database,
|
||||
IArchiveExtractCallback *extractCallback,
|
||||
bool testMode)
|
||||
{
|
||||
m_Database = database;
|
||||
m_ExtractCallback = extractCallback;
|
||||
m_TestMode = testMode;
|
||||
|
||||
m_CurrentIndex = 0;
|
||||
m_FileIsOpen = false;
|
||||
}
|
||||
|
||||
HRESULT CChmFolderOutStream::OpenFile()
|
||||
{
|
||||
Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract) :
|
||||
NExtract::NAskMode::kSkip;
|
||||
m_RealOutStream.Release();
|
||||
RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
|
||||
if (!m_RealOutStream && !m_TestMode)
|
||||
askMode = NExtract::NAskMode::kSkip;
|
||||
return m_ExtractCallback->PrepareOperation(askMode);
|
||||
}
|
||||
|
||||
HRESULT CChmFolderOutStream::WriteEmptyFiles()
|
||||
{
|
||||
if (m_FileIsOpen)
|
||||
return S_OK;
|
||||
for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
|
||||
{
|
||||
UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);
|
||||
if (fileSize != 0)
|
||||
return S_OK;
|
||||
HRESULT result = OpenFile();
|
||||
m_RealOutStream.Release();
|
||||
RINOK(result);
|
||||
RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// This is WritePart function
|
||||
HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
|
||||
{
|
||||
UInt32 realProcessed = 0;
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
if (m_FileIsOpen)
|
||||
{
|
||||
UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));
|
||||
HRESULT res = S_OK;
|
||||
if (numBytesToWrite > 0)
|
||||
{
|
||||
if (!isOK)
|
||||
m_IsOk = false;
|
||||
if (m_RealOutStream)
|
||||
{
|
||||
UInt32 processedSizeLocal = 0;
|
||||
res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
|
||||
numBytesToWrite = processedSizeLocal;
|
||||
}
|
||||
}
|
||||
realProcessed += numBytesToWrite;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessed;
|
||||
data = (const void *)((const Byte *)data + numBytesToWrite);
|
||||
size -= numBytesToWrite;
|
||||
m_RemainFileSize -= numBytesToWrite;
|
||||
m_PosInSection += numBytesToWrite;
|
||||
m_PosInFolder += numBytesToWrite;
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
if (m_RemainFileSize == 0)
|
||||
{
|
||||
m_RealOutStream.Release();
|
||||
RINOK(m_ExtractCallback->SetOperationResult(
|
||||
m_IsOk ?
|
||||
NExtract::NOperationResult::kOK:
|
||||
NExtract::NOperationResult::kDataError));
|
||||
m_FileIsOpen = false;
|
||||
}
|
||||
if (realProcessed > 0)
|
||||
break; // with this break this function works as write part
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_CurrentIndex >= m_NumFiles)
|
||||
{
|
||||
realProcessed += size;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessed;
|
||||
return S_OK;
|
||||
// return E_FAIL;
|
||||
}
|
||||
|
||||
unsigned fullIndex = m_StartIndex + m_CurrentIndex;
|
||||
m_RemainFileSize = m_Database->GetFileSize(fullIndex);
|
||||
UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);
|
||||
if (fileOffset < m_PosInSection)
|
||||
return E_FAIL;
|
||||
|
||||
if (fileOffset > m_PosInSection)
|
||||
{
|
||||
UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size));
|
||||
realProcessed += numBytesToWrite;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessed;
|
||||
data = (const void *)((const Byte *)data + numBytesToWrite);
|
||||
size -= numBytesToWrite;
|
||||
m_PosInSection += numBytesToWrite;
|
||||
m_PosInFolder += numBytesToWrite;
|
||||
}
|
||||
|
||||
if (fileOffset == m_PosInSection)
|
||||
{
|
||||
RINOK(OpenFile());
|
||||
m_FileIsOpen = true;
|
||||
m_CurrentIndex++;
|
||||
m_IsOk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WriteEmptyFiles();
|
||||
}
|
||||
|
||||
STDMETHODIMP CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
return Write2(data, size, processedSize, true);
|
||||
}
|
||||
|
||||
HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize)
|
||||
{
|
||||
const UInt32 kBufferSize = (1 << 10);
|
||||
Byte buffer[kBufferSize];
|
||||
for (unsigned i = 0; i < kBufferSize; i++)
|
||||
buffer[i] = 0;
|
||||
if (maxSize > m_FolderSize)
|
||||
maxSize = m_FolderSize;
|
||||
while (m_PosInFolder < maxSize)
|
||||
{
|
||||
UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize);
|
||||
UInt32 processedSizeLocal = 0;
|
||||
RINOK(Write2(buffer, size, &processedSizeLocal, false));
|
||||
if (processedSizeLocal == 0)
|
||||
return S_OK;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
|
||||
if (allFilesMode)
|
||||
numItems = m_Database.NewFormat ? 1:
|
||||
(m_Database.LowLevel ?
|
||||
m_Database.Items.Size():
|
||||
m_Database.Indices.Size());
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
bool testMode = (testModeSpec != 0);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
UInt32 i;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(m_Stream);
|
||||
|
||||
if (m_Database.LowLevel)
|
||||
{
|
||||
UInt64 currentItemSize = 0;
|
||||
UInt64 totalSize = 0;
|
||||
|
||||
if (m_Database.NewFormat)
|
||||
totalSize = m_Database.NewFormatString.Len();
|
||||
else
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
|
||||
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
currentItemSize = 0;
|
||||
lps->InSize = currentTotalSize; // Change it
|
||||
lps->OutSize = currentTotalSize;
|
||||
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode= testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
|
||||
if (m_Database.NewFormat)
|
||||
{
|
||||
if (index != 0)
|
||||
return E_FAIL;
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
if (!testMode)
|
||||
{
|
||||
UInt32 size = m_Database.NewFormatString.Len();
|
||||
RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size));
|
||||
}
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
const CItem &item = m_Database.Items[index];
|
||||
|
||||
currentItemSize = item.Size;
|
||||
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (item.Section != 0)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (testMode)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
|
||||
NExtract::NOperationResult::kOK:
|
||||
NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UInt64 lastFolderIndex = ((UInt64)0 - 1);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = m_Database.Items[m_Database.Indices[index]];
|
||||
const UInt64 sectionIndex = item.Section;
|
||||
if (item.IsDir() || item.Size == 0)
|
||||
continue;
|
||||
if (sectionIndex == 0)
|
||||
{
|
||||
currentTotalSize += item.Size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sectionIndex >= m_Database.Sections.Size())
|
||||
continue;
|
||||
|
||||
const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex];
|
||||
if (section.IsLzx())
|
||||
{
|
||||
const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
|
||||
UInt64 folderIndex = m_Database.GetFolder(index);
|
||||
if (lastFolderIndex == folderIndex)
|
||||
folderIndex++;
|
||||
lastFolderIndex = m_Database.GetLastFolder(index);
|
||||
for (; folderIndex <= lastFolderIndex; folderIndex++)
|
||||
currentTotalSize += lzxInfo.GetFolderSize();
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(extractCallback->SetTotal(currentTotalSize));
|
||||
|
||||
NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
|
||||
CMyComPtr<IUnknown> lzxDecoder;
|
||||
CChmFolderOutStream *chmFolderOutStream = 0;
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
|
||||
currentTotalSize = 0;
|
||||
|
||||
CRecordVector<bool> extractStatuses;
|
||||
|
||||
CByteBuffer packBuf;
|
||||
|
||||
for (i = 0;;)
|
||||
{
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
|
||||
if (i >= numItems)
|
||||
break;
|
||||
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
i++;
|
||||
const CItem &item = m_Database.Items[m_Database.Indices[index]];
|
||||
const UInt64 sectionIndex = item.Section;
|
||||
Int32 askMode= testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
|
||||
if (item.IsDir())
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
lps->InSize = currentTotalSize; // Change it
|
||||
lps->OutSize = currentTotalSize;
|
||||
|
||||
if (item.Size == 0 || sectionIndex == 0)
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
if (!testMode && item.Size != 0)
|
||||
{
|
||||
RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize != item.Size)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
}
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(opRes));
|
||||
currentTotalSize += item.Size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sectionIndex >= m_Database.Sections.Size())
|
||||
{
|
||||
// we must report error here;
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError));
|
||||
continue;
|
||||
}
|
||||
|
||||
const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex];
|
||||
|
||||
if (!section.IsLzx())
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if (!testMode && !realOutStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod));
|
||||
continue;
|
||||
}
|
||||
|
||||
const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
|
||||
|
||||
if (!chmFolderOutStream)
|
||||
{
|
||||
chmFolderOutStream = new CChmFolderOutStream;
|
||||
outStream = chmFolderOutStream;
|
||||
}
|
||||
|
||||
chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
|
||||
|
||||
if (!lzxDecoderSpec)
|
||||
{
|
||||
lzxDecoderSpec = new NCompress::NLzx::CDecoder;
|
||||
lzxDecoder = lzxDecoderSpec;
|
||||
}
|
||||
|
||||
UInt64 folderIndex = m_Database.GetFolder(index);
|
||||
|
||||
const UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
|
||||
RINOK(lzxDecoderSpec->SetParams_and_Alloc(lzxInfo.GetNumDictBits()));
|
||||
|
||||
const CItem *lastItem = &item;
|
||||
extractStatuses.Clear();
|
||||
extractStatuses.Add(true);
|
||||
|
||||
for (;; folderIndex++)
|
||||
{
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
|
||||
UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
|
||||
UInt64 finishPos = lastItem->Offset + lastItem->Size;
|
||||
UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);
|
||||
|
||||
lastFolderIndex = m_Database.GetLastFolder(index);
|
||||
UInt64 folderSize = lzxInfo.GetFolderSize();
|
||||
UInt64 unPackSize = folderSize;
|
||||
|
||||
if (extractStatuses.IsEmpty())
|
||||
chmFolderOutStream->m_StartIndex = index + 1;
|
||||
else
|
||||
chmFolderOutStream->m_StartIndex = index;
|
||||
|
||||
if (limitFolderIndex == folderIndex)
|
||||
{
|
||||
for (; i < numItems; i++)
|
||||
{
|
||||
const UInt32 nextIndex = allFilesMode ? i : indices[i];
|
||||
const CItem &nextItem = m_Database.Items[m_Database.Indices[nextIndex]];
|
||||
if (nextItem.Section != sectionIndex)
|
||||
break;
|
||||
UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex);
|
||||
if (nextFolderIndex != folderIndex)
|
||||
break;
|
||||
for (index++; index < nextIndex; index++)
|
||||
extractStatuses.Add(false);
|
||||
extractStatuses.Add(true);
|
||||
index = nextIndex;
|
||||
lastItem = &nextItem;
|
||||
if (nextItem.Size != 0)
|
||||
finishPos = nextItem.Offset + nextItem.Size;
|
||||
lastFolderIndex = m_Database.GetLastFolder(index);
|
||||
}
|
||||
}
|
||||
|
||||
unPackSize = MyMin(finishPos - startPos, unPackSize);
|
||||
|
||||
chmFolderOutStream->m_FolderSize = folderSize;
|
||||
chmFolderOutStream->m_PosInFolder = 0;
|
||||
chmFolderOutStream->m_PosInSection = startPos;
|
||||
chmFolderOutStream->m_ExtractStatuses = &extractStatuses;
|
||||
chmFolderOutStream->m_NumFiles = extractStatuses.Size();
|
||||
chmFolderOutStream->m_CurrentIndex = 0;
|
||||
|
||||
try
|
||||
{
|
||||
UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
|
||||
const CResetTable &rt = lzxInfo.ResetTable;
|
||||
UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize);
|
||||
|
||||
for (UInt32 b = 0; b < numBlocks; b++)
|
||||
{
|
||||
UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos;
|
||||
RINOK(extractCallback->SetCompleted(&completedSize));
|
||||
UInt64 bCur = startBlock + b;
|
||||
if (bCur >= rt.ResetOffsets.Size())
|
||||
return E_FAIL;
|
||||
UInt64 offset = rt.ResetOffsets[(unsigned)bCur];
|
||||
UInt64 compressedSize;
|
||||
rt.GetCompressedSizeOfBlock(bCur, compressedSize);
|
||||
|
||||
// chm writes full blocks. So we don't need to use reduced size for last block
|
||||
|
||||
RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->SetStream(m_Stream);
|
||||
streamSpec->Init(compressedSize);
|
||||
|
||||
lzxDecoderSpec->SetKeepHistory(b > 0);
|
||||
|
||||
size_t compressedSizeT = (size_t)compressedSize;
|
||||
if (compressedSizeT != compressedSize)
|
||||
throw 2;
|
||||
packBuf.AllocAtLeast(compressedSizeT);
|
||||
|
||||
HRESULT res = ReadStream_FALSE(inStream, packBuf, compressedSizeT);
|
||||
|
||||
if (res == S_OK)
|
||||
{
|
||||
lzxDecoderSpec->KeepHistoryForNext = true;
|
||||
res = lzxDecoderSpec->Code(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize;
|
||||
if (res == S_OK)
|
||||
res = WriteStream(chmFolderOutStream,
|
||||
lzxDecoderSpec->GetUnpackData(),
|
||||
lzxDecoderSpec->GetUnpackSize());
|
||||
}
|
||||
|
||||
if (res != S_OK)
|
||||
{
|
||||
if (res != S_FALSE)
|
||||
return res;
|
||||
throw 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
RINOK(chmFolderOutStream->FlushCorrupted(unPackSize));
|
||||
}
|
||||
|
||||
currentTotalSize += folderSize;
|
||||
if (folderIndex == lastFolderIndex)
|
||||
break;
|
||||
extractStatuses.Clear();
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = m_Database.NewFormat ? 1:
|
||||
(m_Database.LowLevel ?
|
||||
m_Database.Items.Size():
|
||||
m_Database.Indices.Size());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
namespace NChm {
|
||||
|
||||
static const Byte k_Signature[] = { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 };
|
||||
|
||||
REGISTER_ARC_I_CLS(
|
||||
CHandler(false),
|
||||
"Chm", "chm chi chq chw", 0, 0xE9,
|
||||
k_Signature,
|
||||
0,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}
|
||||
|
||||
namespace NHxs {
|
||||
|
||||
static const Byte k_Signature[] = { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 };
|
||||
|
||||
REGISTER_ARC_I_CLS(
|
||||
CHandler(true),
|
||||
"Hxs", "hxs hxi hxr hxq hxw lit", 0, 0xCE,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kFindSignature,
|
||||
NULL)
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
35
CPP/7zip/Archive/Chm/ChmHandler.h
Normal file
35
CPP/7zip/Archive/Chm/ChmHandler.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// ChmHandler.h
|
||||
|
||||
#ifndef __ARCHIVE_CHM_HANDLER_H
|
||||
#define __ARCHIVE_CHM_HANDLER_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "ChmIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NChm {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
bool _help2;
|
||||
CHandler(bool help2): _help2(help2) {}
|
||||
|
||||
private:
|
||||
CFilesDatabase m_Database;
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
UInt32 m_ErrorFlags;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
1055
CPP/7zip/Archive/Chm/ChmIn.cpp
Normal file
1055
CPP/7zip/Archive/Chm/ChmIn.cpp
Normal file
File diff suppressed because it is too large
Load Diff
270
CPP/7zip/Archive/Chm/ChmIn.h
Normal file
270
CPP/7zip/Archive/Chm/ChmIn.h
Normal file
@@ -0,0 +1,270 @@
|
||||
// Archive/ChmIn.h
|
||||
|
||||
#ifndef __ARCHIVE_CHM_IN_H
|
||||
#define __ARCHIVE_CHM_IN_H
|
||||
|
||||
#include "../../../Common/MyBuffer.h"
|
||||
#include "../../../Common/MyString.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "../../Common/InBuffer.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NChm {
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UInt64 Section;
|
||||
UInt64 Offset;
|
||||
UInt64 Size;
|
||||
AString Name;
|
||||
|
||||
bool IsFormatRelatedItem() const
|
||||
{
|
||||
if (Name.Len() < 2)
|
||||
return false;
|
||||
return Name[0] == ':' && Name[1] == ':';
|
||||
}
|
||||
|
||||
bool IsUserItem() const
|
||||
{
|
||||
if (Name.Len() < 2)
|
||||
return false;
|
||||
return Name[0] == '/';
|
||||
}
|
||||
|
||||
bool IsDir() const
|
||||
{
|
||||
if (Name.IsEmpty())
|
||||
return false;
|
||||
return (Name.Back() == '/');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CDatabase
|
||||
{
|
||||
UInt64 StartPosition;
|
||||
UInt64 ContentOffset;
|
||||
CObjectVector<CItem> Items;
|
||||
AString NewFormatString;
|
||||
bool Help2Format;
|
||||
bool NewFormat;
|
||||
UInt64 PhySize;
|
||||
|
||||
void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; }
|
||||
|
||||
int FindItem(const AString &name) const
|
||||
{
|
||||
FOR_VECTOR (i, Items)
|
||||
if (Items[i].Name == name)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
NewFormat = false;
|
||||
NewFormatString.Empty();
|
||||
Help2Format = false;
|
||||
Items.Clear();
|
||||
StartPosition = 0;
|
||||
PhySize = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const UInt32 kBlockSize = 1 << 15;
|
||||
|
||||
struct CResetTable
|
||||
{
|
||||
UInt64 UncompressedSize;
|
||||
UInt64 CompressedSize;
|
||||
// unsigned BlockSizeBits;
|
||||
CRecordVector<UInt64> ResetOffsets;
|
||||
|
||||
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
|
||||
{
|
||||
if (blockIndex >= ResetOffsets.Size())
|
||||
return false;
|
||||
UInt64 startPos = ResetOffsets[(unsigned)blockIndex];
|
||||
if (blockIndex + numBlocks >= ResetOffsets.Size())
|
||||
size = CompressedSize - startPos;
|
||||
else
|
||||
size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
|
||||
{
|
||||
return GetCompressedSizeOfBlocks(blockIndex, 1, size);
|
||||
}
|
||||
|
||||
UInt64 GetNumBlocks(UInt64 size) const
|
||||
{
|
||||
return (size + kBlockSize - 1) / kBlockSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CLzxInfo
|
||||
{
|
||||
UInt32 Version;
|
||||
|
||||
unsigned ResetIntervalBits;
|
||||
unsigned WindowSizeBits;
|
||||
UInt32 CacheSize;
|
||||
|
||||
CResetTable ResetTable;
|
||||
|
||||
unsigned GetNumDictBits() const
|
||||
{
|
||||
if (Version == 2 || Version == 3)
|
||||
return 15 + WindowSizeBits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
UInt64 GetFolderSize() const { return kBlockSize << ResetIntervalBits; }
|
||||
UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); }
|
||||
UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); }
|
||||
UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; }
|
||||
|
||||
bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
|
||||
{
|
||||
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
|
||||
if (blockIndex >= ResetTable.ResetOffsets.Size())
|
||||
return false;
|
||||
offset = ResetTable.ResetOffsets[(unsigned)blockIndex];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
|
||||
{
|
||||
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
|
||||
return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CMethodInfo
|
||||
{
|
||||
GUID Guid;
|
||||
CByteBuffer ControlData;
|
||||
CLzxInfo LzxInfo;
|
||||
|
||||
bool IsLzx() const;
|
||||
bool IsDes() const;
|
||||
AString GetGuidString() const;
|
||||
UString GetName() const;
|
||||
};
|
||||
|
||||
|
||||
struct CSectionInfo
|
||||
{
|
||||
UInt64 Offset;
|
||||
UInt64 CompressedSize;
|
||||
UInt64 UncompressedSize;
|
||||
|
||||
AString Name;
|
||||
CObjectVector<CMethodInfo> Methods;
|
||||
|
||||
bool IsLzx() const;
|
||||
UString GetMethodName() const;
|
||||
};
|
||||
|
||||
class CFilesDatabase: public CDatabase
|
||||
{
|
||||
public:
|
||||
bool LowLevel;
|
||||
CUIntVector Indices;
|
||||
CObjectVector<CSectionInfo> Sections;
|
||||
|
||||
UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; }
|
||||
UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; }
|
||||
|
||||
UInt64 GetFolder(unsigned fileIndex) const
|
||||
{
|
||||
const CItem &item = Items[Indices[fileIndex]];
|
||||
if (item.Section < Sections.Size())
|
||||
{
|
||||
const CSectionInfo §ion = Sections[(unsigned)item.Section];
|
||||
if (section.IsLzx())
|
||||
return section.Methods[0].LzxInfo.GetFolder(item.Offset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
UInt64 GetLastFolder(unsigned fileIndex) const
|
||||
{
|
||||
const CItem &item = Items[Indices[fileIndex]];
|
||||
if (item.Section < Sections.Size())
|
||||
{
|
||||
const CSectionInfo §ion = Sections[(unsigned)item.Section];
|
||||
if (section.IsLzx())
|
||||
return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HighLevelClear()
|
||||
{
|
||||
LowLevel = true;
|
||||
Indices.Clear();
|
||||
Sections.Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
CDatabase::Clear();
|
||||
HighLevelClear();
|
||||
}
|
||||
|
||||
void SetIndices();
|
||||
void Sort();
|
||||
bool Check();
|
||||
bool CheckSectionRefs();
|
||||
};
|
||||
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> m_InStreamRef;
|
||||
::CInBuffer _inBuffer;
|
||||
UInt64 _chunkSize;
|
||||
bool _help2;
|
||||
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, UInt32 size);
|
||||
void Skip(size_t size);
|
||||
UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
UInt64 ReadEncInt();
|
||||
void ReadString(unsigned size, AString &s);
|
||||
void ReadUString(unsigned size, UString &s);
|
||||
void ReadGUID(GUID &g);
|
||||
|
||||
HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size);
|
||||
|
||||
HRESULT ReadDirEntry(CDatabase &database);
|
||||
HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name);
|
||||
|
||||
public:
|
||||
bool IsArc;
|
||||
bool HeadersError;
|
||||
bool UnexpectedEnd;
|
||||
bool UnsupportedFeature;
|
||||
|
||||
CInArchive(bool help2) { _help2 = help2; }
|
||||
|
||||
HRESULT OpenChm(IInStream *inStream, CDatabase &database);
|
||||
HRESULT OpenHelp2(IInStream *inStream, CDatabase &database);
|
||||
HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database);
|
||||
HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
|
||||
HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
8
CPP/7zip/Archive/Chm/StdAfx.h
Normal file
8
CPP/7zip/Archive/Chm/StdAfx.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
886
CPP/7zip/Archive/ComHandler.cpp
Normal file
886
CPP/7zip/Archive/ComHandler.cpp
Normal file
@@ -0,0 +1,886 @@
|
||||
// ComHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/IntToString.h"
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/MyCom.h"
|
||||
#include "../../Common/MyBuffer.h"
|
||||
#include "../../Common/MyString.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCom {
|
||||
|
||||
#define SIGNATURE { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }
|
||||
static const Byte kSignature[] = SIGNATURE;
|
||||
|
||||
enum EType
|
||||
{
|
||||
k_Type_Common,
|
||||
k_Type_Msi,
|
||||
k_Type_Msp,
|
||||
k_Type_Doc,
|
||||
k_Type_Ppt,
|
||||
k_Type_Xls,
|
||||
};
|
||||
|
||||
static const char * const kExtensions[] =
|
||||
{
|
||||
"compound"
|
||||
, "msi"
|
||||
, "msp"
|
||||
, "doc"
|
||||
, "ppt"
|
||||
, "xls"
|
||||
};
|
||||
|
||||
namespace NFatID
|
||||
{
|
||||
static const UInt32 kFree = 0xFFFFFFFF;
|
||||
static const UInt32 kEndOfChain = 0xFFFFFFFE;
|
||||
static const UInt32 kFatSector = 0xFFFFFFFD;
|
||||
static const UInt32 kMatSector = 0xFFFFFFFC;
|
||||
static const UInt32 kMaxValue = 0xFFFFFFFA;
|
||||
}
|
||||
|
||||
namespace NItemType
|
||||
{
|
||||
static const Byte kEmpty = 0;
|
||||
static const Byte kStorage = 1;
|
||||
static const Byte kStream = 2;
|
||||
static const Byte kLockBytes = 3;
|
||||
static const Byte kProperty = 4;
|
||||
static const Byte kRootStorage = 5;
|
||||
}
|
||||
|
||||
static const UInt32 kNameSizeMax = 64;
|
||||
|
||||
struct CItem
|
||||
{
|
||||
Byte Name[kNameSizeMax];
|
||||
// UInt16 NameSize;
|
||||
// UInt32 Flags;
|
||||
FILETIME CTime;
|
||||
FILETIME MTime;
|
||||
UInt64 Size;
|
||||
UInt32 LeftDid;
|
||||
UInt32 RightDid;
|
||||
UInt32 SonDid;
|
||||
UInt32 Sid;
|
||||
Byte Type;
|
||||
|
||||
bool IsEmpty() const { return Type == NItemType::kEmpty; }
|
||||
bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
|
||||
|
||||
void Parse(const Byte *p, bool mode64bit);
|
||||
};
|
||||
|
||||
struct CRef
|
||||
{
|
||||
int Parent;
|
||||
UInt32 Did;
|
||||
};
|
||||
|
||||
class CDatabase
|
||||
{
|
||||
UInt32 NumSectorsInMiniStream;
|
||||
CObjArray<UInt32> MiniSids;
|
||||
|
||||
HRESULT AddNode(int parent, UInt32 did);
|
||||
public:
|
||||
|
||||
CObjArray<UInt32> Fat;
|
||||
UInt32 FatSize;
|
||||
|
||||
CObjArray<UInt32> Mat;
|
||||
UInt32 MatSize;
|
||||
|
||||
CObjectVector<CItem> Items;
|
||||
CRecordVector<CRef> Refs;
|
||||
|
||||
UInt32 LongStreamMinSize;
|
||||
unsigned SectorSizeBits;
|
||||
unsigned MiniSectorSizeBits;
|
||||
|
||||
Int32 MainSubfile;
|
||||
|
||||
UInt64 PhySize;
|
||||
EType Type;
|
||||
|
||||
bool IsNotArcType() const
|
||||
{
|
||||
return
|
||||
Type != k_Type_Msi &&
|
||||
Type != k_Type_Msp;
|
||||
}
|
||||
|
||||
void UpdatePhySize(UInt64 val)
|
||||
{
|
||||
if (PhySize < val)
|
||||
PhySize = val;
|
||||
}
|
||||
HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid);
|
||||
HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest);
|
||||
|
||||
HRESULT Update_PhySize_WithItem(unsigned index);
|
||||
|
||||
void Clear();
|
||||
bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
|
||||
UString GetItemPath(UInt32 index) const;
|
||||
|
||||
UInt64 GetItemPackSize(UInt64 size) const
|
||||
{
|
||||
UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
|
||||
return (size + mask) & ~mask;
|
||||
}
|
||||
|
||||
bool GetMiniCluster(UInt32 sid, UInt64 &res) const
|
||||
{
|
||||
unsigned subBits = SectorSizeBits - MiniSectorSizeBits;
|
||||
UInt32 fid = sid >> subBits;
|
||||
if (fid >= NumSectorsInMiniStream)
|
||||
return false;
|
||||
res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT Open(IInStream *inStream);
|
||||
};
|
||||
|
||||
|
||||
HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid)
|
||||
{
|
||||
UpdatePhySize(((UInt64)sid + 2) << sectorSizeBits);
|
||||
RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL));
|
||||
return ReadStream_FALSE(inStream, buf, (size_t)1 << sectorSizeBits);
|
||||
}
|
||||
|
||||
HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest)
|
||||
{
|
||||
RINOK(ReadSector(inStream, buf, sectorSizeBits, sid));
|
||||
UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
|
||||
for (UInt32 t = 0; t < sectorSize; t += 4)
|
||||
*dest++ = Get32(buf + t);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
|
||||
{
|
||||
ft->dwLowDateTime = Get32(p);
|
||||
ft->dwHighDateTime = Get32(p + 4);
|
||||
}
|
||||
|
||||
void CItem::Parse(const Byte *p, bool mode64bit)
|
||||
{
|
||||
memcpy(Name, p, kNameSizeMax);
|
||||
// NameSize = Get16(p + 64);
|
||||
Type = p[66];
|
||||
LeftDid = Get32(p + 68);
|
||||
RightDid = Get32(p + 72);
|
||||
SonDid = Get32(p + 76);
|
||||
// Flags = Get32(p + 96);
|
||||
GetFileTimeFromMem(p + 100, &CTime);
|
||||
GetFileTimeFromMem(p + 108, &MTime);
|
||||
Sid = Get32(p + 116);
|
||||
Size = Get32(p + 120);
|
||||
if (mode64bit)
|
||||
Size |= ((UInt64)Get32(p + 124) << 32);
|
||||
}
|
||||
|
||||
void CDatabase::Clear()
|
||||
{
|
||||
PhySize = 0;
|
||||
|
||||
Fat.Free();
|
||||
MiniSids.Free();
|
||||
Mat.Free();
|
||||
Items.Clear();
|
||||
Refs.Clear();
|
||||
}
|
||||
|
||||
static const UInt32 kNoDid = 0xFFFFFFFF;
|
||||
|
||||
HRESULT CDatabase::AddNode(int parent, UInt32 did)
|
||||
{
|
||||
if (did == kNoDid)
|
||||
return S_OK;
|
||||
if (did >= (UInt32)Items.Size())
|
||||
return S_FALSE;
|
||||
const CItem &item = Items[did];
|
||||
if (item.IsEmpty())
|
||||
return S_FALSE;
|
||||
CRef ref;
|
||||
ref.Parent = parent;
|
||||
ref.Did = did;
|
||||
int index = Refs.Add(ref);
|
||||
if (Refs.Size() > Items.Size())
|
||||
return S_FALSE;
|
||||
RINOK(AddNode(parent, item.LeftDid));
|
||||
RINOK(AddNode(parent, item.RightDid));
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(AddNode(index, item.SonDid));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const wchar_t kCharOpenBracket = L'[';
|
||||
static const wchar_t kCharCloseBracket = L']';
|
||||
|
||||
static UString CompoundNameToFileName(const UString &s)
|
||||
{
|
||||
UString res;
|
||||
for (unsigned i = 0; i < s.Len(); i++)
|
||||
{
|
||||
wchar_t c = s[i];
|
||||
if (c < 0x20)
|
||||
{
|
||||
res += kCharOpenBracket;
|
||||
wchar_t buf[32];
|
||||
ConvertUInt32ToString(c, buf);
|
||||
res += buf;
|
||||
res += kCharCloseBracket;
|
||||
}
|
||||
else
|
||||
res += c;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char k_Msi_Chars[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
|
||||
|
||||
// static const char *k_Msi_ID = ""; // "{msi}";
|
||||
static const wchar_t k_Msi_SpecChar = L'!';
|
||||
|
||||
static const unsigned k_Msi_NumBits = 6;
|
||||
static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits;
|
||||
static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1;
|
||||
static const unsigned k_Msi_StartUnicodeChar = 0x3800;
|
||||
static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1);
|
||||
|
||||
|
||||
static bool IsMsiName(const Byte *p)
|
||||
{
|
||||
UInt32 c = Get16(p);
|
||||
return
|
||||
c >= k_Msi_StartUnicodeChar &&
|
||||
c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange;
|
||||
}
|
||||
|
||||
static bool AreEqualNames(const Byte *rawName, const char *asciiName)
|
||||
{
|
||||
for (unsigned i = 0; i < kNameSizeMax / 2; i++)
|
||||
{
|
||||
wchar_t c = Get16(rawName + i * 2);
|
||||
wchar_t c2 = (Byte)asciiName[i];
|
||||
if (c != c2)
|
||||
return false;
|
||||
if (c == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CompoundMsiNameToFileName(const UString &name, UString &res)
|
||||
{
|
||||
res.Empty();
|
||||
for (unsigned i = 0; i < name.Len(); i++)
|
||||
{
|
||||
wchar_t c = name[i];
|
||||
if (c < k_Msi_StartUnicodeChar || c > k_Msi_StartUnicodeChar + k_Msi_UnicodeRange)
|
||||
return false;
|
||||
/*
|
||||
if (i == 0)
|
||||
res += k_Msi_ID;
|
||||
*/
|
||||
c -= k_Msi_StartUnicodeChar;
|
||||
|
||||
unsigned c0 = (unsigned)c & k_Msi_CharMask;
|
||||
unsigned c1 = (unsigned)c >> k_Msi_NumBits;
|
||||
|
||||
if (c1 <= k_Msi_NumChars)
|
||||
{
|
||||
res += (wchar_t)(Byte)k_Msi_Chars[c0];
|
||||
if (c1 == k_Msi_NumChars)
|
||||
break;
|
||||
res += (wchar_t)(Byte)k_Msi_Chars[c1];
|
||||
}
|
||||
else
|
||||
res += k_Msi_SpecChar;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static UString ConvertName(const Byte *p, bool &isMsi)
|
||||
{
|
||||
isMsi = false;
|
||||
UString s;
|
||||
|
||||
for (unsigned i = 0; i < kNameSizeMax; i += 2)
|
||||
{
|
||||
wchar_t c = Get16(p + i);
|
||||
if (c == 0)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
|
||||
UString msiName;
|
||||
if (CompoundMsiNameToFileName(s, msiName))
|
||||
{
|
||||
isMsi = true;
|
||||
return msiName;
|
||||
}
|
||||
return CompoundNameToFileName(s);
|
||||
}
|
||||
|
||||
static UString ConvertName(const Byte *p)
|
||||
{
|
||||
bool isMsi;
|
||||
return ConvertName(p, isMsi);
|
||||
}
|
||||
|
||||
UString CDatabase::GetItemPath(UInt32 index) const
|
||||
{
|
||||
UString s;
|
||||
while (index != kNoDid)
|
||||
{
|
||||
const CRef &ref = Refs[index];
|
||||
const CItem &item = Items[ref.Did];
|
||||
if (!s.IsEmpty())
|
||||
s.InsertAtFront(WCHAR_PATH_SEPARATOR);
|
||||
s.Insert(0, ConvertName(item.Name));
|
||||
index = ref.Parent;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
HRESULT CDatabase::Update_PhySize_WithItem(unsigned index)
|
||||
{
|
||||
const CItem &item = Items[index];
|
||||
bool isLargeStream = (index == 0 || IsLargeStream(item.Size));
|
||||
if (!isLargeStream)
|
||||
return S_OK;
|
||||
unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits;
|
||||
// streamSpec->Size = item.Size;
|
||||
|
||||
UInt32 clusterSize = (UInt32)1 << bsLog;
|
||||
UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
|
||||
if (numClusters64 >= ((UInt32)1 << 31))
|
||||
return S_FALSE;
|
||||
UInt32 sid = item.Sid;
|
||||
UInt64 size = item.Size;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
for (;; size -= clusterSize)
|
||||
{
|
||||
// if (isLargeStream)
|
||||
{
|
||||
if (sid >= FatSize)
|
||||
return S_FALSE;
|
||||
UpdatePhySize(((UInt64)sid + 2) << bsLog);
|
||||
sid = Fat[sid];
|
||||
}
|
||||
if (size <= clusterSize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sid != NFatID::kEndOfChain)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// There is name "[!]MsiPatchSequence" in msp files
|
||||
static const unsigned kMspSequence_Size = 18;
|
||||
static const Byte kMspSequence[kMspSequence_Size] =
|
||||
{ 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45,
|
||||
0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41,
|
||||
0x37, 0x41 };
|
||||
|
||||
HRESULT CDatabase::Open(IInStream *inStream)
|
||||
{
|
||||
MainSubfile = -1;
|
||||
Type = k_Type_Common;
|
||||
const UInt32 kHeaderSize = 512;
|
||||
Byte p[kHeaderSize];
|
||||
PhySize = kHeaderSize;
|
||||
RINOK(ReadStream_FALSE(inStream, p, kHeaderSize));
|
||||
if (memcmp(p, kSignature, ARRAY_SIZE(kSignature)) != 0)
|
||||
return S_FALSE;
|
||||
if (Get16(p + 0x1A) > 4) // majorVer
|
||||
return S_FALSE;
|
||||
if (Get16(p + 0x1C) != 0xFFFE) // Little-endian
|
||||
return S_FALSE;
|
||||
unsigned sectorSizeBits = Get16(p + 0x1E);
|
||||
bool mode64bit = (sectorSizeBits >= 12);
|
||||
unsigned miniSectorSizeBits = Get16(p + 0x20);
|
||||
SectorSizeBits = sectorSizeBits;
|
||||
MiniSectorSizeBits = miniSectorSizeBits;
|
||||
|
||||
if (sectorSizeBits > 24 ||
|
||||
sectorSizeBits < 7 ||
|
||||
miniSectorSizeBits > 24 ||
|
||||
miniSectorSizeBits < 2 ||
|
||||
miniSectorSizeBits > sectorSizeBits)
|
||||
return S_FALSE;
|
||||
UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT
|
||||
LongStreamMinSize = Get32(p + 0x38);
|
||||
|
||||
UInt32 sectSize = (UInt32)1 << sectorSizeBits;
|
||||
|
||||
CByteBuffer sect(sectSize);
|
||||
|
||||
unsigned ssb2 = sectorSizeBits - 2;
|
||||
UInt32 numSidsInSec = (UInt32)1 << ssb2;
|
||||
UInt32 numFatItems = numSectorsForFAT << ssb2;
|
||||
if ((numFatItems >> ssb2) != numSectorsForFAT)
|
||||
return S_FALSE;
|
||||
FatSize = numFatItems;
|
||||
|
||||
{
|
||||
UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table
|
||||
const UInt32 kNumHeaderBatItems = 109;
|
||||
UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
|
||||
if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
|
||||
return S_FALSE;
|
||||
CObjArray<UInt32> bat(numBatItems);
|
||||
UInt32 i;
|
||||
for (i = 0; i < kNumHeaderBatItems; i++)
|
||||
bat[i] = Get32(p + 0x4c + i * 4);
|
||||
UInt32 sid = Get32(p + 0x44);
|
||||
for (UInt32 s = 0; s < numSectorsForBat; s++)
|
||||
{
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i));
|
||||
i += numSidsInSec - 1;
|
||||
sid = bat[i];
|
||||
}
|
||||
numBatItems = i;
|
||||
|
||||
Fat.Alloc(numFatItems);
|
||||
UInt32 j = 0;
|
||||
|
||||
for (i = 0; i < numFatItems; j++, i += numSidsInSec)
|
||||
{
|
||||
if (j >= numBatItems)
|
||||
return S_FALSE;
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i));
|
||||
}
|
||||
FatSize = numFatItems = i;
|
||||
}
|
||||
|
||||
UInt32 numMatItems;
|
||||
{
|
||||
UInt32 numSectorsForMat = Get32(p + 0x40);
|
||||
numMatItems = (UInt32)numSectorsForMat << ssb2;
|
||||
if ((numMatItems >> ssb2) != numSectorsForMat)
|
||||
return S_FALSE;
|
||||
Mat.Alloc(numMatItems);
|
||||
UInt32 i;
|
||||
UInt32 sid = Get32(p + 0x3C); // short-sector table SID
|
||||
for (i = 0; i < numMatItems; i += numSidsInSec)
|
||||
{
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i));
|
||||
if (sid >= numFatItems)
|
||||
return S_FALSE;
|
||||
sid = Fat[sid];
|
||||
}
|
||||
if (sid != NFatID::kEndOfChain)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
CByteBuffer used(numFatItems);
|
||||
for (UInt32 i = 0; i < numFatItems; i++)
|
||||
used[i] = 0;
|
||||
UInt32 sid = Get32(p + 0x30); // directory stream SID
|
||||
for (;;)
|
||||
{
|
||||
if (sid >= numFatItems)
|
||||
return S_FALSE;
|
||||
if (used[sid])
|
||||
return S_FALSE;
|
||||
used[sid] = 1;
|
||||
RINOK(ReadSector(inStream, sect, sectorSizeBits, sid));
|
||||
for (UInt32 i = 0; i < sectSize; i += 128)
|
||||
{
|
||||
CItem item;
|
||||
item.Parse(sect + i, mode64bit);
|
||||
Items.Add(item);
|
||||
}
|
||||
sid = Fat[sid];
|
||||
if (sid == NFatID::kEndOfChain)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const CItem &root = Items[0];
|
||||
|
||||
{
|
||||
UInt32 numSectorsInMiniStream;
|
||||
{
|
||||
UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
|
||||
if (numSatSects64 > NFatID::kMaxValue)
|
||||
return S_FALSE;
|
||||
numSectorsInMiniStream = (UInt32)numSatSects64;
|
||||
}
|
||||
NumSectorsInMiniStream = numSectorsInMiniStream;
|
||||
MiniSids.Alloc(numSectorsInMiniStream);
|
||||
{
|
||||
UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
|
||||
if (matSize64 > NFatID::kMaxValue)
|
||||
return S_FALSE;
|
||||
MatSize = (UInt32)matSize64;
|
||||
if (numMatItems < MatSize)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
UInt32 sid = root.Sid;
|
||||
for (UInt32 i = 0; ; i++)
|
||||
{
|
||||
if (sid == NFatID::kEndOfChain)
|
||||
{
|
||||
if (i != numSectorsInMiniStream)
|
||||
return S_FALSE;
|
||||
break;
|
||||
}
|
||||
if (i >= numSectorsInMiniStream)
|
||||
return S_FALSE;
|
||||
MiniSids[i] = sid;
|
||||
if (sid >= numFatItems)
|
||||
return S_FALSE;
|
||||
sid = Fat[sid];
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(AddNode(-1, root.SonDid));
|
||||
|
||||
unsigned numCabs = 0;
|
||||
|
||||
FOR_VECTOR (i, Refs)
|
||||
{
|
||||
const CItem &item = Items[Refs[i].Did];
|
||||
if (item.IsDir() || numCabs > 1)
|
||||
continue;
|
||||
bool isMsiName;
|
||||
const UString msiName = ConvertName(item.Name, isMsiName);
|
||||
if (isMsiName && !msiName.IsEmpty())
|
||||
{
|
||||
// bool isThereExt = (msiName.Find(L'.') >= 0);
|
||||
bool isMsiSpec = (msiName[0] == k_Msi_SpecChar);
|
||||
if (msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab")
|
||||
|| !isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe")
|
||||
// || !isMsiSpec && !isThereExt
|
||||
)
|
||||
|
||||
{
|
||||
numCabs++;
|
||||
MainSubfile = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numCabs > 1)
|
||||
MainSubfile = -1;
|
||||
|
||||
{
|
||||
FOR_VECTOR (t, Items)
|
||||
{
|
||||
Update_PhySize_WithItem(t);
|
||||
}
|
||||
}
|
||||
{
|
||||
FOR_VECTOR (t, Items)
|
||||
{
|
||||
const CItem &item = Items[t];
|
||||
|
||||
if (IsMsiName(item.Name))
|
||||
{
|
||||
Type = k_Type_Msi;
|
||||
if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0)
|
||||
{
|
||||
Type = k_Type_Msp;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (AreEqualNames(item.Name, "WordDocument"))
|
||||
{
|
||||
Type = k_Type_Doc;
|
||||
break;
|
||||
}
|
||||
if (AreEqualNames(item.Name, "PowerPoint Document"))
|
||||
{
|
||||
Type = k_Type_Ppt;
|
||||
break;
|
||||
}
|
||||
if (AreEqualNames(item.Name, "Workbook"))
|
||||
{
|
||||
Type = k_Type_Xls;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CDatabase _db;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidSize,
|
||||
kpidPackSize,
|
||||
kpidCTime,
|
||||
kpidMTime
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidExtension,
|
||||
kpidClusterSize,
|
||||
kpidSectorSize
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break;
|
||||
case kpidPhySize: prop = _db.PhySize; break;
|
||||
case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
|
||||
case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
|
||||
case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
|
||||
case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
const CRef &ref = _db.Refs[index];
|
||||
const CItem &item = _db.Items[ref.Did];
|
||||
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath: prop = _db.GetItemPath(index); break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidCTime: prop = item.CTime; break;
|
||||
case kpidMTime: prop = item.MTime; break;
|
||||
case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
|
||||
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
try
|
||||
{
|
||||
if (_db.Open(inStream) != S_OK)
|
||||
return S_FALSE;
|
||||
_stream = inStream;
|
||||
}
|
||||
catch(...) { return S_FALSE; }
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_db.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _db.Refs.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt32 i;
|
||||
UInt64 totalSize = 0;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
|
||||
if (!item.IsDir())
|
||||
totalSize += item.Size;
|
||||
}
|
||||
RINOK(extractCallback->SetTotal(totalSize));
|
||||
|
||||
UInt64 totalPackSize;
|
||||
totalSize = totalPackSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = totalPackSize;
|
||||
lps->OutSize = totalSize;
|
||||
RINOK(lps->SetCur());
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = _db.Items[_db.Refs[index].Did];
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
totalPackSize += _db.GetItemPackSize(item.Size);
|
||||
totalSize += item.Size;
|
||||
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
Int32 res = NExtract::NOperationResult::kDataError;
|
||||
CMyComPtr<ISequentialInStream> inStream;
|
||||
HRESULT hres = GetStream(index, &inStream);
|
||||
if (hres == S_FALSE)
|
||||
res = NExtract::NOperationResult::kDataError;
|
||||
else if (hres == E_NOTIMPL)
|
||||
res = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
else
|
||||
{
|
||||
RINOK(hres);
|
||||
if (inStream)
|
||||
{
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize == item.Size)
|
||||
res = NExtract::NOperationResult::kOK;
|
||||
}
|
||||
}
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(res));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _db.Refs.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = 0;
|
||||
UInt32 itemIndex = _db.Refs[index].Did;
|
||||
const CItem &item = _db.Items[itemIndex];
|
||||
CClusterInStream *streamSpec = new CClusterInStream;
|
||||
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
|
||||
streamSpec->Stream = _stream;
|
||||
streamSpec->StartOffset = 0;
|
||||
|
||||
bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size));
|
||||
int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
|
||||
streamSpec->BlockSizeLog = bsLog;
|
||||
streamSpec->Size = item.Size;
|
||||
|
||||
UInt32 clusterSize = (UInt32)1 << bsLog;
|
||||
UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
|
||||
if (numClusters64 >= ((UInt32)1 << 31))
|
||||
return E_NOTIMPL;
|
||||
streamSpec->Vector.ClearAndReserve((unsigned)numClusters64);
|
||||
UInt32 sid = item.Sid;
|
||||
UInt64 size = item.Size;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
for (;; size -= clusterSize)
|
||||
{
|
||||
if (isLargeStream)
|
||||
{
|
||||
if (sid >= _db.FatSize)
|
||||
return S_FALSE;
|
||||
streamSpec->Vector.AddInReserved(sid + 1);
|
||||
sid = _db.Fat[sid];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 val = 0;
|
||||
if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
|
||||
return S_FALSE;
|
||||
streamSpec->Vector.AddInReserved((UInt32)val);
|
||||
sid = _db.Mat[sid];
|
||||
}
|
||||
if (size <= clusterSize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sid != NFatID::kEndOfChain)
|
||||
return S_FALSE;
|
||||
RINOK(streamSpec->InitAndSeek());
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"Compound", "msi msp doc xls ppt", 0, 0xE5,
|
||||
kSignature,
|
||||
0,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
1044
CPP/7zip/Archive/Common/CoderMixer2.cpp
Normal file
1044
CPP/7zip/Archive/Common/CoderMixer2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
437
CPP/7zip/Archive/Common/CoderMixer2.h
Normal file
437
CPP/7zip/Archive/Common/CoderMixer2.h
Normal file
@@ -0,0 +1,437 @@
|
||||
// CoderMixer2.h
|
||||
|
||||
#ifndef __CODER_MIXER2_H
|
||||
#define __CODER_MIXER2_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../../Common/MyVector.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#ifdef _7ZIP_ST
|
||||
#define USE_MIXER_ST
|
||||
#else
|
||||
#define USE_MIXER_MT
|
||||
#ifndef _SFX
|
||||
#define USE_MIXER_ST
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
#include "../../Common/StreamBinder.h"
|
||||
#include "../../Common/VirtThread.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
|
||||
class CSequentialInStreamCalcSize:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ISequentialInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
private:
|
||||
CMyComPtr<ISequentialInStream> _stream;
|
||||
UInt64 _size;
|
||||
bool _wasFinished;
|
||||
public:
|
||||
void SetStream(ISequentialInStream *stream) { _stream = stream; }
|
||||
void Init()
|
||||
{
|
||||
_size = 0;
|
||||
_wasFinished = false;
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
bool WasFinished() const { return _wasFinished; }
|
||||
};
|
||||
|
||||
|
||||
class COutStreamCalcSize:
|
||||
public ISequentialOutStream,
|
||||
public IOutStreamFinish,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFinish)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(OutStreamFinish)();
|
||||
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init() { _size = 0; }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace NCoderMixer2 {
|
||||
|
||||
struct CBond
|
||||
{
|
||||
UInt32 PackIndex;
|
||||
UInt32 UnpackIndex;
|
||||
|
||||
UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; }
|
||||
UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; }
|
||||
};
|
||||
|
||||
|
||||
struct CCoderStreamsInfo
|
||||
{
|
||||
UInt32 NumStreams;
|
||||
};
|
||||
|
||||
|
||||
struct CBindInfo
|
||||
{
|
||||
CRecordVector<CCoderStreamsInfo> Coders;
|
||||
CRecordVector<CBond> Bonds;
|
||||
CRecordVector<UInt32> PackStreams;
|
||||
unsigned UnpackCoder;
|
||||
|
||||
unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); }
|
||||
|
||||
int FindBond_for_PackStream(UInt32 packStream) const
|
||||
{
|
||||
FOR_VECTOR (i, Bonds)
|
||||
if (Bonds[i].PackIndex == packStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindBond_for_UnpackStream(UInt32 unpackStream) const
|
||||
{
|
||||
FOR_VECTOR (i, Bonds)
|
||||
if (Bonds[i].UnpackIndex == unpackStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SetUnpackCoder()
|
||||
{
|
||||
bool isOk = false;
|
||||
FOR_VECTOR(i, Coders)
|
||||
{
|
||||
if (FindBond_for_UnpackStream(i) < 0)
|
||||
{
|
||||
if (isOk)
|
||||
return false;
|
||||
UnpackCoder = i;
|
||||
isOk = true;
|
||||
}
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
|
||||
bool IsStream_in_PackStreams(UInt32 streamIndex) const
|
||||
{
|
||||
return FindStream_in_PackStreams(streamIndex) >= 0;
|
||||
}
|
||||
|
||||
int FindStream_in_PackStreams(UInt32 streamIndex) const
|
||||
{
|
||||
FOR_VECTOR(i, PackStreams)
|
||||
if (PackStreams[i] == streamIndex)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// that function is used before Maps is calculated
|
||||
|
||||
UInt32 GetStream_for_Coder(UInt32 coderIndex) const
|
||||
{
|
||||
UInt32 streamIndex = 0;
|
||||
for (UInt32 i = 0; i < coderIndex; i++)
|
||||
streamIndex += Coders[i].NumStreams;
|
||||
return streamIndex;
|
||||
}
|
||||
|
||||
// ---------- Maps Section ----------
|
||||
|
||||
CRecordVector<UInt32> Coder_to_Stream;
|
||||
CRecordVector<UInt32> Stream_to_Coder;
|
||||
|
||||
void ClearMaps();
|
||||
bool CalcMapsAndCheck();
|
||||
|
||||
// ---------- End of Maps Section ----------
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Coders.Clear();
|
||||
Bonds.Clear();
|
||||
PackStreams.Clear();
|
||||
|
||||
ClearMaps();
|
||||
}
|
||||
|
||||
void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const
|
||||
{
|
||||
coderIndex = Stream_to_Coder[streamIndex];
|
||||
coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CCoder
|
||||
{
|
||||
CLASS_NO_COPY(CCoder);
|
||||
public:
|
||||
CMyComPtr<ICompressCoder> Coder;
|
||||
CMyComPtr<ICompressCoder2> Coder2;
|
||||
UInt32 NumStreams;
|
||||
|
||||
UInt64 UnpackSize;
|
||||
const UInt64 *UnpackSizePointer;
|
||||
|
||||
CRecordVector<UInt64> PackSizes;
|
||||
CRecordVector<const UInt64 *> PackSizePointers;
|
||||
|
||||
CCoder() {}
|
||||
|
||||
void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes);
|
||||
|
||||
IUnknown *GetUnknown() const
|
||||
{
|
||||
return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
|
||||
}
|
||||
|
||||
HRESULT QueryInterface(REFGUID iid, void** pp) const
|
||||
{
|
||||
return GetUnknown()->QueryInterface(iid, pp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CMixer
|
||||
{
|
||||
bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex);
|
||||
|
||||
protected:
|
||||
CBindInfo _bi;
|
||||
|
||||
int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const
|
||||
{
|
||||
if (EncodeMode == forInputStream)
|
||||
return _bi.FindBond_for_UnpackStream(streamIndex);
|
||||
else
|
||||
return _bi.FindBond_for_PackStream(streamIndex);
|
||||
}
|
||||
|
||||
CBoolVector IsFilter_Vector;
|
||||
CBoolVector IsExternal_Vector;
|
||||
bool EncodeMode;
|
||||
public:
|
||||
unsigned MainCoderIndex;
|
||||
|
||||
CMixer(bool encodeMode):
|
||||
EncodeMode(encodeMode),
|
||||
MainCoderIndex(0)
|
||||
{}
|
||||
|
||||
/*
|
||||
Sequence of calling:
|
||||
|
||||
SetBindInfo();
|
||||
for each coder
|
||||
AddCoder();
|
||||
SelectMainCoder();
|
||||
|
||||
for each file
|
||||
{
|
||||
ReInit()
|
||||
for each coder
|
||||
SetCoderInfo();
|
||||
Code();
|
||||
}
|
||||
*/
|
||||
|
||||
virtual HRESULT SetBindInfo(const CBindInfo &bindInfo)
|
||||
{
|
||||
_bi = bindInfo;
|
||||
IsFilter_Vector.Clear();
|
||||
MainCoderIndex = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual void AddCoder(const CCreatedCoder &cod) = 0;
|
||||
virtual CCoder &GetCoder(unsigned index) = 0;
|
||||
virtual void SelectMainCoder(bool useFirst) = 0;
|
||||
virtual void ReInit() = 0;
|
||||
virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) = 0;
|
||||
virtual HRESULT Code(
|
||||
ISequentialInStream * const *inStreams,
|
||||
ISequentialOutStream * const *outStreams,
|
||||
ICompressProgressInfo *progress) = 0;
|
||||
virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0;
|
||||
|
||||
bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex);
|
||||
bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex);
|
||||
bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
|
||||
struct CCoderST: public CCoder
|
||||
{
|
||||
bool CanRead;
|
||||
bool CanWrite;
|
||||
|
||||
CCoderST(): CanRead(false), CanWrite(false) {}
|
||||
};
|
||||
|
||||
|
||||
struct CStBinderStream
|
||||
{
|
||||
CSequentialInStreamCalcSize *InStreamSpec;
|
||||
COutStreamCalcSize *OutStreamSpec;
|
||||
CMyComPtr<IUnknown> StreamRef;
|
||||
|
||||
CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {}
|
||||
};
|
||||
|
||||
|
||||
class CMixerST:
|
||||
public IUnknown,
|
||||
public CMixer,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
|
||||
UInt32 outStreamIndex, ISequentialInStream **inStreamRes);
|
||||
HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
|
||||
UInt32 inStreamIndex, ISequentialInStream **inStreamRes);
|
||||
HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
|
||||
UInt32 outStreamIndex, ISequentialOutStream **outStreamRes);
|
||||
|
||||
HRESULT FinishStream(UInt32 streamIndex);
|
||||
HRESULT FinishCoder(UInt32 coderIndex);
|
||||
|
||||
public:
|
||||
CObjectVector<CCoderST> _coders;
|
||||
|
||||
CObjectVector<CStBinderStream> _binderStreams;
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
CMixerST(bool encodeMode);
|
||||
~CMixerST();
|
||||
|
||||
virtual void AddCoder(const CCreatedCoder &cod);
|
||||
virtual CCoder &GetCoder(unsigned index);
|
||||
virtual void SelectMainCoder(bool useFirst);
|
||||
virtual void ReInit();
|
||||
virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes)
|
||||
{ _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); }
|
||||
virtual HRESULT Code(
|
||||
ISequentialInStream * const *inStreams,
|
||||
ISequentialOutStream * const *outStreams,
|
||||
ICompressProgressInfo *progress);
|
||||
virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;
|
||||
|
||||
HRESULT GetMainUnpackStream(
|
||||
ISequentialInStream * const *inStreams,
|
||||
ISequentialInStream **inStreamRes);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
|
||||
class CCoderMT: public CCoder, public CVirtThread
|
||||
{
|
||||
CLASS_NO_COPY(CCoderMT)
|
||||
CRecordVector<ISequentialInStream*> InStreamPointers;
|
||||
CRecordVector<ISequentialOutStream*> OutStreamPointers;
|
||||
|
||||
private:
|
||||
void Execute();
|
||||
public:
|
||||
bool EncodeMode;
|
||||
HRESULT Result;
|
||||
CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
|
||||
CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
|
||||
|
||||
void Release()
|
||||
{
|
||||
InStreamPointers.Clear();
|
||||
OutStreamPointers.Clear();
|
||||
unsigned i;
|
||||
for (i = 0; i < InStreams.Size(); i++)
|
||||
InStreams[i].Release();
|
||||
for (i = 0; i < OutStreams.Size(); i++)
|
||||
OutStreams[i].Release();
|
||||
}
|
||||
|
||||
class CReleaser
|
||||
{
|
||||
CLASS_NO_COPY(CReleaser)
|
||||
CCoderMT &_c;
|
||||
public:
|
||||
CReleaser(CCoderMT &c): _c(c) {}
|
||||
~CReleaser() { _c.Release(); }
|
||||
};
|
||||
|
||||
CCoderMT(): EncodeMode(false) {}
|
||||
~CCoderMT() { CVirtThread::WaitThreadFinish(); }
|
||||
|
||||
void Code(ICompressProgressInfo *progress);
|
||||
};
|
||||
|
||||
|
||||
class CMixerMT:
|
||||
public IUnknown,
|
||||
public CMixer,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CStreamBinder> _streamBinders;
|
||||
|
||||
HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);
|
||||
HRESULT ReturnIfError(HRESULT code);
|
||||
|
||||
public:
|
||||
CObjectVector<CCoderMT> _coders;
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
virtual HRESULT SetBindInfo(const CBindInfo &bindInfo);
|
||||
virtual void AddCoder(const CCreatedCoder &cod);
|
||||
virtual CCoder &GetCoder(unsigned index);
|
||||
virtual void SelectMainCoder(bool useFirst);
|
||||
virtual void ReInit();
|
||||
virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes)
|
||||
{ _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); }
|
||||
virtual HRESULT Code(
|
||||
ISequentialInStream * const *inStreams,
|
||||
ISequentialOutStream * const *outStreams,
|
||||
ICompressProgressInfo *progress);
|
||||
virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;
|
||||
|
||||
CMixerMT(bool encodeMode): CMixer(encodeMode) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
17
CPP/7zip/Archive/Common/DummyOutStream.cpp
Normal file
17
CPP/7zip/Archive/Common/DummyOutStream.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// DummyOutStream.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "DummyOutStream.h"
|
||||
|
||||
STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize = size;
|
||||
HRESULT res = S_OK;
|
||||
if (_stream)
|
||||
res = _stream->Write(data, size, &realProcessedSize);
|
||||
_size += realProcessedSize;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return res;
|
||||
}
|
||||
25
CPP/7zip/Archive/Common/DummyOutStream.h
Normal file
25
CPP/7zip/Archive/Common/DummyOutStream.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// DummyOutStream.h
|
||||
|
||||
#ifndef __DUMMY_OUT_STREAM_H
|
||||
#define __DUMMY_OUT_STREAM_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class CDummyOutStream:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
public:
|
||||
void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init() { _size = 0; }
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
UInt64 GetSize() const { return _size; }
|
||||
};
|
||||
|
||||
#endif
|
||||
62
CPP/7zip/Archive/Common/FindSignature.cpp
Normal file
62
CPP/7zip/Archive/Common/FindSignature.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// FindSignature.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../Common/MyBuffer.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "FindSignature.h"
|
||||
|
||||
HRESULT FindSignatureInStream(ISequentialInStream *stream,
|
||||
const Byte *signature, unsigned signatureSize,
|
||||
const UInt64 *limit, UInt64 &resPos)
|
||||
{
|
||||
resPos = 0;
|
||||
CByteBuffer byteBuffer2(signatureSize);
|
||||
RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize));
|
||||
|
||||
if (memcmp(byteBuffer2, signature, signatureSize) == 0)
|
||||
return S_OK;
|
||||
|
||||
const UInt32 kBufferSize = (1 << 16);
|
||||
CByteBuffer byteBuffer(kBufferSize);
|
||||
Byte *buffer = byteBuffer;
|
||||
UInt32 numPrevBytes = signatureSize - 1;
|
||||
memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
|
||||
resPos = 1;
|
||||
for (;;)
|
||||
{
|
||||
if (limit != NULL)
|
||||
if (resPos > *limit)
|
||||
return S_FALSE;
|
||||
do
|
||||
{
|
||||
UInt32 numReadBytes = kBufferSize - numPrevBytes;
|
||||
UInt32 processedSize;
|
||||
RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
|
||||
numPrevBytes += processedSize;
|
||||
if (processedSize == 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
while (numPrevBytes < signatureSize);
|
||||
UInt32 numTests = numPrevBytes - signatureSize + 1;
|
||||
for (UInt32 pos = 0; pos < numTests; pos++)
|
||||
{
|
||||
Byte b = signature[0];
|
||||
for (; buffer[pos] != b && pos < numTests; pos++);
|
||||
if (pos == numTests)
|
||||
break;
|
||||
if (memcmp(buffer + pos, signature, signatureSize) == 0)
|
||||
{
|
||||
resPos += pos;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
resPos += numTests;
|
||||
numPrevBytes -= numTests;
|
||||
memmove(buffer, buffer + numTests, numPrevBytes);
|
||||
}
|
||||
}
|
||||
12
CPP/7zip/Archive/Common/FindSignature.h
Normal file
12
CPP/7zip/Archive/Common/FindSignature.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// FindSignature.h
|
||||
|
||||
#ifndef __FIND_SIGNATURE_H
|
||||
#define __FIND_SIGNATURE_H
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
HRESULT FindSignatureInStream(ISequentialInStream *stream,
|
||||
const Byte *signature, unsigned signatureSize,
|
||||
const UInt64 *limit, UInt64 &resPos);
|
||||
|
||||
#endif
|
||||
157
CPP/7zip/Archive/Common/HandlerOut.cpp
Normal file
157
CPP/7zip/Archive/Common/HandlerOut.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
// HandlerOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
#include "../../../Windows/System.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/ParseProperties.h"
|
||||
|
||||
#include "HandlerOut.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
|
||||
static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value)
|
||||
{
|
||||
if (m.FindProp(propID) < 0)
|
||||
m.AddProp32(propID, value);
|
||||
}
|
||||
|
||||
void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo
|
||||
#ifndef _7ZIP_ST
|
||||
, UInt32 numThreads
|
||||
#endif
|
||||
)
|
||||
{
|
||||
UInt32 level = _level;
|
||||
if (level != (UInt32)(Int32)-1)
|
||||
SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CMultiMethodProps::Init()
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
_numProcessors = _numThreads = NSystem::GetNumberOfProcessors();
|
||||
#endif
|
||||
|
||||
_level = (UInt32)(Int32)-1;
|
||||
_analysisLevel = -1;
|
||||
|
||||
_autoFilter = true;
|
||||
_crcSize = 4;
|
||||
_filterMethod.Clear();
|
||||
_methods.Clear();
|
||||
}
|
||||
|
||||
HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
|
||||
{
|
||||
UString name = nameSpec;
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (name[0] == 'x')
|
||||
{
|
||||
name.Delete(0);
|
||||
_level = 9;
|
||||
return ParsePropToUInt32(name, value, _level);
|
||||
}
|
||||
|
||||
if (name.IsPrefixedBy_Ascii_NoCase("yx"))
|
||||
{
|
||||
name.Delete(0, 2);
|
||||
UInt32 v = 9;
|
||||
RINOK(ParsePropToUInt32(name, value, v));
|
||||
_analysisLevel = (int)v;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (name.IsEqualTo("crc"))
|
||||
{
|
||||
name.Delete(0, 3);
|
||||
_crcSize = 4;
|
||||
return ParsePropToUInt32(name, value, _crcSize);
|
||||
}
|
||||
|
||||
UInt32 number;
|
||||
unsigned index = ParseStringToUInt32(name, number);
|
||||
UString realName = name.Ptr(index);
|
||||
if (index == 0)
|
||||
{
|
||||
if (name.IsPrefixedBy_Ascii_NoCase("mt"))
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads));
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
if (name.IsEqualTo("f"))
|
||||
{
|
||||
HRESULT res = PROPVARIANT_to_bool(value, _autoFilter);
|
||||
if (res == S_OK)
|
||||
return res;
|
||||
if (value.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
return _filterMethod.ParseMethodFromPROPVARIANT(UString(), value);
|
||||
}
|
||||
number = 0;
|
||||
}
|
||||
if (number > 64)
|
||||
return E_FAIL;
|
||||
for (int j = _methods.Size(); j <= (int)number; j++)
|
||||
_methods.Add(COneMethodInfo());
|
||||
return _methods[number].ParseMethodFromPROPVARIANT(realName, value);
|
||||
}
|
||||
|
||||
void CSingleMethodProps::Init()
|
||||
{
|
||||
Clear();
|
||||
_level = (UInt32)(Int32)-1;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
_numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
|
||||
AddProp_NumThreads(_numThreads);
|
||||
#endif
|
||||
}
|
||||
|
||||
HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
Init();
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
const PROPVARIANT &value = values[i];
|
||||
if (name[0] == L'x')
|
||||
{
|
||||
UInt32 a = 9;
|
||||
RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
|
||||
_level = a;
|
||||
AddProp_Level(a);
|
||||
}
|
||||
else if (name.IsPrefixedBy_Ascii_NoCase("mt"))
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads));
|
||||
AddProp_NumThreads(_numThreads);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(ParseMethodFromPROPVARIANT(names[i], value));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}
|
||||
67
CPP/7zip/Archive/Common/HandlerOut.h
Normal file
67
CPP/7zip/Archive/Common/HandlerOut.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// HandlerOut.h
|
||||
|
||||
#ifndef __HANDLER_OUT_H
|
||||
#define __HANDLER_OUT_H
|
||||
|
||||
#include "../../Common/MethodProps.h"
|
||||
|
||||
namespace NArchive {
|
||||
|
||||
class CMultiMethodProps
|
||||
{
|
||||
UInt32 _level;
|
||||
int _analysisLevel;
|
||||
public:
|
||||
#ifndef _7ZIP_ST
|
||||
UInt32 _numThreads;
|
||||
UInt32 _numProcessors;
|
||||
#endif
|
||||
|
||||
UInt32 _crcSize;
|
||||
CObjectVector<COneMethodInfo> _methods;
|
||||
COneMethodInfo _filterMethod;
|
||||
bool _autoFilter;
|
||||
|
||||
void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo
|
||||
#ifndef _7ZIP_ST
|
||||
, UInt32 numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
unsigned GetNumEmptyMethods() const
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < _methods.Size(); i++)
|
||||
if (!_methods[i].IsEmpty())
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
|
||||
int GetAnalysisLevel() const { return _analysisLevel; }
|
||||
|
||||
void Init();
|
||||
|
||||
CMultiMethodProps() { Init(); }
|
||||
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
|
||||
};
|
||||
|
||||
class CSingleMethodProps: public COneMethodInfo
|
||||
{
|
||||
UInt32 _level;
|
||||
|
||||
public:
|
||||
#ifndef _7ZIP_ST
|
||||
UInt32 _numThreads;
|
||||
UInt32 _numProcessors;
|
||||
#endif
|
||||
|
||||
void Init();
|
||||
CSingleMethodProps() { Init(); }
|
||||
int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
|
||||
HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
46
CPP/7zip/Archive/Common/InStreamWithCRC.cpp
Normal file
46
CPP/7zip/Archive/Common/InStreamWithCRC.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// InStreamWithCRC.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "InStreamWithCRC.h"
|
||||
|
||||
STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessed = 0;
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Read(data, size, &realProcessed);
|
||||
_size += realProcessed;
|
||||
if (size != 0 && realProcessed == 0)
|
||||
_wasFinished = true;
|
||||
_crc = CrcUpdate(_crc, data, realProcessed);
|
||||
if (processedSize)
|
||||
*processedSize = realProcessed;
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessed = 0;
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Read(data, size, &realProcessed);
|
||||
_size += realProcessed;
|
||||
/*
|
||||
if (size != 0 && realProcessed == 0)
|
||||
_wasFinished = true;
|
||||
*/
|
||||
_crc = CrcUpdate(_crc, data, realProcessed);
|
||||
if (processedSize)
|
||||
*processedSize = realProcessed;
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
if (seekOrigin != STREAM_SEEK_SET || offset != 0)
|
||||
return E_FAIL;
|
||||
_size = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
return _stream->Seek(offset, seekOrigin, newPosition);
|
||||
}
|
||||
67
CPP/7zip/Archive/Common/InStreamWithCRC.h
Normal file
67
CPP/7zip/Archive/Common/InStreamWithCRC.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// InStreamWithCRC.h
|
||||
|
||||
#ifndef __IN_STREAM_WITH_CRC_H
|
||||
#define __IN_STREAM_WITH_CRC_H
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class CSequentialInStreamWithCRC:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
private:
|
||||
CMyComPtr<ISequentialInStream> _stream;
|
||||
UInt64 _size;
|
||||
UInt32 _crc;
|
||||
bool _wasFinished;
|
||||
public:
|
||||
void SetStream(ISequentialInStream *stream) { _stream = stream; }
|
||||
void Init()
|
||||
{
|
||||
_size = 0;
|
||||
_wasFinished = false;
|
||||
_crc = CRC_INIT_VAL;
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
bool WasFinished() const { return _wasFinished; }
|
||||
};
|
||||
|
||||
class CInStreamWithCRC:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
private:
|
||||
CMyComPtr<IInStream> _stream;
|
||||
UInt64 _size;
|
||||
UInt32 _crc;
|
||||
// bool _wasFinished;
|
||||
public:
|
||||
void SetStream(IInStream *stream) { _stream = stream; }
|
||||
void Init()
|
||||
{
|
||||
_size = 0;
|
||||
// _wasFinished = false;
|
||||
_crc = CRC_INIT_VAL;
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
// bool WasFinished() const { return _wasFinished; }
|
||||
};
|
||||
|
||||
#endif
|
||||
88
CPP/7zip/Archive/Common/ItemNameUtils.cpp
Normal file
88
CPP/7zip/Archive/Common/ItemNameUtils.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Archive/Common/ItemNameUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "ItemNameUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NItemName {
|
||||
|
||||
static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR;
|
||||
static const wchar_t kDirDelimiter = L'/';
|
||||
|
||||
void ReplaceToOsPathSeparator(wchar_t *s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (;;)
|
||||
{
|
||||
wchar_t c = *s;
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c == kDirDelimiter)
|
||||
*s = kOSDirDelimiter;
|
||||
s++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
UString MakeLegalName(const UString &name)
|
||||
{
|
||||
UString zipName = name;
|
||||
zipName.Replace(kOSDirDelimiter, kDirDelimiter);
|
||||
return zipName;
|
||||
}
|
||||
|
||||
UString GetOSName(const UString &name)
|
||||
{
|
||||
UString newName = name;
|
||||
newName.Replace(kDirDelimiter, kOSDirDelimiter);
|
||||
return newName;
|
||||
}
|
||||
|
||||
UString GetOSName2(const UString &name)
|
||||
{
|
||||
if (name.IsEmpty())
|
||||
return UString();
|
||||
UString newName = GetOSName(name);
|
||||
if (newName.Back() == kOSDirDelimiter)
|
||||
newName.DeleteBack();
|
||||
return newName;
|
||||
}
|
||||
|
||||
void ConvertToOSName2(UString &name)
|
||||
{
|
||||
if (!name.IsEmpty())
|
||||
{
|
||||
name.Replace(kDirDelimiter, kOSDirDelimiter);
|
||||
if (name.Back() == kOSDirDelimiter)
|
||||
name.DeleteBack();
|
||||
}
|
||||
}
|
||||
|
||||
bool HasTailSlash(const AString &name, UINT
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
codePage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (name.IsEmpty())
|
||||
return false;
|
||||
LPCSTR prev =
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
CharPrevExA((WORD)codePage, name, &name[name.Len()], 0);
|
||||
#else
|
||||
(LPCSTR)(name) + (name.Len() - 1);
|
||||
#endif
|
||||
return (*prev == '/');
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
UString WinNameToOSName(const UString &name)
|
||||
{
|
||||
UString newName = name;
|
||||
newName.Replace(L'\\', kOSDirDelimiter);
|
||||
return newName;
|
||||
}
|
||||
#endif
|
||||
|
||||
}}
|
||||
27
CPP/7zip/Archive/Common/ItemNameUtils.h
Normal file
27
CPP/7zip/Archive/Common/ItemNameUtils.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Archive/Common/ItemNameUtils.h
|
||||
|
||||
#ifndef __ARCHIVE_ITEM_NAME_UTILS_H
|
||||
#define __ARCHIVE_ITEM_NAME_UTILS_H
|
||||
|
||||
#include "../../../Common/MyString.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NItemName {
|
||||
|
||||
void ReplaceToOsPathSeparator(wchar_t *s);
|
||||
|
||||
UString MakeLegalName(const UString &name);
|
||||
UString GetOSName(const UString &name);
|
||||
UString GetOSName2(const UString &name);
|
||||
void ConvertToOSName2(UString &name);
|
||||
bool HasTailSlash(const AString &name, UINT codePage);
|
||||
|
||||
#ifdef _WIN32
|
||||
inline UString WinNameToOSName(const UString &name) { return name; }
|
||||
#else
|
||||
UString WinNameToOSName(const UString &name);
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
191
CPP/7zip/Archive/Common/MultiStream.cpp
Normal file
191
CPP/7zip/Archive/Common/MultiStream.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
// MultiStream.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "MultiStream.h"
|
||||
|
||||
STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
if (_pos >= _totalLength)
|
||||
return S_OK;
|
||||
|
||||
{
|
||||
unsigned left = 0, mid = _streamIndex, right = Streams.Size();
|
||||
for (;;)
|
||||
{
|
||||
CSubStreamInfo &m = Streams[mid];
|
||||
if (_pos < m.GlobalOffset)
|
||||
right = mid;
|
||||
else if (_pos >= m.GlobalOffset + m.Size)
|
||||
left = mid + 1;
|
||||
else
|
||||
{
|
||||
_streamIndex = mid;
|
||||
break;
|
||||
}
|
||||
mid = (left + right) / 2;
|
||||
}
|
||||
_streamIndex = mid;
|
||||
}
|
||||
|
||||
CSubStreamInfo &s = Streams[_streamIndex];
|
||||
UInt64 localPos = _pos - s.GlobalOffset;
|
||||
if (localPos != s.LocalPos)
|
||||
{
|
||||
RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));
|
||||
}
|
||||
UInt64 rem = s.Size - localPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
HRESULT result = s.Stream->Read(data, size, &size);
|
||||
_pos += size;
|
||||
s.LocalPos += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch (seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: break;
|
||||
case STREAM_SEEK_CUR: offset += _pos; break;
|
||||
case STREAM_SEEK_END: offset += _totalLength; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (offset < 0)
|
||||
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
|
||||
_pos = offset;
|
||||
if (newPosition)
|
||||
*newPosition = offset;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
class COutVolumeStream:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
unsigned _volIndex;
|
||||
UInt64 _volSize;
|
||||
UInt64 _curPos;
|
||||
CMyComPtr<ISequentialOutStream> _volumeStream;
|
||||
COutArchive _archive;
|
||||
CCRC _crc;
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
CFileItem _file;
|
||||
CUpdateOptions _options;
|
||||
CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
|
||||
void Init(IArchiveUpdateCallback2 *volumeCallback,
|
||||
const UString &name)
|
||||
{
|
||||
_file.Name = name;
|
||||
_file.IsStartPosDefined = true;
|
||||
_file.StartPos = 0;
|
||||
|
||||
VolumeCallback = volumeCallback;
|
||||
_volIndex = 0;
|
||||
_volSize = 0;
|
||||
}
|
||||
|
||||
HRESULT Flush();
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
HRESULT COutVolumeStream::Flush()
|
||||
{
|
||||
if (_volumeStream)
|
||||
{
|
||||
_file.UnPackSize = _curPos;
|
||||
_file.FileCRC = _crc.GetDigest();
|
||||
RINOK(WriteVolumeHeader(_archive, _file, _options));
|
||||
_archive.Close();
|
||||
_volumeStream.Release();
|
||||
_file.StartPos += _file.UnPackSize;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
if (_streamIndex >= Streams.Size())
|
||||
{
|
||||
CSubStreamInfo subStream;
|
||||
RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));
|
||||
RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));
|
||||
subStream.Pos = 0;
|
||||
Streams.Add(subStream);
|
||||
continue;
|
||||
}
|
||||
CSubStreamInfo &subStream = Streams[_streamIndex];
|
||||
if (_offsetPos >= subStream.Size)
|
||||
{
|
||||
_offsetPos -= subStream.Size;
|
||||
_streamIndex++;
|
||||
continue;
|
||||
}
|
||||
if (_offsetPos != subStream.Pos)
|
||||
{
|
||||
CMyComPtr<IOutStream> outStream;
|
||||
RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
|
||||
RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
|
||||
subStream.Pos = _offsetPos;
|
||||
}
|
||||
|
||||
UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
|
||||
UInt32 realProcessed;
|
||||
RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
|
||||
data = (void *)((Byte *)data + realProcessed);
|
||||
size -= realProcessed;
|
||||
subStream.Pos += realProcessed;
|
||||
_offsetPos += realProcessed;
|
||||
_absPos += realProcessed;
|
||||
if (_absPos > _length)
|
||||
_length = _absPos;
|
||||
if (processedSize)
|
||||
*processedSize += realProcessed;
|
||||
if (subStream.Pos == subStream.Size)
|
||||
{
|
||||
_streamIndex++;
|
||||
_offsetPos = 0;
|
||||
}
|
||||
if (realProcessed != curSize && realProcessed == 0)
|
||||
return E_FAIL;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch (seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: break;
|
||||
case STREAM_SEEK_CUR: offset += _absPos; break;
|
||||
case STREAM_SEEK_END: offset += _length; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (offset < 0)
|
||||
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
|
||||
_absPos = offset;
|
||||
_offsetPos = _absPos;
|
||||
_streamIndex = 0;
|
||||
if (newPosition)
|
||||
*newPosition = offset;
|
||||
return S_OK;
|
||||
}
|
||||
*/
|
||||
89
CPP/7zip/Archive/Common/MultiStream.h
Normal file
89
CPP/7zip/Archive/Common/MultiStream.h
Normal file
@@ -0,0 +1,89 @@
|
||||
// MultiStream.h
|
||||
|
||||
#ifndef __MULTI_STREAM_H
|
||||
#define __MULTI_STREAM_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../../Common/MyVector.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class CMultiStream:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt64 _pos;
|
||||
UInt64 _totalLength;
|
||||
unsigned _streamIndex;
|
||||
|
||||
public:
|
||||
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Size;
|
||||
UInt64 GlobalOffset;
|
||||
UInt64 LocalPos;
|
||||
|
||||
CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {}
|
||||
};
|
||||
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
|
||||
HRESULT Init()
|
||||
{
|
||||
UInt64 total = 0;
|
||||
FOR_VECTOR (i, Streams)
|
||||
{
|
||||
CSubStreamInfo &s = Streams[i];
|
||||
s.GlobalOffset = total;
|
||||
total += Streams[i].Size;
|
||||
RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos));
|
||||
}
|
||||
_totalLength = total;
|
||||
_pos = 0;
|
||||
_streamIndex = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(IInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
};
|
||||
|
||||
/*
|
||||
class COutMultiStream:
|
||||
public IOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
unsigned _streamIndex; // required stream
|
||||
UInt64 _offsetPos; // offset from start of _streamIndex index
|
||||
UInt64 _absPos;
|
||||
UInt64 _length;
|
||||
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> Stream;
|
||||
UInt64 Size;
|
||||
UInt64 Pos;
|
||||
};
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
public:
|
||||
CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
|
||||
void Init()
|
||||
{
|
||||
_streamIndex = 0;
|
||||
_offsetPos = 0;
|
||||
_absPos = 0;
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(IOutStream)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
};
|
||||
*/
|
||||
|
||||
#endif
|
||||
18
CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
Normal file
18
CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// OutStreamWithCRC.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "OutStreamWithCRC.h"
|
||||
|
||||
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, size, &size);
|
||||
if (_calculate)
|
||||
_crc = CrcUpdate(_crc, data, size);
|
||||
_size += size;
|
||||
if (processedSize != NULL)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
37
CPP/7zip/Archive/Common/OutStreamWithCRC.h
Normal file
37
CPP/7zip/Archive/Common/OutStreamWithCRC.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// OutStreamWithCRC.h
|
||||
|
||||
#ifndef __OUT_STREAM_WITH_CRC_H
|
||||
#define __OUT_STREAM_WITH_CRC_H
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class COutStreamWithCRC:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
UInt32 _crc;
|
||||
bool _calculate;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init(bool calculate = true)
|
||||
{
|
||||
_size = 0;
|
||||
_calculate = calculate;
|
||||
_crc = CRC_INIT_VAL;
|
||||
}
|
||||
void EnableCalc(bool calculate) { _calculate = calculate; }
|
||||
void InitCRC() { _crc = CRC_INIT_VAL; }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
|
||||
};
|
||||
|
||||
#endif
|
||||
18
CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
Normal file
18
CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// OutStreamWithSha1.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "OutStreamWithSha1.h"
|
||||
|
||||
STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, size, &size);
|
||||
if (_calculate)
|
||||
Sha1_Update(&_sha, (const Byte *)data, size);
|
||||
_size += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
36
CPP/7zip/Archive/Common/OutStreamWithSha1.h
Normal file
36
CPP/7zip/Archive/Common/OutStreamWithSha1.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// OutStreamWithSha1.h
|
||||
|
||||
#ifndef __OUT_STREAM_WITH_SHA1_H
|
||||
#define __OUT_STREAM_WITH_SHA1_H
|
||||
|
||||
#include "../../../../C/Sha1.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class COutStreamWithSha1:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
CSha1 _sha;
|
||||
bool _calculate;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init(bool calculate = true)
|
||||
{
|
||||
_size = 0;
|
||||
_calculate = calculate;
|
||||
Sha1_Init(&_sha);
|
||||
}
|
||||
void InitSha1() { Sha1_Init(&_sha); }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
void Final(Byte *digest) { Sha1_Final(&_sha, digest); }
|
||||
};
|
||||
|
||||
#endif
|
||||
3
CPP/7zip/Archive/Common/ParseProperties.cpp
Normal file
3
CPP/7zip/Archive/Common/ParseProperties.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// ParseProperties.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
6
CPP/7zip/Archive/Common/ParseProperties.h
Normal file
6
CPP/7zip/Archive/Common/ParseProperties.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// ParseProperties.h
|
||||
|
||||
#ifndef __PARSE_PROPERTIES_H
|
||||
#define __PARSE_PROPERTIES_H
|
||||
|
||||
#endif
|
||||
8
CPP/7zip/Archive/Common/StdAfx.h
Normal file
8
CPP/7zip/Archive/Common/StdAfx.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
795
CPP/7zip/Archive/CpioHandler.cpp
Normal file
795
CPP/7zip/Archive/CpioHandler.cpp
Normal file
@@ -0,0 +1,795 @@
|
||||
// CpioHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/MyLinux.h"
|
||||
#include "../../Common/StringConvert.h"
|
||||
#include "../../Common/StringToInt.h"
|
||||
#include "../../Common/UTFConvert.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
#include "../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/ItemNameUtils.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
static const Byte kMagicBin0 = 0xC7;
|
||||
static const Byte kMagicBin1 = 0x71;
|
||||
|
||||
// #define MAGIC_ASCII { '0', '7', '0', '7', '0' }
|
||||
|
||||
static const Byte kMagicHex = '1'; // New ASCII Format
|
||||
static const Byte kMagicHexCrc = '2'; // New CRC Format
|
||||
static const Byte kMagicOct = '7'; // Portable ASCII Format
|
||||
|
||||
static const char *kName_TRAILER = "TRAILER!!!";
|
||||
|
||||
static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4;
|
||||
static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11;
|
||||
static const unsigned k_HexRecord_Size = 6 + 13 * 8;
|
||||
|
||||
static const unsigned k_RecordSize_Max = k_HexRecord_Size;
|
||||
|
||||
/*
|
||||
struct CBinRecord
|
||||
{
|
||||
unsigned short c_magic;
|
||||
short c_dev;
|
||||
unsigned short c_ino;
|
||||
unsigned short c_mode;
|
||||
unsigned short c_uid;
|
||||
unsigned short c_gid;
|
||||
unsigned short c_nlink;
|
||||
short c_rdev;
|
||||
unsigned short c_mtimes[2];
|
||||
unsigned short c_namesize;
|
||||
unsigned short c_filesizes[2];
|
||||
};
|
||||
|
||||
struct CHexRecord
|
||||
{
|
||||
char Magic[6];
|
||||
char inode[8];
|
||||
char Mode[8];
|
||||
char UID[8];
|
||||
char GID[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char Size[8]; // must be 0 for FIFOs and directories
|
||||
char DevMajor[8];
|
||||
char DevMinor[8];
|
||||
char RDevMajor[8]; //only valid for chr and blk special files
|
||||
char RDevMinor[8]; //only valid for chr and blk special files
|
||||
char NameSize[8]; // count includes terminating NUL in pathname
|
||||
char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
|
||||
};
|
||||
*/
|
||||
|
||||
enum EType
|
||||
{
|
||||
k_Type_BinLe,
|
||||
k_Type_BinBe,
|
||||
k_Type_Oct,
|
||||
k_Type_Hex,
|
||||
k_Type_HexCrc
|
||||
};
|
||||
|
||||
static const char * const k_Types[] =
|
||||
{
|
||||
"Binary LE"
|
||||
, "Binary BE"
|
||||
, "Portable ASCII"
|
||||
, "New ASCII"
|
||||
, "New CRC"
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt32 inode;
|
||||
UInt32 Mode;
|
||||
UInt32 UID;
|
||||
UInt32 GID;
|
||||
UInt64 Size;
|
||||
UInt32 MTime;
|
||||
|
||||
UInt32 NumLinks;
|
||||
UInt32 DevMajor;
|
||||
UInt32 DevMinor;
|
||||
UInt32 RDevMajor;
|
||||
UInt32 RDevMinor;
|
||||
UInt32 ChkSum;
|
||||
|
||||
UInt32 Align;
|
||||
EType Type;
|
||||
|
||||
UInt32 HeaderSize;
|
||||
UInt64 HeaderPos;
|
||||
|
||||
bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; }
|
||||
bool IsCrcFormat() const { return Type == k_Type_HexCrc; }
|
||||
bool IsDir() const { return MY_LIN_S_ISDIR(Mode); }
|
||||
bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; }
|
||||
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
|
||||
};
|
||||
|
||||
enum EErrorType
|
||||
{
|
||||
k_ErrorType_OK,
|
||||
k_ErrorType_Corrupted,
|
||||
k_ErrorType_UnexpectedEnd,
|
||||
};
|
||||
|
||||
struct CInArchive
|
||||
{
|
||||
ISequentialInStream *Stream;
|
||||
UInt64 Processed;
|
||||
|
||||
HRESULT Read(void *data, size_t *size);
|
||||
HRESULT GetNextItem(CItem &item, EErrorType &errorType);
|
||||
};
|
||||
|
||||
HRESULT CInArchive::Read(void *data, size_t *size)
|
||||
{
|
||||
HRESULT res = ReadStream(Stream, data, size);
|
||||
Processed += *size;
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool ReadHex(const Byte *p, UInt32 &resVal)
|
||||
{
|
||||
char sz[16];
|
||||
memcpy(sz, p, 8);
|
||||
sz[8] = 0;
|
||||
const char *end;
|
||||
resVal = ConvertHexStringToUInt32(sz, &end);
|
||||
return (unsigned)(end - sz) == 8;
|
||||
}
|
||||
|
||||
static bool ReadOct6(const Byte *p, UInt32 &resVal)
|
||||
{
|
||||
char sz[16];
|
||||
memcpy(sz, p, 6);
|
||||
sz[6] = 0;
|
||||
const char *end;
|
||||
resVal = ConvertOctStringToUInt32(sz, &end);
|
||||
return (unsigned)(end - sz) == 6;
|
||||
}
|
||||
|
||||
static bool ReadOct11(const Byte *p, UInt64 &resVal)
|
||||
{
|
||||
char sz[16];
|
||||
memcpy(sz, p, 11);
|
||||
sz[11] = 0;
|
||||
const char *end;
|
||||
resVal = ConvertOctStringToUInt64(sz, &end);
|
||||
return (unsigned)(end - sz) == 11;
|
||||
}
|
||||
|
||||
|
||||
#define READ_HEX(y) { if (!ReadHex(p2, y)) return S_OK; p2 += 8; }
|
||||
#define READ_OCT_6(y) { if (!ReadOct6(p2, y)) return S_OK; p2 += 6; }
|
||||
#define READ_OCT_11(y) { if (!ReadOct11(p2, y)) return S_OK; p2 += 11; }
|
||||
|
||||
static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
|
||||
{
|
||||
while ((size & (align - 1)) != 0)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); }
|
||||
static UInt32 Get32(const Byte *p, bool be) { return ((UInt32)Get16(p, be) << 16) + Get16(p + 2, be); }
|
||||
|
||||
#define G16(offs, v) v = Get16(p + (offs), be)
|
||||
#define G32(offs, v) v = Get32(p + (offs), be)
|
||||
|
||||
static const unsigned kNameSizeMax = 1 << 12;
|
||||
|
||||
API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size)
|
||||
{
|
||||
if (size < k_BinRecord_Size)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
|
||||
UInt32 nameSize;
|
||||
UInt32 numLinks;
|
||||
if (p[0] == '0')
|
||||
{
|
||||
if (p[1] != '7' ||
|
||||
p[2] != '0' ||
|
||||
p[3] != '7' ||
|
||||
p[4] != '0')
|
||||
return k_IsArc_Res_NO;
|
||||
if (p[5] == '7')
|
||||
{
|
||||
if (size < k_OctRecord_Size)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
for (int i = 6; i < k_OctRecord_Size; i++)
|
||||
{
|
||||
char c = p[i];
|
||||
if (c < '0' || c > '7')
|
||||
return k_IsArc_Res_NO;
|
||||
}
|
||||
ReadOct6(p + 6 * 6, numLinks);
|
||||
ReadOct6(p + 8 * 6 + 11, nameSize);
|
||||
}
|
||||
else if (p[5] == '1' || p[5] == '2')
|
||||
{
|
||||
if (size < k_HexRecord_Size)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
for (int i = 6; i < k_HexRecord_Size; i++)
|
||||
{
|
||||
char c = p[i];
|
||||
if ((c < '0' || c > '9') &&
|
||||
(c < 'A' || c > 'F') &&
|
||||
(c < 'a' || c > 'f'))
|
||||
return k_IsArc_Res_NO;
|
||||
}
|
||||
ReadHex(p + 6 + 4 * 8, numLinks);
|
||||
ReadHex(p + 6 + 11 * 8, nameSize);
|
||||
}
|
||||
else
|
||||
return k_IsArc_Res_NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 rDevMinor;
|
||||
if (p[0] == kMagicBin0 && p[1] == kMagicBin1)
|
||||
{
|
||||
numLinks = GetUi16(p + 12);
|
||||
rDevMinor = GetUi16(p + 14);
|
||||
nameSize = GetUi16(p + 20);
|
||||
}
|
||||
else if (p[0] == kMagicBin1 && p[1] == kMagicBin0)
|
||||
{
|
||||
numLinks = GetBe16(p + 12);
|
||||
rDevMinor = GetBe16(p + 14);
|
||||
nameSize = GetBe16(p + 20);
|
||||
}
|
||||
else
|
||||
return k_IsArc_Res_NO;
|
||||
|
||||
if (rDevMinor != 0)
|
||||
return k_IsArc_Res_NO;
|
||||
if (nameSize > (1 << 8))
|
||||
return k_IsArc_Res_NO;
|
||||
}
|
||||
if (numLinks == 0 || numLinks >= (1 << 10))
|
||||
return k_IsArc_Res_NO;
|
||||
if (nameSize == 0 || nameSize > kNameSizeMax)
|
||||
return k_IsArc_Res_NO;
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
}
|
||||
|
||||
#define READ_STREAM(_dest_, _size_) \
|
||||
{ size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \
|
||||
if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } }
|
||||
|
||||
HRESULT CInArchive::GetNextItem(CItem &item, EErrorType &errorType)
|
||||
{
|
||||
errorType = k_ErrorType_Corrupted;
|
||||
|
||||
Byte p[k_RecordSize_Max];
|
||||
|
||||
READ_STREAM(p, k_BinRecord_Size)
|
||||
|
||||
UInt32 nameSize;
|
||||
|
||||
if (p[0] != '0')
|
||||
{
|
||||
bool be;
|
||||
if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { be = false; item.Type = k_Type_BinLe; }
|
||||
else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) { be = true; item.Type = k_Type_BinBe; }
|
||||
else return S_FALSE;
|
||||
|
||||
item.Align = 2;
|
||||
item.DevMajor = 0;
|
||||
item.RDevMajor =0;
|
||||
item.ChkSum = 0;
|
||||
|
||||
G16(2, item.DevMinor);
|
||||
G16(4, item.inode);
|
||||
G16(6, item.Mode);
|
||||
G16(8, item.UID);
|
||||
G16(10, item.GID);
|
||||
G16(12, item.NumLinks);
|
||||
G16(14, item.RDevMinor);
|
||||
G32(16, item.MTime);
|
||||
G16(20, nameSize);
|
||||
G32(22, item.Size);
|
||||
|
||||
/*
|
||||
if (item.RDevMinor != 0)
|
||||
return S_FALSE;
|
||||
*/
|
||||
|
||||
item.HeaderSize = GetAlignedSize(nameSize + k_BinRecord_Size, item.Align);
|
||||
nameSize = item.HeaderSize - k_BinRecord_Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p[1] != '7' ||
|
||||
p[2] != '0' ||
|
||||
p[3] != '7' ||
|
||||
p[4] != '0')
|
||||
return S_FALSE;
|
||||
if (p[5] == kMagicOct)
|
||||
{
|
||||
item.Type = k_Type_Oct;
|
||||
READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size)
|
||||
item.Align = 1;
|
||||
item.DevMajor = 0;
|
||||
item.RDevMajor = 0;
|
||||
|
||||
const Byte *p2 = p + 6;
|
||||
READ_OCT_6(item.DevMinor);
|
||||
READ_OCT_6(item.inode);
|
||||
READ_OCT_6(item.Mode);
|
||||
READ_OCT_6(item.UID);
|
||||
READ_OCT_6(item.GID);
|
||||
READ_OCT_6(item.NumLinks);
|
||||
READ_OCT_6(item.RDevMinor);
|
||||
{
|
||||
UInt64 mTime64;
|
||||
READ_OCT_11(mTime64);
|
||||
item.MTime = 0;
|
||||
if (mTime64 < (UInt32)(Int32)-1)
|
||||
item.MTime = (UInt32)mTime64;
|
||||
}
|
||||
READ_OCT_6(nameSize);
|
||||
READ_OCT_11(item.Size); // ?????
|
||||
item.HeaderSize = GetAlignedSize(nameSize + k_OctRecord_Size, item.Align);
|
||||
nameSize = item.HeaderSize - k_OctRecord_Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p[5] == kMagicHex)
|
||||
item.Type = k_Type_Hex;
|
||||
else if (p[5] == kMagicHexCrc)
|
||||
item.Type = k_Type_HexCrc;
|
||||
else
|
||||
return S_FALSE;
|
||||
|
||||
READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size)
|
||||
|
||||
item.Align = 4;
|
||||
|
||||
const Byte *p2 = p + 6;
|
||||
READ_HEX(item.inode);
|
||||
READ_HEX(item.Mode);
|
||||
READ_HEX(item.UID);
|
||||
READ_HEX(item.GID);
|
||||
READ_HEX(item.NumLinks);
|
||||
READ_HEX(item.MTime);
|
||||
{
|
||||
UInt32 size32;
|
||||
READ_HEX(size32);
|
||||
item.Size = size32;
|
||||
}
|
||||
READ_HEX(item.DevMajor);
|
||||
READ_HEX(item.DevMinor);
|
||||
READ_HEX(item.RDevMajor);
|
||||
READ_HEX(item.RDevMinor);
|
||||
READ_HEX(nameSize);
|
||||
READ_HEX(item.ChkSum);
|
||||
if (nameSize >= kNameSizeMax)
|
||||
return S_OK;
|
||||
item.HeaderSize = GetAlignedSize(nameSize + k_HexRecord_Size, item.Align);
|
||||
nameSize = item.HeaderSize - k_HexRecord_Size;
|
||||
}
|
||||
}
|
||||
if (nameSize > kNameSizeMax)
|
||||
return S_FALSE;
|
||||
if (nameSize == 0 || nameSize >= kNameSizeMax)
|
||||
return S_OK;
|
||||
char *s = item.Name.GetBuf(nameSize);
|
||||
size_t processedSize = nameSize;
|
||||
RINOK(Read(s, &processedSize));
|
||||
item.Name.ReleaseBuf_CalcLen(nameSize);
|
||||
if (processedSize != nameSize)
|
||||
{
|
||||
errorType = k_ErrorType_UnexpectedEnd;
|
||||
return S_OK;
|
||||
}
|
||||
errorType = k_ErrorType_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CItem> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
UInt64 _phySize;
|
||||
EType _Type;
|
||||
EErrorType _error;
|
||||
bool _isArc;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidSubType
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidIsDir,
|
||||
kpidSize,
|
||||
kpidMTime,
|
||||
kpidPosixAttrib,
|
||||
kpidLinks
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidSubType: prop = k_Types[(unsigned)_Type]; break;
|
||||
case kpidPhySize: prop = _phySize; break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_isArc)
|
||||
v |= kpv_ErrorFlags_IsNotArc;
|
||||
switch (_error)
|
||||
{
|
||||
case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
|
||||
case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break;
|
||||
}
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
{
|
||||
Close();
|
||||
|
||||
UInt64 endPos = 0;
|
||||
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
if (callback)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
}
|
||||
|
||||
_items.Clear();
|
||||
CInArchive arc;
|
||||
|
||||
arc.Stream = stream;
|
||||
arc.Processed = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItem item;
|
||||
item.HeaderPos = arc.Processed;
|
||||
HRESULT result = arc.GetNextItem(item, _error);
|
||||
if (result == S_FALSE)
|
||||
return S_FALSE;
|
||||
if (result != S_OK)
|
||||
return S_FALSE;
|
||||
if (_error != k_ErrorType_OK)
|
||||
{
|
||||
if (_error == k_ErrorType_Corrupted)
|
||||
arc.Processed = item.HeaderPos;
|
||||
break;
|
||||
}
|
||||
if (_items.IsEmpty())
|
||||
_Type = item.Type;
|
||||
else if (_items.Back().Type != item.Type)
|
||||
{
|
||||
_error = k_ErrorType_Corrupted;
|
||||
arc.Processed = item.HeaderPos;
|
||||
break;
|
||||
}
|
||||
if (item.IsTrailer())
|
||||
break;
|
||||
|
||||
_items.Add(item);
|
||||
|
||||
{
|
||||
// archive.SkipDataRecords(item.Size, item.Align);
|
||||
UInt64 dataSize = item.Size;
|
||||
UInt32 align = item.Align;
|
||||
while ((dataSize & (align - 1)) != 0)
|
||||
dataSize++;
|
||||
|
||||
// _error = k_ErrorType_UnexpectedEnd; break;
|
||||
|
||||
arc.Processed += dataSize;
|
||||
if (arc.Processed > endPos)
|
||||
{
|
||||
_error = k_ErrorType_UnexpectedEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt64 newPostion;
|
||||
RINOK(stream->Seek(dataSize, STREAM_SEEK_CUR, &newPostion));
|
||||
if (arc.Processed != newPostion)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (callback && (_items.Size() & 0xFF) == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos));
|
||||
}
|
||||
}
|
||||
_phySize = arc.Processed;
|
||||
if (_error != k_ErrorType_OK)
|
||||
{
|
||||
if (_items.Size() == 0)
|
||||
return S_FALSE;
|
||||
if (_items.Size() == 1 && _items[0].IsBin())
|
||||
{
|
||||
// probably it's false detected archive. So we return error
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read tailing zeros.
|
||||
// Most of cpio files use 512-bytes aligned zeros
|
||||
UInt64 pos = arc.Processed;
|
||||
const UInt32 kTailSize_MAX = 1 << 9;
|
||||
Byte buf[kTailSize_MAX];
|
||||
|
||||
UInt32 rem = (kTailSize_MAX - (UInt32)pos) & (kTailSize_MAX - 1);
|
||||
if (rem != 0)
|
||||
{
|
||||
rem++; // we need to see that it's end of file
|
||||
size_t processed = rem;
|
||||
RINOK(ReadStream(stream, buf, &processed));
|
||||
if (processed < rem)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < processed && buf[i] == 0; i++);
|
||||
if (i == processed)
|
||||
_phySize += processed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isArc = true;
|
||||
_stream = stream;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
_phySize = 0;
|
||||
_Type = k_Type_BinLe;
|
||||
_isArc = false;
|
||||
_error = k_ErrorType_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
const CItem &item = _items[index];
|
||||
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
UString res;
|
||||
bool needConvert = true;
|
||||
#ifdef _WIN32
|
||||
if (ConvertUTF8ToUnicode(item.Name, res))
|
||||
needConvert = false;
|
||||
#endif
|
||||
if (needConvert)
|
||||
res = MultiByteToUnicodeString(item.Name, CP_OEMCP);
|
||||
prop = NItemName::GetOSName(res);
|
||||
break;
|
||||
}
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
prop = (UInt64)item.Size;
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
if (item.MTime != 0)
|
||||
{
|
||||
FILETIME utc;
|
||||
NTime::UnixTimeToFileTime(item.MTime, utc);
|
||||
prop = utc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidPosixAttrib: prop = item.Mode; break;
|
||||
case kpidLinks: prop = item.NumLinks; break;
|
||||
/*
|
||||
case kpidinode: prop = item.inode; break;
|
||||
case kpidiChkSum: prop = item.ChkSum; break;
|
||||
*/
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
class COutStreamWithSum:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
UInt32 _crc;
|
||||
bool _calculate;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init(bool calculate = true)
|
||||
{
|
||||
_size = 0;
|
||||
_calculate = calculate;
|
||||
_crc = 0;
|
||||
}
|
||||
void EnableCalc(bool calculate) { _calculate = calculate; }
|
||||
void InitCRC() { _crc = 0; }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
UInt32 GetCRC() const { return _crc; }
|
||||
};
|
||||
|
||||
STDMETHODIMP COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, size, &size);
|
||||
if (_calculate)
|
||||
{
|
||||
UInt32 crc = 0;
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
crc += (UInt32)(((const Byte *)data)[i]);
|
||||
_crc += crc;
|
||||
}
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum;
|
||||
CMyComPtr<ISequentialOutStream> outStreamSum(outStreamSumSpec);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
currentTotalSize += item.Size;
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
outStreamSumSpec->Init(item.IsCrcFormat());
|
||||
outStreamSumSpec->SetStream(outStream);
|
||||
outStream.Release();
|
||||
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
RINOK(copyCoder->Code(inStream, outStreamSum, NULL, NULL, progress));
|
||||
outStreamSumSpec->ReleaseStream();
|
||||
Int32 res = NExtract::NOperationResult::kDataError;
|
||||
if (copyCoderSpec->TotalSize == item.Size)
|
||||
{
|
||||
res = NExtract::NOperationResult::kOK;
|
||||
if (item.IsCrcFormat() && item.ChkSum != outStreamSumSpec->GetCRC())
|
||||
res = NExtract::NOperationResult::kCRCError;
|
||||
}
|
||||
RINOK(extractCallback->SetOperationResult(res));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CItem &item = _items[index];
|
||||
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static const Byte k_Signature[] = {
|
||||
5, '0', '7', '0', '7', '0',
|
||||
2, kMagicBin0, kMagicBin1,
|
||||
2, kMagicBin1, kMagicBin0 };
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"Cpio", "cpio", 0, 0xED,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kMultiSignature,
|
||||
IsArc_Cpio)
|
||||
|
||||
}}
|
||||
787
CPP/7zip/Archive/CramfsHandler.cpp
Normal file
787
CPP/7zip/Archive/CramfsHandler.cpp
Normal file
@@ -0,0 +1,787 @@
|
||||
// CramfsHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/7zCrc.h"
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
#include "../../../C/LzmaDec.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/MyLinux.h"
|
||||
#include "../../Common/StringConvert.h"
|
||||
|
||||
#include "../../Windows/PropVariantUtils.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
#include "../Compress/ZlibDecoder.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCramfs {
|
||||
|
||||
#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' }
|
||||
|
||||
static const Byte kSignature[] = SIGNATURE;
|
||||
|
||||
static const UInt32 kArcSizeMax = (256 + 16) << 20;
|
||||
static const UInt32 kNumFilesMax = (1 << 19);
|
||||
static const unsigned kNumDirLevelsMax = (1 << 8);
|
||||
|
||||
static const UInt32 kHeaderSize = 0x40;
|
||||
static const unsigned kHeaderNameSize = 16;
|
||||
static const UInt32 kNodeSize = 12;
|
||||
|
||||
static const UInt32 kFlag_FsVer2 = (1 << 0);
|
||||
|
||||
static const unsigned k_Flags_BlockSize_Shift = 11;
|
||||
static const unsigned k_Flags_BlockSize_Mask = 7;
|
||||
static const unsigned k_Flags_Method_Shift = 14;
|
||||
static const unsigned k_Flags_Method_Mask = 3;
|
||||
|
||||
/*
|
||||
There is possible collision in flags:
|
||||
- Original CramFS writes 0 in method field. But it uses ZLIB.
|
||||
- Modified CramFS writes 0 in method field for "NONE" compression?
|
||||
How to solve that collision?
|
||||
*/
|
||||
|
||||
#define k_Flags_Method_NONE 0
|
||||
#define k_Flags_Method_ZLIB 1
|
||||
#define k_Flags_Method_LZMA 2
|
||||
|
||||
static const char * const k_Methods[] =
|
||||
{
|
||||
"Copy"
|
||||
, "ZLIB"
|
||||
, "LZMA"
|
||||
, "Unknown"
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair k_Flags[] =
|
||||
{
|
||||
{ 0, "Ver2" },
|
||||
{ 1, "SortedDirs" },
|
||||
{ 8, "Holes" },
|
||||
{ 9, "WrongSignature" },
|
||||
{ 10, "ShiftedRootOffset" }
|
||||
};
|
||||
|
||||
static const unsigned kBlockSizeLog = 12;
|
||||
|
||||
/*
|
||||
struct CNode
|
||||
{
|
||||
UInt16 Mode;
|
||||
UInt16 Uid;
|
||||
UInt32 Size;
|
||||
Byte Gid;
|
||||
UInt32 NameLen;
|
||||
UInt32 Offset;
|
||||
|
||||
void Parse(const Byte *p)
|
||||
{
|
||||
Mode = GetUi16(p);
|
||||
Uid = GetUi16(p + 2);
|
||||
Size = Get32(p + 4) & 0xFFFFFF;
|
||||
Gid = p[7];
|
||||
NameLen = p[8] & 0x3F;
|
||||
Offset = Get32(p + 8) >> 6;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
|
||||
|
||||
static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
|
||||
static bool IsDir(const Byte *p, bool be) { return MY_LIN_S_ISDIR(GetMode(p, be)); }
|
||||
|
||||
static UInt32 GetSize(const Byte *p, bool be)
|
||||
{
|
||||
if (be)
|
||||
return GetBe32(p + 4) >> 8;
|
||||
else
|
||||
return GetUi32(p + 4) & 0xFFFFFF;
|
||||
}
|
||||
|
||||
static UInt32 GetNameLen(const Byte *p, bool be)
|
||||
{
|
||||
if (be)
|
||||
return (p[8] & 0xFC);
|
||||
else
|
||||
return (p[8] & 0x3F) << 2;
|
||||
}
|
||||
|
||||
static UInt32 GetOffset(const Byte *p, bool be)
|
||||
{
|
||||
if (be)
|
||||
return (GetBe32(p + 8) & 0x03FFFFFF) << 2;
|
||||
else
|
||||
return GetUi32(p + 8) >> 6 << 2;
|
||||
}
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UInt32 Offset;
|
||||
int Parent;
|
||||
};
|
||||
|
||||
struct CHeader
|
||||
{
|
||||
bool be;
|
||||
UInt32 Size;
|
||||
UInt32 Flags;
|
||||
// UInt32 Future;
|
||||
UInt32 Crc;
|
||||
// UInt32 Edition;
|
||||
UInt32 NumBlocks;
|
||||
UInt32 NumFiles;
|
||||
char Name[kHeaderNameSize];
|
||||
|
||||
bool Parse(const Byte *p)
|
||||
{
|
||||
if (memcmp(p + 16, kSignature, ARRAY_SIZE(kSignature)) != 0)
|
||||
return false;
|
||||
switch (GetUi32(p))
|
||||
{
|
||||
case 0x28CD3D45: be = false; break;
|
||||
case 0x453DCD28: be = true; break;
|
||||
default: return false;
|
||||
}
|
||||
Size = Get32(p + 4);
|
||||
Flags = Get32(p + 8);
|
||||
// Future = Get32(p + 0xC);
|
||||
Crc = Get32(p + 0x20);
|
||||
// Edition = Get32(p + 0x24);
|
||||
NumBlocks = Get32(p + 0x28);
|
||||
NumFiles = Get32(p + 0x2C);
|
||||
memcpy(Name, p + 0x30, kHeaderNameSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; }
|
||||
unsigned GetBlockSizeShift() const { return (unsigned)(Flags >> k_Flags_BlockSize_Shift) & k_Flags_BlockSize_Mask; }
|
||||
unsigned GetMethod() const { return (unsigned)(Flags >> k_Flags_Method_Shift) & k_Flags_Method_Mask; }
|
||||
};
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CRecordVector<CItem> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
Byte *_data;
|
||||
UInt32 _size;
|
||||
UInt32 _headersSize;
|
||||
|
||||
UInt32 _errorFlags;
|
||||
bool _isArc;
|
||||
|
||||
CHeader _h;
|
||||
UInt32 _phySize;
|
||||
|
||||
unsigned _method;
|
||||
unsigned _blockSizeLog;
|
||||
|
||||
// Current file
|
||||
|
||||
NCompress::NZlib::CDecoder *_zlibDecoderSpec;
|
||||
CMyComPtr<ICompressCoder> _zlibDecoder;
|
||||
|
||||
CBufInStream *_inStreamSpec;
|
||||
CMyComPtr<ISequentialInStream> _inStream;
|
||||
|
||||
CBufPtrSeqOutStream *_outStreamSpec;
|
||||
CMyComPtr<ISequentialOutStream> _outStream;
|
||||
|
||||
UInt32 _curBlocksOffset;
|
||||
UInt32 _curNumBlocks;
|
||||
|
||||
HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level);
|
||||
HRESULT Open2(IInStream *inStream);
|
||||
AString GetPath(int index) const;
|
||||
bool GetPackSize(int index, UInt32 &res) const;
|
||||
void Free();
|
||||
|
||||
UInt32 GetNumBlocks(UInt32 size) const
|
||||
{
|
||||
return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog;
|
||||
}
|
||||
|
||||
void UpdatePhySize(UInt32 s)
|
||||
{
|
||||
if (_phySize < s)
|
||||
_phySize = s;
|
||||
}
|
||||
|
||||
public:
|
||||
CHandler(): _data(0) {}
|
||||
~CHandler() { Free(); }
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidIsDir,
|
||||
kpidSize,
|
||||
kpidPackSize,
|
||||
kpidPosixAttrib
|
||||
// kpidOffset
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidVolumeName,
|
||||
kpidBigEndian,
|
||||
kpidCharacts,
|
||||
kpidClusterSize,
|
||||
kpidMethod,
|
||||
kpidHeadersSize,
|
||||
kpidNumSubFiles,
|
||||
kpidNumBlocks
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
|
||||
{
|
||||
const Byte *p = _data + baseOffset;
|
||||
bool be = _h.be;
|
||||
if (!IsDir(p, be))
|
||||
return S_OK;
|
||||
UInt32 offset = GetOffset(p, be);
|
||||
UInt32 size = GetSize(p, be);
|
||||
if (offset == 0 && size == 0)
|
||||
return S_OK;
|
||||
UInt32 end = offset + size;
|
||||
if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
|
||||
return S_FALSE;
|
||||
UpdatePhySize(end);
|
||||
if (end > _headersSize)
|
||||
_headersSize = end;
|
||||
|
||||
unsigned startIndex = _items.Size();
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax)
|
||||
return S_FALSE;
|
||||
CItem item;
|
||||
item.Parent = parent;
|
||||
item.Offset = offset;
|
||||
_items.Add(item);
|
||||
UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be);
|
||||
if (size < nodeLen)
|
||||
return S_FALSE;
|
||||
offset += nodeLen;
|
||||
size -= nodeLen;
|
||||
}
|
||||
|
||||
unsigned endIndex = _items.Size();
|
||||
for (unsigned i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
RINOK(OpenDir(i, _items[i].Offset, level + 1));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *inStream)
|
||||
{
|
||||
Byte buf[kHeaderSize];
|
||||
RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
|
||||
if (!_h.Parse(buf))
|
||||
return S_FALSE;
|
||||
_method = k_Flags_Method_ZLIB;
|
||||
_blockSizeLog = kBlockSizeLog;
|
||||
_phySize = kHeaderSize;
|
||||
if (_h.IsVer2())
|
||||
{
|
||||
_method = _h.GetMethod();
|
||||
// FIT IT. Now we don't know correct way to work with collision in method field.
|
||||
if (_method == k_Flags_Method_NONE)
|
||||
_method = k_Flags_Method_ZLIB;
|
||||
_blockSizeLog = kBlockSizeLog + _h.GetBlockSizeShift();
|
||||
if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax)
|
||||
return S_FALSE;
|
||||
_phySize = _h.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 size;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_END, &size));
|
||||
if (size > kArcSizeMax)
|
||||
size = kArcSizeMax;
|
||||
_h.Size = (UInt32)size;
|
||||
RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
_data = (Byte *)MidAlloc(_h.Size);
|
||||
if (_data == 0)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(_data, buf, kHeaderSize);
|
||||
size_t processed = _h.Size - kHeaderSize;
|
||||
RINOK(ReadStream(inStream, _data + kHeaderSize, &processed));
|
||||
if (processed < kNodeSize)
|
||||
return S_FALSE;
|
||||
_size = kHeaderSize + (UInt32)processed;
|
||||
if (_h.IsVer2())
|
||||
{
|
||||
if (_size != _h.Size)
|
||||
_errorFlags = kpv_ErrorFlags_UnexpectedEnd;
|
||||
else
|
||||
{
|
||||
SetUi32(_data + 0x20, 0);
|
||||
if (CrcCalc(_data, _h.Size) != _h.Crc)
|
||||
{
|
||||
_errorFlags = kpv_ErrorFlags_HeadersError;
|
||||
// _errorMessage = "CRC error";
|
||||
}
|
||||
}
|
||||
if (_h.NumFiles >= 1)
|
||||
_items.ClearAndReserve(_h.NumFiles - 1);
|
||||
}
|
||||
|
||||
RINOK(OpenDir(-1, kHeaderSize, 0));
|
||||
|
||||
if (!_h.IsVer2())
|
||||
{
|
||||
FOR_VECTOR (i, _items)
|
||||
{
|
||||
const CItem &item = _items[i];
|
||||
const Byte *p = _data + item.Offset;
|
||||
bool be = _h.be;
|
||||
if (IsDir(p, be))
|
||||
continue;
|
||||
UInt32 offset = GetOffset(p, be);
|
||||
if (offset < kHeaderSize)
|
||||
continue;
|
||||
UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
|
||||
if (numBlocks == 0)
|
||||
continue;
|
||||
UInt32 start = offset + numBlocks * 4;
|
||||
if (start > _size)
|
||||
continue;
|
||||
UInt32 end = Get32(_data + start - 4);
|
||||
if (end >= start)
|
||||
UpdatePhySize(end);
|
||||
}
|
||||
|
||||
// Read tailing zeros. Most cramfs archives use 4096-bytes aligned zeros
|
||||
const UInt32 kTailSize_MAX = 1 << 12;
|
||||
UInt32 endPos = (_phySize + kTailSize_MAX - 1) & ~(kTailSize_MAX - 1);
|
||||
if (endPos > _size)
|
||||
endPos = _size;
|
||||
UInt32 pos;
|
||||
for (pos = _phySize; pos < endPos && _data[pos] == 0; pos++);
|
||||
if (pos == endPos)
|
||||
_phySize = endPos;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
AString CHandler::GetPath(int index) const
|
||||
{
|
||||
unsigned len = 0;
|
||||
int indexMem = index;
|
||||
do
|
||||
{
|
||||
const CItem &item = _items[index];
|
||||
index = item.Parent;
|
||||
const Byte *p = _data + item.Offset;
|
||||
unsigned size = GetNameLen(p, _h.be);
|
||||
p += kNodeSize;
|
||||
unsigned i;
|
||||
for (i = 0; i < size && p[i]; i++);
|
||||
len += i + 1;
|
||||
}
|
||||
while (index >= 0);
|
||||
len--;
|
||||
|
||||
AString path;
|
||||
char *dest = path.GetBuf_SetEnd(len) + len;
|
||||
index = indexMem;
|
||||
for (;;)
|
||||
{
|
||||
const CItem &item = _items[index];
|
||||
index = item.Parent;
|
||||
const Byte *p = _data + item.Offset;
|
||||
unsigned size = GetNameLen(p, _h.be);
|
||||
p += kNodeSize;
|
||||
unsigned i;
|
||||
for (i = 0; i < size && p[i]; i++);
|
||||
dest -= i;
|
||||
memcpy(dest, p, i);
|
||||
if (index < 0)
|
||||
break;
|
||||
*(--dest) = CHAR_PATH_SEPARATOR;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
bool CHandler::GetPackSize(int index, UInt32 &res) const
|
||||
{
|
||||
res = 0;
|
||||
const CItem &item = _items[index];
|
||||
const Byte *p = _data + item.Offset;
|
||||
bool be = _h.be;
|
||||
UInt32 offset = GetOffset(p, be);
|
||||
if (offset < kHeaderSize)
|
||||
return false;
|
||||
UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
|
||||
if (numBlocks == 0)
|
||||
return true;
|
||||
UInt32 start = offset + numBlocks * 4;
|
||||
if (start > _size)
|
||||
return false;
|
||||
UInt32 end = Get32(_data + start - 4);
|
||||
if (end < start)
|
||||
return false;
|
||||
res = end - start;
|
||||
return true;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
{
|
||||
Close();
|
||||
RINOK(Open2(stream));
|
||||
_isArc = true;
|
||||
_stream = stream;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
void CHandler::Free()
|
||||
{
|
||||
MidFree(_data);
|
||||
_data = 0;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_isArc = false;
|
||||
_phySize = 0;
|
||||
_errorFlags = 0;
|
||||
_headersSize = 0;
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
Free();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidVolumeName:
|
||||
{
|
||||
char dest[kHeaderNameSize + 4];
|
||||
memcpy(dest, _h.Name, kHeaderNameSize);
|
||||
dest[kHeaderNameSize] = 0;
|
||||
prop = dest;
|
||||
break;
|
||||
}
|
||||
case kpidBigEndian: prop = _h.be; break;
|
||||
case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
|
||||
case kpidMethod: prop = k_Methods[_method]; break;
|
||||
case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
|
||||
case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break;
|
||||
case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break;
|
||||
case kpidPhySize: prop = _phySize; break;
|
||||
case kpidHeadersSize: prop = _headersSize; break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = _errorFlags;
|
||||
if (!_isArc)
|
||||
v |= kpv_ErrorFlags_IsNotArc;
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
const CItem &item = _items[index];
|
||||
const Byte *p = _data + item.Offset;
|
||||
bool be = _h.be;
|
||||
bool isDir = IsDir(p, be);
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
|
||||
case kpidIsDir: prop = isDir; break;
|
||||
// case kpidOffset: prop = (UInt32)GetOffset(p, be); break;
|
||||
case kpidSize: if (!isDir) prop = GetSize(p, be); break;
|
||||
case kpidPackSize:
|
||||
if (!isDir)
|
||||
{
|
||||
UInt32 size;
|
||||
if (GetPackSize(index, size))
|
||||
prop = size;
|
||||
}
|
||||
break;
|
||||
case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
class CCramfsInStream: public CCachedInStream
|
||||
{
|
||||
HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
|
||||
public:
|
||||
CHandler *Handler;
|
||||
};
|
||||
|
||||
HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
|
||||
{
|
||||
return Handler->ReadBlock(blockIndex, dest, blockSize);
|
||||
}
|
||||
|
||||
HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
|
||||
{
|
||||
if (_method == k_Flags_Method_ZLIB)
|
||||
{
|
||||
if (!_zlibDecoder)
|
||||
{
|
||||
_zlibDecoderSpec = new NCompress::NZlib::CDecoder();
|
||||
_zlibDecoder = _zlibDecoderSpec;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_method != k_Flags_Method_LZMA)
|
||||
{
|
||||
// probably we must support no-compression archives here.
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
const bool be = _h.be;
|
||||
const Byte *p2 = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
|
||||
const UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p2 - 4));
|
||||
const UInt32 end = Get32(p2);
|
||||
if (end < start || end > _size)
|
||||
return S_FALSE;
|
||||
const UInt32 inSize = end - start;
|
||||
|
||||
if (_method == k_Flags_Method_LZMA)
|
||||
{
|
||||
const unsigned kLzmaHeaderSize = LZMA_PROPS_SIZE + 4;
|
||||
if (inSize < kLzmaHeaderSize)
|
||||
return S_FALSE;
|
||||
const Byte *p = _data + start;
|
||||
UInt32 destSize32 = GetUi32(p + LZMA_PROPS_SIZE);
|
||||
if (destSize32 > blockSize)
|
||||
return S_FALSE;
|
||||
SizeT destLen = destSize32;
|
||||
SizeT srcLen = inSize - kLzmaHeaderSize;
|
||||
ELzmaStatus status;
|
||||
SRes res = LzmaDecode(dest, &destLen, p + kLzmaHeaderSize, &srcLen,
|
||||
p, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc);
|
||||
if (res != SZ_OK
|
||||
|| (status != LZMA_STATUS_FINISHED_WITH_MARK &&
|
||||
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||
|| destLen != destSize32
|
||||
|| srcLen != inSize - kLzmaHeaderSize)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!_inStream)
|
||||
{
|
||||
_inStreamSpec = new CBufInStream();
|
||||
_inStream = _inStreamSpec;
|
||||
}
|
||||
if (!_outStream)
|
||||
{
|
||||
_outStreamSpec = new CBufPtrSeqOutStream();
|
||||
_outStream = _outStreamSpec;
|
||||
}
|
||||
_inStreamSpec->Init(_data + start, inSize);
|
||||
_outStreamSpec->Init(dest, blockSize);
|
||||
RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL));
|
||||
return (inSize == _zlibDecoderSpec->GetInputProcessedSize() &&
|
||||
_outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
bool be = _h.be;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset;
|
||||
if (!IsDir(p, be))
|
||||
totalSize += GetSize(p, be);
|
||||
}
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 totalPackSize;
|
||||
totalSize = totalPackSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = totalPackSize;
|
||||
lps->OutSize = totalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
const Byte *p = _data + item.Offset;
|
||||
|
||||
if (IsDir(p, be))
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
UInt32 curSize = GetSize(p, be);
|
||||
totalSize += curSize;
|
||||
UInt32 packSize;
|
||||
if (GetPackSize(index, packSize))
|
||||
totalPackSize += packSize;
|
||||
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
|
||||
UInt32 offset = GetOffset(p, be);
|
||||
if (offset < kHeaderSize)
|
||||
curSize = 0;
|
||||
|
||||
int res = NExtract::NOperationResult::kDataError;
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> inSeqStream;
|
||||
HRESULT hres = GetStream(index, &inSeqStream);
|
||||
if (hres == E_OUTOFMEMORY)
|
||||
return E_OUTOFMEMORY;
|
||||
if (hres == S_FALSE || !inSeqStream)
|
||||
res = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
else
|
||||
{
|
||||
RINOK(hres);
|
||||
{
|
||||
hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
|
||||
if (hres == S_OK)
|
||||
{
|
||||
if (copyCoderSpec->TotalSize == curSize)
|
||||
res = NExtract::NOperationResult::kOK;
|
||||
}
|
||||
else if (hres == E_NOTIMPL)
|
||||
res = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
else if (hres != S_FALSE)
|
||||
return hres;
|
||||
}
|
||||
}
|
||||
}
|
||||
RINOK(extractCallback->SetOperationResult(res));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
const CItem &item = _items[index];
|
||||
const Byte *p = _data + item.Offset;
|
||||
|
||||
bool be = _h.be;
|
||||
if (IsDir(p, be))
|
||||
return E_FAIL;
|
||||
|
||||
UInt32 size = GetSize(p, be);
|
||||
UInt32 numBlocks = GetNumBlocks(size);
|
||||
UInt32 offset = GetOffset(p, be);
|
||||
if (offset < kHeaderSize)
|
||||
{
|
||||
if (offset != 0)
|
||||
return S_FALSE;
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init(NULL, 0);
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (offset + numBlocks * 4 > _size)
|
||||
return S_FALSE;
|
||||
UInt32 prev = offset;
|
||||
for (UInt32 i = 0; i < numBlocks; i++)
|
||||
{
|
||||
UInt32 next = Get32(_data + offset + i * 4);
|
||||
if (next < prev || next > _size)
|
||||
return S_FALSE;
|
||||
prev = next;
|
||||
}
|
||||
|
||||
CCramfsInStream *streamSpec = new CCramfsInStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
_curNumBlocks = numBlocks;
|
||||
_curBlocksOffset = offset;
|
||||
streamSpec->Handler = this;
|
||||
if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog))
|
||||
return E_OUTOFMEMORY;
|
||||
streamSpec->Init(size);
|
||||
*stream = streamTemp.Detach();
|
||||
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"CramFS", "cramfs", 0, 0xD3,
|
||||
kSignature,
|
||||
16,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
3
CPP/7zip/Archive/DeflateProps.cpp
Normal file
3
CPP/7zip/Archive/DeflateProps.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// DeflateProps.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
6
CPP/7zip/Archive/DeflateProps.h
Normal file
6
CPP/7zip/Archive/DeflateProps.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// DeflateProps.h
|
||||
|
||||
#ifndef __DEFLATE_PROPS_H
|
||||
#define __DEFLATE_PROPS_H
|
||||
|
||||
#endif
|
||||
94
CPP/7zip/Archive/DllExports.cpp
Normal file
94
CPP/7zip/Archive/DllExports.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// DLLExports.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#if defined(_7ZIP_LARGE_PAGES)
|
||||
#include "../../../C/Alloc.h"
|
||||
#endif
|
||||
|
||||
#include "../../Common/MyInitGuid.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
|
||||
#include "../../Windows/NtCheck.h"
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
#include "../IPassword.h"
|
||||
|
||||
#include "../Common/CreateCoder.h"
|
||||
|
||||
#include "IArchive.h"
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
|
||||
#define NT_CHECK_FAIL_ACTION return FALSE;
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
g_hInstance = hInstance;
|
||||
NT_CHECK;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DEFINE_GUID(CLSID_CArchiveHandler,
|
||||
k_7zip_GUID_Data1,
|
||||
k_7zip_GUID_Data2,
|
||||
k_7zip_GUID_Data3_Common,
|
||||
0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
|
||||
|
||||
STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
|
||||
|
||||
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
{
|
||||
return CreateArchiver(clsid, iid, outObject);
|
||||
}
|
||||
|
||||
STDAPI SetLargePageMode()
|
||||
{
|
||||
#if defined(_7ZIP_LARGE_PAGES)
|
||||
SetLargePageSize();
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
extern bool g_CaseSensitive;
|
||||
|
||||
STDAPI SetCaseSensitive(Int32 caseSensitive)
|
||||
{
|
||||
g_CaseSensitive = (caseSensitive != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
|
||||
CExternalCodecs g_ExternalCodecs;
|
||||
|
||||
STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
// OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL");
|
||||
if (compressCodecsInfo)
|
||||
{
|
||||
g_ExternalCodecs.GetCodecs = compressCodecsInfo;
|
||||
return g_ExternalCodecs.Load();
|
||||
}
|
||||
g_ExternalCodecs.ClearAndRelease();
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
STDAPI SetCodecs(ICompressCodecsInfo *)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
122
CPP/7zip/Archive/DllExports2.cpp
Normal file
122
CPP/7zip/Archive/DllExports2.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// DLLExports2.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/MyWindows.h"
|
||||
|
||||
#include "../../Common/MyInitGuid.h"
|
||||
|
||||
#if defined(_7ZIP_LARGE_PAGES)
|
||||
#include "../../../C/Alloc.h"
|
||||
#endif
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
|
||||
#include "../../Windows/NtCheck.h"
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
#include "../IPassword.h"
|
||||
|
||||
#include "../Common/CreateCoder.h"
|
||||
|
||||
#include "IArchive.h"
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
|
||||
#define NT_CHECK_FAIL_ACTION return FALSE;
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(
|
||||
#ifdef UNDER_CE
|
||||
HANDLE
|
||||
#else
|
||||
HINSTANCE
|
||||
#endif
|
||||
hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
// OutputDebugStringA("7z.dll DLL_PROCESS_ATTACH");
|
||||
g_hInstance = (HINSTANCE)hInstance;
|
||||
NT_CHECK;
|
||||
}
|
||||
/*
|
||||
if (dwReason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
OutputDebugStringA("7z.dll DLL_PROCESS_DETACH");
|
||||
}
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEFINE_GUID(CLSID_CArchiveHandler,
|
||||
k_7zip_GUID_Data1,
|
||||
k_7zip_GUID_Data2,
|
||||
k_7zip_GUID_Data3_Common,
|
||||
0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
|
||||
|
||||
STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
|
||||
STDAPI CreateHasher(const GUID *clsid, IHasher **hasher);
|
||||
STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject);
|
||||
|
||||
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
{
|
||||
// COM_TRY_BEGIN
|
||||
*outObject = 0;
|
||||
if (*iid == IID_ICompressCoder ||
|
||||
*iid == IID_ICompressCoder2 ||
|
||||
*iid == IID_ICompressFilter)
|
||||
return CreateCoder(clsid, iid, outObject);
|
||||
if (*iid == IID_IHasher)
|
||||
return CreateHasher(clsid, (IHasher **)outObject);
|
||||
return CreateArchiver(clsid, iid, outObject);
|
||||
// COM_TRY_END
|
||||
}
|
||||
|
||||
STDAPI SetLargePageMode()
|
||||
{
|
||||
#if defined(_7ZIP_LARGE_PAGES)
|
||||
SetLargePageSize();
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
extern bool g_CaseSensitive;
|
||||
|
||||
STDAPI SetCaseSensitive(Int32 caseSensitive)
|
||||
{
|
||||
g_CaseSensitive = (caseSensitive != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
|
||||
CExternalCodecs g_ExternalCodecs;
|
||||
|
||||
STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
// OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL");
|
||||
if (compressCodecsInfo)
|
||||
{
|
||||
g_ExternalCodecs.GetCodecs = compressCodecsInfo;
|
||||
return g_ExternalCodecs.Load();
|
||||
}
|
||||
g_ExternalCodecs.ClearAndRelease();
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
STDAPI SetCodecs(ICompressCodecsInfo *)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
1586
CPP/7zip/Archive/DmgHandler.cpp
Normal file
1586
CPP/7zip/Archive/DmgHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
975
CPP/7zip/Archive/ElfHandler.cpp
Normal file
975
CPP/7zip/Archive/ElfHandler.cpp
Normal file
@@ -0,0 +1,975 @@
|
||||
// ElfHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/IntToString.h"
|
||||
#include "../../Common/MyBuffer.h"
|
||||
|
||||
#include "../../Windows/PropVariantUtils.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); }
|
||||
static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); }
|
||||
static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); }
|
||||
|
||||
#define G16(offs, v) v = Get16(p + (offs), be)
|
||||
#define G32(offs, v) v = Get32(p + (offs), be)
|
||||
#define G64(offs, v) v = Get64(p + (offs), be)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NElf {
|
||||
|
||||
/*
|
||||
ELF Structure for most files (real order can be different):
|
||||
Header
|
||||
Program (segment) header table (used at runtime)
|
||||
Segment1 (Section ... Section)
|
||||
Segment2
|
||||
...
|
||||
SegmentN
|
||||
Section header table (the data for linking and relocation)
|
||||
*/
|
||||
|
||||
#define ELF_CLASS_32 1
|
||||
#define ELF_CLASS_64 2
|
||||
|
||||
#define ELF_DATA_2LSB 1
|
||||
#define ELF_DATA_2MSB 2
|
||||
|
||||
static const UInt32 kHeaderSize32 = 0x34;
|
||||
static const UInt32 kHeaderSize64 = 0x40;
|
||||
|
||||
static const UInt32 kSegmentSize32 = 0x20;
|
||||
static const UInt32 kSegmentSize64 = 0x38;
|
||||
|
||||
static const UInt32 kSectionSize32 = 0x28;
|
||||
static const UInt32 kSectionSize64 = 0x40;
|
||||
|
||||
struct CHeader
|
||||
{
|
||||
bool Mode64;
|
||||
bool Be;
|
||||
Byte Os;
|
||||
Byte AbiVer;
|
||||
|
||||
UInt16 Type;
|
||||
UInt16 Machine;
|
||||
// UInt32 Version;
|
||||
|
||||
// UInt64 EntryVa;
|
||||
UInt64 ProgOffset;
|
||||
UInt64 SectOffset;
|
||||
UInt32 Flags;
|
||||
UInt16 HeaderSize;
|
||||
UInt16 SegmentEntrySize;
|
||||
UInt16 NumSegments;
|
||||
UInt16 SectionEntrySize;
|
||||
UInt16 NumSections;
|
||||
UInt16 NamesSectIndex;
|
||||
|
||||
bool Parse(const Byte *buf);
|
||||
|
||||
UInt64 GetHeadersSize() const { return (UInt64)HeaderSize +
|
||||
(UInt32)NumSegments * SegmentEntrySize +
|
||||
(UInt32)NumSections * SectionEntrySize; }
|
||||
};
|
||||
|
||||
bool CHeader::Parse(const Byte *p)
|
||||
{
|
||||
switch (p[4])
|
||||
{
|
||||
case ELF_CLASS_32: Mode64 = false; break;
|
||||
case ELF_CLASS_64: Mode64 = true; break;
|
||||
default: return false;
|
||||
}
|
||||
bool be;
|
||||
switch (p[5])
|
||||
{
|
||||
case ELF_DATA_2LSB: be = false; break;
|
||||
case ELF_DATA_2MSB: be = true; break;
|
||||
default: return false;
|
||||
}
|
||||
Be = be;
|
||||
if (p[6] != 1) // Version
|
||||
return false;
|
||||
Os = p[7];
|
||||
AbiVer = p[8];
|
||||
for (int i = 9; i < 16; i++)
|
||||
if (p[i] != 0)
|
||||
return false;
|
||||
|
||||
G16(0x10, Type);
|
||||
G16(0x12, Machine);
|
||||
if (Get32(p + 0x14, be) != 1) // Version
|
||||
return false;
|
||||
|
||||
if (Mode64)
|
||||
{
|
||||
// G64(0x18, EntryVa);
|
||||
G64(0x20, ProgOffset);
|
||||
G64(0x28, SectOffset);
|
||||
p += 0x30;
|
||||
}
|
||||
else
|
||||
{
|
||||
// G32(0x18, EntryVa);
|
||||
G32(0x1C, ProgOffset);
|
||||
G32(0x20, SectOffset);
|
||||
p += 0x24;
|
||||
}
|
||||
|
||||
G32(0, Flags);
|
||||
G16(4, HeaderSize);
|
||||
if (HeaderSize != (Mode64 ? kHeaderSize64 : kHeaderSize32))
|
||||
return false;
|
||||
|
||||
G16(6, SegmentEntrySize);
|
||||
G16(8, NumSegments);
|
||||
G16(10, SectionEntrySize);
|
||||
G16(12, NumSections);
|
||||
G16(14, NamesSectIndex);
|
||||
|
||||
if (ProgOffset < HeaderSize && (ProgOffset != 0 || NumSegments != 0)) return false;
|
||||
if (SectOffset < HeaderSize && (SectOffset != 0 || NumSections != 0)) return false;
|
||||
|
||||
if (SegmentEntrySize == 0) { if (NumSegments != 0) return false; }
|
||||
else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false;
|
||||
|
||||
if (SectionEntrySize == 0) { if (NumSections != 0) return false; }
|
||||
else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The program header table itself.
|
||||
|
||||
#define PT_PHDR 6
|
||||
|
||||
static const char *g_SegnmentTypes[] =
|
||||
{
|
||||
"Unused",
|
||||
"Loadable segment",
|
||||
"Dynamic linking tables",
|
||||
"Program interpreter path name",
|
||||
"Note section",
|
||||
"SHLIB",
|
||||
"Program header table",
|
||||
"TLS"
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_SegmentFlags[] =
|
||||
{
|
||||
{ 0, "Execute" },
|
||||
{ 1, "Write" },
|
||||
{ 2, "Read" }
|
||||
};
|
||||
|
||||
struct CSegment
|
||||
{
|
||||
UInt32 Type;
|
||||
UInt32 Flags;
|
||||
UInt64 Offset;
|
||||
UInt64 Va;
|
||||
// UInt64 Pa;
|
||||
UInt64 Size;
|
||||
UInt64 VSize;
|
||||
UInt64 Align;
|
||||
|
||||
void UpdateTotalSize(UInt64 &totalSize)
|
||||
{
|
||||
UInt64 t = Offset + Size;
|
||||
if (totalSize < t)
|
||||
totalSize = t;
|
||||
}
|
||||
void Parse(const Byte *p, bool mode64, bool be);
|
||||
};
|
||||
|
||||
void CSegment::Parse(const Byte *p, bool mode64, bool be)
|
||||
{
|
||||
G32(0, Type);
|
||||
if (mode64)
|
||||
{
|
||||
G32(4, Flags);
|
||||
G64(8, Offset);
|
||||
G64(0x10, Va);
|
||||
// G64(0x18, Pa);
|
||||
G64(0x20, Size);
|
||||
G64(0x28, VSize);
|
||||
G64(0x30, Align);
|
||||
}
|
||||
else
|
||||
{
|
||||
G32(4, Offset);
|
||||
G32(8, Va);
|
||||
// G32(0x0C, Pa);
|
||||
G32(0x10, Size);
|
||||
G32(0x14, VSize);
|
||||
G32(0x18, Flags);
|
||||
G32(0x1C, Align);
|
||||
}
|
||||
}
|
||||
|
||||
// Section_index = 0 means NO section
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
|
||||
// Section types
|
||||
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
#define SHT_UNKNOWN12 12
|
||||
#define SHT_UNKNOWN13 13
|
||||
#define SHT_INIT_ARRAY 14
|
||||
#define SHT_FINI_ARRAY 15
|
||||
#define SHT_PREINIT_ARRAY 16
|
||||
#define SHT_GROUP 17
|
||||
#define SHT_SYMTAB_SHNDX 18
|
||||
|
||||
|
||||
static const CUInt32PCharPair g_SectTypes[] =
|
||||
{
|
||||
{ 0, "NULL" },
|
||||
{ 1, "PROGBITS" },
|
||||
{ 2, "SYMTAB" },
|
||||
{ 3, "STRTAB" },
|
||||
{ 4, "RELA" },
|
||||
{ 5, "HASH" },
|
||||
{ 6, "DYNAMIC" },
|
||||
{ 7, "NOTE" },
|
||||
{ 8, "NOBITS" },
|
||||
{ 9, "REL" },
|
||||
{ 10, "SHLIB" },
|
||||
{ 11, "DYNSYM" },
|
||||
{ 12, "UNKNOWN12" },
|
||||
{ 13, "UNKNOWN13" },
|
||||
{ 14, "INIT_ARRAY" },
|
||||
{ 15, "FINI_ARRAY" },
|
||||
{ 16, "PREINIT_ARRAY" },
|
||||
{ 17, "GROUP" },
|
||||
{ 18, "SYMTAB_SHNDX" },
|
||||
{ 0x6ffffff5, "GNU_ATTRIBUTES" },
|
||||
{ 0x6ffffff6, "GNU_HASH" },
|
||||
{ 0x6ffffffd, "GNU_verdef" },
|
||||
{ 0x6ffffffe, "GNU_verneed" },
|
||||
{ 0x6fffffff, "GNU_versym" },
|
||||
// { 0x70000001, "X86_64_UNWIND" },
|
||||
{ 0x70000001, "ARM_EXIDX" },
|
||||
{ 0x70000002, "ARM_PREEMPTMAP" },
|
||||
{ 0x70000003, "ARM_ATTRIBUTES" },
|
||||
{ 0x70000004, "ARM_DEBUGOVERLAY" },
|
||||
{ 0x70000005, "ARM_OVERLAYSECTION" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_SectionFlags[] =
|
||||
{
|
||||
{ 0, "WRITE" },
|
||||
{ 1, "ALLOC" },
|
||||
{ 2, "EXECINSTR" },
|
||||
|
||||
{ 4, "MERGE" },
|
||||
{ 5, "STRINGS" },
|
||||
{ 6, "INFO_LINK" },
|
||||
{ 7, "LINK_ORDER" },
|
||||
{ 8, "OS_NONCONFORMING" },
|
||||
{ 9, "GROUP" },
|
||||
{ 10, "TLS" },
|
||||
{ 11, "CP_SECTION" },
|
||||
{ 12, "DP_SECTION" },
|
||||
{ 13, "XCORE_SHF_CP_SECTION" },
|
||||
{ 28, "64_LARGE" },
|
||||
};
|
||||
|
||||
struct CSection
|
||||
{
|
||||
UInt32 Name;
|
||||
UInt32 Type;
|
||||
UInt64 Flags;
|
||||
UInt64 Va;
|
||||
UInt64 Offset;
|
||||
UInt64 VSize;
|
||||
UInt32 Link;
|
||||
UInt32 Info;
|
||||
UInt64 AddrAlign;
|
||||
UInt64 EntSize;
|
||||
|
||||
UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; }
|
||||
|
||||
void UpdateTotalSize(UInt64 &totalSize)
|
||||
{
|
||||
UInt64 t = Offset + GetSize();
|
||||
if (totalSize < t)
|
||||
totalSize = t;
|
||||
}
|
||||
bool Parse(const Byte *p, bool mode64, bool be);
|
||||
};
|
||||
|
||||
bool CSection::Parse(const Byte *p, bool mode64, bool be)
|
||||
{
|
||||
G32(0, Name);
|
||||
G32(4, Type);
|
||||
if (mode64)
|
||||
{
|
||||
G64(0x08, Flags);
|
||||
G64(0x10, Va);
|
||||
G64(0x18, Offset);
|
||||
G64(0x20, VSize);
|
||||
G32(0x28, Link);
|
||||
G32(0x2C, Info);
|
||||
G64(0x30, AddrAlign);
|
||||
G64(0x38, EntSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
G32(0x08, Flags);
|
||||
G32(0x0C, Va);
|
||||
G32(0x10, Offset);
|
||||
G32(0x14, VSize);
|
||||
G32(0x18, Link);
|
||||
G32(0x1C, Info);
|
||||
G32(0x20, AddrAlign);
|
||||
G32(0x24, EntSize);
|
||||
}
|
||||
if (EntSize >= ((UInt32)1 << 31))
|
||||
return false;
|
||||
if (EntSize >= ((UInt32)1 << 10) &&
|
||||
EntSize >= VSize &&
|
||||
VSize != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const CUInt32PCharPair g_Machines[] =
|
||||
{
|
||||
{ 0, "None" },
|
||||
{ 1, "AT&T WE 32100" },
|
||||
{ 2, "SPARC" },
|
||||
{ 3, "Intel 386" },
|
||||
{ 4, "Motorola 68000" },
|
||||
{ 5, "Motorola 88000" },
|
||||
{ 6, "Intel 486" },
|
||||
{ 7, "Intel i860" },
|
||||
{ 8, "MIPS" },
|
||||
{ 9, "IBM S/370" },
|
||||
{ 10, "MIPS RS3000 LE" },
|
||||
{ 11, "RS6000" },
|
||||
|
||||
{ 15, "PA-RISC" },
|
||||
{ 16, "nCUBE" },
|
||||
{ 17, "Fujitsu VPP500" },
|
||||
{ 18, "SPARC 32+" },
|
||||
{ 19, "Intel i960" },
|
||||
{ 20, "PowerPC" },
|
||||
{ 21, "PowerPC 64-bit" },
|
||||
{ 22, "IBM S/390" },
|
||||
{ 23, "SPU" },
|
||||
|
||||
{ 36, "NEX v800" },
|
||||
{ 37, "Fujitsu FR20" },
|
||||
{ 38, "TRW RH-32" },
|
||||
{ 39, "Motorola RCE" },
|
||||
{ 40, "ARM" },
|
||||
{ 41, "Alpha" },
|
||||
{ 42, "Hitachi SH" },
|
||||
{ 43, "SPARC-V9" },
|
||||
{ 44, "Siemens Tricore" },
|
||||
{ 45, "ARC" },
|
||||
{ 46, "H8/300" },
|
||||
{ 47, "H8/300H" },
|
||||
{ 48, "H8S" },
|
||||
{ 49, "H8/500" },
|
||||
{ 50, "IA-64" },
|
||||
{ 51, "Stanford MIPS-X" },
|
||||
{ 52, "Motorola ColdFire" },
|
||||
{ 53, "M68HC12" },
|
||||
{ 54, "Fujitsu MMA" },
|
||||
{ 55, "Siemens PCP" },
|
||||
{ 56, "Sony nCPU" },
|
||||
{ 57, "Denso NDR1" },
|
||||
{ 58, "Motorola StarCore" },
|
||||
{ 59, "Toyota ME16" },
|
||||
{ 60, "ST100" },
|
||||
{ 61, "Advanced Logic TinyJ" },
|
||||
{ 62, "AMD64" },
|
||||
{ 63, "Sony DSP" },
|
||||
|
||||
|
||||
{ 66, "Siemens FX66" },
|
||||
{ 67, "ST9+" },
|
||||
{ 68, "ST7" },
|
||||
{ 69, "MC68HC16" },
|
||||
{ 70, "MC68HC11" },
|
||||
{ 71, "MC68HC08" },
|
||||
{ 72, "MC68HC05" },
|
||||
{ 73, "Silicon Graphics SVx" },
|
||||
{ 74, "ST19" },
|
||||
{ 75, "Digital VAX" },
|
||||
{ 76, "Axis CRIS" },
|
||||
{ 77, "Infineon JAVELIN" },
|
||||
{ 78, "Element 14 FirePath" },
|
||||
{ 79, "LSI ZSP" },
|
||||
{ 80, "MMIX" },
|
||||
{ 81, "HUANY" },
|
||||
{ 82, "SiTera Prism" },
|
||||
{ 83, "Atmel AVR" },
|
||||
{ 84, "Fujitsu FR30" },
|
||||
{ 85, "Mitsubishi D10V" },
|
||||
{ 86, "Mitsubishi D30V" },
|
||||
{ 87, "NEC v850" },
|
||||
{ 88, "Mitsubishi M32R" },
|
||||
{ 89, "Matsushita MN10300" },
|
||||
{ 90, "Matsushita MN10200" },
|
||||
{ 91, "picoJava" },
|
||||
{ 92, "OpenRISC" },
|
||||
{ 93, "ARC Tangent-A5" },
|
||||
{ 94, "Tensilica Xtensa" },
|
||||
{ 95, "Alphamosaic VideoCore" },
|
||||
{ 96, "Thompson MM GPP" },
|
||||
{ 97, "National Semiconductor 32K" },
|
||||
{ 98, "Tenor Network TPC" },
|
||||
{ 99, "Trebia SNP 1000" },
|
||||
{ 100, "ST200" },
|
||||
{ 101, "Ubicom IP2xxx" },
|
||||
{ 102, "MAX" },
|
||||
{ 103, "NS CompactRISC" },
|
||||
{ 104, "Fujitsu F2MC16" },
|
||||
{ 105, "TI msp430" },
|
||||
{ 106, "Blackfin (DSP)" },
|
||||
{ 107, "SE S1C33" },
|
||||
{ 108, "Sharp embedded" },
|
||||
{ 109, "Arca RISC" },
|
||||
{ 110, "Unicore" },
|
||||
{ 111, "eXcess" },
|
||||
{ 112, "DXP" },
|
||||
{ 113, "Altera Nios II" },
|
||||
{ 114, "NS CRX" },
|
||||
{ 115, "Motorola XGATE" },
|
||||
{ 116, "Infineon C16x/XC16x" },
|
||||
{ 117, "Renesas M16C" },
|
||||
{ 118, "Microchip Technology dsPIC30F" },
|
||||
{ 119, "Freescale CE" },
|
||||
{ 120, "Renesas M32C" },
|
||||
|
||||
{ 131, "Altium TSK3000" },
|
||||
{ 132, "Freescale RS08" },
|
||||
{ 133, "Analog Devices SHARC" },
|
||||
{ 134, "Cyan Technology eCOG2" },
|
||||
{ 135, "Sunplus S+core7 RISC" },
|
||||
{ 136, "NJR 24-bit DSP" },
|
||||
{ 137, "Broadcom VideoCore III" },
|
||||
{ 138, "Lattice FPGA" },
|
||||
{ 139, "SE C17" },
|
||||
{ 140, "TI TMS320C6000" },
|
||||
{ 141, "TI TMS320C2000" },
|
||||
{ 142, "TI TMS320C55x" },
|
||||
|
||||
{ 160, "STM 64bit VLIW Data Signal" },
|
||||
{ 161, "Cypress M8C" },
|
||||
{ 162, "Renesas R32C" },
|
||||
{ 163, "NXP TriMedia" },
|
||||
{ 164, "Qualcomm Hexagon" },
|
||||
{ 165, "Intel 8051" },
|
||||
{ 166, "STMicroelectronics STxP7x" },
|
||||
{ 167, "Andes" },
|
||||
{ 168, "Cyan Technology eCOG1X" },
|
||||
{ 169, "Dallas Semiconductor MAXQ30" },
|
||||
{ 170, "NJR 16-bit DSP" },
|
||||
{ 171, "M2000" },
|
||||
{ 172, "Cray NV2" },
|
||||
{ 173, "Renesas RX" },
|
||||
{ 174, "Imagination Technologies META" },
|
||||
{ 175, "MCST Elbrus" },
|
||||
{ 176, "Cyan Technology eCOG16" },
|
||||
{ 177, "National Semiconductor CR16" },
|
||||
{ 178, "Freescale ETPUnit" },
|
||||
{ 179, "Infineon SLE9X" },
|
||||
{ 180, "Intel L10M" },
|
||||
{ 181, "Intel K10M" },
|
||||
|
||||
{ 183, "ARM64" },
|
||||
|
||||
{ 185, "Atmel AVR32" },
|
||||
{ 186, "STM8" },
|
||||
{ 187, "Tilera TILE64" },
|
||||
{ 188, "Tilera TILEPro" },
|
||||
{ 189, "Xilinx MicroBlaze" },
|
||||
{ 190, "NVIDIA CUDA" },
|
||||
{ 191, "Tilera TILE-Gx" },
|
||||
{ 192, "CloudShield" },
|
||||
{ 193, "KIPO-KAIST Core-A 1st" },
|
||||
{ 194, "KIPO-KAIST Core-A 2nd" },
|
||||
{ 195, "Synopsys ARCompact V2" },
|
||||
{ 196, "Open8" },
|
||||
{ 197, "Renesas RL78" },
|
||||
{ 198, "Broadcom VideoCore V" },
|
||||
{ 199, "Renesas 78KOR" },
|
||||
{ 200, "Freescale 56800EX" },
|
||||
|
||||
{ 47787, "Xilinx MicroBlaze" },
|
||||
// { 0x9026, "Alpha" }
|
||||
};
|
||||
|
||||
static const CUInt32PCharPair g_OS[] =
|
||||
{
|
||||
{ 0, "None" },
|
||||
{ 1, "HP-UX" },
|
||||
{ 2, "NetBSD" },
|
||||
{ 3, "Linux" },
|
||||
{ 4, "Hurd" },
|
||||
|
||||
{ 6, "Solaris" },
|
||||
{ 7, "AIX" },
|
||||
{ 8, "IRIX" },
|
||||
{ 9, "FreeBSD" },
|
||||
{ 10, "TRU64" },
|
||||
{ 11, "Novell Modesto" },
|
||||
{ 12, "OpenBSD" },
|
||||
{ 13, "OpenVMS" },
|
||||
{ 14, "HP NSK" },
|
||||
{ 15, "AROS" },
|
||||
{ 16, "FenixOS" },
|
||||
{ 64, "Bare-metal TMS320C6000" },
|
||||
{ 65, "Linux TMS320C6000" },
|
||||
{ 97, "ARM" },
|
||||
{ 255, "Standalone" }
|
||||
};
|
||||
|
||||
#define ET_NONE 0
|
||||
#define ET_REL 1
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define ET_CORE 4
|
||||
|
||||
static const char *g_Types[] =
|
||||
{
|
||||
"None",
|
||||
"Relocatable file",
|
||||
"Executable file",
|
||||
"Shared object file",
|
||||
"Core file"
|
||||
};
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveAllowTail,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CRecordVector<CSegment> _segments;
|
||||
CRecordVector<CSection> _sections;
|
||||
CByteBuffer _namesData;
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
UInt64 _totalSize;
|
||||
CHeader _header;
|
||||
bool _headersError;
|
||||
bool _allowTail;
|
||||
|
||||
void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const;
|
||||
HRESULT Open2(IInStream *stream);
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(AllowTail)(Int32 allowTail);
|
||||
|
||||
CHandler(): _allowTail(false) {}
|
||||
};
|
||||
|
||||
void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const
|
||||
{
|
||||
if (index >= _sections.Size())
|
||||
return;
|
||||
const CSection §ion = _sections[index];
|
||||
UInt32 offset = section.Name;
|
||||
if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */)
|
||||
{
|
||||
if (showNULL)
|
||||
prop = "NULL";
|
||||
return;
|
||||
}
|
||||
const Byte *p = _namesData;
|
||||
size_t size = _namesData.Size();
|
||||
for (size_t i = offset; i < size; i++)
|
||||
if (p[i] == 0)
|
||||
{
|
||||
prop = (const char *)(p + offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidCpu,
|
||||
kpidBit64,
|
||||
kpidBigEndian,
|
||||
kpidHostOS,
|
||||
kpidCharacts,
|
||||
kpidHeadersSize,
|
||||
kpidName
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kpidLinkSection = kpidUserDefined,
|
||||
kpidInfoSection
|
||||
};
|
||||
|
||||
static const CStatProp kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR },
|
||||
{ NULL, kpidSize, VT_UI8 },
|
||||
{ NULL, kpidVirtualSize, VT_UI8 },
|
||||
{ NULL, kpidOffset, VT_UI8 },
|
||||
{ NULL, kpidVa, VT_UI8 },
|
||||
{ NULL, kpidType, VT_BSTR },
|
||||
{ NULL, kpidCharacts, VT_BSTR }
|
||||
, { "Link Section", kpidLinkSection, VT_BSTR}
|
||||
, { "Info Section", kpidInfoSection, VT_BSTR}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props_WITH_NAME
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: prop = _totalSize; break;
|
||||
case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
|
||||
case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
|
||||
case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
|
||||
case kpidShortComment:
|
||||
case kpidCpu: PAIR_TO_PROP(g_Machines, _header.Machine, prop); break;
|
||||
case kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break;
|
||||
case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
|
||||
case kpidExtension:
|
||||
{
|
||||
const char *s = NULL;
|
||||
if (_header.Type == ET_DYN)
|
||||
s = "so";
|
||||
else if (_header.Type == ET_REL)
|
||||
s = "o";
|
||||
if (s)
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
// case kpidIsSelfExe: prop = (_header.Type != ET_DYN) && (_header.Type == ET_REL); break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 flags = 0;
|
||||
if (_headersError) flags |= kpv_ErrorFlags_HeadersError;
|
||||
if (flags != 0)
|
||||
prop = flags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
if (index < _segments.Size())
|
||||
{
|
||||
const CSegment &item = _segments[index];
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
char sz[16];
|
||||
ConvertUInt32ToString(index, sz);
|
||||
prop = sz;
|
||||
break;
|
||||
}
|
||||
case kpidOffset: prop = item.Offset; break;
|
||||
case kpidVa: prop = item.Va; break;
|
||||
case kpidSize:
|
||||
case kpidPackSize: prop = (UInt64)item.Size; break;
|
||||
case kpidVirtualSize: prop = (UInt64)item.VSize; break;
|
||||
case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
|
||||
case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= _segments.Size();
|
||||
const CSection &item = _sections[index];
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath: GetSectionName(index, prop, true); break;
|
||||
case kpidOffset: prop = item.Offset; break;
|
||||
case kpidVa: prop = item.Va; break;
|
||||
case kpidSize:
|
||||
case kpidPackSize: prop = (UInt64)(item.Type == SHT_NOBITS ? 0 : item.VSize); break;
|
||||
case kpidVirtualSize: prop = item.GetSize(); break;
|
||||
case kpidType: PAIR_TO_PROP(g_SectTypes, item.Type, prop); break;
|
||||
case kpidCharacts: FLAGS_TO_PROP(g_SectionFlags, (UInt32)item.Flags, prop); break;
|
||||
case kpidLinkSection: GetSectionName(item.Link, prop, false); break;
|
||||
case kpidInfoSection: GetSectionName(item.Info, prop, false); break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream)
|
||||
{
|
||||
const UInt32 kStartSize = kHeaderSize64;
|
||||
Byte h[kStartSize];
|
||||
RINOK(ReadStream_FALSE(stream, h, kStartSize));
|
||||
if (h[0] != 0x7F || h[1] != 'E' || h[2] != 'L' || h[3] != 'F')
|
||||
return S_FALSE;
|
||||
if (!_header.Parse(h))
|
||||
return S_FALSE;
|
||||
|
||||
_totalSize = _header.HeaderSize;
|
||||
|
||||
bool addSegments = false;
|
||||
bool addSections = false;
|
||||
|
||||
if (_header.NumSections > 1)
|
||||
addSections = true;
|
||||
else
|
||||
addSegments = true;
|
||||
|
||||
if (_header.NumSegments != 0)
|
||||
{
|
||||
if (_header.ProgOffset > (UInt64)1 << 60) return S_FALSE;
|
||||
RINOK(stream->Seek(_header.ProgOffset, STREAM_SEEK_SET, NULL));
|
||||
size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments;
|
||||
|
||||
CByteArr buf(size);
|
||||
|
||||
RINOK(ReadStream_FALSE(stream, buf, size));
|
||||
|
||||
UInt64 total = _header.ProgOffset + size;
|
||||
if (_totalSize < total)
|
||||
_totalSize = total;
|
||||
|
||||
const Byte *p = buf;
|
||||
|
||||
if (addSegments)
|
||||
_segments.ClearAndReserve(_header.NumSegments);
|
||||
for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
|
||||
{
|
||||
CSegment seg;
|
||||
seg.Parse(p, _header.Mode64, _header.Be);
|
||||
seg.UpdateTotalSize(_totalSize);
|
||||
if (addSegments)
|
||||
if (seg.Type != PT_PHDR)
|
||||
_segments.AddInReserved(seg);
|
||||
}
|
||||
}
|
||||
|
||||
if (_header.NumSections != 0)
|
||||
{
|
||||
if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE;
|
||||
RINOK(stream->Seek(_header.SectOffset, STREAM_SEEK_SET, NULL));
|
||||
size_t size = (size_t)_header.SectionEntrySize * _header.NumSections;
|
||||
|
||||
CByteArr buf(size);
|
||||
|
||||
RINOK(ReadStream_FALSE(stream, buf, size));
|
||||
|
||||
UInt64 total = _header.SectOffset + size;
|
||||
if (_totalSize < total)
|
||||
_totalSize = total;
|
||||
|
||||
const Byte *p = buf;
|
||||
|
||||
if (addSections)
|
||||
_sections.ClearAndReserve(_header.NumSections);
|
||||
for (unsigned i = 0; i < _header.NumSections; i++, p += _header.SectionEntrySize)
|
||||
{
|
||||
CSection sect;
|
||||
if (!sect.Parse(p, _header.Mode64, _header.Be))
|
||||
{
|
||||
_headersError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
sect.UpdateTotalSize(_totalSize);
|
||||
if (addSections)
|
||||
_sections.AddInReserved(sect);
|
||||
}
|
||||
}
|
||||
|
||||
if (addSections)
|
||||
{
|
||||
if (_header.NamesSectIndex < _sections.Size())
|
||||
{
|
||||
const CSection § = _sections[_header.NamesSectIndex];
|
||||
UInt64 size = sect.GetSize();
|
||||
if (size != 0
|
||||
&& size < ((UInt64)1 << 31)
|
||||
&& (Int64)sect.Offset >= 0)
|
||||
{
|
||||
_namesData.Alloc((size_t)size);
|
||||
RINOK(stream->Seek(sect.Offset, STREAM_SEEK_SET, NULL));
|
||||
RINOK(ReadStream_FALSE(stream, _namesData, (size_t)size));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// we will not delete NULL sections, since we have links to section via indexes
|
||||
for (int i = _sections.Size() - 1; i >= 0; i--)
|
||||
if (_sections[i].Type == SHT_NULL)
|
||||
_items.Delete(i);
|
||||
*/
|
||||
}
|
||||
|
||||
if (!_allowTail)
|
||||
{
|
||||
UInt64 fileSize;
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
|
||||
if (fileSize > _totalSize)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
RINOK(Open2(inStream));
|
||||
_inStream = inStream;
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_totalSize = 0;
|
||||
_headersError = false;
|
||||
|
||||
_inStream.Release();
|
||||
_segments.Clear();
|
||||
_sections.Clear();
|
||||
_namesData.Free();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _segments.Size() + _sections.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _segments.Size() + _sections.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
totalSize += (index < _segments.Size()) ?
|
||||
_segments[index].Size :
|
||||
_sections[index - _segments.Size()].GetSize();
|
||||
}
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
UInt64 currentItemSize;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_inStream);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
UInt64 offset;
|
||||
if (index < _segments.Size())
|
||||
{
|
||||
const CSegment &item = _segments[index];
|
||||
currentItemSize = item.Size;
|
||||
offset = item.Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
const CSection &item = _sections[index - _segments.Size()];
|
||||
currentItemSize = item.GetSize();
|
||||
offset = item.Offset;
|
||||
}
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(_inStream->Seek(offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(currentItemSize);
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
|
||||
NExtract::NOperationResult::kOK:
|
||||
NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::AllowTail(Int32 allowTail)
|
||||
{
|
||||
_allowTail = IntToBool(allowTail);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' };
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"ELF", "elf", 0, 0xDE,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kPreArc,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
2867
CPP/7zip/Archive/ExtHandler.cpp
Normal file
2867
CPP/7zip/Archive/ExtHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1056
CPP/7zip/Archive/FatHandler.cpp
Normal file
1056
CPP/7zip/Archive/FatHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
526
CPP/7zip/Archive/FlvHandler.cpp
Normal file
526
CPP/7zip/Archive/FlvHandler.cpp
Normal file
@@ -0,0 +1,526 @@
|
||||
// FlvHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/MyBuffer.h"
|
||||
#include "../../Common/MyString.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#define GetBe24(p) ( \
|
||||
((UInt32)((const Byte *)(p))[0] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[1] << 8) | \
|
||||
((const Byte *)(p))[2] )
|
||||
|
||||
#define Get16(p) GetBe16(p)
|
||||
#define Get24(p) GetBe24(p)
|
||||
#define Get32(p) GetBe32(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NFlv {
|
||||
|
||||
static const UInt32 kFileSizeMax = (UInt32)1 << 30;
|
||||
static const UInt32 kNumChunksMax = (UInt32)1 << 23;
|
||||
|
||||
static const UInt32 kTagHeaderSize = 11;
|
||||
|
||||
static const Byte kFlag_Video = 1;
|
||||
static const Byte kFlag_Audio = 4;
|
||||
|
||||
static const Byte kType_Audio = 8;
|
||||
static const Byte kType_Video = 9;
|
||||
static const Byte kType_Meta = 18;
|
||||
static const unsigned kNumTypes = 19;
|
||||
|
||||
struct CItem
|
||||
{
|
||||
CByteBuffer Data;
|
||||
Byte Type;
|
||||
};
|
||||
|
||||
struct CItem2
|
||||
{
|
||||
Byte Type;
|
||||
Byte SubType;
|
||||
Byte Props;
|
||||
bool SameSubTypes;
|
||||
unsigned NumChunks;
|
||||
size_t Size;
|
||||
|
||||
CReferenceBuf *BufSpec;
|
||||
CMyComPtr<IUnknown> RefBuf;
|
||||
|
||||
bool IsAudio() const { return Type == kType_Audio; }
|
||||
};
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CObjectVector<CItem2> _items2;
|
||||
CByteBuffer _metadata;
|
||||
bool _isRaw;
|
||||
UInt64 _phySize;
|
||||
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
// AString GetComment();
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidSize,
|
||||
kpidNumBlocks,
|
||||
kpidComment
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
|
||||
static const char *g_AudioTypes[16] =
|
||||
{
|
||||
"pcm"
|
||||
, "adpcm"
|
||||
, "mp3"
|
||||
, "pcm_le"
|
||||
, "nellymoser16"
|
||||
, "nellymoser8"
|
||||
, "nellymoser"
|
||||
, "g711a"
|
||||
, "g711m"
|
||||
, "audio9"
|
||||
, "aac"
|
||||
, "speex"
|
||||
, "audio12"
|
||||
, "audio13"
|
||||
, "mp3"
|
||||
, "audio15"
|
||||
};
|
||||
|
||||
static const char *g_VideoTypes[16] =
|
||||
{
|
||||
"video0"
|
||||
, "jpeg"
|
||||
, "h263"
|
||||
, "screen"
|
||||
, "vp6"
|
||||
, "vp6alpha"
|
||||
, "screen2"
|
||||
, "avc"
|
||||
, "video8"
|
||||
, "video9"
|
||||
, "video10"
|
||||
, "video11"
|
||||
, "video12"
|
||||
, "video13"
|
||||
, "video14"
|
||||
, "video15"
|
||||
};
|
||||
|
||||
static const char *g_Rates[4] =
|
||||
{
|
||||
"5.5 kHz"
|
||||
, "11 kHz"
|
||||
, "22 kHz"
|
||||
, "44 kHz"
|
||||
};
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
const CItem2 &item = _items2[index];
|
||||
switch (propID)
|
||||
{
|
||||
case kpidExtension:
|
||||
prop = _isRaw ?
|
||||
(item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) :
|
||||
(item.IsAudio() ? "audio.flv" : "video.flv");
|
||||
break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
prop = (UInt64)item.Size;
|
||||
break;
|
||||
case kpidNumBlocks: prop = (UInt32)item.NumChunks; break;
|
||||
case kpidComment:
|
||||
{
|
||||
char sz[64];
|
||||
char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
|
||||
if (item.IsAudio())
|
||||
{
|
||||
*s++ = ' ';
|
||||
s = MyStpCpy(s, g_Rates[(item.Props >> 2) & 3]);
|
||||
s = MyStpCpy(s, (item.Props & 2) ? " 16-bit" : " 8-bit");
|
||||
s = MyStpCpy(s, (item.Props & 1) ? " stereo" : " mono");
|
||||
}
|
||||
prop = sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
AString CHandler::GetComment()
|
||||
{
|
||||
const Byte *p = _metadata;
|
||||
size_t size = _metadata.Size();
|
||||
AString res;
|
||||
if (size > 0)
|
||||
{
|
||||
p++;
|
||||
size--;
|
||||
for (;;)
|
||||
{
|
||||
if (size < 2)
|
||||
break;
|
||||
int len = Get16(p);
|
||||
p += 2;
|
||||
size -= 2;
|
||||
if (len == 0 || (size_t)len > size)
|
||||
break;
|
||||
{
|
||||
AString temp;
|
||||
temp.SetFrom_CalcLen((const char *)p, len);
|
||||
if (!res.IsEmpty())
|
||||
res += '\n';
|
||||
res += temp;
|
||||
}
|
||||
p += len;
|
||||
size -= len;
|
||||
if (size < 1)
|
||||
break;
|
||||
Byte type = *p++;
|
||||
size--;
|
||||
bool ok = false;
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (size < 8)
|
||||
break;
|
||||
ok = true;
|
||||
Byte reverse[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
bool little_endian = 1;
|
||||
if (little_endian)
|
||||
reverse[i] = p[7 - i];
|
||||
else
|
||||
reverse[i] = p[i];
|
||||
}
|
||||
double d = *(double *)reverse;
|
||||
char temp[32];
|
||||
sprintf(temp, " = %.3f", d);
|
||||
res += temp;
|
||||
p += 8;
|
||||
size -= 8;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
if (size < 4)
|
||||
break;
|
||||
ok = true;
|
||||
// UInt32 numItems = Get32(p);
|
||||
p += 4;
|
||||
size -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
// COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
// case kpidComment: prop = GetComment(); break;
|
||||
case kpidPhySize: prop = (UInt64)_phySize; break;
|
||||
case kpidIsNotArcType: prop = true; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
// COM_TRY_END
|
||||
}
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
{
|
||||
const UInt32 kHeaderSize = 13;
|
||||
Byte header[kHeaderSize];
|
||||
RINOK(ReadStream_FALSE(stream, header, kHeaderSize));
|
||||
if (header[0] != 'F' ||
|
||||
header[1] != 'L' ||
|
||||
header[2] != 'V' ||
|
||||
header[3] != 1 ||
|
||||
(header[4] & 0xFA) != 0)
|
||||
return S_FALSE;
|
||||
UInt64 offset = Get32(header + 5);
|
||||
if (offset != 9 || Get32(header + 9) != 0)
|
||||
return S_FALSE;
|
||||
offset = kHeaderSize;
|
||||
|
||||
CInBuffer inBuf;
|
||||
if (!inBuf.Create(1 << 15))
|
||||
return E_OUTOFMEMORY;
|
||||
inBuf.SetStream(stream);
|
||||
|
||||
CObjectVector<CItem> items;
|
||||
int lasts[kNumTypes];
|
||||
unsigned i;
|
||||
for (i = 0; i < kNumTypes; i++)
|
||||
lasts[i] = -1;
|
||||
|
||||
_phySize = offset;
|
||||
for (;;)
|
||||
{
|
||||
Byte buf[kTagHeaderSize];
|
||||
CItem item;
|
||||
if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize)
|
||||
break;
|
||||
item.Type = buf[0];
|
||||
UInt32 size = Get24(buf + 1);
|
||||
if (size < 1)
|
||||
break;
|
||||
// item.Time = Get24(buf + 4);
|
||||
// item.Time |= (UInt32)buf[7] << 24;
|
||||
if (Get24(buf + 8) != 0) // streamID
|
||||
break;
|
||||
|
||||
UInt32 curSize = kTagHeaderSize + size + 4;
|
||||
item.Data.Alloc(curSize);
|
||||
memcpy(item.Data, buf, kTagHeaderSize);
|
||||
if (inBuf.ReadBytes(item.Data + kTagHeaderSize, size) != size)
|
||||
break;
|
||||
if (inBuf.ReadBytes(item.Data + kTagHeaderSize + size, 4) != 4)
|
||||
break;
|
||||
|
||||
if (Get32(item.Data + kTagHeaderSize + size) != kTagHeaderSize + size)
|
||||
break;
|
||||
|
||||
offset += curSize;
|
||||
|
||||
// printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size);
|
||||
|
||||
if (item.Type == kType_Meta)
|
||||
{
|
||||
// _metadata = item.Buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.Type != kType_Audio && item.Type != kType_Video)
|
||||
break;
|
||||
if (items.Size() >= kNumChunksMax)
|
||||
return S_FALSE;
|
||||
Byte firstByte = item.Data[kTagHeaderSize];
|
||||
Byte subType, props;
|
||||
if (item.Type == kType_Audio)
|
||||
{
|
||||
subType = (Byte)(firstByte >> 4);
|
||||
props = (Byte)(firstByte & 0xF);
|
||||
}
|
||||
else
|
||||
{
|
||||
subType = (Byte)(firstByte & 0xF);
|
||||
props = (Byte)(firstByte >> 4);
|
||||
}
|
||||
int last = lasts[item.Type];
|
||||
if (last < 0)
|
||||
{
|
||||
CItem2 item2;
|
||||
item2.RefBuf = item2.BufSpec = new CReferenceBuf;
|
||||
item2.Size = curSize;
|
||||
item2.Type = item.Type;
|
||||
item2.SubType = subType;
|
||||
item2.Props = props;
|
||||
item2.NumChunks = 1;
|
||||
item2.SameSubTypes = true;
|
||||
lasts[item.Type] = _items2.Add(item2);
|
||||
}
|
||||
else
|
||||
{
|
||||
CItem2 &item2 = _items2[last];
|
||||
if (subType != item2.SubType)
|
||||
item2.SameSubTypes = false;
|
||||
item2.Size += curSize;
|
||||
item2.NumChunks++;
|
||||
}
|
||||
items.Add(item);
|
||||
}
|
||||
_phySize = offset;
|
||||
if (callback && (items.Size() & 0xFF) == 0)
|
||||
{
|
||||
RINOK(callback->SetCompleted(NULL, &offset))
|
||||
}
|
||||
}
|
||||
if (items.IsEmpty())
|
||||
return S_FALSE;
|
||||
|
||||
_isRaw = (_items2.Size() == 1);
|
||||
for (i = 0; i < _items2.Size(); i++)
|
||||
{
|
||||
CItem2 &item2 = _items2[i];
|
||||
CByteBuffer &itemBuf = item2.BufSpec->Buf;
|
||||
if (_isRaw)
|
||||
{
|
||||
if (!item2.SameSubTypes)
|
||||
return S_FALSE;
|
||||
itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks);
|
||||
item2.Size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemBuf.Alloc(kHeaderSize + (size_t)item2.Size);
|
||||
memcpy(itemBuf, header, kHeaderSize);
|
||||
itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video;
|
||||
item2.Size = kHeaderSize;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < items.Size(); i++)
|
||||
{
|
||||
const CItem &item = items[i];
|
||||
CItem2 &item2 = _items2[lasts[item.Type]];
|
||||
size_t size = item.Data.Size();
|
||||
const Byte *src = item.Data;
|
||||
if (_isRaw)
|
||||
{
|
||||
src += kTagHeaderSize + 1;
|
||||
size -= (kTagHeaderSize + 4 + 1);
|
||||
}
|
||||
if (size != 0)
|
||||
{
|
||||
memcpy(item2.BufSpec->Buf + item2.Size, src, size);
|
||||
item2.Size += size;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
HRESULT res;
|
||||
try
|
||||
{
|
||||
res = Open2(inStream, callback);
|
||||
if (res == S_OK)
|
||||
_stream = inStream;
|
||||
}
|
||||
catch(...) { res = S_FALSE; }
|
||||
if (res != S_OK)
|
||||
{
|
||||
Close();
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_phySize = 0;
|
||||
_stream.Release();
|
||||
_items2.Clear();
|
||||
// _metadata.SetCapacity(0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items2.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items2.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += _items2[allFilesMode ? i : indices[i]].Size;
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
totalSize = 0;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = lps->OutSize = totalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
const CItem2 &item = _items2[index];
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
totalSize += item.Size;
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (outStream)
|
||||
{
|
||||
RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size()));
|
||||
}
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = 0;
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init(_items2[index].BufSpec);
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static const Byte k_Signature[] = { 'F', 'L', 'V', 1, };
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"FLV", "flv", 0, 0xD6,
|
||||
k_Signature,
|
||||
0,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
405
CPP/7zip/Archive/GptHandler.cpp
Normal file
405
CPP/7zip/Archive/GptHandler.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
// GptHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/7zCrc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/IntToString.h"
|
||||
#include "../../Common/MyBuffer.h"
|
||||
|
||||
#include "../../Windows/PropVariantUtils.h"
|
||||
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "HandlerCont.h"
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
#define Get64(p) GetUi64(p)
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGpt {
|
||||
|
||||
#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }
|
||||
|
||||
static const unsigned k_SignatureSize = 12;
|
||||
static const Byte k_Signature[k_SignatureSize] = SIGNATURE;
|
||||
|
||||
static const UInt32 kSectorSize = 512;
|
||||
|
||||
static const CUInt32PCharPair g_PartitionFlags[] =
|
||||
{
|
||||
{ 0, "Sys" },
|
||||
{ 1, "Ignore" },
|
||||
{ 2, "Legacy" },
|
||||
{ 60, "Win-Read-only" },
|
||||
{ 62, "Win-Hidden" },
|
||||
{ 63, "Win-Not-Automount" }
|
||||
};
|
||||
|
||||
static const unsigned kNameLen = 36;
|
||||
|
||||
struct CPartition
|
||||
{
|
||||
Byte Type[16];
|
||||
Byte Id[16];
|
||||
UInt64 FirstLba;
|
||||
UInt64 LastLba;
|
||||
UInt64 Flags;
|
||||
Byte Name[kNameLen * 2];
|
||||
|
||||
bool IsUnused() const
|
||||
{
|
||||
for (unsigned i = 0; i < 16; i++)
|
||||
if (Type[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
UInt64 GetSize() const { return (LastLba - FirstLba + 1) * kSectorSize; }
|
||||
UInt64 GetPos() const { return FirstLba * kSectorSize; }
|
||||
UInt64 GetEnd() const { return (LastLba + 1) * kSectorSize; }
|
||||
|
||||
void Parse(const Byte *p)
|
||||
{
|
||||
memcpy(Type, p, 16);
|
||||
memcpy(Id, p + 16, 16);
|
||||
FirstLba = Get64(p + 32);
|
||||
LastLba = Get64(p + 40);
|
||||
Flags = Get64(p + 48);
|
||||
memcpy(Name, p + 56, kNameLen * 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CPartType
|
||||
{
|
||||
UInt32 Id;
|
||||
const char *Ext;
|
||||
const char *Type;
|
||||
};
|
||||
|
||||
static const CPartType kPartTypes[] =
|
||||
{
|
||||
// { 0x0, 0, "Unused" },
|
||||
|
||||
{ 0x21686148, 0, "BIOS Boot" },
|
||||
|
||||
{ 0xC12A7328, 0, "EFI System" },
|
||||
{ 0x024DEE41, 0, "MBR" },
|
||||
|
||||
{ 0xE3C9E316, 0, "Windows MSR" },
|
||||
{ 0xEBD0A0A2, 0, "Windows BDP" },
|
||||
{ 0x5808C8AA, 0, "Windows LDM Metadata" },
|
||||
{ 0xAF9B60A0, 0, "Windows LDM Data" },
|
||||
{ 0xDE94BBA4, 0, "Windows Recovery" },
|
||||
// { 0x37AFFC90, 0, "IBM GPFS" },
|
||||
// { 0xE75CAF8F, 0, "Windows Storage Spaces" },
|
||||
|
||||
{ 0x0FC63DAF, 0, "Linux Data" },
|
||||
{ 0x0657FD6D, 0, "Linux Swap" },
|
||||
|
||||
{ 0x83BD6B9D, 0, "FreeBSD Boot" },
|
||||
{ 0x516E7CB4, 0, "FreeBSD Data" },
|
||||
{ 0x516E7CB5, 0, "FreeBSD Swap" },
|
||||
{ 0x516E7CB6, "ufs", "FreeBSD UFS" },
|
||||
{ 0x516E7CB8, 0, "FreeBSD Vinum" },
|
||||
{ 0x516E7CB8, "zfs", "FreeBSD ZFS" },
|
||||
|
||||
{ 0x48465300, "hfsx", "HFS+" },
|
||||
};
|
||||
|
||||
static int FindPartType(const Byte *guid)
|
||||
{
|
||||
UInt32 val = Get32(guid);
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++)
|
||||
if (kPartTypes[i].Id == val)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); }
|
||||
|
||||
static void PrintHex(unsigned v, char *s)
|
||||
{
|
||||
s[0] = GetHex((v >> 4) & 0xF);
|
||||
s[1] = GetHex(v & 0xF);
|
||||
}
|
||||
|
||||
static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()
|
||||
{
|
||||
PrintHex(val >> 8, s);
|
||||
PrintHex(val & 0xFF, s + 2);
|
||||
}
|
||||
|
||||
static void GuidToString(const Byte *g, char *s)
|
||||
{
|
||||
ConvertUInt32ToHex8Digits(Get32(g ), s); s += 8; *s++ = '-';
|
||||
ConvertUInt16ToHex4Digits(Get16(g + 4), s); s += 4; *s++ = '-';
|
||||
ConvertUInt16ToHex4Digits(Get16(g + 6), s); s += 4; *s++ = '-';
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
{
|
||||
if (i == 2)
|
||||
*s++ = '-';
|
||||
PrintHex(g[8 + i], s);
|
||||
s += 2;
|
||||
}
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
|
||||
class CHandler: public CHandlerCont
|
||||
{
|
||||
CRecordVector<CPartition> _items;
|
||||
UInt64 _totalSize;
|
||||
Byte Guid[16];
|
||||
|
||||
CByteBuffer _buffer;
|
||||
|
||||
HRESULT Open2(IInStream *stream);
|
||||
|
||||
virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
|
||||
{
|
||||
const CPartition &item = _items[index];
|
||||
pos = item.GetPos();
|
||||
size = item.GetSize();
|
||||
return NExtract::NOperationResult::kOK;
|
||||
}
|
||||
|
||||
public:
|
||||
INTERFACE_IInArchive_Cont(;)
|
||||
};
|
||||
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream)
|
||||
{
|
||||
_buffer.Alloc(kSectorSize * 2);
|
||||
RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2));
|
||||
|
||||
const Byte *buf = _buffer;
|
||||
if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
|
||||
return S_FALSE;
|
||||
|
||||
buf += kSectorSize;
|
||||
if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
|
||||
return S_FALSE;
|
||||
{
|
||||
// if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision
|
||||
UInt32 headerSize = Get32(buf + 12); // = 0x5C usually
|
||||
if (headerSize > kSectorSize)
|
||||
return S_FALSE;
|
||||
UInt32 crc = Get32(buf + 0x10);
|
||||
SetUi32(_buffer + kSectorSize + 0x10, 0);
|
||||
if (CrcCalc(_buffer + kSectorSize, headerSize) != crc)
|
||||
return S_FALSE;
|
||||
}
|
||||
// UInt32 reserved = Get32(buf + 0x14);
|
||||
UInt64 curLba = Get64(buf + 0x18);
|
||||
if (curLba != 1)
|
||||
return S_FALSE;
|
||||
UInt64 backupLba = Get64(buf + 0x20);
|
||||
// UInt64 firstUsableLba = Get64(buf + 0x28);
|
||||
// UInt64 lastUsableLba = Get64(buf + 0x30);
|
||||
memcpy(Guid, buf + 0x38, 16);
|
||||
UInt64 tableLba = Get64(buf + 0x48);
|
||||
if (tableLba < 2)
|
||||
return S_FALSE;
|
||||
UInt32 numEntries = Get32(buf + 0x50);
|
||||
UInt32 entrySize = Get32(buf + 0x54); // = 128 usually
|
||||
UInt32 entriesCrc = Get32(buf + 0x58);
|
||||
|
||||
if (entrySize < 128
|
||||
|| entrySize > (1 << 12)
|
||||
|| numEntries > (1 << 16)
|
||||
|| tableLba < 2
|
||||
|| tableLba >= ((UInt64)1 << (64 - 10)))
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 tableSize = entrySize * numEntries;
|
||||
UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1);
|
||||
_buffer.Alloc(tableSizeAligned);
|
||||
UInt64 tableOffset = tableLba * kSectorSize;
|
||||
RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL));
|
||||
RINOK(ReadStream_FALSE(stream, _buffer, tableSizeAligned));
|
||||
|
||||
if (CrcCalc(_buffer, tableSize) != entriesCrc)
|
||||
return S_FALSE;
|
||||
|
||||
_totalSize = tableOffset + tableSizeAligned;
|
||||
|
||||
for (UInt32 i = 0; i < numEntries; i++)
|
||||
{
|
||||
CPartition item;
|
||||
item.Parse(_buffer + i * entrySize);
|
||||
if (item.IsUnused())
|
||||
continue;
|
||||
UInt64 endPos = item.GetEnd();
|
||||
if (_totalSize < endPos)
|
||||
_totalSize = endPos;
|
||||
_items.Add(item);
|
||||
}
|
||||
|
||||
UInt64 end = (backupLba + 1) * kSectorSize;
|
||||
if (_totalSize < end)
|
||||
_totalSize = end;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
RINOK(Open2(stream));
|
||||
_stream = stream;
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_totalSize = 0;
|
||||
memset(Guid, 0, sizeof(Guid));
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
kpidPath,
|
||||
kpidSize,
|
||||
kpidFileSystem,
|
||||
kpidCharacts,
|
||||
kpidOffset,
|
||||
kpidId
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidId
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
case kpidMainSubfile:
|
||||
{
|
||||
if (_items.Size() == 1)
|
||||
prop = (UInt32)0;
|
||||
break;
|
||||
}
|
||||
case kpidPhySize: prop = _totalSize; break;
|
||||
case kpidId:
|
||||
{
|
||||
char s[48];
|
||||
GuidToString(Guid, s);
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant prop;
|
||||
|
||||
const CPartition &item = _items[index];
|
||||
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
UString s;
|
||||
for (unsigned i = 0; i < kNameLen; i++)
|
||||
{
|
||||
wchar_t c = (wchar_t)Get16(item.Name + i * 2);
|
||||
if (c == 0)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
if (s.IsEmpty())
|
||||
{
|
||||
char temp[16];
|
||||
ConvertUInt32ToString(index, temp);
|
||||
s.AddAscii(temp);
|
||||
}
|
||||
{
|
||||
int typeIndex = FindPartType(item.Type);
|
||||
s += L'.';
|
||||
const char *ext = "img";
|
||||
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Ext)
|
||||
ext = kPartTypes[(unsigned)typeIndex].Ext;
|
||||
s.AddAscii(ext);
|
||||
}
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidSize:
|
||||
case kpidPackSize: prop = item.GetSize(); break;
|
||||
case kpidOffset: prop = item.GetPos(); break;
|
||||
|
||||
case kpidFileSystem:
|
||||
{
|
||||
char s[48];
|
||||
const char *res;
|
||||
int typeIndex = FindPartType(item.Type);
|
||||
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
|
||||
res = kPartTypes[(unsigned)typeIndex].Type;
|
||||
else
|
||||
{
|
||||
GuidToString(item.Type, s);
|
||||
res = s;
|
||||
}
|
||||
prop = res;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidId:
|
||||
{
|
||||
char s[48];
|
||||
GuidToString(item.Id, s);
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break;
|
||||
}
|
||||
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
REGISTER_ARC_I(
|
||||
"GPT", "gpt mbr", NULL, 0xCB,
|
||||
k_Signature,
|
||||
kSectorSize,
|
||||
0,
|
||||
NULL)
|
||||
|
||||
}}
|
||||
1044
CPP/7zip/Archive/GzHandler.cpp
Normal file
1044
CPP/7zip/Archive/GzHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
288
CPP/7zip/Archive/HandlerCont.cpp
Normal file
288
CPP/7zip/Archive/HandlerCont.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
// HandlerCont.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "HandlerCont.h"
|
||||
|
||||
namespace NArchive {
|
||||
|
||||
STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
{
|
||||
RINOK(GetNumberOfItems(&numItems));
|
||||
}
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt64 pos, size;
|
||||
GetItem_ExtractInfo(allFilesMode ? i : indices[i], pos, size);
|
||||
totalSize += size;
|
||||
}
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
totalSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = totalSize;
|
||||
lps->OutSize = totalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
|
||||
UInt64 pos, size;
|
||||
int opRes = GetItem_ExtractInfo(index, pos, size);
|
||||
totalSize += size;
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
|
||||
if (opRes == NExtract::NOperationResult::kOK)
|
||||
{
|
||||
RINOK(_stream->Seek(pos, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(size);
|
||||
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
|
||||
if (copyCoderSpec->TotalSize == size)
|
||||
opRes = NExtract::NOperationResult::kOK;
|
||||
else if (copyCoderSpec->TotalSize < size)
|
||||
opRes = NExtract::NOperationResult::kUnexpectedEnd;
|
||||
}
|
||||
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(opRes));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = NULL;
|
||||
UInt64 pos, size;
|
||||
if (GetItem_ExtractInfo(index, pos, size) != NExtract::NOperationResult::kOK)
|
||||
return S_FALSE;
|
||||
return CreateLimitedInStream(_stream, pos, size, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
|
||||
CHandlerImg::CHandlerImg():
|
||||
_imgExt(NULL)
|
||||
{
|
||||
ClearStreamVars();
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch (seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: break;
|
||||
case STREAM_SEEK_CUR: offset += _virtPos; break;
|
||||
case STREAM_SEEK_END: offset += _size; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (offset < 0)
|
||||
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
|
||||
_virtPos = offset;
|
||||
if (newPosition)
|
||||
*newPosition = offset;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
|
||||
|
||||
static const char *GetImgExt(ISequentialInStream *stream)
|
||||
{
|
||||
const size_t kHeaderSize = 1 << 10;
|
||||
Byte buf[kHeaderSize];
|
||||
if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
|
||||
{
|
||||
if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA)
|
||||
{
|
||||
if (memcmp(buf + 512, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0)
|
||||
return "gpt";
|
||||
return "mbr";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CHandlerImg::CloseAtError()
|
||||
{
|
||||
Stream.Release();
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandlerImg::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * openCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
{
|
||||
Close();
|
||||
HRESULT res;
|
||||
try
|
||||
{
|
||||
res = Open2(stream, openCallback);
|
||||
if (res == S_OK)
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> inStream;
|
||||
HRESULT res2 = GetStream(0, &inStream);
|
||||
if (res2 == S_OK && inStream)
|
||||
_imgExt = GetImgExt(inStream);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
CloseAtError();
|
||||
throw;
|
||||
}
|
||||
CloseAtError();
|
||||
return res;
|
||||
}
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
|
||||
return E_INVALIDARG;
|
||||
|
||||
RINOK(extractCallback->SetTotal(_size));
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(0, &outStream, askMode));
|
||||
if (!testMode && !outStream)
|
||||
return S_OK;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
int opRes = NExtract::NOperationResult::kDataError;
|
||||
|
||||
ClearStreamVars();
|
||||
|
||||
CMyComPtr<ISequentialInStream> inStream;
|
||||
HRESULT hres = GetStream(0, &inStream);
|
||||
if (hres == S_FALSE)
|
||||
hres = E_NOTIMPL;
|
||||
|
||||
if (hres == S_OK && inStream)
|
||||
{
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
hres = copyCoder->Code(inStream, outStream, NULL, &_size, progress);
|
||||
if (hres == S_OK)
|
||||
{
|
||||
if (copyCoderSpec->TotalSize == _size)
|
||||
opRes = NExtract::NOperationResult::kOK;
|
||||
|
||||
if (_stream_unavailData)
|
||||
opRes = NExtract::NOperationResult::kUnavailable;
|
||||
else if (_stream_unsupportedMethod)
|
||||
opRes = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
else if (_stream_dataError)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
else if (copyCoderSpec->TotalSize < _size)
|
||||
opRes = NExtract::NOperationResult::kUnexpectedEnd;
|
||||
}
|
||||
}
|
||||
|
||||
inStream.Release();
|
||||
outStream.Release();
|
||||
|
||||
if (hres != S_OK)
|
||||
{
|
||||
if (hres == S_FALSE)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
else if (hres == E_NOTIMPL)
|
||||
opRes = NExtract::NOperationResult::kUnsupportedMethod;
|
||||
else
|
||||
return hres;
|
||||
}
|
||||
|
||||
return extractCallback->SetOperationResult(opRes);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
|
||||
{
|
||||
areThereNonZeros = false;
|
||||
numZeros = 0;
|
||||
const size_t kBufSize = 1 << 11;
|
||||
Byte buf[kBufSize];
|
||||
for (;;)
|
||||
{
|
||||
UInt32 size = 0;
|
||||
HRESULT(stream->Read(buf, kBufSize, &size));
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
if (buf[i] != 0)
|
||||
{
|
||||
areThereNonZeros = true;
|
||||
numZeros += i;
|
||||
return S_OK;
|
||||
}
|
||||
numZeros += size;
|
||||
if (numZeros > maxSize)
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
116
CPP/7zip/Archive/HandlerCont.h
Normal file
116
CPP/7zip/Archive/HandlerCont.h
Normal file
@@ -0,0 +1,116 @@
|
||||
// HandlerCont.h
|
||||
|
||||
#ifndef __HANDLER_CONT_H
|
||||
#define __HANDLER_CONT_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "IArchive.h"
|
||||
|
||||
namespace NArchive {
|
||||
|
||||
#define INTERFACE_IInArchive_Cont(x) \
|
||||
STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
|
||||
/* STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; */ \
|
||||
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
|
||||
|
||||
|
||||
class CHandlerCont:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
protected:
|
||||
CMyComPtr<IInStream> _stream;
|
||||
|
||||
virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0;
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive_Cont(PURE)
|
||||
|
||||
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY;
|
||||
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
|
||||
// destructor must be virtual for this class
|
||||
virtual ~CHandlerCont() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define INTERFACE_IInArchive_Img(x) \
|
||||
/* STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; */ \
|
||||
STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
|
||||
/* STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; */ \
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
|
||||
/* STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; */ \
|
||||
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
|
||||
|
||||
|
||||
class CHandlerImg:
|
||||
public IInStream,
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
protected:
|
||||
UInt64 _virtPos;
|
||||
UInt64 _posInArc;
|
||||
UInt64 _size;
|
||||
CMyComPtr<IInStream> Stream;
|
||||
const char *_imgExt;
|
||||
|
||||
bool _stream_unavailData;
|
||||
bool _stream_unsupportedMethod;
|
||||
bool _stream_dataError;
|
||||
// bool _stream_UsePackSize;
|
||||
// UInt64 _stream_PackSize;
|
||||
|
||||
void ClearStreamVars()
|
||||
{
|
||||
_stream_unavailData = false;
|
||||
_stream_unsupportedMethod = false;
|
||||
_stream_dataError = false;
|
||||
// _stream_UsePackSize = false;
|
||||
// _stream_PackSize = 0;
|
||||
}
|
||||
|
||||
|
||||
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
|
||||
virtual void CloseAtError();
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
|
||||
INTERFACE_IInArchive_Img(PURE)
|
||||
|
||||
STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback);
|
||||
STDMETHOD(GetNumberOfItems)(UInt32 *numItems);
|
||||
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback);
|
||||
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) = 0;
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) = 0;
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
|
||||
CHandlerImg();
|
||||
// destructor must be virtual for this class
|
||||
virtual ~CHandlerImg() {}
|
||||
};
|
||||
|
||||
|
||||
HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1880
CPP/7zip/Archive/HfsHandler.cpp
Normal file
1880
CPP/7zip/Archive/HfsHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
598
CPP/7zip/Archive/IArchive.h
Normal file
598
CPP/7zip/Archive/IArchive.h
Normal file
@@ -0,0 +1,598 @@
|
||||
// IArchive.h
|
||||
|
||||
#ifndef __IARCHIVE_H
|
||||
#define __IARCHIVE_H
|
||||
|
||||
#include "../IProgress.h"
|
||||
#include "../IStream.h"
|
||||
#include "../PropID.h"
|
||||
|
||||
#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
|
||||
#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
|
||||
|
||||
namespace NFileTimeType
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kWindows,
|
||||
kUnix,
|
||||
kDOS
|
||||
};
|
||||
}
|
||||
|
||||
namespace NArcInfoFlags
|
||||
{
|
||||
const UInt32 kKeepName = 1 << 0; // keep name of file in archive name
|
||||
const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams
|
||||
const UInt32 kNtSecure = 1 << 2; // the handler supports NT security
|
||||
const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive
|
||||
const UInt32 kMultiSignature = 1 << 4; // there are several signatures
|
||||
const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset
|
||||
const UInt32 kStartOpen = 1 << 6; // call handler for each start position
|
||||
const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file
|
||||
const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward
|
||||
const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub)
|
||||
const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links
|
||||
const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
|
||||
}
|
||||
|
||||
namespace NArchive
|
||||
{
|
||||
namespace NHandlerPropID
|
||||
{
|
||||
enum
|
||||
{
|
||||
kName = 0, // VT_BSTR
|
||||
kClassID, // binary GUID in VT_BSTR
|
||||
kExtension, // VT_BSTR
|
||||
kAddExtension, // VT_BSTR
|
||||
kUpdate, // VT_BOOL
|
||||
kKeepName, // VT_BOOL
|
||||
kSignature, // binary in VT_BSTR
|
||||
kMultiSignature, // binary in VT_BSTR
|
||||
kSignatureOffset, // VT_UI4
|
||||
kAltStreams, // VT_BOOL
|
||||
kNtSecure, // VT_BOOL
|
||||
kFlags // VT_UI4
|
||||
// kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR)
|
||||
};
|
||||
}
|
||||
|
||||
namespace NExtract
|
||||
{
|
||||
namespace NAskMode
|
||||
{
|
||||
enum
|
||||
{
|
||||
kExtract = 0,
|
||||
kTest,
|
||||
kSkip
|
||||
};
|
||||
}
|
||||
|
||||
namespace NOperationResult
|
||||
{
|
||||
enum
|
||||
{
|
||||
kOK = 0,
|
||||
kUnsupportedMethod,
|
||||
kDataError,
|
||||
kCRCError,
|
||||
kUnavailable,
|
||||
kUnexpectedEnd,
|
||||
kDataAfterEnd,
|
||||
kIsNotArc,
|
||||
kHeadersError,
|
||||
kWrongPassword
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace NEventIndexType
|
||||
{
|
||||
enum
|
||||
{
|
||||
kNoIndex = 0,
|
||||
kInArcIndex,
|
||||
kBlockIndex,
|
||||
kOutArcIndex
|
||||
};
|
||||
}
|
||||
|
||||
namespace NUpdate
|
||||
{
|
||||
namespace NOperationResult
|
||||
{
|
||||
enum
|
||||
{
|
||||
kOK = 0
|
||||
, // kError
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define INTERFACE_IArchiveOpenCallback(x) \
|
||||
STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \
|
||||
STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
|
||||
{
|
||||
INTERFACE_IArchiveOpenCallback(PURE);
|
||||
};
|
||||
|
||||
/*
|
||||
IArchiveExtractCallback::
|
||||
|
||||
7-Zip doesn't call IArchiveExtractCallback functions
|
||||
GetStream()
|
||||
PrepareOperation()
|
||||
SetOperationResult()
|
||||
from different threads simultaneously.
|
||||
But 7-Zip can call functions for IProgress or ICompressProgressInfo functions
|
||||
from another threads simultaneously with calls for IArchiveExtractCallback interface.
|
||||
|
||||
IArchiveExtractCallback::GetStream()
|
||||
UInt32 index - index of item in Archive
|
||||
Int32 askExtractMode (Extract::NAskMode)
|
||||
if (askMode != NExtract::NAskMode::kExtract)
|
||||
{
|
||||
then the callee can not real stream: (*inStream == NULL)
|
||||
}
|
||||
|
||||
Out:
|
||||
(*inStream == NULL) - for directories
|
||||
(*inStream == NULL) - if link (hard link or symbolic link) was created
|
||||
if (*inStream == NULL && askMode == NExtract::NAskMode::kExtract)
|
||||
{
|
||||
then the caller must skip extracting of that file.
|
||||
}
|
||||
|
||||
returns:
|
||||
S_OK : OK
|
||||
S_FALSE : data error (for decoders)
|
||||
|
||||
if (IProgress::SetTotal() was called)
|
||||
{
|
||||
IProgress::SetCompleted(completeValue) uses
|
||||
packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd).
|
||||
unpackSize - for another formats.
|
||||
}
|
||||
else
|
||||
{
|
||||
IProgress::SetCompleted(completeValue) uses packSize.
|
||||
}
|
||||
|
||||
SetOperationResult()
|
||||
7-Zip calls SetOperationResult at the end of extracting,
|
||||
so the callee can close the file, set attributes, timestamps and security information.
|
||||
|
||||
Int32 opRes (NExtract::NOperationResult)
|
||||
*/
|
||||
|
||||
#define INTERFACE_IArchiveExtractCallback(x) \
|
||||
INTERFACE_IProgress(x) \
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
|
||||
STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
|
||||
STDMETHOD(SetOperationResult)(Int32 opRes) x; \
|
||||
|
||||
ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
|
||||
{
|
||||
INTERFACE_IArchiveExtractCallback(PURE)
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
IArchiveExtractCallbackMessage can be requested from IArchiveExtractCallback object
|
||||
by Extract() or UpdateItems() functions to report about extracting errors
|
||||
ReportExtractResult()
|
||||
UInt32 indexType (NEventIndexType)
|
||||
UInt32 index
|
||||
Int32 opRes (NExtract::NOperationResult)
|
||||
*/
|
||||
|
||||
#define INTERFACE_IArchiveExtractCallbackMessage(x) \
|
||||
STDMETHOD(ReportExtractResult)(UInt32 indexType, UInt32 index, Int32 opRes) x; \
|
||||
|
||||
ARCHIVE_INTERFACE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21)
|
||||
{
|
||||
INTERFACE_IArchiveExtractCallbackMessage(PURE)
|
||||
};
|
||||
|
||||
|
||||
#define INTERFACE_IArchiveOpenVolumeCallback(x) \
|
||||
STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \
|
||||
STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
|
||||
{
|
||||
INTERFACE_IArchiveOpenVolumeCallback(PURE);
|
||||
};
|
||||
|
||||
|
||||
ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
|
||||
{
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;
|
||||
};
|
||||
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
|
||||
{
|
||||
STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
IInArchive::Open
|
||||
stream
|
||||
if (kUseGlobalOffset), stream current position can be non 0.
|
||||
if (!kUseGlobalOffset), stream current position is 0.
|
||||
if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream
|
||||
if (*maxCheckStartPosition == 0), the handler must check only current position as archive start
|
||||
|
||||
IInArchive::Extract:
|
||||
indices must be sorted
|
||||
numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files"
|
||||
testMode != 0 means "test files without writing to outStream"
|
||||
|
||||
IInArchive::GetArchiveProperty:
|
||||
kpidOffset - start offset of archive.
|
||||
VT_EMPTY : means offset = 0.
|
||||
VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed
|
||||
kpidPhySize - size of archive. VT_EMPTY means unknown size.
|
||||
kpidPhySize is allowed to be larger than file size. In that case it must show
|
||||
supposed size.
|
||||
|
||||
kpidIsDeleted:
|
||||
kpidIsAltStream:
|
||||
kpidIsAux:
|
||||
kpidINode:
|
||||
must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty.
|
||||
|
||||
|
||||
Notes:
|
||||
Don't call IInArchive functions for same IInArchive object from different threads simultaneously.
|
||||
Some IInArchive handlers will work incorrectly in that case.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define MY_NO_THROW_DECL_ONLY throw()
|
||||
#else
|
||||
#define MY_NO_THROW_DECL_ONLY
|
||||
#endif
|
||||
|
||||
#define INTERFACE_IInArchive(x) \
|
||||
STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
|
||||
STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
|
||||
|
||||
ARCHIVE_INTERFACE(IInArchive, 0x60)
|
||||
{
|
||||
INTERFACE_IInArchive(PURE)
|
||||
};
|
||||
|
||||
namespace NParentType
|
||||
{
|
||||
enum
|
||||
{
|
||||
kDir = 0,
|
||||
kAltStream
|
||||
};
|
||||
};
|
||||
|
||||
namespace NPropDataType
|
||||
{
|
||||
const UInt32 kMask_ZeroEnd = 1 << 4;
|
||||
// const UInt32 kMask_BigEndian = 1 << 5;
|
||||
const UInt32 kMask_Utf = 1 << 6;
|
||||
const UInt32 kMask_Utf8 = kMask_Utf | 0;
|
||||
const UInt32 kMask_Utf16 = kMask_Utf | 1;
|
||||
// const UInt32 kMask_Utf32 = kMask_Utf | 2;
|
||||
|
||||
const UInt32 kNotDefined = 0;
|
||||
const UInt32 kRaw = 1;
|
||||
|
||||
const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd;
|
||||
const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd;
|
||||
};
|
||||
|
||||
// UTF string (pointer to wchar_t) with zero end and little-endian.
|
||||
#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1))
|
||||
|
||||
/*
|
||||
GetRawProp:
|
||||
Result:
|
||||
S_OK - even if property is not set
|
||||
*/
|
||||
|
||||
#define INTERFACE_IArchiveGetRawProps(x) \
|
||||
STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \
|
||||
STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \
|
||||
STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \
|
||||
STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x;
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70)
|
||||
{
|
||||
INTERFACE_IArchiveGetRawProps(PURE)
|
||||
};
|
||||
|
||||
#define INTERFACE_IArchiveGetRootProps(x) \
|
||||
STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \
|
||||
STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71)
|
||||
{
|
||||
INTERFACE_IArchiveGetRootProps(PURE)
|
||||
};
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)
|
||||
{
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;
|
||||
};
|
||||
|
||||
/*
|
||||
OpenForSize
|
||||
Result:
|
||||
S_FALSE - is not archive
|
||||
? - DATA error
|
||||
*/
|
||||
|
||||
/*
|
||||
const UInt32 kOpenFlags_RealPhySize = 1 << 0;
|
||||
const UInt32 kOpenFlags_NoSeek = 1 << 1;
|
||||
// const UInt32 kOpenFlags_BeforeExtract = 1 << 2;
|
||||
*/
|
||||
|
||||
/*
|
||||
Flags:
|
||||
0 - opens archive with IInStream, if IInStream interface is supported
|
||||
- if phySize is not available, it doesn't try to make full parse to get phySize
|
||||
kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available
|
||||
kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file
|
||||
|
||||
if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified,
|
||||
the handler can return S_OK, but it doesn't check even Signature.
|
||||
So next Extract can be called for that sequential stream.
|
||||
*/
|
||||
|
||||
/*
|
||||
ARCHIVE_INTERFACE(IArchiveOpen2, 0x62)
|
||||
{
|
||||
STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE;
|
||||
};
|
||||
*/
|
||||
|
||||
// ---------- UPDATE ----------
|
||||
|
||||
/*
|
||||
GetUpdateItemInfo outs:
|
||||
*newData *newProps
|
||||
0 0 - Copy data and properties from archive
|
||||
0 1 - Copy data from archive, request new properties
|
||||
1 0 - that combination is unused now
|
||||
1 1 - Request new data and new properties. It can be used even for folders
|
||||
|
||||
indexInArchive = -1 if there is no item in archive, or if it doesn't matter.
|
||||
|
||||
|
||||
GetStream out:
|
||||
Result:
|
||||
S_OK:
|
||||
(*inStream == NULL) - only for directories
|
||||
- the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file
|
||||
(*inStream != NULL) - for any file, even for empty file or anti-file
|
||||
S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason)
|
||||
(*inStream == NULL)
|
||||
|
||||
The order of calling for hard links:
|
||||
- GetStream()
|
||||
- GetProperty(kpidHardLink)
|
||||
|
||||
SetOperationResult()
|
||||
Int32 opRes (NExtract::NOperationResult::kOK)
|
||||
*/
|
||||
|
||||
#define INTERFACE_IArchiveUpdateCallback(x) \
|
||||
INTERFACE_IProgress(x); \
|
||||
STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \
|
||||
STDMETHOD(SetOperationResult)(Int32 operationResult) x; \
|
||||
|
||||
ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
|
||||
{
|
||||
INTERFACE_IArchiveUpdateCallback(PURE);
|
||||
};
|
||||
|
||||
#define INTERFACE_IArchiveUpdateCallback2(x) \
|
||||
INTERFACE_IArchiveUpdateCallback(x) \
|
||||
STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \
|
||||
STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \
|
||||
|
||||
ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
|
||||
{
|
||||
INTERFACE_IArchiveUpdateCallback2(PURE);
|
||||
};
|
||||
|
||||
namespace NUpdateNotifyOp
|
||||
{
|
||||
enum
|
||||
{
|
||||
kAdd = 0,
|
||||
kUpdate,
|
||||
kAnalyze,
|
||||
kReplicate,
|
||||
kRepack,
|
||||
kSkip,
|
||||
kDelete,
|
||||
kHeader
|
||||
|
||||
// kNumDefined
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
IArchiveUpdateCallbackFile::ReportOperation
|
||||
UInt32 indexType (NEventIndexType)
|
||||
UInt32 index
|
||||
UInt32 notifyOp (NUpdateNotifyOp)
|
||||
*/
|
||||
|
||||
#define INTERFACE_IArchiveUpdateCallbackFile(x) \
|
||||
STDMETHOD(GetStream2)(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp) x; \
|
||||
STDMETHOD(ReportOperation)(UInt32 indexType, UInt32 index, UInt32 notifyOp) x; \
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveUpdateCallbackFile, 0x83)
|
||||
{
|
||||
INTERFACE_IArchiveUpdateCallbackFile(PURE);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
UpdateItems()
|
||||
-------------
|
||||
|
||||
outStream: output stream. (the handler) MUST support the case when
|
||||
Seek position in outStream is not ZERO.
|
||||
but the caller calls with empty outStream and seek position is ZERO??
|
||||
|
||||
archives with stub:
|
||||
|
||||
If archive is open and the handler and (Offset > 0), then the handler
|
||||
knows about stub size.
|
||||
UpdateItems():
|
||||
1) the handler MUST copy that stub to outStream
|
||||
2) the caller MUST NOT copy the stub to outStream, if
|
||||
"rsfx" property is set with SetProperties
|
||||
|
||||
the handler must support the case where
|
||||
ISequentialOutStream *outStream
|
||||
*/
|
||||
|
||||
|
||||
#define INTERFACE_IOutArchive(x) \
|
||||
STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \
|
||||
STDMETHOD(GetFileTimeType)(UInt32 *type) x;
|
||||
|
||||
ARCHIVE_INTERFACE(IOutArchive, 0xA0)
|
||||
{
|
||||
INTERFACE_IOutArchive(PURE)
|
||||
};
|
||||
|
||||
|
||||
ARCHIVE_INTERFACE(ISetProperties, 0x03)
|
||||
{
|
||||
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) PURE;
|
||||
};
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04)
|
||||
{
|
||||
STDMETHOD(KeepModeForNextOpen)() PURE;
|
||||
};
|
||||
|
||||
/* Exe handler: the handler for executable format (PE, ELF, Mach-O).
|
||||
SFX archive: executable stub + some tail data.
|
||||
before 9.31: exe handler didn't parse SFX archives as executable format.
|
||||
for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05)
|
||||
{
|
||||
STDMETHOD(AllowTail)(Int32 allowTail) PURE;
|
||||
};
|
||||
|
||||
|
||||
#define IMP_IInArchive_GetProp(k) \
|
||||
(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
|
||||
{ if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
|
||||
*propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = 0; return S_OK; } \
|
||||
|
||||
|
||||
struct CStatProp
|
||||
{
|
||||
const char *Name;
|
||||
UInt32 PropID;
|
||||
VARTYPE vt;
|
||||
};
|
||||
|
||||
namespace NWindows {
|
||||
namespace NCOM {
|
||||
// PropVariant.cpp
|
||||
BSTR AllocBstrFromAscii(const char *s) throw();
|
||||
}}
|
||||
|
||||
#define IMP_IInArchive_GetProp_WITH_NAME(k) \
|
||||
(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
|
||||
{ if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
|
||||
const CStatProp &prop = k[index]; \
|
||||
*propID = (PROPID)prop.PropID; *varType = prop.vt; \
|
||||
*name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \
|
||||
|
||||
#define IMP_IInArchive_Props \
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
|
||||
{ *numProps = ARRAY_SIZE(kProps); return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)
|
||||
|
||||
#define IMP_IInArchive_Props_WITH_NAME \
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
|
||||
{ *numProps = ARRAY_SIZE(kProps); return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)
|
||||
|
||||
|
||||
#define IMP_IInArchive_ArcProps \
|
||||
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
|
||||
{ *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)
|
||||
|
||||
#define IMP_IInArchive_ArcProps_WITH_NAME \
|
||||
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
|
||||
{ *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)
|
||||
|
||||
#define IMP_IInArchive_ArcProps_NO_Table \
|
||||
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
|
||||
{ *numProps = 0; return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
|
||||
{ return E_NOTIMPL; } \
|
||||
|
||||
#define IMP_IInArchive_ArcProps_NO \
|
||||
IMP_IInArchive_ArcProps_NO_Table \
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
|
||||
{ value->vt = VT_EMPTY; return S_OK; }
|
||||
|
||||
|
||||
|
||||
#define k_IsArc_Res_NO 0
|
||||
#define k_IsArc_Res_YES 1
|
||||
#define k_IsArc_Res_NEED_MORE 2
|
||||
// #define k_IsArc_Res_YES_LOW_PROB 3
|
||||
|
||||
#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI
|
||||
#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI
|
||||
|
||||
extern "C"
|
||||
{
|
||||
typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject);
|
||||
|
||||
typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size);
|
||||
typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc);
|
||||
|
||||
typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats);
|
||||
typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value);
|
||||
typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
|
||||
typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
|
||||
typedef HRESULT (WINAPI *Func_SetLargePageMode)();
|
||||
|
||||
typedef IOutArchive * (*Func_CreateOutArchive)();
|
||||
typedef IInArchive * (*Func_CreateInArchive)();
|
||||
}
|
||||
|
||||
#endif
|
||||
BIN
CPP/7zip/Archive/Icons/7z.ico
Normal file
BIN
CPP/7zip/Archive/Icons/7z.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
CPP/7zip/Archive/Icons/arj.ico
Normal file
BIN
CPP/7zip/Archive/Icons/arj.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
CPP/7zip/Archive/Icons/bz2.ico
Normal file
BIN
CPP/7zip/Archive/Icons/bz2.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
CPP/7zip/Archive/Icons/cab.ico
Normal file
BIN
CPP/7zip/Archive/Icons/cab.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user