28 changed files with 228 additions and 2316 deletions
@ -1,4 +0,0 @@ |
|||||||
add_library(PKWare STATIC |
|
||||||
explode.cpp |
|
||||||
implode.cpp) |
|
||||||
target_include_directories(PKWare PUBLIC .) |
|
||||||
@ -1,59 +0,0 @@ |
|||||||
VC5_DIR ?= $(HOME)/DevStudio_5.10/VC
|
|
||||||
|
|
||||||
# The $(VS6_DIR) directory is a copy of the "Microsoft Visual Studio" directory.
|
|
||||||
#
|
|
||||||
# To get a working setup on Linux or other "portable" copies of VS,
|
|
||||||
# the following DLLs have to be copied to the
|
|
||||||
# $(VS6_DIR)/VC98/Bin directory.
|
|
||||||
#
|
|
||||||
# - $(VS6_DIR)/Common/MSDev98/Bin/MSPDB60.DLL
|
|
||||||
#
|
|
||||||
# And to the $(VC5_DIR)/bin directory.
|
|
||||||
#
|
|
||||||
# - $(VC5_DIR)/SharedIDE/bin/MSDIS100.DLL
|
|
||||||
# - $(VC5_DIR)/SharedIDE/bin/MSPDB50.DLL
|
|
||||||
VS6_DIR ?= $(HOME)/VS6
|
|
||||||
|
|
||||||
VC6_DIR = $(VS6_DIR)/VC98
|
|
||||||
|
|
||||||
VC6_BIN_DIR = $(VC6_DIR)/Bin
|
|
||||||
VC6_INC_DIR = $(VC6_DIR)/Include
|
|
||||||
VC6_LIB_DIR = $(VC6_DIR)/Lib
|
|
||||||
|
|
||||||
VC5_LIB_DIR = $(VC5_DIR)/lib
|
|
||||||
|
|
||||||
IDE_DIR ?= $(VS6_DIR)/Common/MSDev98
|
|
||||||
IDE_BIN_DIR = $(IDE_DIR)/bin
|
|
||||||
ifeq ($(OS),Windows_NT) |
|
||||||
CL = $(VC6_BIN_DIR)/CL.EXE
|
|
||||||
RC = $(IDE_BIN_DIR)/RC.EXE
|
|
||||||
VC5_LINK = $(VC5_DIR)/bin/link.exe
|
|
||||||
VC6_LINK = $(VC6_BIN_DIR)/link.exe
|
|
||||||
else |
|
||||||
CL = wine $(VC6_BIN_DIR)/CL.EXE
|
|
||||||
RC = wine $(IDE_BIN_DIR)/RC.EXE
|
|
||||||
VC5_LINK = wine $(VC5_DIR)/bin/link.exe
|
|
||||||
VC6_LINK = wine $(VC6_BIN_DIR)/link.exe
|
|
||||||
endif |
|
||||||
|
|
||||||
CFLAGS=/nologo /c /GX /W3 /O1 /I $(VC6_INC_DIR) /FD /MT /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /Gm /Zi
|
|
||||||
LINKFLAGS=/nologo /subsystem:windows /machine:I386 /incremental:no
|
|
||||||
|
|
||||||
VC_LINK=$(VC5_LINK)
|
|
||||||
LINKFLAGS+= /LIBPATH:$(VC5_LIB_DIR)
|
|
||||||
|
|
||||||
all: pkware.lib |
|
||||||
|
|
||||||
PKWARE_SRC=$(sort $(wildcard *.cpp))
|
|
||||||
PKWARE_OBJS=$(PKWARE_SRC:.cpp=.obj)
|
|
||||||
|
|
||||||
pkware.lib: $(PKWARE_OBJS) |
|
||||||
$(VC_LINK) -lib /OUT:$@ $^ /nologo
|
|
||||||
|
|
||||||
%.obj: %.cpp |
|
||||||
$(CL) $(CFLAGS) /Fo$@ $<
|
|
||||||
|
|
||||||
clean: |
|
||||||
@$(RM) -v $(PKWARE_OBJS) pkware.lib vc60.{idb,pch,pdb}
|
|
||||||
|
|
||||||
.PHONY: clean all |
|
||||||
@ -1,100 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
||||||
<ItemGroup Label="ProjectConfigurations"> |
|
||||||
<ProjectConfiguration Include="Debug|Win32"> |
|
||||||
<Configuration>Debug</Configuration> |
|
||||||
<Platform>Win32</Platform> |
|
||||||
</ProjectConfiguration> |
|
||||||
<ProjectConfiguration Include="Release|Win32"> |
|
||||||
<Configuration>Release</Configuration> |
|
||||||
<Platform>Win32</Platform> |
|
||||||
</ProjectConfiguration> |
|
||||||
</ItemGroup> |
|
||||||
<ItemGroup> |
|
||||||
<ClCompile Include="explode.cpp" /> |
|
||||||
<ClCompile Include="implode.cpp" /> |
|
||||||
</ItemGroup> |
|
||||||
<ItemGroup> |
|
||||||
<ClInclude Include="pkware.h" /> |
|
||||||
</ItemGroup> |
|
||||||
<PropertyGroup Label="Globals"> |
|
||||||
<VCProjectVersion>15.0</VCProjectVersion> |
|
||||||
<ProjectGuid>{C7F9F3B4-2F7C-4672-9586-94D8BA0950B6}</ProjectGuid> |
|
||||||
<Keyword>Win32Proj</Keyword> |
|
||||||
<RootNamespace>PKWare</RootNamespace> |
|
||||||
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion> |
|
||||||
</PropertyGroup> |
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType> |
|
||||||
<UseDebugLibraries>true</UseDebugLibraries> |
|
||||||
<PlatformToolset>v141</PlatformToolset> |
|
||||||
<CharacterSet>Unicode</CharacterSet> |
|
||||||
</PropertyGroup> |
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType> |
|
||||||
<UseDebugLibraries>false</UseDebugLibraries> |
|
||||||
<PlatformToolset>v141</PlatformToolset> |
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization> |
|
||||||
<CharacterSet>Unicode</CharacterSet> |
|
||||||
</PropertyGroup> |
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
|
||||||
<ImportGroup Label="ExtensionSettings"> |
|
||||||
</ImportGroup> |
|
||||||
<ImportGroup Label="Shared"> |
|
||||||
</ImportGroup> |
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
|
||||||
</ImportGroup> |
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
|
||||||
</ImportGroup> |
|
||||||
<PropertyGroup Label="UserMacros" /> |
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
|
||||||
<LinkIncremental>true</LinkIncremental> |
|
||||||
<OutDir>.\WinDebug\</OutDir> |
|
||||||
<IntDir>.\WinDebug\</IntDir> |
|
||||||
</PropertyGroup> |
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
|
||||||
<LinkIncremental>false</LinkIncremental> |
|
||||||
<OutDir>.\WinRel</OutDir> |
|
||||||
<IntDir>.\WinRel</IntDir> |
|
||||||
</PropertyGroup> |
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
|
||||||
<ClCompile> |
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
|
||||||
<WarningLevel>Level3</WarningLevel> |
|
||||||
<Optimization>Disabled</Optimization> |
|
||||||
<SDLCheck>true</SDLCheck> |
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
|
||||||
<ConformanceMode>true</ConformanceMode> |
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> |
|
||||||
</ClCompile> |
|
||||||
<Link> |
|
||||||
<SubSystem>Windows</SubSystem> |
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
|
||||||
</Link> |
|
||||||
</ItemDefinitionGroup> |
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
|
||||||
<ClCompile> |
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
|
||||||
<WarningLevel>Level3</WarningLevel> |
|
||||||
<Optimization>MaxSpeed</Optimization> |
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking> |
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions> |
|
||||||
<SDLCheck>true</SDLCheck> |
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
|
||||||
<ConformanceMode>true</ConformanceMode> |
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
|
||||||
</ClCompile> |
|
||||||
<Link> |
|
||||||
<SubSystem>Windows</SubSystem> |
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
|
||||||
<OptimizeReferences>true</OptimizeReferences> |
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
|
||||||
</Link> |
|
||||||
</ItemDefinitionGroup> |
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
|
||||||
<ImportGroup Label="ExtensionTargets"> |
|
||||||
</ImportGroup> |
|
||||||
</Project> |
|
||||||
@ -1,30 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
||||||
<ItemGroup> |
|
||||||
<Filter Include="Source Files"> |
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> |
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> |
|
||||||
</Filter> |
|
||||||
<Filter Include="Header Files"> |
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> |
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions> |
|
||||||
</Filter> |
|
||||||
<Filter Include="Resource Files"> |
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> |
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> |
|
||||||
</Filter> |
|
||||||
</ItemGroup> |
|
||||||
<ItemGroup> |
|
||||||
<ClCompile Include="explode.cpp"> |
|
||||||
<Filter>Source Files</Filter> |
|
||||||
</ClCompile> |
|
||||||
<ClCompile Include="implode.cpp"> |
|
||||||
<Filter>Source Files</Filter> |
|
||||||
</ClCompile> |
|
||||||
</ItemGroup> |
|
||||||
<ItemGroup> |
|
||||||
<ClInclude Include="pkware.h"> |
|
||||||
<Filter>Header Files</Filter> |
|
||||||
</ClInclude> |
|
||||||
</ItemGroup> |
|
||||||
</Project> |
|
||||||
@ -1,100 +0,0 @@ |
|||||||
# Microsoft Developer Studio Project File - Name="Pkware" - Package Owner=<4> |
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00 |
|
||||||
# ** DO NOT EDIT ** |
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104 |
|
||||||
|
|
||||||
CFG=Pkware - 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 "Pkware.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 "Pkware.mak" CFG="Pkware - Win32 Debug" |
|
||||||
!MESSAGE |
|
||||||
!MESSAGE Possible choices for configuration are: |
|
||||||
!MESSAGE |
|
||||||
!MESSAGE "Pkware - Win32 Release" (based on "Win32 (x86) Static Library") |
|
||||||
!MESSAGE "Pkware - Win32 Debug" (based on "Win32 (x86) Static Library") |
|
||||||
!MESSAGE |
|
||||||
|
|
||||||
# Begin Project |
|
||||||
# PROP AllowPerConfigDependencies 0 |
|
||||||
# PROP Scc_ProjName "" |
|
||||||
# PROP Scc_LocalPath "" |
|
||||||
CPP=cl.exe |
|
||||||
RSC=rc.exe |
|
||||||
|
|
||||||
!IF "$(CFG)" == "Pkware - Win32 Release" |
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0 |
|
||||||
# PROP BASE Use_Debug_Libraries 0 |
|
||||||
# PROP BASE Output_Dir "WinRel" |
|
||||||
# PROP BASE Intermediate_Dir "WinRel" |
|
||||||
# PROP BASE Target_Dir "" |
|
||||||
# PROP Use_MFC 0 |
|
||||||
# PROP Use_Debug_Libraries 0 |
|
||||||
# PROP Output_Dir "WinRel" |
|
||||||
# PROP Intermediate_Dir "WinRel" |
|
||||||
# PROP Target_Dir "" |
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c |
|
||||||
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c |
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG" |
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG" |
|
||||||
BSC32=bscmake.exe |
|
||||||
# ADD BASE BSC32 /nologo |
|
||||||
# ADD BSC32 /nologo |
|
||||||
LIB32=link.exe -lib |
|
||||||
# ADD BASE LIB32 /nologo |
|
||||||
# ADD LIB32 /nologo |
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "Pkware - Win32 Debug" |
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0 |
|
||||||
# PROP BASE Use_Debug_Libraries 1 |
|
||||||
# PROP BASE Output_Dir "WinDebug" |
|
||||||
# PROP BASE Intermediate_Dir "WinDebug" |
|
||||||
# PROP BASE Target_Dir "" |
|
||||||
# PROP Use_MFC 0 |
|
||||||
# PROP Use_Debug_Libraries 1 |
|
||||||
# PROP Output_Dir "WinDebug" |
|
||||||
# PROP Intermediate_Dir "WinDebug" |
|
||||||
# PROP Target_Dir "" |
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c |
|
||||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c |
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG" |
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG" |
|
||||||
BSC32=bscmake.exe |
|
||||||
# ADD BASE BSC32 /nologo |
|
||||||
# ADD BSC32 /nologo |
|
||||||
LIB32=link.exe -lib |
|
||||||
# ADD BASE LIB32 /nologo |
|
||||||
# ADD LIB32 /nologo |
|
||||||
|
|
||||||
!ENDIF |
|
||||||
|
|
||||||
# Begin Target |
|
||||||
|
|
||||||
# Name "Pkware - Win32 Release" |
|
||||||
# Name "Pkware - Win32 Debug" |
|
||||||
# Begin Group "Source Files" |
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" |
|
||||||
# Begin Source File |
|
||||||
|
|
||||||
SOURCE=.\explode.cpp |
|
||||||
# End Source File |
|
||||||
# Begin Source File |
|
||||||
|
|
||||||
SOURCE=.\implode.cpp |
|
||||||
# End Source File |
|
||||||
# End Group |
|
||||||
# Begin Group "Header Files" |
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl" |
|
||||||
# End Group |
|
||||||
# End Target |
|
||||||
# End Project |
|
||||||
@ -1,522 +0,0 @@ |
|||||||
/*****************************************************************************/ |
|
||||||
/* explode.cpp Copyright (c) Ladislav Zezula 2003 */ |
|
||||||
/*---------------------------------------------------------------------------*/ |
|
||||||
/* Implode function of PKWARE Data Compression library */ |
|
||||||
/*---------------------------------------------------------------------------*/ |
|
||||||
/* Date Ver Who Comment */ |
|
||||||
/* -------- ---- --- ------- */ |
|
||||||
/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */ |
|
||||||
/* 08.04.03 1.01 Lad Renamed to explode.cpp to be compatible with pkware */ |
|
||||||
/* 02.05.03 1.01 Lad Stress test done */ |
|
||||||
/* 22.04.10 1.01 Lad Documented */ |
|
||||||
/*****************************************************************************/ |
|
||||||
|
|
||||||
#include <assert.h> |
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include "pkware.h" |
|
||||||
|
|
||||||
#define PKDCL_OK 0 |
|
||||||
#define PKDCL_STREAM_END 1 // All data from the input stream is read
|
|
||||||
#define PKDCL_NEED_DICT 2 // Need more data (dictionary)
|
|
||||||
#define PKDCL_CONTINUE 10 // Internal flag, not returned to user
|
|
||||||
#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user
|
|
||||||
|
|
||||||
static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" |
|
||||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" |
|
||||||
"Patent No. 5,051,745\r\n" |
|
||||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" |
|
||||||
"Version 1.11\r\n"; |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Tables
|
|
||||||
|
|
||||||
static unsigned char DistBits[] =
|
|
||||||
{ |
|
||||||
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
|
||||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
|
||||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
|
||||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char DistCode[] =
|
|
||||||
{ |
|
||||||
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, |
|
||||||
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, |
|
||||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, |
|
||||||
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char ExLenBits[] = |
|
||||||
{ |
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned short LenBase[] = |
|
||||||
{ |
|
||||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, |
|
||||||
0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char LenBits[] = |
|
||||||
{ |
|
||||||
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char LenCode[] = |
|
||||||
{ |
|
||||||
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char ChBitsAsc[] = |
|
||||||
{ |
|
||||||
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, |
|
||||||
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, |
|
||||||
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, |
|
||||||
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, |
|
||||||
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, |
|
||||||
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, |
|
||||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, |
|
||||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, |
|
||||||
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned short ChCodeAsc[] =
|
|
||||||
{ |
|
||||||
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, |
|
||||||
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, |
|
||||||
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, |
|
||||||
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, |
|
||||||
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, |
|
||||||
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, |
|
||||||
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, |
|
||||||
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, |
|
||||||
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, |
|
||||||
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, |
|
||||||
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, |
|
||||||
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, |
|
||||||
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, |
|
||||||
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, |
|
||||||
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, |
|
||||||
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, |
|
||||||
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, |
|
||||||
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, |
|
||||||
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, |
|
||||||
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, |
|
||||||
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, |
|
||||||
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, |
|
||||||
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, |
|
||||||
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, |
|
||||||
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, |
|
||||||
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, |
|
||||||
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, |
|
||||||
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, |
|
||||||
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, |
|
||||||
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, |
|
||||||
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, |
|
||||||
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
|
|
||||||
}; |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Local functions
|
|
||||||
|
|
||||||
static void PKWAREAPI GenDecodeTabs( |
|
||||||
unsigned char * positions, // [out] Table of positions
|
|
||||||
unsigned char * start_indexes, // [in] Table of start indexes
|
|
||||||
unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits
|
|
||||||
size_t elements) // [in] Number of elements in start_indexes and length_bits
|
|
||||||
{ |
|
||||||
unsigned int index; |
|
||||||
unsigned int length; |
|
||||||
size_t i; |
|
||||||
|
|
||||||
for(i = 0; i < elements; i++) |
|
||||||
{ |
|
||||||
length = 1 << length_bits[i]; // Get the length in bytes
|
|
||||||
|
|
||||||
for(index = start_indexes[i]; index < 0x100; index += length) |
|
||||||
{ |
|
||||||
positions[index] = (unsigned char)i; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void PKWAREAPI GenAscTabs(TDcmpStruct * pWork) |
|
||||||
{ |
|
||||||
unsigned short * pChCodeAsc = &ChCodeAsc[0xFF]; |
|
||||||
unsigned int acc, add; |
|
||||||
unsigned short count; |
|
||||||
|
|
||||||
for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--) |
|
||||||
{ |
|
||||||
unsigned char * pChBitsAsc = pWork->ChBitsAsc + count; |
|
||||||
unsigned char bits_asc = *pChBitsAsc; |
|
||||||
|
|
||||||
if(bits_asc <= 8) |
|
||||||
{ |
|
||||||
add = (1 << bits_asc); |
|
||||||
acc = *pChCodeAsc; |
|
||||||
|
|
||||||
do |
|
||||||
{ |
|
||||||
pWork->offs2C34[acc] = (unsigned char)count; |
|
||||||
acc += add; |
|
||||||
} |
|
||||||
while(acc < 0x100); |
|
||||||
} |
|
||||||
else if((acc = (*pChCodeAsc & 0xFF)) != 0) |
|
||||||
{ |
|
||||||
pWork->offs2C34[acc] = 0xFF; |
|
||||||
|
|
||||||
if(*pChCodeAsc & 0x3F) |
|
||||||
{ |
|
||||||
bits_asc -= 4; |
|
||||||
*pChBitsAsc = bits_asc; |
|
||||||
|
|
||||||
add = (1 << bits_asc); |
|
||||||
acc = *pChCodeAsc >> 4; |
|
||||||
do |
|
||||||
{ |
|
||||||
pWork->offs2D34[acc] = (unsigned char)count; |
|
||||||
acc += add; |
|
||||||
} |
|
||||||
while(acc < 0x100); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
bits_asc -= 6; |
|
||||||
*pChBitsAsc = bits_asc; |
|
||||||
|
|
||||||
add = (1 << bits_asc); |
|
||||||
acc = *pChCodeAsc >> 6; |
|
||||||
do |
|
||||||
{ |
|
||||||
pWork->offs2E34[acc] = (unsigned char)count; |
|
||||||
acc += add; |
|
||||||
} |
|
||||||
while(acc < 0x80); |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
bits_asc -= 8; |
|
||||||
*pChBitsAsc = bits_asc; |
|
||||||
|
|
||||||
add = (1 << bits_asc); |
|
||||||
acc = *pChCodeAsc >> 8; |
|
||||||
do |
|
||||||
{ |
|
||||||
pWork->offs2EB4[acc] = (unsigned char)count; |
|
||||||
acc += add; |
|
||||||
} |
|
||||||
while(acc < 0x100); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Removes given number of bits in the bit buffer. New bits are reloaded from
|
|
||||||
// the input buffer, if needed.
|
|
||||||
// Returns: PKDCL_OK: Operation was successful
|
|
||||||
// PKDCL_STREAM_END: There are no more bits in the input buffer
|
|
||||||
|
|
||||||
static int PKWAREAPI WasteBits(TDcmpStruct * pWork, unsigned int nBits) |
|
||||||
{ |
|
||||||
// If number of bits required is less than number of (bits in the buffer) ?
|
|
||||||
if(nBits <= pWork->extra_bits) |
|
||||||
{ |
|
||||||
pWork->extra_bits -= nBits; |
|
||||||
pWork->bit_buff >>= nBits; |
|
||||||
return PKDCL_OK; |
|
||||||
} |
|
||||||
|
|
||||||
// Load input buffer if necessary
|
|
||||||
pWork->bit_buff >>= pWork->extra_bits; |
|
||||||
if(pWork->in_pos == pWork->in_bytes) |
|
||||||
{ |
|
||||||
pWork->in_pos = sizeof(pWork->in_buff); |
|
||||||
if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0) |
|
||||||
return PKDCL_STREAM_END; |
|
||||||
pWork->in_pos = 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Update bit buffer
|
|
||||||
pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8); |
|
||||||
pWork->bit_buff >>= (nBits - pWork->extra_bits); |
|
||||||
pWork->extra_bits = (pWork->extra_bits - nBits) + 8; |
|
||||||
return PKDCL_OK; |
|
||||||
} |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Decodes next literal from the input (compressed) data.
|
|
||||||
// Returns : 0x000: One byte 0x00
|
|
||||||
// 0x001: One byte 0x01
|
|
||||||
// ...
|
|
||||||
// 0x0FF: One byte 0xFF
|
|
||||||
// 0x100: Repetition, length of 0x02 bytes
|
|
||||||
// 0x101: Repetition, length of 0x03 bytes
|
|
||||||
// ...
|
|
||||||
// 0x304: Repetition, length of 0x206 bytes
|
|
||||||
// 0x305: End of stream
|
|
||||||
// 0x306: Error
|
|
||||||
|
|
||||||
static unsigned int PKWAREAPI DecodeLit(TDcmpStruct * pWork) |
|
||||||
{ |
|
||||||
unsigned int extra_length_bits; // Number of bits of extra literal length
|
|
||||||
unsigned int length_code; // Length code
|
|
||||||
unsigned int value; |
|
||||||
|
|
||||||
// Test the current bit in byte buffer. If is not set, simply return the next 8 bits.
|
|
||||||
if(pWork->bit_buff & 1) |
|
||||||
{ |
|
||||||
// Remove one bit from the input data
|
|
||||||
if(WasteBits(pWork, 1)) |
|
||||||
return 0x306;
|
|
||||||
|
|
||||||
// The next 8 bits hold the index to the length code table
|
|
||||||
length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF]; |
|
||||||
|
|
||||||
// Remove the apropriate number of bits
|
|
||||||
if(WasteBits(pWork, pWork->LenBits[length_code])) |
|
||||||
return 0x306; |
|
||||||
|
|
||||||
// Are there some extra bits for the obtained length code ?
|
|
||||||
if((extra_length_bits = pWork->ExLenBits[length_code]) != 0) |
|
||||||
{ |
|
||||||
unsigned int extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1); |
|
||||||
|
|
||||||
if(WasteBits(pWork, extra_length_bits)) |
|
||||||
{ |
|
||||||
if((length_code + extra_length) != 0x10E) |
|
||||||
return 0x306; |
|
||||||
} |
|
||||||
length_code = pWork->LenBase[length_code] + extra_length; |
|
||||||
} |
|
||||||
|
|
||||||
// In order to distinguish uncompressed byte from repetition length,
|
|
||||||
// we have to add 0x100 to the length.
|
|
||||||
return length_code + 0x100; |
|
||||||
} |
|
||||||
|
|
||||||
// Remove one bit from the input data
|
|
||||||
if(WasteBits(pWork, 1)) |
|
||||||
return 0x306; |
|
||||||
|
|
||||||
// If the binary compression type, read 8 bits and return them as one byte.
|
|
||||||
if(pWork->ctype == CMP_BINARY) |
|
||||||
{ |
|
||||||
unsigned int uncompressed_byte = pWork->bit_buff & 0xFF; |
|
||||||
|
|
||||||
if(WasteBits(pWork, 8)) |
|
||||||
return 0x306; |
|
||||||
return uncompressed_byte; |
|
||||||
} |
|
||||||
|
|
||||||
// When ASCII compression ...
|
|
||||||
if(pWork->bit_buff & 0xFF) |
|
||||||
{ |
|
||||||
value = pWork->offs2C34[pWork->bit_buff & 0xFF]; |
|
||||||
|
|
||||||
if(value == 0xFF) |
|
||||||
{ |
|
||||||
if(pWork->bit_buff & 0x3F) |
|
||||||
{ |
|
||||||
if(WasteBits(pWork, 4)) |
|
||||||
return 0x306; |
|
||||||
|
|
||||||
value = pWork->offs2D34[pWork->bit_buff & 0xFF]; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
if(WasteBits(pWork, 6)) |
|
||||||
return 0x306; |
|
||||||
|
|
||||||
value = pWork->offs2E34[pWork->bit_buff & 0x7F]; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
if(WasteBits(pWork, 8)) |
|
||||||
return 0x306; |
|
||||||
|
|
||||||
value = pWork->offs2EB4[pWork->bit_buff & 0xFF]; |
|
||||||
} |
|
||||||
|
|
||||||
return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value; |
|
||||||
} |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Decodes the distance of the repetition, backwards relative to the
|
|
||||||
// current output buffer position
|
|
||||||
|
|
||||||
static unsigned int PKWAREAPI DecodeDist(TDcmpStruct * pWork, unsigned int rep_length) |
|
||||||
{ |
|
||||||
unsigned int dist_pos_code; // Distance position code
|
|
||||||
unsigned int dist_pos_bits; // Number of bits of distance position
|
|
||||||
unsigned int distance; // Distance position
|
|
||||||
|
|
||||||
// Next 2-8 bits in the input buffer is the distance position code
|
|
||||||
dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF]; |
|
||||||
dist_pos_bits = pWork->DistBits[dist_pos_code]; |
|
||||||
if(WasteBits(pWork, dist_pos_bits)) |
|
||||||
return 0; |
|
||||||
|
|
||||||
if(rep_length == 2) |
|
||||||
{ |
|
||||||
// If the repetition is only 2 bytes length,
|
|
||||||
// then take 2 bits from the stream in order to get the distance
|
|
||||||
distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03); |
|
||||||
if(WasteBits(pWork, 2)) |
|
||||||
return 0; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
// If the repetition is more than 2 bytes length,
|
|
||||||
// then take "dsize_bits" bits in order to get the distance
|
|
||||||
distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask); |
|
||||||
if(WasteBits(pWork, pWork->dsize_bits)) |
|
||||||
return 0; |
|
||||||
} |
|
||||||
return distance + 1; |
|
||||||
} |
|
||||||
|
|
||||||
static unsigned int PKWAREAPI Expand(TDcmpStruct * pWork) |
|
||||||
{ |
|
||||||
unsigned int next_literal; // Literal decoded from the compressed data
|
|
||||||
unsigned int result; // Value to be returned
|
|
||||||
unsigned int copyBytes; // Number of bytes to copy to the output buffer
|
|
||||||
|
|
||||||
pWork->outputPos = 0x1000; // Initialize output buffer position
|
|
||||||
|
|
||||||
// Decode the next literal from the input data.
|
|
||||||
// The returned literal can either be an uncompressed byte (next_literal < 0x100)
|
|
||||||
// or an encoded length of the repeating byte sequence that
|
|
||||||
// is to be copied to the current buffer position
|
|
||||||
while((result = next_literal = DecodeLit(pWork)) < 0x305) |
|
||||||
{ |
|
||||||
// If the literal is greater than 0x100, it holds length
|
|
||||||
// of repeating byte sequence
|
|
||||||
// literal of 0x100 means repeating sequence of 0x2 bytes
|
|
||||||
// literal of 0x101 means repeating sequence of 0x3 bytes
|
|
||||||
// ...
|
|
||||||
// literal of 0x305 means repeating sequence of 0x207 bytes
|
|
||||||
if(next_literal >= 0x100) |
|
||||||
{ |
|
||||||
unsigned char * source; |
|
||||||
unsigned char * target; |
|
||||||
unsigned int rep_length; // Length of the repetition, in bytes
|
|
||||||
unsigned int minus_dist; // Backward distance to the repetition, relative to the current buffer position
|
|
||||||
|
|
||||||
// Get the length of the repeating sequence.
|
|
||||||
// Note that the repeating block may overlap the current output position,
|
|
||||||
// for example if there was a sequence of equal bytes
|
|
||||||
rep_length = next_literal - 0xFE; |
|
||||||
|
|
||||||
// Get backward distance to the repetition
|
|
||||||
if((minus_dist = DecodeDist(pWork, rep_length)) == 0) |
|
||||||
{ |
|
||||||
result = 0x306; |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
// Target and source pointer
|
|
||||||
target = &pWork->out_buff[pWork->outputPos]; |
|
||||||
source = target - minus_dist; |
|
||||||
|
|
||||||
// Update buffer output position
|
|
||||||
pWork->outputPos += rep_length; |
|
||||||
|
|
||||||
// Copy the repeating sequence
|
|
||||||
while(rep_length-- > 0) |
|
||||||
*target++ = *source++; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal; |
|
||||||
} |
|
||||||
|
|
||||||
// Flush the output buffer, if number of extracted bytes has reached the end
|
|
||||||
if(pWork->outputPos >= 0x2000) |
|
||||||
{ |
|
||||||
// Copy decompressed data into user buffer
|
|
||||||
copyBytes = 0x1000; |
|
||||||
pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); |
|
||||||
|
|
||||||
// Now copy the decompressed data to the first half of the buffer.
|
|
||||||
// This is needed because the decompression might reuse them as repetitions.
|
|
||||||
// Note that if the output buffer overflowed previously, the extra decompressed bytes
|
|
||||||
// are stored in "out_buff_overflow", and they will now be
|
|
||||||
// within decompressed part of the output buffer.
|
|
||||||
memmove(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000); |
|
||||||
pWork->outputPos -= 0x1000; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Flush any remaining decompressed bytes
|
|
||||||
copyBytes = pWork->outputPos - 0x1000; |
|
||||||
pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Main exploding function.
|
|
||||||
|
|
||||||
unsigned int PKWAREAPI explode( |
|
||||||
unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
char *work_buf, |
|
||||||
void *param) |
|
||||||
{ |
|
||||||
TDcmpStruct * pWork = (TDcmpStruct *)work_buf; |
|
||||||
|
|
||||||
// Initialize work struct and load compressed data
|
|
||||||
// Note: The caller must zero the "work_buff" before passing it to explode
|
|
||||||
pWork->read_buf = read_buf; |
|
||||||
pWork->write_buf = write_buf; |
|
||||||
pWork->param = param; |
|
||||||
pWork->in_pos = sizeof(pWork->in_buff); |
|
||||||
pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param); |
|
||||||
if(pWork->in_bytes <= 4) |
|
||||||
return CMP_BAD_DATA; |
|
||||||
|
|
||||||
pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII)
|
|
||||||
pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size
|
|
||||||
pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer
|
|
||||||
pWork->extra_bits = 0; // Extra (over 8) bits
|
|
||||||
pWork->in_pos = 3; // Position in input buffer
|
|
||||||
|
|
||||||
// Test for the valid dictionary size
|
|
||||||
if(4 > pWork->dsize_bits || pWork->dsize_bits > 6)
|
|
||||||
return CMP_INVALID_DICTSIZE; |
|
||||||
|
|
||||||
pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction
|
|
||||||
|
|
||||||
if(pWork->ctype != CMP_BINARY) |
|
||||||
{ |
|
||||||
if(pWork->ctype != CMP_ASCII) |
|
||||||
return CMP_INVALID_MODE; |
|
||||||
|
|
||||||
memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc)); |
|
||||||
GenAscTabs(pWork); |
|
||||||
} |
|
||||||
|
|
||||||
memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits)); |
|
||||||
GenDecodeTabs(pWork->LengthCodes, LenCode, pWork->LenBits, sizeof(pWork->LenBits)); |
|
||||||
memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits)); |
|
||||||
memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase)); |
|
||||||
memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits)); |
|
||||||
GenDecodeTabs(pWork->DistPosCodes, DistCode, pWork->DistBits, sizeof(pWork->DistBits)); |
|
||||||
if(Expand(pWork) != 0x306) |
|
||||||
return CMP_NO_ERROR; |
|
||||||
|
|
||||||
return CMP_ABORT; |
|
||||||
} |
|
||||||
@ -1,775 +0,0 @@ |
|||||||
/*****************************************************************************/ |
|
||||||
/* implode.cpp Copyright (c) Ladislav Zezula 2003 */ |
|
||||||
/*---------------------------------------------------------------------------*/ |
|
||||||
/* Implode function of PKWARE Data Compression library */ |
|
||||||
/*---------------------------------------------------------------------------*/ |
|
||||||
/* Date Ver Who Comment */ |
|
||||||
/* -------- ---- --- ------- */ |
|
||||||
/* 11.04.03 1.00 Lad First version of implode.cpp */ |
|
||||||
/* 02.05.03 1.00 Lad Stress test done */ |
|
||||||
/* 22.04.10 1.01 Lad Documented */ |
|
||||||
/*****************************************************************************/ |
|
||||||
|
|
||||||
#include <assert.h> |
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include "pkware.h" |
|
||||||
|
|
||||||
#if ((1200 < _MSC_VER) && (_MSC_VER < 1400)) |
|
||||||
#pragma optimize("", off) |
|
||||||
#endif |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Defines
|
|
||||||
|
|
||||||
#define MAX_REP_LENGTH 0x204 // The longest allowed repetition
|
|
||||||
|
|
||||||
static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" |
|
||||||
"Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" |
|
||||||
"Patent No. 5,051,745\r\n" |
|
||||||
"PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" |
|
||||||
"Version 1.11\r\n"; |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Tables
|
|
||||||
|
|
||||||
static unsigned char DistBits[] =
|
|
||||||
{ |
|
||||||
0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
|
||||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
|
||||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, |
|
||||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char DistCode[] =
|
|
||||||
{ |
|
||||||
0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, |
|
||||||
0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, |
|
||||||
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, |
|
||||||
0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char ExLenBits[] = |
|
||||||
{ |
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char LenBits[] = |
|
||||||
{ |
|
||||||
0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char LenCode[] = |
|
||||||
{ |
|
||||||
0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned char ChBitsAsc[] = |
|
||||||
{ |
|
||||||
0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, |
|
||||||
0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, |
|
||||||
0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, |
|
||||||
0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, |
|
||||||
0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, |
|
||||||
0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, |
|
||||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, |
|
||||||
0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, |
|
||||||
0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, |
|
||||||
0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D |
|
||||||
}; |
|
||||||
|
|
||||||
static unsigned short ChCodeAsc[] =
|
|
||||||
{ |
|
||||||
0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, |
|
||||||
0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, |
|
||||||
0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, |
|
||||||
0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, |
|
||||||
0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, |
|
||||||
0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, |
|
||||||
0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, |
|
||||||
0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, |
|
||||||
0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, |
|
||||||
0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, |
|
||||||
0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, |
|
||||||
0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, |
|
||||||
0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, |
|
||||||
0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, |
|
||||||
0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, |
|
||||||
0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, |
|
||||||
0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, |
|
||||||
0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, |
|
||||||
0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, |
|
||||||
0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, |
|
||||||
0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, |
|
||||||
0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, |
|
||||||
0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, |
|
||||||
0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, |
|
||||||
0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, |
|
||||||
0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, |
|
||||||
0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, |
|
||||||
0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, |
|
||||||
0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, |
|
||||||
0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, |
|
||||||
0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, |
|
||||||
0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000
|
|
||||||
}; |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Macros
|
|
||||||
|
|
||||||
// Macro for calculating hash of the current byte pair.
|
|
||||||
// Note that most exact byte pair hash would be buffer[0] + buffer[1] << 0x08,
|
|
||||||
// but even this way gives nice indication of equal byte pairs, with significantly
|
|
||||||
// smaller size of the array that holds numbers of those hashes
|
|
||||||
#define BYTE_PAIR_HASH(buffer) ((buffer[0] * 4) + (buffer[1] * 5)) |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Local functions
|
|
||||||
|
|
||||||
// Builds the "hash_to_index" table and "pair_hash_offsets" table.
|
|
||||||
// Every element of "hash_to_index" will contain lowest index to the
|
|
||||||
// "pair_hash_offsets" table, effectively giving offset of the first
|
|
||||||
// occurence of the given PAIR_HASH in the input data.
|
|
||||||
static void PKWAREAPI SortBuffer(TCmpStruct * pWork, unsigned char * buffer_begin, unsigned char * buffer_end) |
|
||||||
{ |
|
||||||
unsigned short * phash_to_index; |
|
||||||
unsigned char * buffer_ptr; |
|
||||||
unsigned short total_sum = 0; |
|
||||||
unsigned long byte_pair_hash; // Hash value of the byte pair
|
|
||||||
unsigned short byte_pair_offs; // Offset of the byte pair, relative to "work_buff"
|
|
||||||
|
|
||||||
// Zero the entire "phash_to_index" table
|
|
||||||
memset(pWork->phash_to_index, 0, sizeof(pWork->phash_to_index)); |
|
||||||
|
|
||||||
// Step 1: Count amount of each PAIR_HASH in the input buffer
|
|
||||||
// The table will look like this:
|
|
||||||
// offs 0x000: Number of occurences of PAIR_HASH 0
|
|
||||||
// offs 0x001: Number of occurences of PAIR_HASH 1
|
|
||||||
// ...
|
|
||||||
// offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 (the highest hash value)
|
|
||||||
for(buffer_ptr = buffer_begin; buffer_ptr < buffer_end; buffer_ptr++) |
|
||||||
pWork->phash_to_index[BYTE_PAIR_HASH(buffer_ptr)]++; |
|
||||||
|
|
||||||
// Step 2: Convert the table to the array of PAIR_HASH amounts.
|
|
||||||
// Each element contains count of PAIR_HASHes that is less or equal
|
|
||||||
// to element index
|
|
||||||
// The table will look like this:
|
|
||||||
// offs 0x000: Number of occurences of PAIR_HASH 0 or lower
|
|
||||||
// offs 0x001: Number of occurences of PAIR_HASH 1 or lower
|
|
||||||
// ...
|
|
||||||
// offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 or lower
|
|
||||||
for(phash_to_index = pWork->phash_to_index; phash_to_index < &pWork->phash_to_index_end; phash_to_index++) |
|
||||||
{ |
|
||||||
total_sum = total_sum + phash_to_index[0]; |
|
||||||
phash_to_index[0] = total_sum; |
|
||||||
} |
|
||||||
|
|
||||||
// Step 3: Convert the table to the array of indexes.
|
|
||||||
// Now, each element contains index to the first occurence of given PAIR_HASH
|
|
||||||
for(buffer_end--; buffer_end >= buffer_begin; buffer_end--) |
|
||||||
{ |
|
||||||
byte_pair_hash = BYTE_PAIR_HASH(buffer_end); |
|
||||||
byte_pair_offs = (unsigned short)(buffer_end - pWork->work_buff); |
|
||||||
|
|
||||||
pWork->phash_to_index[byte_pair_hash]--; |
|
||||||
pWork->phash_offs[pWork->phash_to_index[byte_pair_hash]] = byte_pair_offs; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void PKWAREAPI FlushBuf(TCmpStruct * pWork) |
|
||||||
{ |
|
||||||
unsigned char save_ch1; |
|
||||||
unsigned char save_ch2; |
|
||||||
unsigned int size = 0x800; |
|
||||||
|
|
||||||
pWork->write_buf(pWork->out_buff, &size, pWork->param); |
|
||||||
|
|
||||||
save_ch1 = pWork->out_buff[0x800]; |
|
||||||
save_ch2 = pWork->out_buff[pWork->out_bytes]; |
|
||||||
pWork->out_bytes -= 0x800; |
|
||||||
|
|
||||||
memset(pWork->out_buff, 0, sizeof(pWork->out_buff)); |
|
||||||
|
|
||||||
if(pWork->out_bytes != 0) |
|
||||||
pWork->out_buff[0] = save_ch1; |
|
||||||
if(pWork->out_bits != 0) |
|
||||||
pWork->out_buff[pWork->out_bytes] = save_ch2; |
|
||||||
} |
|
||||||
|
|
||||||
static void PKWAREAPI OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff) |
|
||||||
{ |
|
||||||
unsigned int out_bits; |
|
||||||
|
|
||||||
// If more than 8 bits to output, do recursion
|
|
||||||
if(nbits > 8) |
|
||||||
{ |
|
||||||
OutputBits(pWork, 8, bit_buff); |
|
||||||
bit_buff >>= 8; |
|
||||||
nbits -= 8; |
|
||||||
} |
|
||||||
|
|
||||||
// Add bits to the last out byte in out_buff;
|
|
||||||
out_bits = pWork->out_bits; |
|
||||||
pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits); |
|
||||||
pWork->out_bits += nbits; |
|
||||||
|
|
||||||
// If 8 or more bits, increment number of bytes
|
|
||||||
if(pWork->out_bits > 8) |
|
||||||
{ |
|
||||||
pWork->out_bytes++; |
|
||||||
bit_buff >>= (8 - out_bits); |
|
||||||
|
|
||||||
pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff; |
|
||||||
pWork->out_bits &= 7; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
pWork->out_bits &= 7; |
|
||||||
if(pWork->out_bits == 0) |
|
||||||
pWork->out_bytes++; |
|
||||||
} |
|
||||||
|
|
||||||
// If there is enough compressed bytes, flush them
|
|
||||||
if(pWork->out_bytes >= 0x800) |
|
||||||
FlushBuf(pWork); |
|
||||||
} |
|
||||||
|
|
||||||
// This function searches for a repetition
|
|
||||||
// (a previous occurence of the current byte sequence)
|
|
||||||
// Returns length of the repetition, and stores the backward distance
|
|
||||||
// to pWork structure.
|
|
||||||
static unsigned int PKWAREAPI FindRep(TCmpStruct * pWork, unsigned char * input_data) |
|
||||||
{ |
|
||||||
unsigned short * phash_to_index; // Pointer into pWork->phash_to_index table
|
|
||||||
unsigned short * phash_offs; // Pointer to the table containing offsets of each PAIR_HASH
|
|
||||||
unsigned char * repetition_limit; // An eventual repetition must be at position below this pointer
|
|
||||||
unsigned char * prev_repetition; // Pointer to the previous occurence of the current PAIR_HASH
|
|
||||||
unsigned char * prev_rep_end; // End of the previous repetition
|
|
||||||
unsigned char * input_data_ptr; |
|
||||||
unsigned short phash_offs_index; // Index to the table with PAIR_HASH positions
|
|
||||||
unsigned short min_phash_offs; // The lowest allowed hash offset
|
|
||||||
unsigned short offs_in_rep; // Offset within found repetition
|
|
||||||
unsigned int equal_byte_count; // Number of bytes that are equal to the previous occurence
|
|
||||||
unsigned int rep_length = 1; // Length of the found repetition
|
|
||||||
unsigned int rep_length2; // Secondary repetition
|
|
||||||
unsigned char pre_last_byte; // Last but one byte from a repetion
|
|
||||||
unsigned short di_val; |
|
||||||
|
|
||||||
// Calculate the previous position of the PAIR_HASH
|
|
||||||
phash_to_index = pWork->phash_to_index + BYTE_PAIR_HASH(input_data); |
|
||||||
min_phash_offs = (unsigned short)((input_data - pWork->work_buff) - pWork->dsize_bytes + 1); |
|
||||||
phash_offs_index = phash_to_index[0]; |
|
||||||
|
|
||||||
// If the PAIR_HASH offset is below the limit, find a next one
|
|
||||||
phash_offs = pWork->phash_offs + phash_offs_index; |
|
||||||
if(*phash_offs < min_phash_offs) |
|
||||||
{ |
|
||||||
while(*phash_offs < min_phash_offs) |
|
||||||
{ |
|
||||||
phash_offs_index++; |
|
||||||
phash_offs++; |
|
||||||
} |
|
||||||
*phash_to_index = phash_offs_index; |
|
||||||
} |
|
||||||
|
|
||||||
// Get the first location of the PAIR_HASH,
|
|
||||||
// and thus the first eventual location of byte repetition
|
|
||||||
phash_offs = pWork->phash_offs + phash_offs_index; |
|
||||||
prev_repetition = pWork->work_buff + phash_offs[0]; |
|
||||||
repetition_limit = input_data - 1; |
|
||||||
|
|
||||||
// If the current PAIR_HASH was not encountered before,
|
|
||||||
// we haven't found a repetition.
|
|
||||||
if(prev_repetition >= repetition_limit) |
|
||||||
return 0; |
|
||||||
|
|
||||||
// We have found a match of a PAIR_HASH. Now we have to make sure
|
|
||||||
// that it is also a byte match, because PAIR_HASH is not unique.
|
|
||||||
// We compare the bytes and count the length of the repetition
|
|
||||||
input_data_ptr = input_data; |
|
||||||
for(;;) |
|
||||||
{ |
|
||||||
// If the first byte of the repetition and the so-far-last byte
|
|
||||||
// of the repetition are equal, we will compare the blocks.
|
|
||||||
if(*input_data_ptr == *prev_repetition && input_data_ptr[rep_length-1] == prev_repetition[rep_length-1]) |
|
||||||
{ |
|
||||||
// Skip the current byte
|
|
||||||
prev_repetition++; |
|
||||||
input_data_ptr++; |
|
||||||
equal_byte_count = 2; |
|
||||||
|
|
||||||
// Now count how many more bytes are equal
|
|
||||||
while(equal_byte_count < MAX_REP_LENGTH) |
|
||||||
{ |
|
||||||
prev_repetition++; |
|
||||||
input_data_ptr++; |
|
||||||
|
|
||||||
// Are the bytes different ?
|
|
||||||
if(*prev_repetition != *input_data_ptr) |
|
||||||
break; |
|
||||||
|
|
||||||
equal_byte_count++; |
|
||||||
} |
|
||||||
|
|
||||||
// If we found a repetition of at least the same length, take it.
|
|
||||||
// If there are multiple repetitions in the input buffer, this will
|
|
||||||
// make sure that we find the most recent one, which in turn allows
|
|
||||||
// us to store backward length in less amount of bits
|
|
||||||
input_data_ptr = input_data; |
|
||||||
if(equal_byte_count >= rep_length) |
|
||||||
{ |
|
||||||
// Calculate the backward distance of the repetition.
|
|
||||||
// Note that the distance is stored as decremented by 1
|
|
||||||
pWork->distance = (unsigned int)(input_data - prev_repetition + equal_byte_count - 1); |
|
||||||
|
|
||||||
// Repetitions longer than 10 bytes will be stored in more bits,
|
|
||||||
// so they need a bit different handling
|
|
||||||
if((rep_length = equal_byte_count) > 10) |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Move forward in the table of PAIR_HASH repetitions.
|
|
||||||
// There might be a more recent occurence of the same repetition.
|
|
||||||
phash_offs_index++; |
|
||||||
phash_offs++; |
|
||||||
prev_repetition = pWork->work_buff + phash_offs[0]; |
|
||||||
|
|
||||||
// If the next repetition is beyond the minimum allowed repetition, we are done.
|
|
||||||
if(prev_repetition >= repetition_limit) |
|
||||||
{ |
|
||||||
// A repetition must have at least 2 bytes, otherwise it's not worth it
|
|
||||||
return (rep_length >= 2) ? rep_length : 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// If the repetition has max length of 0x204 bytes, we can't go any fuhrter
|
|
||||||
if(equal_byte_count == MAX_REP_LENGTH) |
|
||||||
{ |
|
||||||
pWork->distance--; |
|
||||||
return equal_byte_count; |
|
||||||
} |
|
||||||
|
|
||||||
// Check for possibility of a repetition that occurs at more recent position
|
|
||||||
phash_offs = pWork->phash_offs + phash_offs_index; |
|
||||||
if(pWork->work_buff + phash_offs[1] >= repetition_limit) |
|
||||||
return rep_length; |
|
||||||
|
|
||||||
//
|
|
||||||
// The following part checks if there isn't a longer repetition at
|
|
||||||
// a latter offset, that would lead to better compression.
|
|
||||||
//
|
|
||||||
// Example of data that can trigger this optimization:
|
|
||||||
//
|
|
||||||
// "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEQQQQQQQQQQQQ"
|
|
||||||
// "XYZ"
|
|
||||||
// "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ";
|
|
||||||
//
|
|
||||||
// Description of data in this buffer
|
|
||||||
// [0x00] Single byte "E"
|
|
||||||
// [0x01] Single byte "E"
|
|
||||||
// [0x02] Repeat 0x1E bytes from [0x00]
|
|
||||||
// [0x20] Single byte "X"
|
|
||||||
// [0x21] Single byte "Y"
|
|
||||||
// [0x22] Single byte "Z"
|
|
||||||
// [0x23] 17 possible previous repetitions of length at least 0x10 bytes:
|
|
||||||
// - Repetition of 0x10 bytes from [0x00] "EEEEEEEEEEEEEEEE"
|
|
||||||
// - Repetition of 0x10 bytes from [0x01] "EEEEEEEEEEEEEEEE"
|
|
||||||
// - Repetition of 0x10 bytes from [0x02] "EEEEEEEEEEEEEEEE"
|
|
||||||
// ...
|
|
||||||
// - Repetition of 0x10 bytes from [0x0F] "EEEEEEEEEEEEEEEE"
|
|
||||||
// - Repetition of 0x1C bytes from [0x10] "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ"
|
|
||||||
// The last repetition is the best one.
|
|
||||||
//
|
|
||||||
|
|
||||||
pWork->offs09BC[0] = 0xFFFF; |
|
||||||
pWork->offs09BC[1] = 0x0000; |
|
||||||
di_val = 0; |
|
||||||
|
|
||||||
// Note: I failed to figure out what does the table "offs09BC" mean.
|
|
||||||
// If anyone has an idea, let me know to zezula_at_volny_dot_cz
|
|
||||||
for(offs_in_rep = 1; offs_in_rep < rep_length; ) |
|
||||||
{ |
|
||||||
if(input_data[offs_in_rep] != input_data[di_val]) |
|
||||||
{ |
|
||||||
di_val = pWork->offs09BC[di_val]; |
|
||||||
if(di_val != 0xFFFF) |
|
||||||
continue; |
|
||||||
} |
|
||||||
pWork->offs09BC[++offs_in_rep] = ++di_val; |
|
||||||
} |
|
||||||
|
|
||||||
//
|
|
||||||
// Now go through all the repetitions from the first found one
|
|
||||||
// to the current input data, and check if any of them migh be
|
|
||||||
// a start of a greater sequence match.
|
|
||||||
//
|
|
||||||
|
|
||||||
prev_repetition = pWork->work_buff + phash_offs[0]; |
|
||||||
prev_rep_end = prev_repetition + rep_length; |
|
||||||
rep_length2 = rep_length; |
|
||||||
|
|
||||||
for(;;) |
|
||||||
{ |
|
||||||
rep_length2 = pWork->offs09BC[rep_length2]; |
|
||||||
if(rep_length2 == 0xFFFF) |
|
||||||
rep_length2 = 0; |
|
||||||
|
|
||||||
// Get the pointer to the previous repetition
|
|
||||||
phash_offs = pWork->phash_offs + phash_offs_index; |
|
||||||
|
|
||||||
// Skip those repetitions that don't reach the end
|
|
||||||
// of the first found repetition
|
|
||||||
do |
|
||||||
{ |
|
||||||
phash_offs++; |
|
||||||
phash_offs_index++; |
|
||||||
prev_repetition = pWork->work_buff + *phash_offs; |
|
||||||
if(prev_repetition >= repetition_limit) |
|
||||||
return rep_length; |
|
||||||
} |
|
||||||
while(prev_repetition + rep_length2 < prev_rep_end); |
|
||||||
|
|
||||||
// Verify if the last but one byte from the repetition matches
|
|
||||||
// the last but one byte from the input data.
|
|
||||||
// If not, find a next repetition
|
|
||||||
pre_last_byte = input_data[rep_length - 2]; |
|
||||||
if(pre_last_byte == prev_repetition[rep_length - 2]) |
|
||||||
{ |
|
||||||
// If the new repetition reaches beyond the end
|
|
||||||
// of previously found repetition, reset the repetition length to zero.
|
|
||||||
if(prev_repetition + rep_length2 != prev_rep_end) |
|
||||||
{ |
|
||||||
prev_rep_end = prev_repetition; |
|
||||||
rep_length2 = 0; |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
phash_offs = pWork->phash_offs + phash_offs_index; |
|
||||||
do |
|
||||||
{ |
|
||||||
phash_offs++; |
|
||||||
phash_offs_index++; |
|
||||||
prev_repetition = pWork->work_buff + *phash_offs; |
|
||||||
if(prev_repetition >= repetition_limit) |
|
||||||
return rep_length; |
|
||||||
} |
|
||||||
while(prev_repetition[rep_length - 2] != pre_last_byte || prev_repetition[0] != input_data[0]); |
|
||||||
|
|
||||||
// Reset the length of the repetition to 2 bytes only
|
|
||||||
prev_rep_end = prev_repetition + 2; |
|
||||||
rep_length2 = 2; |
|
||||||
} |
|
||||||
|
|
||||||
// Find out how many more characters are equal to the first repetition.
|
|
||||||
while(*prev_rep_end == input_data[rep_length2]) |
|
||||||
{ |
|
||||||
if(++rep_length2 >= 0x204) |
|
||||||
break; |
|
||||||
prev_rep_end++; |
|
||||||
} |
|
||||||
|
|
||||||
// Is the newly found repetion at least as long as the previous one ?
|
|
||||||
if(rep_length2 >= rep_length) |
|
||||||
{ |
|
||||||
// Calculate the distance of the new repetition
|
|
||||||
pWork->distance = (unsigned int)(input_data - prev_repetition - 1); |
|
||||||
if((rep_length = rep_length2) == 0x204) |
|
||||||
return rep_length; |
|
||||||
|
|
||||||
// Update the additional elements in the "offs09BC" table
|
|
||||||
// to reflect new rep length
|
|
||||||
while(offs_in_rep < rep_length2) |
|
||||||
{ |
|
||||||
if(input_data[offs_in_rep] != input_data[di_val]) |
|
||||||
{ |
|
||||||
di_val = pWork->offs09BC[di_val]; |
|
||||||
if(di_val != 0xFFFF) |
|
||||||
continue; |
|
||||||
} |
|
||||||
pWork->offs09BC[++offs_in_rep] = ++di_val; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void PKWAREAPI WriteCmpData(TCmpStruct * pWork) |
|
||||||
{ |
|
||||||
unsigned char * input_data_end; // Pointer to the end of the input data
|
|
||||||
unsigned char * input_data = pWork->work_buff + pWork->dsize_bytes + 0x204; |
|
||||||
unsigned int input_data_ended = 0; // If 1, then all data from the input stream have been already loaded
|
|
||||||
unsigned int save_rep_length; // Saved length of current repetition
|
|
||||||
unsigned int save_distance = 0; // Saved distance of current repetition
|
|
||||||
unsigned int rep_length; // Length of the found repetition
|
|
||||||
unsigned int phase = 0; //
|
|
||||||
|
|
||||||
// Store the compression type and dictionary size
|
|
||||||
pWork->out_buff[0] = (char)pWork->ctype; |
|
||||||
pWork->out_buff[1] = (char)pWork->dsize_bits; |
|
||||||
pWork->out_bytes = 2; |
|
||||||
|
|
||||||
// Reset output buffer to zero
|
|
||||||
memset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2); |
|
||||||
pWork->out_bits = 0; |
|
||||||
|
|
||||||
while(input_data_ended == 0) |
|
||||||
{ |
|
||||||
unsigned int bytes_to_load = 0x1000; |
|
||||||
int total_loaded = 0; |
|
||||||
int bytes_loaded; |
|
||||||
|
|
||||||
// Load the bytes from the input stream, up to 0x1000 bytes
|
|
||||||
while(bytes_to_load != 0) |
|
||||||
{ |
|
||||||
bytes_loaded = pWork->read_buf((char *)pWork->work_buff + pWork->dsize_bytes + 0x204 + total_loaded, |
|
||||||
&bytes_to_load, |
|
||||||
pWork->param); |
|
||||||
if(bytes_loaded == 0) |
|
||||||
{ |
|
||||||
if(total_loaded == 0 && phase == 0) |
|
||||||
goto __Exit; |
|
||||||
input_data_ended = 1; |
|
||||||
break; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
bytes_to_load -= bytes_loaded; |
|
||||||
total_loaded += bytes_loaded; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
input_data_end = pWork->work_buff + pWork->dsize_bytes + total_loaded; |
|
||||||
if(input_data_ended) |
|
||||||
input_data_end += 0x204; |
|
||||||
|
|
||||||
//
|
|
||||||
// Warning: The end of the buffer passed to "SortBuffer" is actually 2 bytes beyond
|
|
||||||
// valid data. It is questionable if this is actually a bug or not,
|
|
||||||
// but it might cause the compressed data output to be dependent on random bytes
|
|
||||||
// that are in the buffer.
|
|
||||||
// To prevent that, the calling application must always zero the compression
|
|
||||||
// buffer before passing it to "implode"
|
|
||||||
//
|
|
||||||
|
|
||||||
// Search the PAIR_HASHes of the loaded blocks. Also, include
|
|
||||||
// previously compressed data, if any.
|
|
||||||
switch(phase) |
|
||||||
{ |
|
||||||
case 0:
|
|
||||||
SortBuffer(pWork, input_data, input_data_end + 1); |
|
||||||
phase++; |
|
||||||
if(pWork->dsize_bytes != 0x1000) |
|
||||||
phase++; |
|
||||||
break; |
|
||||||
|
|
||||||
case 1: |
|
||||||
SortBuffer(pWork, input_data - pWork->dsize_bytes + 0x204, input_data_end + 1); |
|
||||||
phase++; |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
SortBuffer(pWork, input_data - pWork->dsize_bytes, input_data_end + 1); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
// Perform the compression of the current block
|
|
||||||
while(input_data < input_data_end) |
|
||||||
{ |
|
||||||
// Find if the current byte sequence wasn't there before.
|
|
||||||
rep_length = FindRep(pWork, input_data); |
|
||||||
while(rep_length != 0) |
|
||||||
{ |
|
||||||
// If we found repetition of 2 bytes, that is 0x100 or fuhrter back,
|
|
||||||
// don't bother. Storing the distance of 0x100 bytes would actually
|
|
||||||
// take more space than storing the 2 bytes as-is.
|
|
||||||
if(rep_length == 2 && pWork->distance >= 0x100) |
|
||||||
break; |
|
||||||
|
|
||||||
// When we are at the end of the input data, we cannot allow
|
|
||||||
// the repetition to go past the end of the input data.
|
|
||||||
if(input_data_ended && input_data + rep_length > input_data_end) |
|
||||||
{ |
|
||||||
// Shorten the repetition length so that it only covers valid data
|
|
||||||
rep_length = (unsigned long)(input_data_end - input_data); |
|
||||||
if(rep_length < 2) |
|
||||||
break; |
|
||||||
|
|
||||||
// If we got repetition of 2 bytes, that is 0x100 or more backward, don't bother
|
|
||||||
if(rep_length == 2 && pWork->distance >= 0x100) |
|
||||||
break; |
|
||||||
goto __FlushRepetition; |
|
||||||
} |
|
||||||
|
|
||||||
if(rep_length >= 8 || input_data + 1 >= input_data_end) |
|
||||||
goto __FlushRepetition; |
|
||||||
|
|
||||||
// Try to find better repetition 1 byte later.
|
|
||||||
// Example: "ARROCKFORT" "AROCKFORT"
|
|
||||||
// When "input_data" points to the second string, FindRep
|
|
||||||
// returns the occurence of "AR". But there is longer repetition "ROCKFORT",
|
|
||||||
// beginning 1 byte after.
|
|
||||||
save_rep_length = rep_length; |
|
||||||
save_distance = pWork->distance; |
|
||||||
rep_length = FindRep(pWork, input_data + 1); |
|
||||||
|
|
||||||
// Only use the new repetition if it's length is greater than the previous one
|
|
||||||
if(rep_length > save_rep_length) |
|
||||||
{ |
|
||||||
// If the new repetition if only 1 byte better
|
|
||||||
// and the previous distance is less than 0x80 bytes, use the previous repetition
|
|
||||||
if(rep_length > save_rep_length + 1 || save_distance > 0x80) |
|
||||||
{ |
|
||||||
// Flush one byte, so that input_data will point to the secondary repetition
|
|
||||||
OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); |
|
||||||
input_data++; |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Revert to the previous repetition
|
|
||||||
rep_length = save_rep_length; |
|
||||||
pWork->distance = save_distance; |
|
||||||
|
|
||||||
__FlushRepetition: |
|
||||||
|
|
||||||
OutputBits(pWork, pWork->nChBits[rep_length + 0xFE], pWork->nChCodes[rep_length + 0xFE]); |
|
||||||
if(rep_length == 2) |
|
||||||
{ |
|
||||||
OutputBits(pWork, pWork->dist_bits[pWork->distance >> 2], |
|
||||||
pWork->dist_codes[pWork->distance >> 2]); |
|
||||||
OutputBits(pWork, 2, pWork->distance & 3); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
OutputBits(pWork, pWork->dist_bits[pWork->distance >> pWork->dsize_bits], |
|
||||||
pWork->dist_codes[pWork->distance >> pWork->dsize_bits]); |
|
||||||
OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->distance); |
|
||||||
} |
|
||||||
|
|
||||||
// Move the begin of the input data by the length of the repetition
|
|
||||||
input_data += rep_length; |
|
||||||
goto _00402252; |
|
||||||
} |
|
||||||
|
|
||||||
// If there was no previous repetition for the current position in the input data,
|
|
||||||
// just output the 9-bit literal for the one character
|
|
||||||
OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); |
|
||||||
input_data++; |
|
||||||
_00402252:; |
|
||||||
} |
|
||||||
|
|
||||||
if(input_data_ended == 0) |
|
||||||
{ |
|
||||||
input_data -= 0x1000; |
|
||||||
memmove(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + 0x204); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
__Exit: |
|
||||||
|
|
||||||
// Write the termination literal
|
|
||||||
OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]); |
|
||||||
if(pWork->out_bits != 0) |
|
||||||
pWork->out_bytes++; |
|
||||||
pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Main imploding function
|
|
||||||
|
|
||||||
unsigned int PKWAREAPI implode( |
|
||||||
unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
char *work_buf, |
|
||||||
void *param, |
|
||||||
unsigned int *type, |
|
||||||
unsigned int *dsize) |
|
||||||
{ |
|
||||||
TCmpStruct * pWork = (TCmpStruct *)work_buf; |
|
||||||
unsigned int nChCode; |
|
||||||
unsigned int nCount; |
|
||||||
unsigned int i; |
|
||||||
int nCount2; |
|
||||||
|
|
||||||
// Fill the work buffer information
|
|
||||||
// Note: The caller must zero the "work_buff" before passing it to implode
|
|
||||||
pWork->read_buf = read_buf; |
|
||||||
pWork->write_buf = write_buf; |
|
||||||
pWork->dsize_bytes = *dsize; |
|
||||||
pWork->ctype = *type; |
|
||||||
pWork->param = param; |
|
||||||
pWork->dsize_bits = 4; |
|
||||||
pWork->dsize_mask = 0x0F; |
|
||||||
|
|
||||||
// Test dictionary size
|
|
||||||
switch(*dsize) |
|
||||||
{ |
|
||||||
case CMP_IMPLODE_DICT_SIZE3: // 0x1000 bytes
|
|
||||||
pWork->dsize_bits++; |
|
||||||
pWork->dsize_mask |= 0x20; |
|
||||||
// No break here !!!
|
|
||||||
|
|
||||||
case CMP_IMPLODE_DICT_SIZE2: // 0x800 bytes
|
|
||||||
pWork->dsize_bits++; |
|
||||||
pWork->dsize_mask |= 0x10; |
|
||||||
// No break here !!!
|
|
||||||
|
|
||||||
case CMP_IMPLODE_DICT_SIZE1: // 0x400
|
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
return CMP_INVALID_DICTSIZE; |
|
||||||
} |
|
||||||
|
|
||||||
// Test the compression type
|
|
||||||
switch(*type) |
|
||||||
{ |
|
||||||
case CMP_BINARY: // We will compress data with binary compression type
|
|
||||||
for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++) |
|
||||||
{ |
|
||||||
pWork->nChBits[nCount] = 9; |
|
||||||
pWork->nChCodes[nCount] = (unsigned short)nChCode; |
|
||||||
nChCode = (nChCode & 0x0000FFFF) + 2; |
|
||||||
} |
|
||||||
break; |
|
||||||
|
|
||||||
|
|
||||||
case CMP_ASCII: // We will compress data with ASCII compression type
|
|
||||||
for(nCount = 0; nCount < 0x100; nCount++) |
|
||||||
{ |
|
||||||
pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1); |
|
||||||
pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2); |
|
||||||
} |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
return CMP_INVALID_MODE; |
|
||||||
} |
|
||||||
|
|
||||||
for(i = 0; i < 0x10; i++) |
|
||||||
{ |
|
||||||
if(1 << ExLenBits[i]) |
|
||||||
{ |
|
||||||
for(nCount2 = 0; nCount2 < (1 << ExLenBits[i]); nCount2++) |
|
||||||
{ |
|
||||||
pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1); |
|
||||||
pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1); |
|
||||||
nCount++; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Copy the distance codes and distance bits and perform the compression
|
|
||||||
memcpy(&pWork->dist_codes, DistCode, sizeof(DistCode)); |
|
||||||
memcpy(&pWork->dist_bits, DistBits, sizeof(DistBits)); |
|
||||||
WriteCmpData(pWork); |
|
||||||
return CMP_NO_ERROR; |
|
||||||
} |
|
||||||
@ -1,142 +0,0 @@ |
|||||||
/*****************************************************************************/ |
|
||||||
/* pkware.h Copyright (c) Ladislav Zezula 2003 */ |
|
||||||
/*---------------------------------------------------------------------------*/ |
|
||||||
/* Header file for PKWARE Data Compression Library */ |
|
||||||
/*---------------------------------------------------------------------------*/ |
|
||||||
/* Date Ver Who Comment */ |
|
||||||
/* -------- ---- --- ------- */ |
|
||||||
/* 31.03.03 1.00 Lad The first version of pkware.h */ |
|
||||||
/*****************************************************************************/ |
|
||||||
|
|
||||||
#ifndef __PKWARE_H__ |
|
||||||
#define __PKWARE_H__ |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Defines
|
|
||||||
|
|
||||||
#define CMP_BINARY 0 // Binary compression
|
|
||||||
#define CMP_ASCII 1 // Ascii compression
|
|
||||||
|
|
||||||
#define CMP_NO_ERROR 0 |
|
||||||
#define CMP_INVALID_DICTSIZE 1 |
|
||||||
#define CMP_INVALID_MODE 2 |
|
||||||
#define CMP_BAD_DATA 3 |
|
||||||
#define CMP_ABORT 4 |
|
||||||
|
|
||||||
#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024
|
|
||||||
#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048
|
|
||||||
#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Define calling convention
|
|
||||||
|
|
||||||
#ifndef PKWAREAPI |
|
||||||
#ifdef WIN32 |
|
||||||
#define PKWAREAPI __cdecl // Use for normal __cdecl calling
|
|
||||||
#else |
|
||||||
#define PKWAREAPI |
|
||||||
#endif |
|
||||||
#endif |
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Internal structures
|
|
||||||
|
|
||||||
// Compression structure
|
|
||||||
typedef struct |
|
||||||
{ |
|
||||||
unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1
|
|
||||||
unsigned int out_bytes; // 0004: # bytes available in out_buff
|
|
||||||
unsigned int out_bits; // 0008: # of bits available in the last out byte
|
|
||||||
unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000
|
|
||||||
unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000
|
|
||||||
unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY)
|
|
||||||
unsigned int dsize_bytes; // 0018: Dictionary size in bytes
|
|
||||||
unsigned char dist_bits[0x40]; // 001C: Distance bits
|
|
||||||
unsigned char dist_codes[0x40]; // 005C: Distance codes
|
|
||||||
unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream
|
|
||||||
unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream
|
|
||||||
unsigned short offs09AE; // 09AE:
|
|
||||||
|
|
||||||
void * param; // 09B0: User parameter
|
|
||||||
unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param); // 9B4
|
|
||||||
void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param); // 9B8
|
|
||||||
|
|
||||||
unsigned short offs09BC[0x204]; // 09BC:
|
|
||||||
unsigned long offs0DC4; // 0DC4:
|
|
||||||
unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table
|
|
||||||
unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table
|
|
||||||
char out_buff[0x802]; // 1FCA: Compressed data
|
|
||||||
unsigned char work_buff[0x2204]; // 27CC: Work buffer
|
|
||||||
// + DICT_OFFSET => Dictionary
|
|
||||||
// + UNCMP_OFFSET => Uncompressed data
|
|
||||||
unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH
|
|
||||||
} TCmpStruct; |
|
||||||
|
|
||||||
#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure.
|
|
||||||
// Defined as 36312 in pkware header file
|
|
||||||
|
|
||||||
|
|
||||||
// Decompression structure
|
|
||||||
typedef struct |
|
||||||
{ |
|
||||||
unsigned long offs0000; // 0000
|
|
||||||
unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII)
|
|
||||||
unsigned long outputPos; // 0008: Position in output buffer
|
|
||||||
unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000)
|
|
||||||
unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000)
|
|
||||||
unsigned long bit_buff; // 0014: 16-bit buffer for processing input data
|
|
||||||
unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer
|
|
||||||
unsigned int in_pos; // 001C: Position in in_buff
|
|
||||||
unsigned long in_bytes; // 0020: Number of bytes in input buffer
|
|
||||||
void * param; // 0024: Custom parameter
|
|
||||||
unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream
|
|
||||||
void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream
|
|
||||||
|
|
||||||
unsigned char out_buff[0x2204]; // 0030: Output circle buffer.
|
|
||||||
// 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions
|
|
||||||
// 0x1000 - 0x1FFF: Currently decompressed data
|
|
||||||
// 0x2000 - 0x2203: Reserve space for the longest possible repetition
|
|
||||||
unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed
|
|
||||||
unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes
|
|
||||||
unsigned char LengthCodes[0x100]; // 2B34: Table of length codes
|
|
||||||
unsigned char offs2C34[0x100]; // 2C34: Buffer for
|
|
||||||
unsigned char offs2D34[0x100]; // 2D34: Buffer for
|
|
||||||
unsigned char offs2E34[0x80]; // 2EB4: Buffer for
|
|
||||||
unsigned char offs2EB4[0x100]; // 2EB4: Buffer for
|
|
||||||
unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for
|
|
||||||
unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length
|
|
||||||
unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length
|
|
||||||
unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block
|
|
||||||
unsigned short LenBase[0x10]; // 3114: Buffer for
|
|
||||||
} TDcmpStruct; |
|
||||||
|
|
||||||
#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure
|
|
||||||
// Defined as 12596 in pkware headers
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Public functions
|
|
||||||
|
|
||||||
#ifdef __cplusplus |
|
||||||
extern "C" { |
|
||||||
#endif |
|
||||||
|
|
||||||
unsigned int PKWAREAPI implode( |
|
||||||
unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
char *work_buf, |
|
||||||
void *param, |
|
||||||
unsigned int *type, |
|
||||||
unsigned int *dsize); |
|
||||||
|
|
||||||
|
|
||||||
unsigned int PKWAREAPI explode( |
|
||||||
unsigned int (PKWAREAPI *read_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
void (PKWAREAPI *write_buf)(char *buf, unsigned int *size, void *param), |
|
||||||
char *work_buf, |
|
||||||
void *param); |
|
||||||
|
|
||||||
#ifdef __cplusplus |
|
||||||
} // End of 'extern "C"' declaration
|
|
||||||
#endif |
|
||||||
|
|
||||||
#endif // __PKWARE_H__
|
|
||||||
@ -1,38 +0,0 @@ |
|||||||
if(NOT TARGET ZLIB::ZLIB) |
|
||||||
find_package(ZLIB REQUIRED) |
|
||||||
endif() |
|
||||||
|
|
||||||
if(NOT TARGET BZip2::BZip2) |
|
||||||
find_package(BZip2 REQUIRED) |
|
||||||
endif() |
|
||||||
|
|
||||||
include(functions/FetchContent_ExcludeFromAll_backport) |
|
||||||
|
|
||||||
include(FetchContent) |
|
||||||
FetchContent_Declare_ExcludeFromAll(libmpq |
|
||||||
URL https://github.com/diasurgical/libmpq/archive/7c2924d4553513eba1a70bbdb558198dd8c2726a.tar.gz |
|
||||||
URL_HASH MD5=315c88c02b45851cdfee8460322de044 |
|
||||||
) |
|
||||||
FetchContent_MakeAvailable_ExcludeFromAll(libmpq) |
|
||||||
|
|
||||||
add_library(libmpq STATIC |
|
||||||
${libmpq_SOURCE_DIR}/libmpq/common.c |
|
||||||
${libmpq_SOURCE_DIR}/libmpq/explode.c |
|
||||||
${libmpq_SOURCE_DIR}/libmpq/extract.c |
|
||||||
${libmpq_SOURCE_DIR}/libmpq/huffman.c |
|
||||||
${libmpq_SOURCE_DIR}/libmpq/mpq.c |
|
||||||
${libmpq_SOURCE_DIR}/libmpq/wave.c |
|
||||||
) |
|
||||||
|
|
||||||
target_include_directories(libmpq PUBLIC ${libmpq_SOURCE_DIR}) |
|
||||||
target_include_directories(libmpq PRIVATE ${CMAKE_CURRENT_LIST_DIR}) |
|
||||||
|
|
||||||
target_link_libraries(libmpq PRIVATE ZLIB::ZLIB BZip2::BZip2) |
|
||||||
|
|
||||||
if(LIBMPQ_FILE_BUFFER_SIZE) |
|
||||||
target_compile_definitions(libmpq PRIVATE "LIBMPQ_FILE_BUFFER_SIZE=${LIBMPQ_FILE_BUFFER_SIZE}") |
|
||||||
endif() |
|
||||||
|
|
||||||
if(DEVILUTIONX_WINDOWS_NO_WCHAR) |
|
||||||
target_compile_definitions(libmpq PRIVATE LIBMPQ_WINDOWS_NO_WCHAR) |
|
||||||
endif() |
|
||||||
@ -0,0 +1,9 @@ |
|||||||
|
include(functions/FetchContent_ExcludeFromAll_backport) |
||||||
|
|
||||||
|
include(FetchContent) |
||||||
|
|
||||||
|
FetchContent_Declare_ExcludeFromAll(mpqfs |
||||||
|
URL https://github.com/diasurgical/mpqfs/archive/27144129a5d8f84ddbe058a7c5d7f2c8a724af67.tar.gz |
||||||
|
URL_HASH MD5=c137f8eb7f5e097c63f9b46769ff2b5c |
||||||
|
) |
||||||
|
FetchContent_MakeAvailable_ExcludeFromAll(mpqfs) |
||||||
@ -1,149 +1,145 @@ |
|||||||
#include "mpq/mpq_reader.hpp" |
#include "mpq/mpq_reader.hpp" |
||||||
|
|
||||||
#include <cstddef> |
#include <cstring> |
||||||
#include <cstdint> |
#include <utility> |
||||||
#include <optional> |
|
||||||
#include <string_view> |
|
||||||
|
|
||||||
#include <libmpq/mpq.h> |
#include <mpqfs/mpqfs.h> |
||||||
|
|
||||||
|
#include "utils/file_util.h" |
||||||
|
|
||||||
namespace devilution { |
namespace devilution { |
||||||
|
|
||||||
std::optional<MpqArchive> MpqArchive::Open(const char *path, int32_t &error) |
// Helper: NUL-terminate a string_view into a stack buffer.
|
||||||
|
// Returns false if the name doesn't fit.
|
||||||
|
static bool CopyToPathBuf(std::string_view sv, char *buf, size_t bufSize) |
||||||
{ |
{ |
||||||
mpq_archive_s *archive; |
if (sv.size() >= bufSize) return false; |
||||||
error = libmpq__archive_open(&archive, path, -1); |
std::memcpy(buf, sv.data(), sv.size()); |
||||||
if (error != 0) { |
buf[sv.size()] = '\0'; |
||||||
if (error == LIBMPQ_ERROR_EXIST) |
return true; |
||||||
error = 0; |
|
||||||
return std::nullopt; |
|
||||||
} |
|
||||||
return MpqArchive { std::string(path), archive }; |
|
||||||
} |
} |
||||||
|
|
||||||
std::optional<MpqArchive> MpqArchive::Clone(int32_t &error) |
MpqArchive::MpqArchive(std::string path, mpqfs_archive_t *archive) |
||||||
|
: path_(std::move(path)) |
||||||
|
, archive_(archive) |
||||||
{ |
{ |
||||||
mpq_archive_s *copy; |
|
||||||
error = libmpq__archive_dup(archive_, path_.c_str(), ©); |
|
||||||
if (error != 0) |
|
||||||
return std::nullopt; |
|
||||||
return MpqArchive { path_, copy }; |
|
||||||
} |
} |
||||||
|
|
||||||
const char *MpqArchive::ErrorMessage(int32_t errorCode) |
MpqArchive::MpqArchive(MpqArchive &&other) noexcept |
||||||
|
: path_(std::move(other.path_)) |
||||||
|
, archive_(other.archive_) |
||||||
{ |
{ |
||||||
return libmpq__strerror(errorCode); |
other.archive_ = nullptr; |
||||||
} |
} |
||||||
|
|
||||||
MpqArchive &MpqArchive::operator=(MpqArchive &&other) noexcept |
MpqArchive &MpqArchive::operator=(MpqArchive &&other) noexcept |
||||||
{ |
{ |
||||||
path_ = std::move(other.path_); |
if (this != &other) { |
||||||
if (archive_ != nullptr) |
mpqfs_close(archive_); |
||||||
libmpq__archive_close(archive_); |
path_ = std::move(other.path_); |
||||||
archive_ = other.archive_; |
archive_ = other.archive_; |
||||||
other.archive_ = nullptr; |
other.archive_ = nullptr; |
||||||
tmp_buf_ = std::move(other.tmp_buf_); |
} |
||||||
return *this; |
return *this; |
||||||
} |
} |
||||||
|
|
||||||
MpqArchive::~MpqArchive() |
MpqArchive::~MpqArchive() |
||||||
{ |
{ |
||||||
if (archive_ != nullptr) |
mpqfs_close(archive_); |
||||||
libmpq__archive_close(archive_); |
|
||||||
} |
} |
||||||
|
|
||||||
bool MpqArchive::GetFileNumber(MpqFileHash fileHash, uint32_t &fileNumber) |
std::optional<MpqArchive> MpqArchive::Open(const char *path, int32_t &error) |
||||||
{ |
{ |
||||||
return libmpq__file_number_from_hash(archive_, fileHash[0], fileHash[1], fileHash[2], &fileNumber) == 0; |
if (!FileExists(path)) { |
||||||
|
error = 0; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
mpqfs_archive_t *handle = mpqfs_open(path); |
||||||
|
if (!handle) { |
||||||
|
error = -1; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
error = 0; |
||||||
|
return MpqArchive(path, handle); |
||||||
} |
} |
||||||
|
|
||||||
std::unique_ptr<std::byte[]> MpqArchive::ReadFile(std::string_view filename, std::size_t &fileSize, int32_t &error) |
std::optional<MpqArchive> MpqArchive::Clone(int32_t &error) |
||||||
{ |
{ |
||||||
std::unique_ptr<std::byte[]> result; |
mpqfs_archive_t *clone = mpqfs_clone(archive_); |
||||||
std::uint32_t fileNumber; |
if (!clone) { |
||||||
error = libmpq__file_number_s(archive_, filename.data(), filename.size(), &fileNumber); |
error = -1; |
||||||
if (error != 0) |
return std::nullopt; |
||||||
return result; |
|
||||||
|
|
||||||
libmpq__off_t unpackedSize; |
|
||||||
error = libmpq__file_size_unpacked(archive_, fileNumber, &unpackedSize); |
|
||||||
if (error != 0) |
|
||||||
return result; |
|
||||||
|
|
||||||
error = OpenBlockOffsetTable(fileNumber, filename); |
|
||||||
if (error != 0) |
|
||||||
return result; |
|
||||||
|
|
||||||
result = std::make_unique<std::byte[]>(static_cast<size_t>(unpackedSize)); |
|
||||||
|
|
||||||
const std::size_t blockSize = GetBlockSize(fileNumber, 0, error); |
|
||||||
if (error != 0) |
|
||||||
return result; |
|
||||||
|
|
||||||
std::vector<std::uint8_t> &tmp = GetTemporaryBuffer(blockSize); |
|
||||||
if (error != 0) |
|
||||||
return result; |
|
||||||
|
|
||||||
error = libmpq__file_read_with_filename_and_temporary_buffer_s( |
|
||||||
archive_, fileNumber, filename.data(), filename.size(), reinterpret_cast<std::uint8_t *>(result.get()), unpackedSize, |
|
||||||
tmp.data(), static_cast<libmpq__off_t>(blockSize), nullptr); |
|
||||||
if (error != 0) { |
|
||||||
result = nullptr; |
|
||||||
CloseBlockOffsetTable(fileNumber); |
|
||||||
return result; |
|
||||||
} |
} |
||||||
CloseBlockOffsetTable(fileNumber); |
error = 0; |
||||||
|
return MpqArchive(path_, clone); |
||||||
fileSize = static_cast<size_t>(unpackedSize); |
|
||||||
return result; |
|
||||||
} |
} |
||||||
|
|
||||||
int32_t MpqArchive::ReadBlock(uint32_t fileNumber, uint32_t blockNumber, uint8_t *out, size_t outSize) |
const char *MpqArchive::ErrorMessage() |
||||||
{ |
{ |
||||||
std::vector<std::uint8_t> &tmpBuf = GetTemporaryBuffer(outSize); |
const char *msg = mpqfs_last_error(); |
||||||
return libmpq__block_read_with_temporary_buffer( |
return msg ? msg : "Unknown error"; |
||||||
archive_, fileNumber, blockNumber, out, static_cast<libmpq__off_t>(outSize), |
|
||||||
tmpBuf.data(), outSize, |
|
||||||
/*transferred=*/nullptr); |
|
||||||
} |
} |
||||||
|
|
||||||
std::size_t MpqArchive::GetUnpackedFileSize(uint32_t fileNumber, int32_t &error) |
bool MpqArchive::HasFile(std::string_view filename) const |
||||||
{ |
{ |
||||||
libmpq__off_t unpackedSize; |
char buf[256]; |
||||||
error = libmpq__file_size_unpacked(archive_, fileNumber, &unpackedSize); |
if (!CopyToPathBuf(filename, buf, sizeof(buf))) |
||||||
return static_cast<size_t>(unpackedSize); |
return false; |
||||||
|
return mpqfs_has_file(archive_, buf); |
||||||
} |
} |
||||||
|
|
||||||
uint32_t MpqArchive::GetNumBlocks(uint32_t fileNumber, int32_t &error) |
size_t MpqArchive::GetFileSize(std::string_view filename) const |
||||||
{ |
{ |
||||||
uint32_t numBlocks; |
char buf[256]; |
||||||
error = libmpq__file_blocks(archive_, fileNumber, &numBlocks); |
if (!CopyToPathBuf(filename, buf, sizeof(buf))) |
||||||
return numBlocks; |
return 0; |
||||||
|
return mpqfs_file_size(archive_, buf); |
||||||
} |
} |
||||||
|
|
||||||
int32_t MpqArchive::OpenBlockOffsetTable(uint32_t fileNumber, std::string_view filename) |
uint32_t MpqArchive::FindHash(std::string_view filename) const |
||||||
{ |
{ |
||||||
return libmpq__block_open_offset_with_filename_s(archive_, fileNumber, filename.data(), filename.size()); |
char buf[256]; |
||||||
|
if (!CopyToPathBuf(filename, buf, sizeof(buf))) |
||||||
|
return UINT32_MAX; |
||||||
|
return mpqfs_find_hash(archive_, buf); |
||||||
} |
} |
||||||
|
|
||||||
int32_t MpqArchive::CloseBlockOffsetTable(uint32_t fileNumber) |
bool MpqArchive::HasFileHash(uint32_t hash) const |
||||||
{ |
{ |
||||||
return libmpq__block_close_offset(archive_, fileNumber); |
return mpqfs_has_file_hash(archive_, hash); |
||||||
} |
} |
||||||
|
|
||||||
// Requires the block offset table to be open
|
size_t MpqArchive::GetFileSizeFromHash(uint32_t hash) const |
||||||
std::size_t MpqArchive::GetBlockSize(uint32_t fileNumber, uint32_t blockNumber, int32_t &error) |
|
||||||
{ |
{ |
||||||
libmpq__off_t blockSize; |
return mpqfs_file_size_from_hash(archive_, hash); |
||||||
error = libmpq__block_size_unpacked(archive_, fileNumber, blockNumber, &blockSize); |
|
||||||
return static_cast<size_t>(blockSize); |
|
||||||
} |
} |
||||||
|
|
||||||
bool MpqArchive::HasFile(std::string_view filename) const |
std::unique_ptr<std::byte[]> MpqArchive::ReadFile( |
||||||
|
std::string_view filename, std::size_t &fileSize, int32_t &error) |
||||||
{ |
{ |
||||||
std::uint32_t fileNumber; |
char buf[256]; |
||||||
const int32_t error = libmpq__file_number_s(archive_, filename.data(), filename.size(), &fileNumber); |
if (!CopyToPathBuf(filename, buf, sizeof(buf))) { |
||||||
return error == 0; |
error = -1; |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
const size_t size = mpqfs_file_size(archive_, buf); |
||||||
|
if (size == 0) { |
||||||
|
error = -1; |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
auto result = std::make_unique<std::byte[]>(size); |
||||||
|
const size_t read = mpqfs_read_file_into(archive_, buf, |
||||||
|
result.get(), size); |
||||||
|
if (read == 0) { |
||||||
|
error = -1; |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
error = 0; |
||||||
|
fileSize = read; |
||||||
|
return result; |
||||||
} |
} |
||||||
|
|
||||||
} // namespace devilution
|
} // namespace devilution
|
||||||
|
|||||||
@ -1,20 +1,23 @@ |
|||||||
#pragma once |
#pragma once |
||||||
|
|
||||||
#include <cstdint> |
|
||||||
#include <string_view> |
#include <string_view> |
||||||
|
|
||||||
|
#include "mpq/mpq_reader.hpp" |
||||||
|
|
||||||
|
// Forward-declare the SDL type for the active SDL version.
|
||||||
#ifdef USE_SDL3 |
#ifdef USE_SDL3 |
||||||
#include <SDL3/SDL_iostream.h> |
struct SDL_IOStream; |
||||||
|
using SdlRwopsType = SDL_IOStream; |
||||||
#else |
#else |
||||||
#include <SDL.h> |
struct SDL_RWops; |
||||||
|
using SdlRwopsType = SDL_RWops; |
||||||
#include "utils/sdl_compat.h" |
|
||||||
#endif |
#endif |
||||||
|
|
||||||
#include "mpq/mpq_reader.hpp" |
|
||||||
|
|
||||||
namespace devilution { |
namespace devilution { |
||||||
|
|
||||||
SDL_IOStream *SDL_RWops_FromMpqFile(MpqArchive &mpqArchive, uint32_t fileNumber, std::string_view filename, bool threadsafe); |
SdlRwopsType *SDL_RWops_FromMpqFile(MpqArchive &archive, |
||||||
|
uint32_t hashIndex, |
||||||
|
std::string_view filename, |
||||||
|
bool threadsafe); |
||||||
|
|
||||||
} // namespace devilution
|
} // namespace devilution
|
||||||
|
|||||||
Loading…
Reference in new issue