Initialer Commit

This commit is contained in:
Tino Reichardt
2016-06-25 21:15:50 +02:00
commit c3967fe27a
1199 changed files with 290375 additions and 0 deletions

248
CPP/7zip/7zip.mak Normal file
View 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
View 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
View 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

View 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>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,3 @@
// CompressionMethod.cpp
#include "StdAfx.h"

View 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

View 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
}
}}

View 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

View 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() {}
}}

View 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

View 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
}
}}

View 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;
}
}}

View 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

View 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
}}

View 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

View 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
}
}}

View 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;
}}

View 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
View File

File diff suppressed because it is too large Load Diff

431
CPP/7zip/Archive/7z/7zIn.h Normal file
View 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

View 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

View 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
View 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

View 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;
}
}}

View 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

View 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);
}}

View 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);
}

View 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

View File

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -0,0 +1,3 @@
// StdAfx.cpp
#include "StdAfx.h"

View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/Common.h"
#endif

View 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"

View 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

View 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)
}}

View 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)
}}

View File

@@ -0,0 +1,12 @@
EXPORTS
CreateObject PRIVATE
GetHandlerProperty PRIVATE
GetNumberOfFormats PRIVATE
GetHandlerProperty2 PRIVATE
GetIsArc PRIVATE
SetCodecs PRIVATE
SetLargePageMode PRIVATE
SetCaseSensitive PRIVATE

View 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

View 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;
}

View 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)
}}

View 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)
}}

View 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;
}
}}

View 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

View File

File diff suppressed because it is too large Load Diff

View 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

View 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;
}}}

View 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

View 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;
}
}}

View 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

View 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

View 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)
}}

View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/Common.h"
#endif

View 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 &section = 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(&currentTotalSize));
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 &section = 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(&currentTotalSize));
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)
}
}}

View 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

View File

File diff suppressed because it is too large Load Diff

View 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 &section = 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 &section = 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

View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/Common.h"
#endif

View 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)
}}

View File

File diff suppressed because it is too large Load Diff

View 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

View 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;
}

View 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

View 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);
}
}

View 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

View 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;
}
}

View 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

View 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);
}

View 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

View 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
}}

View 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

View 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;
}
*/

View 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

View 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;
}

View 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

View 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;
}

View 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

View File

@@ -0,0 +1,3 @@
// ParseProperties.cpp
#include "StdAfx.h"

View File

@@ -0,0 +1,6 @@
// ParseProperties.h
#ifndef __PARSE_PROPERTIES_H
#define __PARSE_PROPERTIES_H
#endif

View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/Common.h"
#endif

View 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)
}}

View 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)
}}

View File

@@ -0,0 +1,3 @@
// DeflateProps.cpp
#include "StdAfx.h"

View File

@@ -0,0 +1,6 @@
// DeflateProps.h
#ifndef __DEFLATE_PROPS_H
#define __DEFLATE_PROPS_H
#endif

View 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

View 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

View File

File diff suppressed because it is too large Load Diff

View 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 &section = _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 &sect = _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)
}}

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View 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)
}}

View 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)
}}

View File

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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

View File

File diff suppressed because it is too large Load Diff

598
CPP/7zip/Archive/IArchive.h Normal file
View 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

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View 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