mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-09 04:07:08 -06:00
4.44 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
804edc5756
commit
d9666cf046
337
CPP/7zip/Archive/Chm/Chm.dsp
Executable file
337
CPP/7zip/Archive/Chm/Chm.dsp
Executable file
@@ -0,0 +1,337 @@
|
||||
# Microsoft Developer Studio Project File - Name="Chm" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=Chm - 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 "Chm.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 "Chm.mak" CFG="Chm - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Chm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "Chm - 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)" == "Chm - 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 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CHM_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "../../../" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CHM_EXPORTS" /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 0x419 /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\chm.dll" /opt:NOWIN98
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "Chm - 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 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CHM_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CHM_EXPORTS" /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 0x419 /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\chm.dll" /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "Chm - Win32 Release"
|
||||
# Name "Chm - Win32 Debug"
|
||||
# Begin Group "Spec"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Archive.def
|
||||
# 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=.\ChmHandler.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ChmHandler.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ChmHeader.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ChmHeader.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ChmIn.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ChmIn.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "7zip Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\InBuffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\InBuffer.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\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\StreamUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Common\StreamUtils.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Alloc.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Alloc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Buffer.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\String.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\String.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\UTFConvert.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\UTFConvert.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Vector.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Common\Vector.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Windows"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\PropVariant.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\Windows\PropVariant.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Archive Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\ItemNameUtils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Common\ItemNameUtils.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Compress"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "LZ"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\LZ\LZOutWindow.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\LZ\LZOutWindow.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lzx"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzx\Lzx.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzx\Lzx86Converter.cpp
|
||||
|
||||
!IF "$(CFG)" == "Chm - Win32 Release"
|
||||
|
||||
# ADD CPP /O2
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
|
||||
!ELSEIF "$(CFG)" == "Chm - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzx\Lzx86Converter.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzx\LzxDecoder.cpp
|
||||
|
||||
!IF "$(CFG)" == "Chm - Win32 Release"
|
||||
|
||||
# ADD CPP /O2
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
|
||||
!ELSEIF "$(CFG)" == "Chm - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzx\LzxDecoder.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Copy\CopyCoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Copy\CopyCoder.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
29
CPP/7zip/Archive/Chm/Chm.dsw
Executable file
29
CPP/7zip/Archive/Chm/Chm.dsw
Executable file
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "Chm"=.\Chm.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
731
CPP/7zip/Archive/Chm/ChmHandler.cpp
Executable file
731
CPP/7zip/Archive/Chm/ChmHandler.cpp
Executable file
@@ -0,0 +1,731 @@
|
||||
// Chm/Handler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
#include "Common/ComTry.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../Compress/Copy/CopyCoder.h"
|
||||
#include "../../Compress/Lzx/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,
|
||||
kpidOffset
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
STATPROPSTG kProperties[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
// { NULL, kpidIsFolder, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidMethod, VT_BSTR},
|
||||
{ NULL, kpidBlock, VT_UI4}
|
||||
|
||||
#ifdef _CHM_DETAILS
|
||||
,
|
||||
{ L"Section", kpidSection, VT_UI4},
|
||||
{ L"Offset", kpidOffset, VT_UI4}
|
||||
#endif
|
||||
};
|
||||
|
||||
static const int kNumProperties = sizeof(kProperties) / sizeof(kProperties[0]);
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID /* propID */, PROPVARIANT *value)
|
||||
{
|
||||
value->vt = VT_EMPTY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
|
||||
{
|
||||
*numProperties = sizeof(kProperties) / sizeof(kProperties[0]);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType)
|
||||
{
|
||||
if(index >= sizeof(kProperties) / sizeof(kProperties[0]))
|
||||
return E_INVALIDARG;
|
||||
const STATPROPSTG &srcItem = kProperties[index];
|
||||
*propID = srcItem.propid;
|
||||
*varType = srcItem.vt;
|
||||
if (srcItem.lpwstrName == 0)
|
||||
*name = 0;
|
||||
else
|
||||
*name = ::SysAllocString(srcItem.lpwstrName);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties)
|
||||
{
|
||||
*numProperties = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 /* index */,
|
||||
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
if (m_Database.NewFormat)
|
||||
{
|
||||
switch(propID)
|
||||
{
|
||||
case kpidSize:
|
||||
propVariant = (UInt64)m_Database.NewFormatString.Length();
|
||||
break;
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
int 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.Length() > 1)
|
||||
if (us[0] == L'/')
|
||||
us.Delete(0);
|
||||
}
|
||||
propVariant = NItemName::GetOSName2(us);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidIsFolder:
|
||||
propVariant = item.IsDirectory();
|
||||
break;
|
||||
case kpidSize:
|
||||
propVariant = item.Size;
|
||||
break;
|
||||
case kpidMethod:
|
||||
{
|
||||
if (!item.IsDirectory())
|
||||
if (item.Section == 0)
|
||||
propVariant = L"Copy";
|
||||
else if (item.Section < m_Database.Sections.Size())
|
||||
propVariant = m_Database.Sections[(int)item.Section].GetMethodName();
|
||||
break;
|
||||
}
|
||||
case kpidBlock:
|
||||
if (m_Database.LowLevel)
|
||||
propVariant = item.Section;
|
||||
else if (item.Section != 0)
|
||||
propVariant = m_Database.GetFolder(index);
|
||||
break;
|
||||
|
||||
#ifdef _CHM_DETAILS
|
||||
|
||||
case kpidSection:
|
||||
propVariant = (UInt32)item.Section;
|
||||
break;
|
||||
case kpidOffset:
|
||||
propVariant = (UInt32)item.Offset;
|
||||
break;
|
||||
|
||||
#endif
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
class CPropgressImp: public CProgressVirt
|
||||
{
|
||||
CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
|
||||
public:
|
||||
STDMETHOD(SetTotal)(const UInt64 *numFiles);
|
||||
STDMETHOD(SetCompleted)(const UInt64 *numFiles);
|
||||
void Init(IArchiveOpenCallback *openArchiveCallback)
|
||||
{ m_OpenArchiveCallback = openArchiveCallback; }
|
||||
};
|
||||
|
||||
STDMETHODIMP CPropgressImp::SetTotal(const UInt64 *numFiles)
|
||||
{
|
||||
if (m_OpenArchiveCallback)
|
||||
return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CPropgressImp::SetCompleted(const UInt64 *numFiles)
|
||||
{
|
||||
if (m_OpenArchiveCallback)
|
||||
return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
m_Stream.Release();
|
||||
try
|
||||
{
|
||||
CInArchive archive;
|
||||
CPropgressImp progressImp;
|
||||
progressImp.Init(openArchiveCallback);
|
||||
RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database));
|
||||
/*
|
||||
if (m_Database.LowLevel)
|
||||
return S_FALSE;
|
||||
*/
|
||||
m_Stream = inStream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
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;
|
||||
int m_StartIndex;
|
||||
int m_CurrentIndex;
|
||||
int 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();
|
||||
};
|
||||
|
||||
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 = NArchive::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(NArchive::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 != NULL)
|
||||
*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 != NULL)
|
||||
*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 ?
|
||||
NArchive::NExtract::NOperationResult::kOK:
|
||||
NArchive::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)
|
||||
return E_FAIL;
|
||||
int 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 != NULL)
|
||||
*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()
|
||||
{
|
||||
const UInt32 kBufferSize = (1 << 10);
|
||||
Byte buffer[kBufferSize];
|
||||
for (int i = 0; i < kBufferSize; i++)
|
||||
buffer[i] = 0;
|
||||
while(m_PosInFolder < m_FolderSize)
|
||||
{
|
||||
UInt32 size = (UInt32)MyMin(m_FolderSize - m_PosInFolder, (UInt64)kBufferSize);
|
||||
UInt32 processedSizeLocal = 0;
|
||||
RINOK(Write2(buffer, size, &processedSizeLocal, false));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == UInt32(-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 = (_aTestMode != 0);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
UInt32 i;
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
|
||||
if (m_Database.LowLevel)
|
||||
{
|
||||
UInt64 currentItemSize = 0;
|
||||
UInt64 totalSize = 0;
|
||||
if (m_Database.NewFormat)
|
||||
totalSize = m_Database.NewFormatString.Length();
|
||||
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)
|
||||
{
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode;
|
||||
askMode = testMode ? NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::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.Length();
|
||||
RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size, 0));
|
||||
}
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::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(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (testMode)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->SetStream(m_Stream);
|
||||
streamSpec->Init(item.Size);
|
||||
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = localProgressSpec;
|
||||
localProgressSpec->Init(extractCallback, false);
|
||||
|
||||
CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
|
||||
CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
|
||||
localCompressProgressSpec->Init(progress, ¤tTotalSize, ¤tTotalSize);
|
||||
|
||||
if(!copyCoder)
|
||||
copyCoder = new NCompress::CCopyCoder;
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, compressProgress));
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UInt64 lastFolderIndex = ((UInt64)0 - 1);
|
||||
for(i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
int entryIndex = m_Database.Indices[index];
|
||||
const CItem &item = m_Database.Items[entryIndex];
|
||||
UInt64 sectionIndex = item.Section;
|
||||
if (item.IsDirectory() || item.Size == 0)
|
||||
continue;
|
||||
if (sectionIndex == 0)
|
||||
{
|
||||
currentTotalSize += item.Size;
|
||||
continue;
|
||||
}
|
||||
const CSectionInfo §ion = m_Database.Sections[(int)item.Section];
|
||||
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 = 0;
|
||||
CMyComPtr<ICompressCoder> lzxDecoder;
|
||||
CChmFolderOutStream *chmFolderOutStream = 0;
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
|
||||
currentTotalSize = 0;
|
||||
|
||||
CRecordVector<bool> extractStatuses;
|
||||
for(i = 0; i < numItems;)
|
||||
{
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
i++;
|
||||
int entryIndex = m_Database.Indices[index];
|
||||
const CItem &item = m_Database.Items[entryIndex];
|
||||
UInt64 sectionIndex = item.Section;
|
||||
Int32 askMode= testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
if (item.IsDirectory())
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = localProgressSpec;
|
||||
localProgressSpec->Init(extractCallback, false);
|
||||
|
||||
CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
|
||||
CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
|
||||
localCompressProgressSpec->Init(progress, NULL, ¤tTotalSize);
|
||||
|
||||
if (item.Size == 0 || sectionIndex == 0)
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if(!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (!testMode && item.Size != 0)
|
||||
{
|
||||
RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->SetStream(m_Stream);
|
||||
streamSpec->Init(item.Size);
|
||||
if(!copyCoder)
|
||||
copyCoder = new NCompress::CCopyCoder;
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, compressProgress));
|
||||
}
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
currentTotalSize += item.Size;
|
||||
continue;
|
||||
}
|
||||
|
||||
const CSectionInfo §ion = m_Database.Sections[(int)sectionIndex];
|
||||
|
||||
if (!section.IsLzx())
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if(!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
|
||||
continue;
|
||||
}
|
||||
|
||||
const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
|
||||
|
||||
if (chmFolderOutStream == 0)
|
||||
{
|
||||
chmFolderOutStream = new CChmFolderOutStream;
|
||||
outStream = chmFolderOutStream;
|
||||
}
|
||||
|
||||
chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
|
||||
|
||||
if(lzxDecoderSpec == NULL)
|
||||
{
|
||||
lzxDecoderSpec = new NCompress::NLzx::CDecoder;
|
||||
lzxDecoder = lzxDecoderSpec;
|
||||
}
|
||||
|
||||
UInt64 folderIndex = m_Database.GetFolder(index);
|
||||
|
||||
UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
|
||||
UInt32 numDictBits = lzxInfo.GetNumDictBits();
|
||||
RINOK(lzxDecoderSpec->SetParams(numDictBits));
|
||||
|
||||
const CItem *lastItem = &item;
|
||||
extractStatuses.Clear();
|
||||
extractStatuses.Add(true);
|
||||
|
||||
for (;; folderIndex++)
|
||||
{
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
|
||||
UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
|
||||
UInt64 finishPos = lastItem->Offset + lastItem->Size;
|
||||
UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);
|
||||
|
||||
lastFolderIndex = m_Database.GetLastFolder(index);
|
||||
UInt64 folderSize = lzxInfo.GetFolderSize();
|
||||
UInt64 unPackSize = folderSize;
|
||||
if (extractStatuses.IsEmpty())
|
||||
chmFolderOutStream->m_StartIndex = index + 1;
|
||||
else
|
||||
chmFolderOutStream->m_StartIndex = index;
|
||||
if (limitFolderIndex == folderIndex)
|
||||
{
|
||||
for(; i < numItems; i++)
|
||||
{
|
||||
UInt32 nextIndex = allFilesMode ? i : indices[i];
|
||||
int entryIndex = m_Database.Indices[nextIndex];
|
||||
const CItem &nextItem = m_Database.Items[entryIndex];
|
||||
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 startOffset = rt.ResetOffsets[(int)startBlock];
|
||||
UInt64 offset = rt.ResetOffsets[(int)bCur];
|
||||
UInt64 compressedSize;
|
||||
rt.GetCompressedSizeOfBlock(bCur, compressedSize);
|
||||
UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection;
|
||||
if (rem > rt.BlockSize)
|
||||
rem = rt.BlockSize;
|
||||
// const UInt64 *offsets = (const UInt64 *)&rt.ResetOffsets.Front();
|
||||
RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->SetStream(m_Stream);
|
||||
streamSpec->Init(compressedSize);
|
||||
lzxDecoderSpec->SetKeepHistory(b > 0, (int)((offset - startOffset) & 1));
|
||||
RINOK(lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
RINOK(chmFolderOutStream->FlushCorrupted());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}}
|
||||
46
CPP/7zip/Archive/Chm/ChmHandler.h
Executable file
46
CPP/7zip/Archive/Chm/ChmHandler.h
Executable file
@@ -0,0 +1,46 @@
|
||||
// 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_IMP
|
||||
|
||||
STDMETHOD(Open)(IInStream *stream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback);
|
||||
STDMETHOD(Close)();
|
||||
STDMETHOD(GetNumberOfItems)(UInt32 *numItems);
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback);
|
||||
|
||||
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value);
|
||||
|
||||
STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties);
|
||||
STDMETHOD(GetPropertyInfo)(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType);
|
||||
|
||||
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties);
|
||||
STDMETHOD(GetArchivePropertyInfo)(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType);
|
||||
|
||||
private:
|
||||
CFilesDatabase m_Database;
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
24
CPP/7zip/Archive/Chm/ChmHeader.cpp
Executable file
24
CPP/7zip/Archive/Chm/ChmHeader.cpp
Executable file
@@ -0,0 +1,24 @@
|
||||
// Archive/Chm/Header.h
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "ChmHeader.h"
|
||||
|
||||
namespace NArchive{
|
||||
namespace NChm{
|
||||
namespace NHeader{
|
||||
|
||||
UInt32 kItsfSignature = 0x46535449 + 1;
|
||||
UInt32 kItolSignature = 0x4C4F5449 + 1;
|
||||
static class CSignatureInitializer
|
||||
{
|
||||
public:
|
||||
CSignatureInitializer()
|
||||
{
|
||||
kItsfSignature--;
|
||||
kItolSignature--;
|
||||
}
|
||||
}g_SignatureInitializer;
|
||||
|
||||
|
||||
}}}
|
||||
28
CPP/7zip/Archive/Chm/ChmHeader.h
Executable file
28
CPP/7zip/Archive/Chm/ChmHeader.h
Executable file
@@ -0,0 +1,28 @@
|
||||
// Archive/Chm/Header.h
|
||||
|
||||
#ifndef __ARCHIVE_CHM_HEADER_H
|
||||
#define __ARCHIVE_CHM_HEADER_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NChm {
|
||||
namespace NHeader{
|
||||
|
||||
const UInt32 kItspSignature = 0x50535449;
|
||||
const UInt32 kPmglSignature = 0x4C474D50;
|
||||
const UInt32 kLzxcSignature = 0x43585A4C;
|
||||
|
||||
const UInt32 kIfcmSignature = 0x4D434649;
|
||||
const UInt32 kAollSignature = 0x4C4C4F41;
|
||||
const UInt32 kCaolSignature = 0x4C4F4143;
|
||||
|
||||
extern UInt32 kItsfSignature;
|
||||
|
||||
extern UInt32 kItolSignature;
|
||||
const UInt32 kItlsSignature = 0x534C5449;
|
||||
UInt64 inline GetHxsSignature() { return ((UInt64)kItlsSignature << 32) | kItolSignature; }
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
925
CPP/7zip/Archive/Chm/ChmIn.cpp
Executable file
925
CPP/7zip/Archive/Chm/ChmIn.cpp
Executable file
@@ -0,0 +1,925 @@
|
||||
// Archive/ChmIn.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/MyCom.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Windows/Defs.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "ChmIn.h"
|
||||
|
||||
namespace NArchive{
|
||||
namespace NChm{
|
||||
|
||||
// define CHM_LOW, if you want to see low level items
|
||||
// #define CHM_LOW
|
||||
|
||||
static const GUID kChmLzxGuid =
|
||||
{ 0x7FC28940, 0x9D31, 0x11D0, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C };
|
||||
static const GUID kHelp2LzxGuid =
|
||||
{ 0x0A9007C6, 0x4076, 0x11D3, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 };
|
||||
static const GUID kDesGuid =
|
||||
{ 0x67F6E4A2, 0x60BF, 0x11D3, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF };
|
||||
|
||||
static bool AreGuidsEqual(REFGUID g1, REFGUID g2)
|
||||
{
|
||||
if (g1.Data1 != g2.Data1 ||
|
||||
g1.Data2 != g2.Data2 ||
|
||||
g1.Data3 != g2.Data3)
|
||||
return false;
|
||||
for (int i = 0; i < 8; i++)
|
||||
if (g1.Data4[i] != g2.Data4[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static char GetHex(Byte value)
|
||||
{
|
||||
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
|
||||
}
|
||||
|
||||
static void PrintByte(Byte b, AString &s)
|
||||
{
|
||||
s += GetHex(b >> 4);
|
||||
s += GetHex(b & 0xF);
|
||||
}
|
||||
|
||||
static void PrintUInt16(UInt16 v, AString &s)
|
||||
{
|
||||
PrintByte((Byte)(v >> 8), s);
|
||||
PrintByte((Byte)v, s);
|
||||
}
|
||||
|
||||
static void PrintUInt32(UInt32 v, AString &s)
|
||||
{
|
||||
PrintUInt16((UInt16)(v >> 16), s);
|
||||
PrintUInt16((UInt16)v, s);
|
||||
}
|
||||
|
||||
AString CMethodInfo::GetGuidString() const
|
||||
{
|
||||
AString s;
|
||||
s += '{';
|
||||
PrintUInt32(Guid.Data1, s);
|
||||
s += '-';
|
||||
PrintUInt16(Guid.Data2, s);
|
||||
s += '-';
|
||||
PrintUInt16(Guid.Data3, s);
|
||||
s += '-';
|
||||
PrintByte(Guid.Data4[0], s);
|
||||
PrintByte(Guid.Data4[1], s);
|
||||
s += '-';
|
||||
for (int i = 2; i < 8; i++)
|
||||
PrintByte(Guid.Data4[i], s);
|
||||
s += '}';
|
||||
return s;
|
||||
}
|
||||
|
||||
bool CMethodInfo::IsLzx() const
|
||||
{
|
||||
if (AreGuidsEqual(Guid, kChmLzxGuid))
|
||||
return true;
|
||||
return AreGuidsEqual(Guid, kHelp2LzxGuid);
|
||||
}
|
||||
|
||||
bool CMethodInfo::IsDes() const
|
||||
{
|
||||
return AreGuidsEqual(Guid, kDesGuid);
|
||||
}
|
||||
|
||||
UString CMethodInfo::GetName() const
|
||||
{
|
||||
UString s;
|
||||
if (IsLzx())
|
||||
{
|
||||
s = L"LZX:";
|
||||
UInt32 numDictBits = LzxInfo.GetNumDictBits();
|
||||
wchar_t temp[32];
|
||||
ConvertUInt64ToString(numDictBits, temp);
|
||||
s += temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
AString s2;
|
||||
if (IsDes())
|
||||
s2 = "DES";
|
||||
else
|
||||
{
|
||||
s2 = GetGuidString();
|
||||
if (ControlData.GetCapacity() > 0)
|
||||
{
|
||||
s2 += ":";
|
||||
for (size_t i = 0; i < ControlData.GetCapacity(); i++)
|
||||
PrintByte(ControlData[i], s2);
|
||||
}
|
||||
}
|
||||
ConvertUTF8ToUnicode(s2, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool CSectionInfo::IsLzx() const
|
||||
{
|
||||
if (Methods.Size() != 1)
|
||||
return false;
|
||||
return Methods[0].IsLzx();
|
||||
}
|
||||
|
||||
UString CSectionInfo::GetMethodName() const
|
||||
{
|
||||
UString s;
|
||||
if (!IsLzx())
|
||||
{
|
||||
UString temp;
|
||||
if (ConvertUTF8ToUnicode(Name, temp))
|
||||
s += temp;
|
||||
s += L": ";
|
||||
}
|
||||
for (int i = 0; i < Methods.Size(); i++)
|
||||
{
|
||||
if (i != 0)
|
||||
s += L" ";
|
||||
s += Methods[i].GetName();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Byte CInArchive::ReadByte()
|
||||
{
|
||||
Byte b;
|
||||
if (!_inBuffer.ReadByte(b))
|
||||
throw 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
void CInArchive::Skeep(size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
ReadByte();
|
||||
}
|
||||
|
||||
void CInArchive::ReadBytes(Byte *data, UInt32 size)
|
||||
{
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
data[i] = ReadByte();
|
||||
}
|
||||
|
||||
UInt16 CInArchive::ReadUInt16()
|
||||
{
|
||||
UInt16 value = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
value |= ((UInt16)(ReadByte()) << (8 * i));
|
||||
return value;
|
||||
}
|
||||
|
||||
UInt32 CInArchive::ReadUInt32()
|
||||
{
|
||||
UInt32 value = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
value |= ((UInt32)(ReadByte()) << (8 * i));
|
||||
return value;
|
||||
}
|
||||
|
||||
UInt64 CInArchive::ReadUInt64()
|
||||
{
|
||||
UInt64 value = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
value |= ((UInt64)(ReadByte()) << (8 * i));
|
||||
return value;
|
||||
}
|
||||
|
||||
UInt64 CInArchive::ReadEncInt()
|
||||
{
|
||||
UInt64 val = 0;;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Byte b = ReadByte();
|
||||
val |= (b & 0x7F);
|
||||
if (b < 0x80)
|
||||
return val;
|
||||
val <<= 7;
|
||||
}
|
||||
throw 1;
|
||||
}
|
||||
|
||||
void CInArchive::ReadGUID(GUID &g)
|
||||
{
|
||||
g.Data1 = ReadUInt32();
|
||||
g.Data2 = ReadUInt16();
|
||||
g.Data3 = ReadUInt16();
|
||||
ReadBytes(g.Data4, 8);
|
||||
}
|
||||
|
||||
void CInArchive::ReadString(int size, AString &s)
|
||||
{
|
||||
s.Empty();
|
||||
while(size-- != 0)
|
||||
{
|
||||
char c = (char)ReadByte();
|
||||
if (c == 0)
|
||||
{
|
||||
Skeep(size);
|
||||
return;
|
||||
}
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
|
||||
void CInArchive::ReadUString(int size, UString &s)
|
||||
{
|
||||
s.Empty();
|
||||
while(size-- != 0)
|
||||
{
|
||||
wchar_t c = ReadUInt16();
|
||||
if (c == 0)
|
||||
{
|
||||
Skeep(2 * size);
|
||||
return;
|
||||
}
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size)
|
||||
{
|
||||
RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL));
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
|
||||
streamSpec->SetStream(inStream);
|
||||
streamSpec->Init(size);
|
||||
_inBuffer.SetStream(limitedStream);
|
||||
_inBuffer.Init();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadDirEntry(CDatabase &database)
|
||||
{
|
||||
CItem item;
|
||||
UInt64 nameLength = ReadEncInt();
|
||||
if (nameLength == 0 || nameLength >= 0x10000000)
|
||||
return S_FALSE;
|
||||
ReadString((int)nameLength, item.Name);
|
||||
item.Section = ReadEncInt();
|
||||
item.Offset = ReadEncInt();
|
||||
item.Size = ReadEncInt();
|
||||
database.Items.Add(item);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
|
||||
{
|
||||
UInt32 headerSize = ReadUInt32();
|
||||
if (headerSize != 0x60)
|
||||
return S_FALSE;
|
||||
UInt32 unknown1 = ReadUInt32();
|
||||
if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file
|
||||
return S_FALSE;
|
||||
/* UInt32 timeStamp = */ ReadUInt32();
|
||||
// Considered as a big-endian DWORD, it appears to contain seconds (MSB) and
|
||||
// fractional seconds (second byte).
|
||||
// The third and fourth bytes may contain even more fractional bits.
|
||||
// The 4 least significant bits in the last byte are constant.
|
||||
/* UInt32 lang = */ ReadUInt32();
|
||||
GUID g;
|
||||
ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
|
||||
ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
|
||||
const int kNumSections = 2;
|
||||
UInt64 sectionOffsets[kNumSections];
|
||||
UInt64 sectionSizes[kNumSections];
|
||||
int i;
|
||||
for (i = 0; i < kNumSections; i++)
|
||||
{
|
||||
sectionOffsets[i] = ReadUInt64();
|
||||
sectionSizes[i] = ReadUInt64();
|
||||
}
|
||||
// if (chmVersion == 3)
|
||||
database.ContentOffset = ReadUInt64();
|
||||
/*
|
||||
else
|
||||
database.ContentOffset = _startPosition + 0x58
|
||||
*/
|
||||
|
||||
/*
|
||||
// Section 0
|
||||
ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]);
|
||||
if (sectionSizes[0] != 0x18)
|
||||
return S_FALSE;
|
||||
ReadUInt32(); // unknown: 01FE
|
||||
ReadUInt32(); // unknown: 0
|
||||
UInt64 fileSize = ReadUInt64();
|
||||
ReadUInt32(); // unknown: 0
|
||||
ReadUInt32(); // unknown: 0
|
||||
*/
|
||||
|
||||
// Section 1: The Directory Listing
|
||||
ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]);
|
||||
if (ReadUInt32() != NHeader::kItspSignature)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 1) // version
|
||||
return S_FALSE;
|
||||
/* UInt32 dirHeaderSize = */ ReadUInt32();
|
||||
ReadUInt32(); // 0x0A (unknown)
|
||||
UInt32 dirChunkSize = ReadUInt32(); // $1000
|
||||
if (dirChunkSize < 32)
|
||||
return S_FALSE;
|
||||
/* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2.
|
||||
/* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index,
|
||||
// 2 if there is one level of PMGI chunks.
|
||||
|
||||
/* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none
|
||||
// (though at least one file has 0 despite there being no
|
||||
// index chunk, probably a bug.)
|
||||
/* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk
|
||||
/* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk
|
||||
ReadUInt32(); // -1 (unknown)
|
||||
UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total)
|
||||
/* UInt32 windowsLangId = */ ReadUInt32();
|
||||
ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC}
|
||||
ReadUInt32(); // 0x54 (This is the length again)
|
||||
ReadUInt32(); // -1 (unknown)
|
||||
ReadUInt32(); // -1 (unknown)
|
||||
ReadUInt32(); // -1 (unknown)
|
||||
|
||||
for (UInt32 ci = 0; ci < numDirChunks; ci++)
|
||||
{
|
||||
UInt64 chunkPos = _inBuffer.GetProcessedSize();
|
||||
if (ReadUInt32() == NHeader::kPmglSignature)
|
||||
{
|
||||
// The quickref area is written backwards from the end of the chunk.
|
||||
// One quickref entry exists for every n entries in the file, where n
|
||||
// is calculated as 1 + (1 << quickref density). So for density = 2, n = 5.
|
||||
|
||||
UInt32 quickrefLength = ReadUInt32(); // Length of free space and/or quickref area at end of directory chunk
|
||||
if (quickrefLength > dirChunkSize || quickrefLength < 2)
|
||||
return S_FALSE;
|
||||
ReadUInt32(); // Always 0
|
||||
ReadUInt32(); // Chunk number of previous listing chunk when reading
|
||||
// directory in sequence (-1 if this is the first listing chunk)
|
||||
ReadUInt32(); // Chunk number of next listing chunk when reading
|
||||
// directory in sequence (-1 if this is the last listing chunk)
|
||||
int numItems = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
|
||||
UInt32 offsetLimit = dirChunkSize - quickrefLength;
|
||||
if (offset > offsetLimit)
|
||||
return S_FALSE;
|
||||
if (offset == offsetLimit)
|
||||
break;
|
||||
RINOK(ReadDirEntry(database));
|
||||
numItems++;
|
||||
}
|
||||
Skeep(quickrefLength - 2);
|
||||
if (ReadUInt16() != numItems)
|
||||
return S_FALSE;
|
||||
}
|
||||
else
|
||||
Skeep(dirChunkSize - 4);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
|
||||
{
|
||||
if (ReadUInt32() != 1) // version
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 0x28) // Location of header section table
|
||||
return S_FALSE;
|
||||
UInt32 numHeaderSections = ReadUInt32();
|
||||
const int kNumHeaderSectionsMax = 5;
|
||||
if (numHeaderSections != kNumHeaderSectionsMax)
|
||||
return S_FALSE;
|
||||
ReadUInt32(); // Length of post-header table
|
||||
GUID g;
|
||||
ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754}
|
||||
|
||||
// header section table
|
||||
UInt64 sectionOffsets[kNumHeaderSectionsMax];
|
||||
UInt64 sectionSizes[kNumHeaderSectionsMax];
|
||||
UInt32 i;
|
||||
for (i = 0; i < numHeaderSections; i++)
|
||||
{
|
||||
sectionOffsets[i] = ReadUInt64();
|
||||
sectionSizes[i] = ReadUInt64();
|
||||
}
|
||||
|
||||
// Post-Header
|
||||
ReadUInt32(); // 2
|
||||
ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header)
|
||||
// ----- Directory information
|
||||
ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1
|
||||
ReadUInt64(); // Chunk number of first AOLL chunk in directory
|
||||
ReadUInt64(); // Chunk number of last AOLL chunk in directory
|
||||
ReadUInt64(); // 0 (unknown)
|
||||
ReadUInt32(); // $2000 (Directory chunk size of directory)
|
||||
ReadUInt32(); // Quickref density for main directory, usually 2
|
||||
ReadUInt32(); // 0 (unknown)
|
||||
ReadUInt32(); // Depth of main directory index tree
|
||||
// 1 there is no index, 2 if there is one level of AOLI chunks.
|
||||
ReadUInt64(); // 0 (unknown)
|
||||
UInt64 numDirEntries = ReadUInt64(); // Number of directory entries
|
||||
// ----- Directory Index Information
|
||||
ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index)
|
||||
ReadUInt64(); // Chunk number of first AOLL chunk in directory index
|
||||
ReadUInt64(); // Chunk number of last AOLL chunk in directory index
|
||||
ReadUInt64(); // 0 (unknown)
|
||||
ReadUInt32(); // $200 (Directory chunk size of directory index)
|
||||
ReadUInt32(); // Quickref density for directory index, usually 2
|
||||
ReadUInt32(); // 0 (unknown)
|
||||
ReadUInt32(); // Depth of directory index index tree.
|
||||
ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0.
|
||||
ReadUInt64(); // Number of directory index entries (same as number of AOLL
|
||||
// chunks in main directory)
|
||||
|
||||
// (The obvious guess for the following two fields, which recur in a number
|
||||
// of places, is they are maximum sizes for the directory and directory index.
|
||||
// However, I have seen no direct evidence that this is the case.)
|
||||
|
||||
ReadUInt32(); // $100000 (Same as field following chunk size in directory)
|
||||
ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
|
||||
|
||||
ReadUInt64(); // 0 (unknown)
|
||||
if (ReadUInt32() != NHeader::kCaolSignature)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 2) // (Most likely a version number)
|
||||
return S_FALSE;
|
||||
UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section)
|
||||
if (caolLength >= 0x2C)
|
||||
{
|
||||
/* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built.
|
||||
// Does not appear to be a checksum. Many files have
|
||||
// 'HH' (HTML Help?) here, indicating this may be a compiler ID
|
||||
// field. But at least one ITOL/ITLS compiler does not set this
|
||||
// field to a constant value.
|
||||
ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field)
|
||||
ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0.
|
||||
ReadUInt32(); // $2000 (Directory chunk size of directory)
|
||||
ReadUInt32(); // $200 (Directory chunk size of directory index)
|
||||
ReadUInt32(); // $100000 (Same as field following chunk size in directory)
|
||||
ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
|
||||
ReadUInt32(); // 0 (unknown)
|
||||
ReadUInt32(); // 0 (Unknown)
|
||||
if (caolLength == 0x2C)
|
||||
{
|
||||
database.ContentOffset = 0;
|
||||
database.NewFormat = true;
|
||||
}
|
||||
else if (caolLength == 0x50)
|
||||
{
|
||||
ReadUInt32(); // 0 (Unknown)
|
||||
if (ReadUInt32() != NHeader::kItsfSignature)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 0x20) // $20 (length of ITSF)
|
||||
return S_FALSE;
|
||||
UInt32 unknown = ReadUInt32();
|
||||
if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases;
|
||||
return S_FALSE;
|
||||
database.ContentOffset = _startPosition + ReadUInt64();
|
||||
/* UInt32 timeStamp = */ ReadUInt32();
|
||||
// A timestamp of some sort.
|
||||
// Considered as a big-endian DWORD, it appears to contain
|
||||
// seconds (MSB) and fractional seconds (second byte).
|
||||
// The third and fourth bytes may contain even more fractional
|
||||
// bits. The 4 least significant bits in the last byte are constant.
|
||||
/* UInt32 lang = */ ReadUInt32(); // BE?
|
||||
}
|
||||
else
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
// Section 0
|
||||
ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]);
|
||||
if (sectionSizes[0] != 0x18)
|
||||
return S_FALSE;
|
||||
ReadUInt32(); // unknown: 01FE
|
||||
ReadUInt32(); // unknown: 0
|
||||
UInt64 fileSize = ReadUInt64();
|
||||
ReadUInt32(); // unknown: 0
|
||||
ReadUInt32(); // unknown: 0
|
||||
*/
|
||||
|
||||
// Section 1: The Directory Listing
|
||||
ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]);
|
||||
if (ReadUInt32() != NHeader::kIfcmSignature)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 1) // (probably a version number)
|
||||
return S_FALSE;
|
||||
UInt32 dirChunkSize = ReadUInt32(); // $2000
|
||||
if (dirChunkSize < 64)
|
||||
return S_FALSE;
|
||||
ReadUInt32(); // $100000 (unknown)
|
||||
ReadUInt32(); // -1 (unknown)
|
||||
ReadUInt32(); // -1 (unknown)
|
||||
UInt32 numDirChunks = ReadUInt32();
|
||||
ReadUInt32(); // 0 (unknown, probably high word of above)
|
||||
|
||||
for (UInt32 ci = 0; ci < numDirChunks; ci++)
|
||||
{
|
||||
UInt64 chunkPos = _inBuffer.GetProcessedSize();
|
||||
if (ReadUInt32() == NHeader::kAollSignature)
|
||||
{
|
||||
UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk
|
||||
if (quickrefLength > dirChunkSize || quickrefLength < 2)
|
||||
return S_FALSE;
|
||||
ReadUInt64(); // Directory chunk number
|
||||
// This must match physical position in file, that is
|
||||
// the chunk size times the chunk number must be the
|
||||
// offset from the end of the directory header.
|
||||
ReadUInt64(); // Chunk number of previous listing chunk when reading
|
||||
// directory in sequence (-1 if first listing chunk)
|
||||
ReadUInt64(); // Chunk number of next listing chunk when reading
|
||||
// directory in sequence (-1 if last listing chunk)
|
||||
ReadUInt64(); // Number of first listing entry in this chunk
|
||||
ReadUInt32(); // 1 (unknown -- other values have also been seen here)
|
||||
ReadUInt32(); // 0 (unknown)
|
||||
|
||||
int numItems = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
|
||||
UInt32 offsetLimit = dirChunkSize - quickrefLength;
|
||||
if (offset > offsetLimit)
|
||||
return S_FALSE;
|
||||
if (offset == offsetLimit)
|
||||
break;
|
||||
if (database.NewFormat)
|
||||
{
|
||||
UInt16 nameLength = ReadUInt16();
|
||||
if (nameLength == 0)
|
||||
return S_FALSE;
|
||||
UString name;
|
||||
ReadUString((int)nameLength, name);
|
||||
AString s;
|
||||
ConvertUnicodeToUTF8(name, s);
|
||||
Byte b = ReadByte();
|
||||
s += ' ';
|
||||
PrintByte(b, s);
|
||||
s += ' ';
|
||||
UInt64 len = ReadEncInt();
|
||||
// then number of items ?
|
||||
// then length ?
|
||||
// then some data (binary encoding?)
|
||||
while (len-- != 0)
|
||||
{
|
||||
b = ReadByte();
|
||||
PrintByte(b, s);
|
||||
}
|
||||
database.NewFormatString += s;
|
||||
database.NewFormatString += "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(ReadDirEntry(database));
|
||||
}
|
||||
numItems++;
|
||||
}
|
||||
Skeep(quickrefLength - 2);
|
||||
if (ReadUInt16() != numItems)
|
||||
return S_FALSE;
|
||||
if (numItems > numDirEntries)
|
||||
return S_FALSE;
|
||||
numDirEntries -= numItems;
|
||||
}
|
||||
else
|
||||
Skeep(dirChunkSize - 4);
|
||||
}
|
||||
return numDirEntries == 0 ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name)
|
||||
{
|
||||
int index = database.FindItem(name);
|
||||
if (index < 0)
|
||||
return S_FALSE;
|
||||
const CItem &item = database.Items[index];
|
||||
_chunkSize = item.Size;
|
||||
return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size);
|
||||
}
|
||||
|
||||
|
||||
#define DATA_SPACE "::DataSpace/"
|
||||
static const char *kNameList = DATA_SPACE "NameList";
|
||||
static const char *kStorage = DATA_SPACE "Storage/";
|
||||
static const char *kContent = "Content";
|
||||
static const char *kControlData = "ControlData";
|
||||
static const char *kSpanInfo = "SpanInfo";
|
||||
static const char *kTransform = "Transform/";
|
||||
static const char *kResetTable = "/InstanceData/ResetTable";
|
||||
static const char *kTransformList = "List";
|
||||
|
||||
static AString GetSectionPrefix(const AString &name)
|
||||
{
|
||||
return AString(kStorage) + name + AString("/");
|
||||
}
|
||||
|
||||
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
|
||||
|
||||
static int CompareFiles(const int *p1, const int *p2, void *param)
|
||||
{
|
||||
const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
|
||||
const CItem &item1 = items[*p1];
|
||||
const CItem &item2 = items[*p2];
|
||||
bool isDir1 = item1.IsDirectory();
|
||||
bool isDir2 = item2.IsDirectory();
|
||||
if (isDir1 && !isDir2)
|
||||
return -1;
|
||||
if (isDir2)
|
||||
{
|
||||
if (isDir1)
|
||||
return MyCompare(*p1, *p2);
|
||||
return 1;
|
||||
}
|
||||
RINOZ(MyCompare(item1.Section, item2.Section));
|
||||
RINOZ(MyCompare(item1.Offset, item2.Offset));
|
||||
RINOZ(MyCompare(item1.Size, item2.Size));
|
||||
return MyCompare(*p1, *p2);
|
||||
}
|
||||
|
||||
void CFilesDatabase::SetIndices()
|
||||
{
|
||||
for (int i = 0; i < Items.Size(); i++)
|
||||
{
|
||||
const CItem &item = Items[i];
|
||||
if (item.IsUserItem() && item.Name.Length() != 1)
|
||||
Indices.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
void CFilesDatabase::Sort()
|
||||
{
|
||||
Indices.Sort(CompareFiles, (void *)&Items);
|
||||
}
|
||||
|
||||
bool CFilesDatabase::Check()
|
||||
{
|
||||
UInt64 maxPos = 0;
|
||||
UInt64 prevSection = 0;
|
||||
for(int i = 0; i < Indices.Size(); i++)
|
||||
{
|
||||
const CItem &item = Items[Indices[i]];
|
||||
if (item.Section == 0 || item.IsDirectory())
|
||||
continue;
|
||||
if (item.Section != prevSection)
|
||||
{
|
||||
prevSection = item.Section;
|
||||
maxPos = 0;
|
||||
continue;
|
||||
}
|
||||
if (item.Offset < maxPos)
|
||||
return false;
|
||||
maxPos = item.Offset + item.Size;
|
||||
if (maxPos < item.Offset)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
|
||||
{
|
||||
{
|
||||
// The NameList file
|
||||
RINOK(DecompressStream(inStream, database, kNameList));
|
||||
/* UInt16 length = */ ReadUInt16();
|
||||
UInt16 numSections = ReadUInt16();
|
||||
for (int i = 0; i < numSections; i++)
|
||||
{
|
||||
CSectionInfo section;
|
||||
UInt16 nameLength = ReadUInt16();
|
||||
UString name;
|
||||
ReadUString(nameLength, name);
|
||||
if (ReadUInt16() != 0)
|
||||
return S_FALSE;
|
||||
if (!ConvertUnicodeToUTF8(name, section.Name))
|
||||
return S_FALSE;
|
||||
database.Sections.Add(section);
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 1; i < database.Sections.Size(); i++)
|
||||
{
|
||||
CSectionInfo §ion = database.Sections[i];
|
||||
AString sectionPrefix = GetSectionPrefix(section.Name);
|
||||
{
|
||||
// Content
|
||||
int index = database.FindItem(sectionPrefix + kContent);
|
||||
if (index < 0)
|
||||
return S_FALSE;
|
||||
const CItem &item = database.Items[index];
|
||||
section.Offset = item.Offset;
|
||||
section.CompressedSize = item.Size;
|
||||
}
|
||||
AString transformPrefix = sectionPrefix + kTransform;
|
||||
if (database.Help2Format)
|
||||
{
|
||||
// Transform List
|
||||
RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList));
|
||||
if ((_chunkSize & 0xF) != 0)
|
||||
return S_FALSE;
|
||||
int numGuids = (int)(_chunkSize / 0x10);
|
||||
if (numGuids < 1)
|
||||
return S_FALSE;
|
||||
for (int i = 0; i < numGuids; i++)
|
||||
{
|
||||
CMethodInfo method;
|
||||
ReadGUID(method.Guid);
|
||||
section.Methods.Add(method);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CMethodInfo method;
|
||||
method.Guid = kChmLzxGuid;
|
||||
section.Methods.Add(method);
|
||||
}
|
||||
|
||||
{
|
||||
// Control Data
|
||||
RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData));
|
||||
for (int mi = 0; mi < section.Methods.Size(); mi++)
|
||||
{
|
||||
CMethodInfo &method = section.Methods[mi];
|
||||
UInt32 numDWORDS = ReadUInt32();
|
||||
if (method.IsLzx())
|
||||
{
|
||||
if (numDWORDS < 5)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != NHeader::kLzxcSignature)
|
||||
return S_FALSE;
|
||||
CLzxInfo &li = method.LzxInfo;
|
||||
li.Version = ReadUInt32();
|
||||
if (li.Version != 2 && li.Version != 3)
|
||||
return S_FALSE;
|
||||
li.ResetInterval = ReadUInt32();
|
||||
li.WindowSize = ReadUInt32();
|
||||
li.CacheSize = ReadUInt32();
|
||||
if (li.ResetInterval != 2 && li.ResetInterval != 4)
|
||||
return S_FALSE;
|
||||
if (li.WindowSize != 2 && li.WindowSize != 4)
|
||||
return S_FALSE;
|
||||
numDWORDS -= 5;
|
||||
while (numDWORDS-- != 0)
|
||||
ReadUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 numBytes = numDWORDS * 4;
|
||||
method.ControlData.SetCapacity(numBytes);
|
||||
ReadBytes(method.ControlData, numBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// SpanInfo
|
||||
RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo));
|
||||
section.UncompressedSize = ReadUInt64();
|
||||
}
|
||||
|
||||
// read ResetTable for LZX
|
||||
for (int mi = 0; mi < section.Methods.Size(); mi++)
|
||||
{
|
||||
CMethodInfo &method = section.Methods[mi];
|
||||
if (method.IsLzx())
|
||||
{
|
||||
// ResetTable;
|
||||
RINOK(DecompressStream(inStream, database, transformPrefix +
|
||||
method.GetGuidString() + kResetTable));
|
||||
CResetTable &rt = method.LzxInfo.ResetTable;
|
||||
if (_chunkSize < 4)
|
||||
{
|
||||
if (_chunkSize != 0)
|
||||
return S_FALSE;
|
||||
// ResetTable is empty in .chw files
|
||||
if (section.UncompressedSize != 0)
|
||||
return S_FALSE;
|
||||
rt.UncompressedSize = 0;
|
||||
rt.CompressedSize = 0;
|
||||
rt.BlockSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 ver = ReadUInt32(); // 2 unknown (possibly a version number)
|
||||
if (ver != 2 && ver != 3)
|
||||
return S_FALSE;
|
||||
UInt32 numEntries = ReadUInt32();
|
||||
if (ReadUInt32() != 8) // Size of table entry (bytes)
|
||||
return S_FALSE;
|
||||
if (ReadUInt32() != 0x28) // Length of table header
|
||||
return S_FALSE;
|
||||
rt.UncompressedSize = ReadUInt64();
|
||||
rt.CompressedSize = ReadUInt64();
|
||||
rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below
|
||||
if (rt.BlockSize != 0x8000)
|
||||
return S_FALSE;
|
||||
rt.ResetOffsets.Reserve(numEntries);
|
||||
for (UInt32 i = 0; i < numEntries; i++)
|
||||
rt.ResetOffsets.Add(ReadUInt64());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.SetIndices();
|
||||
database.Sort();
|
||||
return database.Check() ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open2(IInStream *inStream,
|
||||
const UInt64 *searchHeaderSizeLimit,
|
||||
CFilesDatabase &database)
|
||||
{
|
||||
database.Clear();
|
||||
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
|
||||
|
||||
database.Help2Format = false;
|
||||
const UInt32 chmVersion = 3;
|
||||
{
|
||||
if (!_inBuffer.Create(1 << 14))
|
||||
return E_OUTOFMEMORY;
|
||||
_inBuffer.SetStream(inStream);
|
||||
_inBuffer.Init();
|
||||
UInt64 value = 0;
|
||||
const int kSignatureSize = 8;
|
||||
UInt64 hxsSignature = NHeader::GetHxsSignature();
|
||||
UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature;
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
if (!_inBuffer.ReadByte(b))
|
||||
return S_FALSE;
|
||||
value >>= 8;
|
||||
value |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
|
||||
if (_inBuffer.GetProcessedSize() >= kSignatureSize)
|
||||
{
|
||||
if (value == chmSignature)
|
||||
break;
|
||||
if (value == hxsSignature)
|
||||
{
|
||||
database.Help2Format = true;
|
||||
break;
|
||||
}
|
||||
if (searchHeaderSizeLimit != NULL)
|
||||
if (_inBuffer.GetProcessedSize() > (*searchHeaderSizeLimit))
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
_startPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
|
||||
}
|
||||
|
||||
if (database.Help2Format)
|
||||
{
|
||||
RINOK(OpenHelp2(inStream, database));
|
||||
if (database.NewFormat)
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(OpenChm(inStream, database));
|
||||
}
|
||||
|
||||
#ifndef CHM_LOW
|
||||
try
|
||||
{
|
||||
HRESULT res = OpenHighLevel(inStream, database);
|
||||
if (res == S_FALSE)
|
||||
{
|
||||
database.HighLevelClear();
|
||||
return S_OK;
|
||||
}
|
||||
RINOK(res);
|
||||
database.LowLevel = false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream,
|
||||
const UInt64 *searchHeaderSizeLimit,
|
||||
CFilesDatabase &database)
|
||||
{
|
||||
try
|
||||
{
|
||||
HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
|
||||
_inBuffer.ReleaseStream();
|
||||
return res;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
_inBuffer.ReleaseStream();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
242
CPP/7zip/Archive/Chm/ChmIn.h
Executable file
242
CPP/7zip/Archive/Chm/ChmIn.h
Executable file
@@ -0,0 +1,242 @@
|
||||
// Archive/ChmIn.h
|
||||
|
||||
#ifndef __ARCHIVE_CHM_IN_H
|
||||
#define __ARCHIVE_CHM_IN_H
|
||||
|
||||
#include "Common/String.h"
|
||||
#include "Common/Buffer.h"
|
||||
#include "../../IStream.h"
|
||||
#include "../../Common/InBuffer.h"
|
||||
#include "ChmHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NChm {
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UInt64 Section;
|
||||
UInt64 Offset;
|
||||
UInt64 Size;
|
||||
AString Name;
|
||||
|
||||
bool IsFormatRelatedItem() const
|
||||
{
|
||||
if (Name.Length() < 2)
|
||||
return false;
|
||||
return Name[0] == ':' && Name[1] == ':';
|
||||
}
|
||||
|
||||
bool IsUserItem() const
|
||||
{
|
||||
if (Name.Length() < 2)
|
||||
return false;
|
||||
return Name[0] == '/';
|
||||
}
|
||||
|
||||
bool IsDirectory() const
|
||||
{
|
||||
if (Name.Length() == 0)
|
||||
return false;
|
||||
return (Name[Name.Length() - 1] == '/');
|
||||
}
|
||||
};
|
||||
|
||||
struct CDatabase
|
||||
{
|
||||
UInt64 ContentOffset;
|
||||
CObjectVector<CItem> Items;
|
||||
AString NewFormatString;
|
||||
bool Help2Format;
|
||||
bool NewFormat;
|
||||
|
||||
int FindItem(const AString &name) const
|
||||
{
|
||||
for (int i = 0; i < Items.Size(); i++)
|
||||
if (Items[i].Name == name)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
NewFormat = false;
|
||||
NewFormatString.Empty();
|
||||
Help2Format = false;
|
||||
Items.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct CResetTable
|
||||
{
|
||||
UInt64 UncompressedSize;
|
||||
UInt64 CompressedSize;
|
||||
UInt64 BlockSize;
|
||||
CRecordVector<UInt64> ResetOffsets;
|
||||
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
|
||||
{
|
||||
if (blockIndex >= ResetOffsets.Size())
|
||||
return false;
|
||||
UInt64 startPos = ResetOffsets[(int)blockIndex];
|
||||
if (blockIndex + numBlocks >= ResetOffsets.Size())
|
||||
size = CompressedSize - startPos;
|
||||
else
|
||||
size = ResetOffsets[(int)(blockIndex + numBlocks)] - startPos;
|
||||
return true;
|
||||
}
|
||||
bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
|
||||
{
|
||||
return GetCompressedSizeOfBlocks(blockIndex, 1, size);
|
||||
}
|
||||
UInt64 GetNumBlocks(UInt64 size) const
|
||||
{
|
||||
return (size + BlockSize - 1) / BlockSize;
|
||||
}
|
||||
};
|
||||
|
||||
struct CLzxInfo
|
||||
{
|
||||
UInt32 Version;
|
||||
UInt32 ResetInterval;
|
||||
UInt32 WindowSize;
|
||||
UInt32 CacheSize;
|
||||
CResetTable ResetTable;
|
||||
|
||||
UInt32 GetNumDictBits() const
|
||||
{
|
||||
if (Version == 2 || Version == 3)
|
||||
{
|
||||
for (int i = 0; i <= 31; i++)
|
||||
if (((UInt32)1 << i) >= WindowSize)
|
||||
return 15 + i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; };
|
||||
UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); };
|
||||
UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); };
|
||||
UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; };
|
||||
bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
|
||||
{
|
||||
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
|
||||
if (blockIndex >= ResetTable.ResetOffsets.Size())
|
||||
return false;
|
||||
offset = ResetTable.ResetOffsets[(int)blockIndex];
|
||||
return true;
|
||||
}
|
||||
bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
|
||||
{
|
||||
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
|
||||
return ResetTable.GetCompressedSizeOfBlocks(blockIndex, ResetInterval, 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;
|
||||
CRecordVector<int> Indices;
|
||||
CObjectVector<CSectionInfo> Sections;
|
||||
|
||||
UInt64 GetFileSize(int fileIndex) const { return Items[Indices[fileIndex]].Size; }
|
||||
UInt64 GetFileOffset(int fileIndex) const { return Items[Indices[fileIndex]].Offset; }
|
||||
|
||||
UInt64 GetFolder(int fileIndex) const
|
||||
{
|
||||
const CItem &item = Items[Indices[fileIndex]];
|
||||
const CSectionInfo §ion = Sections[(int)item.Section];
|
||||
if (section.IsLzx())
|
||||
return section.Methods[0].LzxInfo.GetFolder(item.Offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UInt64 GetLastFolder(int fileIndex) const
|
||||
{
|
||||
const CItem &item = Items[Indices[fileIndex]];
|
||||
const CSectionInfo §ion = Sections[(int)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();
|
||||
};
|
||||
|
||||
class CProgressVirt
|
||||
{
|
||||
public:
|
||||
STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE;
|
||||
STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE;
|
||||
};
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
UInt64 _startPosition;
|
||||
::CInBuffer _inBuffer;
|
||||
UInt64 _chunkSize;
|
||||
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, UInt32 size);
|
||||
void Skeep(size_t size);
|
||||
UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
UInt64 ReadEncInt();
|
||||
void ReadString(int size, AString &s);
|
||||
void ReadUString(int 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:
|
||||
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
|
||||
77
CPP/7zip/Archive/Chm/DllExports.cpp
Executable file
77
CPP/7zip/Archive/Chm/DllExports.cpp
Executable file
@@ -0,0 +1,77 @@
|
||||
// DLLExports.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/MyInitGuid.h"
|
||||
#include "Common/ComTry.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "ChmHandler.h"
|
||||
#include "../../ICoder.h"
|
||||
|
||||
// {23170F69-40C1-278A-1000-000110E90000}
|
||||
DEFINE_GUID(CLSID_CChmHandler,
|
||||
0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0xE9, 0x00, 0x00);
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(HINSTANCE /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STDAPI CreateObject(
|
||||
const GUID *classID,
|
||||
const GUID *interfaceID,
|
||||
void **outObject)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*outObject = 0;
|
||||
if (*classID != CLSID_CChmHandler)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
if (*interfaceID != IID_IInArchive)
|
||||
return E_NOINTERFACE;
|
||||
CMyComPtr<IInArchive> inArchive = (IInArchive *)new NArchive::NChm::CHandler;
|
||||
*outObject = inArchive.Detach();
|
||||
COM_TRY_END
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
switch(propID)
|
||||
{
|
||||
case NArchive::kName:
|
||||
propVariant = L"Chm";
|
||||
break;
|
||||
case NArchive::kClassID:
|
||||
{
|
||||
if ((value->bstrVal = ::SysAllocStringByteLen(
|
||||
(const char *)&CLSID_CChmHandler, sizeof(GUID))) != 0)
|
||||
value->vt = VT_BSTR;
|
||||
return S_OK;
|
||||
}
|
||||
case NArchive::kExtension:
|
||||
propVariant = L"chm chi chq chw hxs hxi hxr hxq hxw lit";
|
||||
break;
|
||||
case NArchive::kUpdate:
|
||||
propVariant = false;
|
||||
break;
|
||||
case NArchive::kKeepName:
|
||||
propVariant = false;
|
||||
break;
|
||||
case NArchive::kStartSignature:
|
||||
{
|
||||
const char sig[] = { 'I', 'T', 'S', 'F' };
|
||||
if ((value->bstrVal = ::SysAllocStringByteLen(sig, 4)) != 0)
|
||||
value->vt = VT_BSTR;
|
||||
return S_OK;
|
||||
}
|
||||
case NArchive::kAssociate:
|
||||
{
|
||||
propVariant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
3
CPP/7zip/Archive/Chm/StdAfx.cpp
Executable file
3
CPP/7zip/Archive/Chm/StdAfx.cpp
Executable file
@@ -0,0 +1,3 @@
|
||||
// StdAfx.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
8
CPP/7zip/Archive/Chm/StdAfx.h
Executable file
8
CPP/7zip/Archive/Chm/StdAfx.h
Executable file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
|
||||
#endif
|
||||
68
CPP/7zip/Archive/Chm/makefile
Executable file
68
CPP/7zip/Archive/Chm/makefile
Executable file
@@ -0,0 +1,68 @@
|
||||
PROG = chm.dll
|
||||
DEF_FILE = ../Archive.def
|
||||
CFLAGS = $(CFLAGS) -I ../../../
|
||||
LIBS = $(LIBS) oleaut32.lib user32.lib
|
||||
|
||||
CHM_OBJS = \
|
||||
$O\DllExports.obj \
|
||||
$O\ChmHandler.obj \
|
||||
$O\ChmHeader.obj \
|
||||
$O\ChmIn.obj \
|
||||
|
||||
COMMON_OBJS = \
|
||||
$O\Alloc.obj \
|
||||
$O\IntToString.obj \
|
||||
$O\NewHandler.obj \
|
||||
$O\String.obj \
|
||||
$O\StringConvert.obj \
|
||||
$O\UTFConvert.obj \
|
||||
$O\Vector.obj \
|
||||
|
||||
WIN_OBJS = \
|
||||
$O\PropVariant.obj \
|
||||
|
||||
7ZIP_COMMON_OBJS = \
|
||||
$O\InBuffer.obj \
|
||||
$O\LimitedStreams.obj \
|
||||
$O\OutBuffer.obj \
|
||||
$O\ProgressUtils.obj \
|
||||
$O\StreamUtils.obj \
|
||||
|
||||
AR_COMMON_OBJS = \
|
||||
$O\ItemNameUtils.obj \
|
||||
|
||||
COMPRESS_LZX_OBJS = \
|
||||
$O\LzxDecoder.obj \
|
||||
$O\Lzx86Converter.obj \
|
||||
|
||||
OBJS = \
|
||||
$O\StdAfx.obj \
|
||||
$(CHM_OBJS) \
|
||||
$(COMMON_OBJS) \
|
||||
$(WIN_OBJS) \
|
||||
$(7ZIP_COMMON_OBJS) \
|
||||
$(AR_COMMON_OBJS) \
|
||||
$(COMPRESS_LZX_OBJS) \
|
||||
$O\LZOutWindow.obj \
|
||||
$O\CopyCoder.obj \
|
||||
$O\resource.res
|
||||
|
||||
!include "../../../Build.mak"
|
||||
|
||||
$(CHM_OBJS): $(*B).cpp
|
||||
$(COMPL)
|
||||
$(COMMON_OBJS): ../../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(WIN_OBJS): ../../../Windows/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(AR_COMMON_OBJS): ../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(COMPRESS_LZX_OBJS): ../../Compress/Lzx/$(*B).cpp
|
||||
$(COMPL_O2)
|
||||
$O\LZOutWindow.obj: ../../Compress/LZ/$(*B).cpp
|
||||
$(COMPL)
|
||||
$O\CopyCoder.obj: ../../Compress/Copy/$(*B).cpp
|
||||
$(COMPL)
|
||||
|
||||
3
CPP/7zip/Archive/Chm/resource.rc
Executable file
3
CPP/7zip/Archive/Chm/resource.rc
Executable file
@@ -0,0 +1,3 @@
|
||||
#include "../../MyVersionInfo.rc"
|
||||
|
||||
MY_VERSION_INFO_DLL("Chm Plugin", "chm")
|
||||
Reference in New Issue
Block a user