Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
parent
2e338c00cb
commit
3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions
369
Generals/Code/Libraries/Source/Compression/Compression.dsp
Normal file
369
Generals/Code/Libraries/Source/Compression/Compression.dsp
Normal file
|
@ -0,0 +1,369 @@
|
|||
# Microsoft Developer Studio Project File - Name="Compression" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=Compression - 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 "Compression.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 "Compression.mak" CFG="Compression - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Compression - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "Compression - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "Compression - Win32 Internal" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName "Compression"
|
||||
# PROP Scc_LocalPath "..\.."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Compression - 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 Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /WX /GX /O2 /Ob2 /I "..\..\include" /D "NDEBUG" /D "_RELEASE" /D "WIN32" /D "_MBCS" /D "_LIB" /D "Z_PREFIX" /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 /out:"..\..\..\Libraries\Lib\Compression.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Compression - 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 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 /W3 /WX /Gm /GX /ZI /Od /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "Z_PREFIX" /FR /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 /out:"..\..\..\Libraries\Lib\CompressionDebug.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Compression - Win32 Internal"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Internal"
|
||||
# PROP BASE Intermediate_Dir "Internal"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Internal"
|
||||
# PROP Intermediate_Dir "Internal"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /WX /GX /O2 /I "..\..\include" /D "NDEBUG" /D "_INTERNAL" /D "WIN32" /D "_MBCS" /D "_LIB" /D "Z_PREFIX" /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 /out:"..\..\..\Libraries\Lib\CompressionInternal.lib"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "Compression - Win32 Release"
|
||||
# Name "Compression - Win32 Debug"
|
||||
# Name "Compression - Win32 Internal"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Group "Zlib"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\adler32.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\compress.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\crc32.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\deflate.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\gzio.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\infblock.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\infcodes.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\inffast.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\inflate.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\inftrees.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\infutil.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\maketree.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\trees.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\uncompr.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\zutil.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "NoxLZH"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Hdec_g.tbl
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Hdec_s.tbl
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Hdisp.tbl
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Henc.tbl
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Huff.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Lz.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Lzhl.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibSource\Lzhl_tcp.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\NoxCompress.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "EAC"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\btreeabout.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\btreedecode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\btreeencode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\huffabout.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\huffdecode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\huffencode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\refabout.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\refdecode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\refencode.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CompressionManager.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Group "Zlib.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\deflate.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\infblock.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\infcodes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\inffast.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\inffixed.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\inftrees.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\infutil.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\trees.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\zconf.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\zlib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ZLib\zutil.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "NoxLZH.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibHeader\_huff.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibHeader\_lz.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibHeader\_lzhl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibHeader\Lzhl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\CompLibHeader\Lzhl_tcp.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LZHCompress\NoxCompress.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "EAC.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\btreecodex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\codex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\gimex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\huffcodex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EAC\refcodex.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Compression.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
71
Generals/Code/Libraries/Source/Compression/Compression.h
Normal file
71
Generals/Code/Libraries/Source/Compression/Compression.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// FILE: Compression.h ///////////////////////////////////////////////////////
|
||||
// Author: Matthew D. Campbell
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __COMPRESSION_H__
|
||||
#define __COMPRESSION_H__
|
||||
|
||||
#include "Lib/BaseType.h"
|
||||
|
||||
enum CompressionType
|
||||
{
|
||||
COMPRESSION_MIN = 0,
|
||||
COMPRESSION_NONE = COMPRESSION_MIN,
|
||||
COMPRESSION_REFPACK,
|
||||
COMPRESSION_MAX = COMPRESSION_REFPACK,
|
||||
COMPRESSION_NOXLZH,
|
||||
COMPRESSION_ZLIB1,
|
||||
COMPRESSION_ZLIB2,
|
||||
COMPRESSION_ZLIB3,
|
||||
COMPRESSION_ZLIB4,
|
||||
COMPRESSION_ZLIB5,
|
||||
COMPRESSION_ZLIB6,
|
||||
COMPRESSION_ZLIB7,
|
||||
COMPRESSION_ZLIB8,
|
||||
COMPRESSION_ZLIB9,
|
||||
COMPRESSION_BTREE,
|
||||
COMPRESSION_HUFF,
|
||||
};
|
||||
|
||||
class CompressionManager
|
||||
{
|
||||
public:
|
||||
|
||||
static Bool isDataCompressed( const void *mem, Int len );
|
||||
static CompressionType getCompressionType( const void *mem, Int len );
|
||||
|
||||
static Int getMaxCompressedSize( Int uncompressedLen, CompressionType compType );
|
||||
static Int getUncompressedSize( const void *mem, Int len );
|
||||
|
||||
static Int compressData( CompressionType compType, void *src, Int srcLen, void *dest, Int destLen ); // 0 on error
|
||||
static Int decompressData( void *src, Int srcLen, void *dest, Int destLen ); // 0 on error
|
||||
|
||||
static const char *getCompressionNameByType( CompressionType compType );
|
||||
|
||||
// For perf timers, so we can have separate ones for compression/decompression
|
||||
static const char *getDecompressionNameByType( CompressionType compType );
|
||||
|
||||
static CompressionType getPreferredCompression( void );
|
||||
};
|
||||
|
||||
#endif // __COMPRESSION_H__
|
|
@ -0,0 +1,509 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// FILE: Compression.cpp /////////////////////////////////////////////////////
|
||||
// Author: Matthew D. Campbell
|
||||
// LZH wrapper taken from Nox, originally from Jeff Brown
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Compression.h"
|
||||
#include "LZHCompress/NoxCompress.h"
|
||||
extern "C" {
|
||||
#include "ZLib/zlib.h"
|
||||
}
|
||||
#include "EAC/codex.h"
|
||||
#include "EAC/btreecodex.h"
|
||||
#include "EAC/huffcodex.h"
|
||||
#include "EAC/refcodex.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOG(x) {}
|
||||
|
||||
const char *CompressionManager::getCompressionNameByType( CompressionType compType )
|
||||
{
|
||||
static const char *s_compressionNames[COMPRESSION_MAX+1] = {
|
||||
"No compression",
|
||||
"RefPack",
|
||||
/*
|
||||
"LZHL",
|
||||
"ZLib 1 (fast)",
|
||||
"ZLib 2",
|
||||
"ZLib 3",
|
||||
"ZLib 4",
|
||||
"ZLib 5 (default)",
|
||||
"ZLib 6",
|
||||
"ZLib 7",
|
||||
"ZLib 8",
|
||||
"ZLib 9 (slow)",
|
||||
"BTree",
|
||||
"Huff",
|
||||
*/
|
||||
};
|
||||
return s_compressionNames[compType];
|
||||
}
|
||||
|
||||
// For perf timers, so we can have separate ones for compression/decompression
|
||||
const char *CompressionManager::getDecompressionNameByType( CompressionType compType )
|
||||
{
|
||||
static const char *s_decompressionNames[COMPRESSION_MAX+1] = {
|
||||
"d_None",
|
||||
"d_RefPack",
|
||||
/*
|
||||
"d_NoxLZW",
|
||||
"d_ZLib1",
|
||||
"d_ZLib2",
|
||||
"d_ZLib3",
|
||||
"d_ZLib4",
|
||||
"d_ZLib5",
|
||||
"d_ZLib6",
|
||||
"d_ZLib7",
|
||||
"d_ZLib8",
|
||||
"d_ZLib9",
|
||||
"d_BTree",
|
||||
"d_Huff",
|
||||
*/
|
||||
};
|
||||
return s_decompressionNames[compType];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
Bool CompressionManager::isDataCompressed( const void *mem, Int len )
|
||||
{
|
||||
CompressionType t = getCompressionType(mem, len);
|
||||
return t != COMPRESSION_NONE;
|
||||
}
|
||||
|
||||
CompressionType CompressionManager::getPreferredCompression( void )
|
||||
{
|
||||
return COMPRESSION_REFPACK;
|
||||
}
|
||||
|
||||
|
||||
CompressionType CompressionManager::getCompressionType( const void *mem, Int len )
|
||||
{
|
||||
if (len < 8)
|
||||
return COMPRESSION_NONE;
|
||||
|
||||
if ( memcmp( mem, "NOX\0", 4 ) == 0 )
|
||||
return COMPRESSION_NOXLZH;
|
||||
|
||||
if ( memcmp( mem, "ZL1\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB1;
|
||||
if ( memcmp( mem, "ZL2\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB2;
|
||||
if ( memcmp( mem, "ZL3\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB3;
|
||||
if ( memcmp( mem, "ZL4\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB4;
|
||||
if ( memcmp( mem, "ZL5\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB5;
|
||||
if ( memcmp( mem, "ZL6\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB6;
|
||||
if ( memcmp( mem, "ZL7\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB7;
|
||||
if ( memcmp( mem, "ZL8\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB8;
|
||||
if ( memcmp( mem, "ZL9\0", 4 ) == 0 )
|
||||
return COMPRESSION_ZLIB9;
|
||||
if ( memcmp( mem, "EAB\0", 4 ) == 0 )
|
||||
return COMPRESSION_BTREE;
|
||||
if ( memcmp( mem, "EAH\0", 4 ) == 0 )
|
||||
return COMPRESSION_HUFF;
|
||||
if ( memcmp( mem, "EAR\0", 4 ) == 0 )
|
||||
return COMPRESSION_REFPACK;
|
||||
|
||||
return COMPRESSION_NONE;
|
||||
}
|
||||
|
||||
Int CompressionManager::getMaxCompressedSize( Int uncompressedLen, CompressionType compType )
|
||||
{
|
||||
switch (compType)
|
||||
{
|
||||
case COMPRESSION_NOXLZH:
|
||||
return CalcNewSize(uncompressedLen) + 8;
|
||||
|
||||
case COMPRESSION_BTREE: // guessing here
|
||||
case COMPRESSION_HUFF: // guessing here
|
||||
case COMPRESSION_REFPACK: // guessing here
|
||||
return uncompressedLen + 8;
|
||||
|
||||
case COMPRESSION_ZLIB1:
|
||||
case COMPRESSION_ZLIB2:
|
||||
case COMPRESSION_ZLIB3:
|
||||
case COMPRESSION_ZLIB4:
|
||||
case COMPRESSION_ZLIB5:
|
||||
case COMPRESSION_ZLIB6:
|
||||
case COMPRESSION_ZLIB7:
|
||||
case COMPRESSION_ZLIB8:
|
||||
case COMPRESSION_ZLIB9:
|
||||
return (Int)(ceil(uncompressedLen * 1.1 + 12 + 8));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int CompressionManager::getUncompressedSize( const void *mem, Int len )
|
||||
{
|
||||
if (len < 8)
|
||||
return len;
|
||||
|
||||
CompressionType compType = getCompressionType( mem, len );
|
||||
switch (compType)
|
||||
{
|
||||
case COMPRESSION_NOXLZH:
|
||||
case COMPRESSION_ZLIB1:
|
||||
case COMPRESSION_ZLIB2:
|
||||
case COMPRESSION_ZLIB3:
|
||||
case COMPRESSION_ZLIB4:
|
||||
case COMPRESSION_ZLIB5:
|
||||
case COMPRESSION_ZLIB6:
|
||||
case COMPRESSION_ZLIB7:
|
||||
case COMPRESSION_ZLIB8:
|
||||
case COMPRESSION_ZLIB9:
|
||||
case COMPRESSION_BTREE:
|
||||
case COMPRESSION_HUFF:
|
||||
case COMPRESSION_REFPACK:
|
||||
return *(Int *)(((UnsignedByte *)mem)+4);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
Int CompressionManager::compressData( CompressionType compType, void *srcVoid, Int srcLen, void *destVoid, Int destLen )
|
||||
{
|
||||
if (destLen < 8)
|
||||
return 0;
|
||||
|
||||
destLen -= 8;
|
||||
|
||||
UnsignedByte *src = (UnsignedByte *)srcVoid;
|
||||
UnsignedByte *dest = (UnsignedByte *)destVoid;
|
||||
|
||||
if (compType == COMPRESSION_BTREE)
|
||||
{
|
||||
memcpy(dest, "EAB\0", 4);
|
||||
*(Int *)(dest+4) = 0;
|
||||
Int ret = BTREE_encode(dest+8, src, srcLen);
|
||||
if (ret)
|
||||
{
|
||||
*(Int *)(dest+4) = srcLen;
|
||||
return ret + 8;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (compType == COMPRESSION_HUFF)
|
||||
{
|
||||
memcpy(dest, "EAH\0", 4);
|
||||
*(Int *)(dest+4) = 0;
|
||||
Int ret = HUFF_encode(dest+8, src, srcLen);
|
||||
if (ret)
|
||||
{
|
||||
*(Int *)(dest+4) = srcLen;
|
||||
return ret + 8;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (compType == COMPRESSION_REFPACK)
|
||||
{
|
||||
memcpy(dest, "EAR\0", 4);
|
||||
*(Int *)(dest+4) = 0;
|
||||
Int ret = REF_encode(dest+8, src, srcLen);
|
||||
if (ret)
|
||||
{
|
||||
*(Int *)(dest+4) = srcLen;
|
||||
return ret + 8;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (compType == COMPRESSION_NOXLZH)
|
||||
{
|
||||
memcpy(dest, "NOX\0", 4);
|
||||
*(Int *)(dest+4) = 0;
|
||||
Bool ret = CompressMemory(src, srcLen, dest+8, destLen);
|
||||
if (ret)
|
||||
{
|
||||
*(Int *)(dest+4) = srcLen;
|
||||
return destLen + 8;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (compType >= COMPRESSION_ZLIB1 && compType <= COMPRESSION_ZLIB9)
|
||||
{
|
||||
Int level = compType - COMPRESSION_ZLIB1 + 1; // 1-9
|
||||
memcpy(dest, "ZL0\0", 4);
|
||||
dest[2] = '0' + level;
|
||||
*(Int *)(dest+4) = 0;
|
||||
|
||||
unsigned long outLen = destLen;
|
||||
Int err = z_compress2( dest+8, &outLen, src, srcLen, level );
|
||||
|
||||
if (err == Z_OK || err == Z_STREAM_END)
|
||||
{
|
||||
*(Int *)(dest+4) = srcLen;
|
||||
return outLen + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(("ZLib compression error (level is %d, src len is %d) %d\n", level, srcLen, err));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int CompressionManager::decompressData( void *srcVoid, Int srcLen, void *destVoid, Int destLen )
|
||||
{
|
||||
if (srcLen < 8)
|
||||
return 0;
|
||||
|
||||
UnsignedByte *src = (UnsignedByte *)srcVoid;
|
||||
UnsignedByte *dest = (UnsignedByte *)destVoid;
|
||||
|
||||
CompressionType compType = getCompressionType(src, srcLen);
|
||||
|
||||
if (compType == COMPRESSION_BTREE)
|
||||
{
|
||||
Int slen = srcLen - 8;
|
||||
Int ret = BTREE_decode(dest, src+8, &slen);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (compType == COMPRESSION_HUFF)
|
||||
{
|
||||
Int slen = srcLen - 8;
|
||||
Int ret = HUFF_decode(dest, src+8, &slen);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (compType == COMPRESSION_REFPACK)
|
||||
{
|
||||
Int slen = srcLen - 8;
|
||||
Int ret = REF_decode(dest, src+8, &slen);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (compType == COMPRESSION_NOXLZH)
|
||||
{
|
||||
Bool ret = DecompressMemory(src+8, srcLen-8, dest, destLen);
|
||||
if (ret)
|
||||
return destLen;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (compType >= COMPRESSION_ZLIB1 && compType <= COMPRESSION_ZLIB9)
|
||||
{
|
||||
#ifdef DEBUG_LOGGING
|
||||
Int level = compType - COMPRESSION_ZLIB1 + 1; // 1-9
|
||||
#endif
|
||||
|
||||
unsigned long outLen = destLen;
|
||||
Int err = z_uncompress(dest, &outLen, src+8, srcLen-8);
|
||||
if (err == Z_OK || err == Z_STREAM_END)
|
||||
{
|
||||
return outLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(("ZLib decompression error (src is level %d, %d bytes long) %d\n", level, srcLen, err));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///// Performance Testing ///////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef TEST_COMPRESSION
|
||||
|
||||
#include "GameClient/MapUtil.h"
|
||||
#include "Common/FileSystem.h"
|
||||
#include "Common/File.h"
|
||||
|
||||
#include "Common/PerfTimer.h"
|
||||
enum { NUM_TIMES = 10 };
|
||||
|
||||
struct CompData
|
||||
{
|
||||
public:
|
||||
Int origSize;
|
||||
Int compressedSize[COMPRESSION_MAX+1];
|
||||
};
|
||||
|
||||
void DoCompressTest( void )
|
||||
{
|
||||
|
||||
Int i;
|
||||
|
||||
PerfGather *s_compressGathers[COMPRESSION_MAX+1];
|
||||
PerfGather *s_decompressGathers[COMPRESSION_MAX+1];
|
||||
for (i = 0; i < COMPRESSION_MAX+1; ++i)
|
||||
{
|
||||
s_compressGathers[i] = new PerfGather(CompressionManager::getCompressionNameByType((CompressionType)i));
|
||||
s_decompressGathers[i] = new PerfGather(CompressionManager::getDecompressionNameByType((CompressionType)i));
|
||||
}
|
||||
|
||||
std::map<AsciiString, CompData> s_sizes;
|
||||
|
||||
std::map<AsciiString, MapMetaData>::const_iterator it = TheMapCache->begin();
|
||||
while (it != TheMapCache->end())
|
||||
{
|
||||
//if (it->second.m_isOfficial)
|
||||
//{
|
||||
//++it;
|
||||
//continue;
|
||||
//}
|
||||
//static Int count = 0;
|
||||
//if (count++ > 2)
|
||||
//break;
|
||||
File *f = TheFileSystem->openFile(it->first.str());
|
||||
if (f)
|
||||
{
|
||||
DEBUG_LOG(("***************************\nTesting '%s'\n\n", it->first.str()));
|
||||
Int origSize = f->size();
|
||||
UnsignedByte *buf = (UnsignedByte *)f->readEntireAndClose();
|
||||
UnsignedByte *uncompressedBuf = NEW UnsignedByte[origSize];
|
||||
|
||||
CompData d = s_sizes[it->first];
|
||||
d.origSize = origSize;
|
||||
d.compressedSize[COMPRESSION_NONE] = origSize;
|
||||
|
||||
for (i=COMPRESSION_MIN; i<=COMPRESSION_MAX; ++i)
|
||||
{
|
||||
DEBUG_LOG(("=================================================\n"));
|
||||
DEBUG_LOG(("Compression Test %d\n", i));
|
||||
|
||||
Int maxCompressedSize = CompressionManager::getMaxCompressedSize( origSize, (CompressionType)i );
|
||||
DEBUG_LOG(("Orig size is %d, max compressed size is %d bytes\n", origSize, maxCompressedSize));
|
||||
|
||||
UnsignedByte *compressedBuf = NEW UnsignedByte[maxCompressedSize];
|
||||
memset(compressedBuf, 0, maxCompressedSize);
|
||||
memset(uncompressedBuf, 0, origSize);
|
||||
|
||||
Int compressedLen, decompressedLen;
|
||||
|
||||
for (Int j=0; j < NUM_TIMES; ++j)
|
||||
{
|
||||
s_compressGathers[i]->startTimer();
|
||||
compressedLen = CompressionManager::compressData((CompressionType)i, buf, origSize, compressedBuf, maxCompressedSize);
|
||||
s_compressGathers[i]->stopTimer();
|
||||
s_decompressGathers[i]->startTimer();
|
||||
decompressedLen = CompressionManager::decompressData(compressedBuf, compressedLen, uncompressedBuf, origSize);
|
||||
s_decompressGathers[i]->stopTimer();
|
||||
}
|
||||
d.compressedSize[i] = compressedLen;
|
||||
DEBUG_LOG(("Compressed len is %d (%g%% of original size)\n", compressedLen, (double)compressedLen/(double)origSize*100.0));
|
||||
DEBUG_ASSERTCRASH(compressedLen, ("Failed to compress\n"));
|
||||
DEBUG_LOG(("Decompressed len is %d (%g%% of original size)\n", decompressedLen, (double)decompressedLen/(double)origSize*100.0));
|
||||
|
||||
DEBUG_ASSERTCRASH(decompressedLen == origSize, ("orig size does not match compressed+uncompressed output\n"));
|
||||
if (decompressedLen == origSize)
|
||||
{
|
||||
Int ret = memcmp(buf, uncompressedBuf, origSize);
|
||||
if (ret != 0)
|
||||
{
|
||||
DEBUG_CRASH(("orig buffer does not match compressed+uncompressed output - ret was %d\n", ret));
|
||||
}
|
||||
}
|
||||
|
||||
delete compressedBuf;
|
||||
compressedBuf = NULL;
|
||||
}
|
||||
|
||||
DEBUG_LOG(("d = %d -> %d\n", d.origSize, d.compressedSize[i]));
|
||||
s_sizes[it->first] = d;
|
||||
DEBUG_LOG(("s_sizes[%s] = %d -> %d\n", it->first.str(), s_sizes[it->first].origSize, s_sizes[it->first].compressedSize[i]));
|
||||
|
||||
delete[] buf;
|
||||
buf = NULL;
|
||||
|
||||
delete[] uncompressedBuf;
|
||||
uncompressedBuf = NULL;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
for (i=COMPRESSION_MIN; i<=COMPRESSION_MAX; ++i)
|
||||
{
|
||||
Real maxCompression = 1000.0f;
|
||||
Real minCompression = 0.0f;
|
||||
Int totalUncompressedBytes = 0;
|
||||
Int totalCompressedBytes = 0;
|
||||
for (std::map<AsciiString, CompData>::iterator cd = s_sizes.begin(); cd != s_sizes.end(); ++cd)
|
||||
{
|
||||
CompData d = cd->second;
|
||||
|
||||
Real ratio = d.compressedSize[i]/(Real)d.origSize;
|
||||
maxCompression = min(maxCompression, ratio);
|
||||
minCompression = max(minCompression, ratio);
|
||||
|
||||
totalUncompressedBytes += d.origSize;
|
||||
totalCompressedBytes += d.compressedSize[i];
|
||||
}
|
||||
DEBUG_LOG(("***************************************************\n"));
|
||||
DEBUG_LOG(("Compression method %s:\n", CompressionManager::getCompressionNameByType((CompressionType)i)));
|
||||
DEBUG_LOG(("%d bytes compressed to %d (%g%%)\n", totalUncompressedBytes, totalCompressedBytes,
|
||||
totalCompressedBytes/(Real)totalUncompressedBytes*100.0f));
|
||||
DEBUG_LOG(("Min ratio: %g%%, Max ratio: %g%%\n",
|
||||
minCompression*100.0f, maxCompression*100.0f));
|
||||
DEBUG_LOG(("\n"));
|
||||
}
|
||||
|
||||
PerfGather::dumpAll(10000);
|
||||
//PerfGather::displayGraph(TheGameLogic->getFrame());
|
||||
PerfGather::resetAll();
|
||||
CopyFile( "AAAPerfStats.csv", "AAACompressPerfStats.csv", FALSE );
|
||||
|
||||
for (i = 0; i < COMPRESSION_MAX+1; ++i)
|
||||
{
|
||||
delete s_compressGathers[i];
|
||||
s_compressGathers[i] = NULL;
|
||||
|
||||
delete s_decompressGathers[i];
|
||||
s_decompressGathers[i] = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // TEST_COMPRESSION
|
105
Generals/Code/Libraries/Source/Compression/EAC/btreeabout.cpp
Normal file
105
Generals/Code/Libraries/Source/Compression/EAC/btreeabout.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
/* ABSTRACT */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* BTree - Binary Tree Codex */
|
||||
/* */
|
||||
/* by FrANK G. Barchard, EAC */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version Date SE History: */
|
||||
/* ------- ---- -- -------- */
|
||||
/* 1.00 950108 FB BTree codex based on hufftree and ref codex */
|
||||
/* 1.01 970117 FB encode check index before going off array */
|
||||
/* 1.02 020716 FB allocate percentage more buffer for large files*/
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Module Notes: */
|
||||
/* ------------- */
|
||||
/* Reentrant */
|
||||
/* Files: btrread.c btrwrite.c btrcodex.h */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Format Notes: */
|
||||
/* ------------- */
|
||||
/* BTree is an EA proprietary compression scheme by Frank Barchard. */
|
||||
/* Each byte is either a raw byte (leaf) or node that points to */
|
||||
/* 2 other nodes. Each node is either a simple byte or 2 nodes. */
|
||||
/* The stream is simple bytes and uses bytes for nodes that werent */
|
||||
/* used in the original file. */
|
||||
/* */
|
||||
/* BTREE (fb6) header format: */
|
||||
/* -------------------------- */
|
||||
/* */
|
||||
/* offset bytes notes */
|
||||
/* id 0 2 id is 46fb */
|
||||
/* ulen 2 3 total unpacked len */
|
||||
/* ilen* 2/5 3 unpacked len for this file */
|
||||
/* clue 5/8 1 */
|
||||
/* nodes 6/9 1 number of nodes */
|
||||
/* { */
|
||||
/* node 7/10+3n 1 */
|
||||
/* left 8/11+3n 1 */
|
||||
/* right 9/12+3n 1 */
|
||||
/* } */
|
||||
/* */
|
||||
/* [packed data] */
|
||||
/* [explicitely packed last byte] */
|
||||
/* */
|
||||
/* * present if composite packed */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* END ABSTRACT */
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "btreecodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Information Functions */
|
||||
/****************************************************************/
|
||||
|
||||
CODEXABOUT *GCALL BTREE_about(void)
|
||||
{
|
||||
CODEXABOUT* info;
|
||||
|
||||
info = (CODEXABOUT*) galloc(sizeof(CODEXABOUT));
|
||||
if (info)
|
||||
{
|
||||
memset(info, 0, sizeof(CODEXABOUT));
|
||||
|
||||
info->signature = QMAKEID('B','T','R','E');
|
||||
info->size = sizeof(CODEXABOUT);
|
||||
info->version = 200; /* codex version number (200) */
|
||||
info->decode = 1; /* supports decoding */
|
||||
info->encode = 1; /* supports encoding */
|
||||
info->size32 = 0; /* supports 32 bit size field */
|
||||
strcpy(info->versionstr, "1.02"); /* version # */
|
||||
strcpy(info->shorttypestr, "btr"); /* type */
|
||||
strcpy(info->longtypestr, "BTree"); /* longtype */
|
||||
}
|
||||
return(info);
|
||||
}
|
||||
|
62
Generals/Code/Libraries/Source/Compression/EAC/btreecodex.h
Normal file
62
Generals/Code/Libraries/Source/Compression/EAC/btreecodex.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved. */
|
||||
|
||||
#ifndef __BTRCODEX
|
||||
#define __BTRCODEX 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __CODEX_H
|
||||
#error "Include codex.h before btreecodex.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* BTR Codex */
|
||||
/****************************************************************/
|
||||
|
||||
/* Information Functions */
|
||||
|
||||
CODEXABOUT *GCALL BTREE_about(void);
|
||||
bool GCALL BTREE_is(const void *compresseddata);
|
||||
|
||||
/* Decode Functions */
|
||||
|
||||
int GCALL BTREE_size(const void *compresseddata);
|
||||
#ifdef __cplusplus
|
||||
int GCALL BTREE_decode(void *dest, const void *compresseddata, int *compressedsize=0);
|
||||
#else
|
||||
int GCALL BTREE_decode(void *dest, const void *compresseddata, int *compressedsize);
|
||||
#endif
|
||||
|
||||
/* Encode Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
int GCALL BTREE_encode(void *compresseddata, const void *source, int sourcesize, int *opts=0);
|
||||
#else
|
||||
int GCALL BTREE_encode(void *compresseddata, const void *source, int sourcesize, int *opts);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
165
Generals/Code/Libraries/Source/Compression/EAC/btreedecode.cpp
Normal file
165
Generals/Code/Libraries/Source/Compression/EAC/btreedecode.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
#ifndef __BTRREAD
|
||||
#define __BTRREAD 1
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "btreecodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Internal Functions */
|
||||
/****************************************************************/
|
||||
|
||||
struct BTreeDecodeContext
|
||||
{
|
||||
signed char cluetbl[256];
|
||||
unsigned char left[256];
|
||||
unsigned char right[256];
|
||||
unsigned char *d;
|
||||
};
|
||||
|
||||
static void BTREE_chase(struct BTreeDecodeContext *DC, unsigned char node)
|
||||
{
|
||||
if (DC->cluetbl[node])
|
||||
{
|
||||
BTREE_chase(DC,DC->left[node]);
|
||||
BTREE_chase(DC,DC->right[node]);
|
||||
return;
|
||||
}
|
||||
*DC->d++ = node;
|
||||
}
|
||||
|
||||
static int BTREE_decompress(unsigned char *packbuf,unsigned char *unpackbuf)
|
||||
{
|
||||
int node;
|
||||
int i;
|
||||
int nodes;
|
||||
int clue;
|
||||
int ulen;
|
||||
unsigned char *s;
|
||||
signed char c;
|
||||
unsigned int type;
|
||||
struct BTreeDecodeContext DC;
|
||||
|
||||
s = packbuf;
|
||||
DC.d = unpackbuf;
|
||||
ulen = 0L;
|
||||
|
||||
if (s)
|
||||
{
|
||||
type = ggetm(s,2);
|
||||
s += 2;
|
||||
|
||||
/* (skip nothing for 0x46fb) */
|
||||
if (type==0x47fb) /* skip ulen */
|
||||
s += 3;
|
||||
|
||||
ulen = ggetm(s,3);
|
||||
s += 3;
|
||||
|
||||
for (i=0;i<256;++i) /* 0 means a code is a leaf */
|
||||
DC.cluetbl[i] = 0;
|
||||
|
||||
clue = *s++;
|
||||
DC.cluetbl[clue] = 1; /* mark clue as special */
|
||||
|
||||
nodes = *s++;
|
||||
for (i=0;i<nodes;++i)
|
||||
{ node = *s++;
|
||||
DC.left[node] = *s++;
|
||||
DC.right[node] = *s++;
|
||||
DC.cluetbl[node] = (signed char)-1;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
node = (int) *s++;
|
||||
c=DC.cluetbl[node];
|
||||
if (!c)
|
||||
{
|
||||
*DC.d++ = (unsigned char) node;
|
||||
continue;
|
||||
}
|
||||
if (c<0)
|
||||
{
|
||||
BTREE_chase(&DC,DC.left[node]);
|
||||
BTREE_chase(&DC,DC.right[node]);
|
||||
continue;
|
||||
}
|
||||
node = (int) *s++;
|
||||
if (node)
|
||||
{
|
||||
*DC.d++ = (char) node;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(ulen);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* Information Functions */
|
||||
/****************************************************************/
|
||||
|
||||
/* check for reasonable header: */
|
||||
/* 46fb header */
|
||||
|
||||
bool GCALL BTREE_is(const void *compresseddata)
|
||||
{
|
||||
bool ok=false;
|
||||
|
||||
if (ggetm(compresseddata,2)==0x46fb
|
||||
|| ggetm(compresseddata,2)==0x47fb)
|
||||
ok = true;
|
||||
|
||||
return(ok);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Decode Functions */
|
||||
/****************************************************************/
|
||||
|
||||
int GCALL BTREE_size(const void *compresseddata)
|
||||
{
|
||||
int len=0;
|
||||
|
||||
if (ggetm(compresseddata,2)==0x46fb)
|
||||
{
|
||||
len = ggetm((char *)compresseddata+2,3);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = ggetm((char *)compresseddata+2+3,3);
|
||||
}
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
int GCALL BTREE_decode(void *dest, const void *compresseddata, int *compressedsize)
|
||||
{
|
||||
return(BTREE_decompress((unsigned char *)compresseddata,(unsigned char *)dest));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
710
Generals/Code/Libraries/Source/Compression/EAC/btreeencode.cpp
Normal file
710
Generals/Code/Libraries/Source/Compression/EAC/btreeencode.cpp
Normal file
|
@ -0,0 +1,710 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
#ifndef __BTRWRITE
|
||||
#define __BTRWRITE 1
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "btreecodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Internal Functions */
|
||||
/****************************************************************/
|
||||
|
||||
#define BTREEWORD short
|
||||
#define BTREECODES 256
|
||||
#define BTREEBIGNUM 32000
|
||||
#define BTREESLOPAGE 16384
|
||||
|
||||
struct BTREEMemStruct
|
||||
{
|
||||
char *ptr;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct BTreeEncodeContext
|
||||
{
|
||||
unsigned int packbits;
|
||||
unsigned int workpattern;
|
||||
unsigned char *bufptr;
|
||||
unsigned int ulen;
|
||||
unsigned int masks[17];
|
||||
unsigned char clueq[BTREECODES];
|
||||
unsigned char right[BTREECODES];
|
||||
unsigned char join[BTREECODES];
|
||||
unsigned int plen;
|
||||
unsigned char *bufbase;
|
||||
unsigned char *bufend;
|
||||
unsigned char *buffer;
|
||||
unsigned char *buf1;
|
||||
unsigned char *buf2;
|
||||
};
|
||||
|
||||
static void BTREE_writebits(struct BTreeEncodeContext *EC,
|
||||
struct BTREEMemStruct *dest,
|
||||
unsigned int bitpattern,
|
||||
unsigned int len)
|
||||
{
|
||||
if (len > 16)
|
||||
{
|
||||
BTREE_writebits(EC,dest,(unsigned int) (bitpattern>>16), len-16);
|
||||
BTREE_writebits(EC,dest,(unsigned int) bitpattern, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
EC->packbits += len;
|
||||
EC->workpattern += (bitpattern & EC->masks[len]) << (24-EC->packbits);
|
||||
while (EC->packbits > 7)
|
||||
{
|
||||
*(dest->ptr+dest->len) = (unsigned char) (EC->workpattern >> 16);
|
||||
++dest->len;
|
||||
|
||||
EC->workpattern = EC->workpattern << 8;
|
||||
EC->packbits -= 8;
|
||||
++EC->plen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void BTREE_adjcount(unsigned char *s, unsigned char *bend, BTREEWORD *count)
|
||||
{
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char b[4];
|
||||
int w;
|
||||
} i;
|
||||
|
||||
#define COUNTADJ(j) i.b[1] = i.b[0]; i.b[0] = *(s+j); ++count[i.w];
|
||||
|
||||
i.w = 0;
|
||||
i.b[0] = (unsigned BTREEWORD) *s++;
|
||||
|
||||
#else
|
||||
|
||||
unsigned BTREEWORD i;
|
||||
|
||||
#define COUNTADJ(j) i = (BTREEWORD)(((i<<8) | *(s+j))); ++*(count+(int)i);
|
||||
|
||||
i = (unsigned BTREEWORD) *s++;
|
||||
|
||||
#endif
|
||||
|
||||
bend -= 16;
|
||||
|
||||
if (s<bend)
|
||||
{
|
||||
do
|
||||
{
|
||||
COUNTADJ(0);
|
||||
COUNTADJ(1);
|
||||
COUNTADJ(2);
|
||||
COUNTADJ(3);
|
||||
|
||||
COUNTADJ(4);
|
||||
COUNTADJ(5);
|
||||
COUNTADJ(6);
|
||||
COUNTADJ(7);
|
||||
|
||||
COUNTADJ(8);
|
||||
COUNTADJ(9);
|
||||
COUNTADJ(10);
|
||||
COUNTADJ(11);
|
||||
|
||||
COUNTADJ(12);
|
||||
COUNTADJ(13);
|
||||
COUNTADJ(14);
|
||||
COUNTADJ(15);
|
||||
s += 16;
|
||||
|
||||
} while (s<bend);
|
||||
}
|
||||
|
||||
bend += 16;
|
||||
|
||||
if (s<bend)
|
||||
{
|
||||
do
|
||||
{
|
||||
COUNTADJ(0);
|
||||
++s;
|
||||
|
||||
} while (s<bend);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear 128 ints (256 words). Done as ints for speed. */
|
||||
|
||||
static void BTREE_clearcount(unsigned char *tryq,BTREEWORD *countbuf)
|
||||
{
|
||||
int zero=0;
|
||||
int i;
|
||||
int j;
|
||||
int *intptr;
|
||||
|
||||
intptr = (int *) countbuf;
|
||||
j = 256;
|
||||
do
|
||||
{
|
||||
if (*tryq)
|
||||
{
|
||||
*tryq++ = 1;
|
||||
|
||||
i = 8;
|
||||
do
|
||||
{
|
||||
*(intptr+0) = zero;
|
||||
*(intptr+1) = zero;
|
||||
*(intptr+2) = zero;
|
||||
*(intptr+3) = zero;
|
||||
|
||||
*(intptr+4) = zero;
|
||||
*(intptr+5) = zero;
|
||||
*(intptr+6) = zero;
|
||||
*(intptr+7) = zero;
|
||||
|
||||
*(intptr+8) = zero;
|
||||
*(intptr+9) = zero;
|
||||
*(intptr+10) = zero;
|
||||
*(intptr+11) = zero;
|
||||
|
||||
*(intptr+12) = zero;
|
||||
*(intptr+13) = zero;
|
||||
*(intptr+14) = zero;
|
||||
*(intptr+15) = zero;
|
||||
intptr += 16;
|
||||
|
||||
} while (--i);
|
||||
}
|
||||
else
|
||||
{
|
||||
++tryq;
|
||||
intptr += 128;
|
||||
}
|
||||
} while (--j);
|
||||
}
|
||||
|
||||
static void BTREE_joinnodes(struct BTreeEncodeContext *EC,
|
||||
unsigned char *cluep,
|
||||
unsigned char *rightp,
|
||||
unsigned char *joinp,
|
||||
unsigned int clue)
|
||||
{
|
||||
unsigned char *s;
|
||||
unsigned char *d;
|
||||
unsigned char *bend;
|
||||
unsigned int i;
|
||||
|
||||
/* pack file */
|
||||
|
||||
s = EC->bufbase;
|
||||
if (s==EC->buf1)
|
||||
{
|
||||
d = EC->buf2;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = EC->buf1;
|
||||
}
|
||||
EC->bufbase = d;
|
||||
bend = EC->bufend;
|
||||
|
||||
*bend = (unsigned char) clue;
|
||||
while (s<=bend)
|
||||
{
|
||||
while (!cluep[(unsigned int) (*d++ = *s++)])
|
||||
;
|
||||
|
||||
i = (unsigned int) *(s-1);
|
||||
|
||||
if (cluep[i]==1)
|
||||
{ if (*s==rightp[i])
|
||||
{ *(d-1) = joinp[i];
|
||||
++s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ if (cluep[i]==3)
|
||||
{ *(d-1) = (unsigned char) clue;
|
||||
*d++ = *(s-1);
|
||||
}
|
||||
else
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
EC->bufend = d-2;
|
||||
}
|
||||
|
||||
|
||||
/* find 48 most common nodes */
|
||||
|
||||
static unsigned int BTREE_findbest(BTREEWORD *countptr,
|
||||
unsigned char *tryq,
|
||||
unsigned int *bestn,
|
||||
unsigned int *bestval,
|
||||
int ratio)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i1;
|
||||
unsigned int i2;
|
||||
unsigned int bestsize;
|
||||
|
||||
unsigned int i3;
|
||||
unsigned int l;
|
||||
|
||||
bestsize = 1;
|
||||
i = 3;
|
||||
l = 0;
|
||||
for (i2=0;i2<256;++i2)
|
||||
{
|
||||
if (tryq[i2])
|
||||
{ for (i1=0;i1<256;++i1)
|
||||
{
|
||||
if (*countptr++>(BTREEWORD)i)
|
||||
{
|
||||
if (tryq[i1])
|
||||
{ i = *(countptr-1);
|
||||
i3=bestsize;
|
||||
while (bestval[i3-1]<i)
|
||||
{
|
||||
bestn[i3] = bestn[i3-1];
|
||||
bestval[i3] = bestval[i3-1];
|
||||
--i3;
|
||||
}
|
||||
bestn[i3] = l+i1;
|
||||
bestval[i3] = i;
|
||||
if (bestsize<48)
|
||||
++bestsize;
|
||||
while (bestval[bestsize-1]<(bestval[1]/ratio))
|
||||
--bestsize;
|
||||
if (bestsize<48)
|
||||
i = bestval[1]/ratio;
|
||||
else
|
||||
i = bestval[bestsize-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
countptr += 256;
|
||||
l += 256;
|
||||
}
|
||||
return(bestsize);
|
||||
}
|
||||
|
||||
static void BTREE_treepack(struct BTreeEncodeContext *EC,
|
||||
struct BTREEMemStruct *dest,
|
||||
unsigned int passes,
|
||||
unsigned int multimax,
|
||||
unsigned int quick,
|
||||
int zerosuppress)
|
||||
{
|
||||
|
||||
unsigned char *bend;
|
||||
unsigned char *ptr1;
|
||||
unsigned char *treebuf;
|
||||
BTREEWORD *count;
|
||||
unsigned int i;
|
||||
unsigned int i1;
|
||||
|
||||
int joinnode, leftnode, rightnode;
|
||||
int ratio;
|
||||
unsigned int hlen;
|
||||
unsigned int domore;
|
||||
unsigned int cost, save;
|
||||
unsigned int tcost, tsave;
|
||||
unsigned int clue;
|
||||
|
||||
unsigned int freeptr;
|
||||
unsigned int count2[BTREECODES];
|
||||
unsigned char tryq[BTREECODES];
|
||||
unsigned char freeq[BTREECODES];
|
||||
|
||||
unsigned int bestsize;
|
||||
unsigned char bestjoin[BTREECODES];
|
||||
unsigned int bestn[BTREECODES];
|
||||
unsigned int bestval[BTREECODES];
|
||||
|
||||
unsigned int bt_size;
|
||||
unsigned int bt_node[BTREECODES];
|
||||
unsigned int bt_left[BTREECODES];
|
||||
unsigned int bt_right[BTREECODES];
|
||||
unsigned int sortptr[BTREECODES];
|
||||
|
||||
int treebufsize;
|
||||
int buf1size;
|
||||
int buf2size;
|
||||
|
||||
// 3/2 allows for worst case, where 2nd most popular
|
||||
treebufsize = 65536L*sizeof(BTREEWORD); /* 131K */
|
||||
buf1size = EC->ulen*3/2+(int)BTREESLOPAGE;
|
||||
buf2size = EC->ulen*3/2+(int)BTREESLOPAGE;
|
||||
|
||||
treebuf = (unsigned char *) galloc(treebufsize);
|
||||
if (!treebuf)
|
||||
return; /* failure Insufficient memory for work buffer */
|
||||
|
||||
EC->buf1 = (unsigned char *) galloc(buf1size);
|
||||
if (!EC->buf1)
|
||||
return; /* failure Insufficient memory for work buffer */
|
||||
|
||||
EC->buf2 = (unsigned char *) galloc(buf2size);
|
||||
if (!EC->buf2)
|
||||
return; /* failure Insufficient memory for work buffer */
|
||||
|
||||
memcpy(EC->buf1, EC->buffer, EC->ulen); /* copy to scratch buffer */
|
||||
|
||||
EC->buffer = EC->buf1;
|
||||
EC->bufptr = EC->buf1+EC->ulen;
|
||||
|
||||
EC->bufbase = EC->buffer;
|
||||
EC->bufend = EC->bufptr;
|
||||
|
||||
count = (BTREEWORD *) treebuf;
|
||||
|
||||
if (quick) ratio = quick;
|
||||
else ratio = 2;
|
||||
|
||||
/*** count file ***/
|
||||
|
||||
for (i=0; i<BTREECODES; ++i)
|
||||
count2[i] = 0;
|
||||
|
||||
i1 = 0;
|
||||
bend = EC->bufptr;
|
||||
ptr1 = EC->buffer;
|
||||
while (ptr1<bend)
|
||||
{ i = (unsigned int) *ptr1++;
|
||||
i1 = i1 + i;
|
||||
++count2[i];
|
||||
}
|
||||
|
||||
/* init clue array */
|
||||
|
||||
for (i=0;i<BTREECODES;++i)
|
||||
EC->clueq[i] = 0;
|
||||
|
||||
/* get a clue byte (forced) */
|
||||
|
||||
for(i=0; i<BTREECODES; ++i)
|
||||
{ freeq[i] = 1;
|
||||
if (count2[i]>3)
|
||||
tryq[i] = 1;
|
||||
else
|
||||
tryq[i] = 0;
|
||||
}
|
||||
|
||||
/* don't use 0 for clue or node (so that [clue][0] is reserved for EOF) */
|
||||
|
||||
count2[0] = BTREEBIGNUM; /* don't use for clue or node */
|
||||
|
||||
/* asciiz btree suppress packing of 0..31 */
|
||||
|
||||
if (zerosuppress)
|
||||
{
|
||||
for (i=0; i<32; ++i)
|
||||
{
|
||||
count2[i] = BTREEBIGNUM; /* don't use for nodes */
|
||||
tryq[i] = 0; /* don't try to pack */
|
||||
freeq[i] = 0; /* don't try to pack */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sort codes with least used codes first */
|
||||
/* primary key is count, secondary key is higher code */
|
||||
|
||||
/* registers vars usage
|
||||
i - code
|
||||
i1 - done flag/swap temp
|
||||
*/
|
||||
|
||||
for (i=0;i<BTREECODES;++i)
|
||||
sortptr[i] = i;
|
||||
|
||||
i1=1;
|
||||
while (i1)
|
||||
{
|
||||
i1 = 0;
|
||||
for (i=1; i<BTREECODES; ++i)
|
||||
{
|
||||
if (count2[sortptr[i]]<count2[sortptr[i-1]] || ((count2[sortptr[i]]==count2[sortptr[i-1]]) && (sortptr[i]>sortptr[i-1])))
|
||||
{
|
||||
i1 = sortptr[i];
|
||||
sortptr[i] = sortptr[i-1];
|
||||
sortptr[i-1] = i1;
|
||||
i1 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeptr = 0;
|
||||
i = sortptr[freeptr++];
|
||||
clue = (unsigned char) i;
|
||||
freeq[i] = 0;
|
||||
tryq[i] = 0;
|
||||
EC->clueq[i] = 3;
|
||||
|
||||
if (count2[i])
|
||||
BTREE_joinnodes(EC,EC->clueq, EC->right, EC->join, clue);
|
||||
|
||||
EC->clueq[i] = 2;
|
||||
|
||||
/* init best array */
|
||||
|
||||
bestval[0] = (unsigned int) -1;
|
||||
|
||||
|
||||
/* count file (pass 2) */
|
||||
|
||||
bt_size = 0;
|
||||
domore = passes;
|
||||
while (domore)
|
||||
{
|
||||
|
||||
/* clear count array */
|
||||
|
||||
BTREE_clearcount(tryq,count);
|
||||
|
||||
/* do an adjacency count */
|
||||
|
||||
ptr1 = EC->bufbase;
|
||||
bend = EC->bufend;
|
||||
|
||||
BTREE_adjcount(ptr1, bend, count);
|
||||
|
||||
/* find most common nodes */
|
||||
|
||||
bestsize = BTREE_findbest(count,tryq,bestn,bestval,ratio);
|
||||
|
||||
/* decide which nodes should be joined to what */
|
||||
|
||||
domore = 0;
|
||||
if (bestsize>1)
|
||||
{
|
||||
tcost = tsave = 0;
|
||||
i = i1 = domore = 1;
|
||||
while (domore)
|
||||
{
|
||||
leftnode = (bestn[i]>>8)&255;
|
||||
rightnode = bestn[i]&255;
|
||||
|
||||
if ((tryq[leftnode]==1) && (tryq[rightnode]==1))
|
||||
{
|
||||
domore = 0;
|
||||
while ((freeptr<BTREECODES) && (!freeq[sortptr[freeptr]]))
|
||||
++freeptr;
|
||||
|
||||
if (freeptr<BTREECODES)
|
||||
{
|
||||
joinnode = sortptr[freeptr];
|
||||
|
||||
cost = 3+count2[joinnode];
|
||||
save = bestval[i];
|
||||
|
||||
if (cost<save)
|
||||
{
|
||||
tcost += cost;
|
||||
tsave += save;
|
||||
|
||||
bestjoin[i1] = (unsigned char) joinnode;
|
||||
bestn[i1] = bestn[i];
|
||||
++i1;
|
||||
|
||||
freeq[joinnode] = 0;
|
||||
tryq[joinnode] = 2;
|
||||
EC->clueq[joinnode] = 3;
|
||||
|
||||
freeq[leftnode] = 0;
|
||||
tryq[leftnode] = 2;
|
||||
EC->clueq[leftnode] = 1;
|
||||
EC->right[leftnode] = (unsigned char) rightnode;
|
||||
EC->join[leftnode] = (unsigned char) joinnode;
|
||||
|
||||
freeq[rightnode] = 0;
|
||||
tryq[rightnode] = 2;
|
||||
|
||||
bt_node[bt_size] = joinnode;
|
||||
bt_left[bt_size] = leftnode;
|
||||
bt_right[bt_size] = rightnode;
|
||||
++bt_size;
|
||||
|
||||
if (i1<=multimax)
|
||||
domore = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
if (i>=bestsize)
|
||||
domore = 0;
|
||||
}
|
||||
|
||||
bestsize = i1;
|
||||
|
||||
if (bestsize>1)
|
||||
{
|
||||
/* multijoin nodes */
|
||||
|
||||
BTREE_joinnodes(EC,EC->clueq, EC->right, EC->join, clue);
|
||||
|
||||
/* restore clue table */
|
||||
|
||||
for(i=1;i<bestsize;++i)
|
||||
{ leftnode = (bestn[i]>>8)&255;
|
||||
joinnode = bestjoin[i];
|
||||
EC->clueq[leftnode] = EC->clueq[joinnode] = 0;
|
||||
}
|
||||
|
||||
domore = --passes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
EC->bufptr = EC->bufend;
|
||||
|
||||
/* write header */
|
||||
|
||||
BTREE_writebits(EC,dest,(unsigned int) clue, 8); /* clue byte */
|
||||
BTREE_writebits(EC,dest,(unsigned int) bt_size, 8); /* tree size */
|
||||
|
||||
for (i=0; i<bt_size;++i)
|
||||
{ BTREE_writebits(EC,dest,(unsigned int) bt_node[i], 8);
|
||||
BTREE_writebits(EC,dest,(unsigned int) bt_left[i], 8);
|
||||
BTREE_writebits(EC,dest,(unsigned int) bt_right[i], 8);
|
||||
}
|
||||
|
||||
hlen = EC->plen;
|
||||
|
||||
/*** write packed file ***/
|
||||
|
||||
ptr1 = EC->bufbase;
|
||||
bend = EC->bufend;
|
||||
|
||||
while (ptr1<bend)
|
||||
BTREE_writebits(EC,dest,(unsigned int) *ptr1++, 8);
|
||||
|
||||
BTREE_writebits(EC,dest,(unsigned int) clue, 8);
|
||||
BTREE_writebits(EC,dest,(unsigned int) 0, 8);
|
||||
|
||||
BTREE_writebits(EC,dest,0L,7); /* flush bits */
|
||||
|
||||
gfree(EC->buf2);
|
||||
gfree(EC->buf1);
|
||||
gfree(treebuf);
|
||||
}
|
||||
|
||||
static int BTREE_compressfile(struct BTreeEncodeContext *EC,
|
||||
struct BTREEMemStruct *infile,
|
||||
struct BTREEMemStruct *outfile,
|
||||
int ulen,
|
||||
int zerosuppress)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned int passes;
|
||||
unsigned int multimax;
|
||||
int flen;
|
||||
|
||||
/* set defaults */
|
||||
|
||||
EC->packbits = 0;
|
||||
|
||||
EC->workpattern = 0L;
|
||||
passes = 256;
|
||||
multimax = 32;
|
||||
EC->masks[0] = 0;
|
||||
for (i=1;i<17;++i)
|
||||
EC->masks[i] = (EC->masks[i-1] << 1) + 1;
|
||||
|
||||
/* read in a source file */
|
||||
|
||||
EC->buffer = (unsigned char *) (infile->ptr);
|
||||
flen = infile->len;
|
||||
|
||||
EC->ulen = flen;
|
||||
EC->bufptr = EC->buffer + flen;
|
||||
|
||||
/* pack a file */
|
||||
|
||||
outfile->ptr = outfile->ptr;
|
||||
outfile->len = 0L;
|
||||
|
||||
EC->packbits = 0;
|
||||
EC->workpattern = 0L;
|
||||
EC->plen = 0L;
|
||||
|
||||
/* write standard header stuff (type/signature/ulen/adjust) */
|
||||
|
||||
/* simple fb6 header */
|
||||
|
||||
if (ulen==infile->len)
|
||||
{
|
||||
BTREE_writebits(EC,outfile,(unsigned int) 0x46fb, 16);
|
||||
BTREE_writebits(EC,outfile,(unsigned int) infile->len, 24);
|
||||
}
|
||||
|
||||
/* composite fb6 header */
|
||||
|
||||
else
|
||||
{
|
||||
BTREE_writebits(EC,outfile,(unsigned int) 0x47fb, 16);
|
||||
BTREE_writebits(EC,outfile,(unsigned int) ulen, 24);
|
||||
BTREE_writebits(EC,outfile,(unsigned int) infile->len, 24);
|
||||
}
|
||||
|
||||
BTREE_treepack(EC,outfile,passes, multimax, 0, zerosuppress);
|
||||
|
||||
return(outfile->len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Encode Function */
|
||||
/****************************************************************/
|
||||
|
||||
int GCALL BTREE_encode(void *compresseddata, const void *source, int sourcesize, int *opts)
|
||||
{
|
||||
int plen;
|
||||
struct BTREEMemStruct infile;
|
||||
struct BTREEMemStruct outfile;
|
||||
struct BTreeEncodeContext EC;
|
||||
int opt=0;
|
||||
if (opts)
|
||||
opt = opts[0];
|
||||
|
||||
infile.ptr = (char *)source;
|
||||
infile.len = sourcesize;
|
||||
outfile.ptr = (char *)compresseddata;
|
||||
outfile.len = sourcesize;
|
||||
|
||||
plen = BTREE_compressfile(&EC,&infile, &outfile, sourcesize, opt);
|
||||
|
||||
return(plen);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
123
Generals/Code/Libraries/Source/Compression/EAC/codex.h
Normal file
123
Generals/Code/Libraries/Source/Compression/EAC/codex.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved. */
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Compression Decompression Exchange(CODEX) v2.00 */
|
||||
/* */
|
||||
/* by FrANK G. Barchard, EAC */
|
||||
/* */
|
||||
/* Header Module - Oct 15, 2001 */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version Date SE History */
|
||||
/* ------- ------ -- ------- */
|
||||
/* 1.00 990824 FB codex API seperated from huff tool */
|
||||
/* 1.01 010427 FB fb6 32 bit size header */
|
||||
/* 1.02 011011 FB c++ defaults */
|
||||
/* 2.00 011015 FB bool, dest/source, new about struct,no QPUBLIC */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __CODEX_H
|
||||
#define __CODEX_H 1
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CODEX_VERSION 200
|
||||
|
||||
/****************************************************************/
|
||||
/* Data Types */
|
||||
/****************************************************************/
|
||||
|
||||
/* Info structure describing bitmaps */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int signature; /* signature of codex ie 'tga ' (optional) */
|
||||
int size; /* size of CODEXABOUT structure */
|
||||
int version; /* version number of CODEXABOUT structure (200) */
|
||||
|
||||
unsigned int decode :1; /* supports decoding */
|
||||
unsigned int encode :1; /* supports encoding */
|
||||
unsigned int size32 :1; /* support 32 bit size field */
|
||||
unsigned int pad :29;
|
||||
|
||||
char versionstr[8]; /* version number of codex module ie 1.00 */
|
||||
char shorttypestr[8]; /* 3 or 4 character type string ie ref */
|
||||
char longtypestr[16]; /* full name of data format ie Refpack */
|
||||
} CODEXABOUT;
|
||||
|
||||
#define QMAKEID(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))
|
||||
|
||||
#if !defined(GCALL)
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#define GCALL __stdcall
|
||||
#else
|
||||
#define GCALL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct QFUNCTIONS
|
||||
{
|
||||
CODEXABOUT * (GCALL * CODEX_about)(void);
|
||||
bool (GCALL * CODEX_is)(const void *compressed);
|
||||
int (GCALL * CODEX_size)(const void *compressed);
|
||||
int (GCALL * CODEX_decode)(void *dest, const void *source, int *sourcesizeptr);
|
||||
int (GCALL * CODEX_encode)(void *dest, const void *source, int sourcesize, int *opts);
|
||||
} QFUNCTIONS;
|
||||
|
||||
extern struct QFUNCTIONS qfunctions[];
|
||||
|
||||
/****************************************************************/
|
||||
/* Codex Module Example Prototypes */
|
||||
/****************************************************************/
|
||||
|
||||
#include "gimex.h" /* for memory IO */
|
||||
|
||||
/* Information Functions */
|
||||
|
||||
CODEXABOUT *GCALL CODEX_about(void);
|
||||
bool GCALL CODEX_is(const void *source);
|
||||
int GCALL CODEX_size(const void *source);
|
||||
|
||||
/* Decode/Encode Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
int GCALL CODEX_decode(void *dest, const void *source, int *sourcesizeptr=0);
|
||||
int GCALL CODEX_encode(void *dest, const void *source, int sourcesize, int *opts=0);
|
||||
#else
|
||||
int GCALL CODEX_decode(void *dest, const void *source, int *sourcesizeptr);
|
||||
int GCALL CODEX_encode(void *dest, const void *source, int sourcesize, int *opts);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
497
Generals/Code/Libraries/Source/Compression/EAC/gimex.h
Normal file
497
Generals/Code/Libraries/Source/Compression/EAC/gimex.h
Normal file
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Copyright (C) Electronic Arts Canada Inc. 1994-2002. All rights reserved. */
|
||||
|
||||
/* ABSTRACT
|
||||
gimex.h - Primary header file for the GIMEX API.
|
||||
@ */
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Graphics IMport EXport API v3.46 */
|
||||
/* */
|
||||
/* by Frank Barchard, EAC */
|
||||
/* */
|
||||
/* Header Module - Dec 05, 2002 */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version Date SE History */
|
||||
/* ------- ------ -- ------- */
|
||||
/* 3.01 ------ FB gref void * */
|
||||
/* 3.02 ------ FB const GIMEX_write */
|
||||
/* 3.10 ------ FB 16 bpp import */
|
||||
/* 3.11 ------ FB gbitmap->image void * */
|
||||
/* 3.12 ------ FB about importstream, exportstream, maxredbits et*/
|
||||
/* 3.13 ------ FB about->movie */
|
||||
/* 3.14 ------ FB GFUNCTIONS table declared */
|
||||
/* 3.15 ------ FB about->mipmap */
|
||||
/* 3.16 ------ FB about->font */
|
||||
/* 3.17 ------ FB linux use intel ordered ARGB */
|
||||
/* 3.20 ------ FB 64 bit file system (GPOS), removed ARGB16 */
|
||||
/* 3.21 ------ FB 64 bit backwards compatibility with 32 */
|
||||
/* 3.22 ------ FB 32 bit file implementation for efficiency */
|
||||
/* 3.23 ------ FB bitfield warning removed */
|
||||
/* 3.24 010426 FB GIMEX_read/write take void * prototyped here */
|
||||
/* 3.25 010427 FB about width/height max,align and obsolete */
|
||||
/* 3.26 010501 FB INT64 for gcc 2.95.3 on ps2 use long */
|
||||
/* 3.27 010504 FB removed _ARGB_T - use ARGB. add GC reference */
|
||||
/* 3.30 010614 LC update for 330 release */
|
||||
/* 3.31 010628 FB GIMEX_COMMENT_SIZE 1024 */
|
||||
/* 3.32 011009 FB about->file64 for 64 bit file sizes */
|
||||
/* 3.40 011022 FB bool returns, ggetm inline, 512 GIMEX_FRAME... */
|
||||
/* 3.41 020225 FB metalbin 240 on ps2 */
|
||||
/* 3.44 020307 FB bumped for next release. no api change */
|
||||
/* 3.45 020927 FB geti 3 bounds safe/purify */
|
||||
/* 3.46 021205 FB about firstextension */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __GIMEX_H
|
||||
#define __GIMEX_H 1
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#pragma warning(disable : 4100)
|
||||
/* warning C4100: unreferenced parameter */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GIMEX_VERSION 346
|
||||
#define GIMEX_PATCH 0
|
||||
|
||||
/****************************************************************************/
|
||||
/* Data Types */
|
||||
/****************************************************************************/
|
||||
|
||||
/* ARGB structure used for palettes/pixels */
|
||||
|
||||
// experimental float channel
|
||||
|
||||
#ifdef GIMEXFLOAT
|
||||
typedef float GCHANNEL;
|
||||
#else
|
||||
typedef unsigned char GCHANNEL;
|
||||
#endif
|
||||
|
||||
#ifndef ARGB
|
||||
#define ARGB ARGB
|
||||
#if defined(_MSC_VER) || defined(__i386__)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GCHANNEL b,g,r,a;
|
||||
} ARGB;
|
||||
|
||||
#elif defined(__R5900) || defined(SGI) /* PS2 */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GCHANNEL r,g,b,a;
|
||||
} ARGB;
|
||||
|
||||
#else /* GameCube/Mac */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GCHANNEL a,r,g,b;
|
||||
} ARGB;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(GPOS)
|
||||
#if defined(_MSC_VER)
|
||||
typedef __int64 GPOS;
|
||||
#elif defined(__R5900)
|
||||
typedef long GPOS;
|
||||
#else
|
||||
typedef long long GPOS;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Info structure describing bitmaps */
|
||||
|
||||
#define GIMEX_FRAMENAME_SIZE 512
|
||||
#define GIMEX_COMMENT_SIZE 1024
|
||||
#define GIMEX_COLOURTBL_SIZE 256
|
||||
#define GIMEX_HOTSPOTTBL_SIZE 1024
|
||||
#define GIMEX_HOTSPOTTBL_VALUES 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int signature; /* signature of gimex ie 'tga ' (optional) */
|
||||
int size; /* size of GINFO structure */
|
||||
int version; /* version number of GINFO structure (300) */
|
||||
int framenum; /* current frame */
|
||||
int width; /* width of bitmap in pixels */
|
||||
int height; /* height of bitmap in pixels */
|
||||
int bpp; /* bits per pixel (8, 16 or 32) */
|
||||
int originalbpp; /* bits per pixel in original image (1 to 32) */
|
||||
int startcolour; /* first colour in palette */
|
||||
int numcolours; /* number of colours in original indexed palette */
|
||||
ARGB colourtbl[GIMEX_COLOURTBL_SIZE]; /* 8 bit palette */
|
||||
int subtype; /* internal format sub-type 0-default */
|
||||
int packed; /* type of packing on original image. 0 none, 1 run, n other */
|
||||
int quality; /* quality of lossy packing 0..100 */
|
||||
int framesize; /* size of frame in bytes */
|
||||
int alphabits; /* number of bits in alpha channel */
|
||||
int redbits; /* number of bits in red channel */
|
||||
int greenbits; /* number of bits in green channel */
|
||||
int bluebits; /* number of bits in blue channel */
|
||||
int centerx; /* center point relative to upper left corner */
|
||||
int centery;
|
||||
int defaultx; /* default coordinate point */
|
||||
int defaulty;
|
||||
int numhotspots; /* number of hot spots defined */
|
||||
char framename[GIMEX_FRAMENAME_SIZE]; /* null terminated name of frame/image */
|
||||
char comment[GIMEX_COMMENT_SIZE]; /* null terminated multiline user comment */
|
||||
int hotspottbl[GIMEX_HOTSPOTTBL_SIZE][GIMEX_HOTSPOTTBL_VALUES];/* up to 256 hot spots, XY pairs relative to upperleft */
|
||||
float dpi; /* dots per inch ie 72.0 */
|
||||
float fps; /* frame per second (one over duration). 15.0 is typical */
|
||||
int reserved[3]; /* reserved for future use - set to zero */
|
||||
} GINFO;
|
||||
|
||||
typedef struct GSTREAM GSTREAM; /* handle used for file functions */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int signature; /* signature of gimex ie '.tga' (optional) */
|
||||
int size; /* size of GINSTANCE structure */
|
||||
int frames; /* Number of frames in file */
|
||||
int framenum; /* current frame (optional) */
|
||||
GSTREAM *gstream; /* stream pointer for file */
|
||||
void *gref; /* gimex reference to additional memory used by module (optional) */
|
||||
} GINSTANCE;
|
||||
|
||||
/* Info structure describing bitmaps */
|
||||
|
||||
#define MAXMACTYPES 8
|
||||
#define MAXEXTENSIONS 8
|
||||
|
||||
#define GIMEX_EXTENSION_SIZE 8
|
||||
#define GIMEX_AUTHORSTR_SIZE 32
|
||||
#define GIMEX_VERSIONSTR_SIZE 8
|
||||
#define GIMEX_SHORTTYPESTR_SIZE 8
|
||||
#define GIMEX_WORDTYPESTR_SIZE 16
|
||||
#define GIMEX_LONGTYPESTR_SIZE 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int signature; /* signature of gimex ie 'tga ' (optional) */
|
||||
int size; /* size of GABOUT structure */
|
||||
int version; /* version number of GABOUT structure (200) */
|
||||
unsigned int canimport :1; /* supports importing */
|
||||
unsigned int canexport :1; /* supports exporting */
|
||||
unsigned int importpacked :2; /* max import packed field 0..3 */
|
||||
unsigned int exportpacked :2; /* max export packed field 0..3 */
|
||||
unsigned int import8 :1; /* supports importing 8 bit indexed */
|
||||
unsigned int export8 :1; /* supports exporting 8 bit indexed */
|
||||
unsigned int import32 :1; /* supports importing 32 bit direct rgb */
|
||||
unsigned int export32 :1; /* supports exporting 32 bit direct rgb */
|
||||
unsigned int multiframe :1; /* supports multiple frames */
|
||||
unsigned int multifile :1; /* format requires additional files or resource fork */
|
||||
unsigned int multisize :1; /* supports different size per frame */
|
||||
unsigned int framebuffer :1; /* module requires memory to buffer entire frame */
|
||||
unsigned int external :1; /* uses external resources */
|
||||
unsigned int usesfile :1; /* module is file based vs ads/printer/generator */
|
||||
unsigned int globalpalette :1; /* limited to a single palette per file */
|
||||
unsigned int greyscale :1; /* use maxcolours for number of levels */
|
||||
unsigned int startcolour :1; /* supports start colour */
|
||||
unsigned int dotsubtype :1; /* subtype based on extension */
|
||||
unsigned int resizable :1; /* read will respect ginfo width & height */
|
||||
unsigned int reserved2 :1; /* reserved for future use */
|
||||
unsigned int reserved3 :1; /* reserved for future use */
|
||||
unsigned int importstream :1; /* supports open with GIMEX_NOFRAMECOUNT */
|
||||
unsigned int exportstream :1; /* will ignore frame count on export */
|
||||
unsigned int movie :1; /* this is a movie format (as opposed to mipmaps, fonts or multipage) */
|
||||
unsigned int mipmap :1; /* mipmaps are supported and will constrain sizes */
|
||||
unsigned int font :1; /* this is a font format */
|
||||
unsigned int obsolete :1; /* this format is obsolete */
|
||||
unsigned int file64 :1; /* this format supports 64 bit file sizes */
|
||||
unsigned int firstextension:1; /* use first extension when assigning default name */
|
||||
unsigned int pad :1; /* pad bitfield to 32 bit boundary for inter compiler compatibility */
|
||||
int maxcolours; /* only use in 8 bit, 0 if module does not care */
|
||||
int maxframename; /* maximum characters in ginfo framename */
|
||||
int defaultquality; /* default pack quality */
|
||||
int mactype[MAXMACTYPES]; /* mac file system types used */
|
||||
char extensions[MAXEXTENSIONS][GIMEX_EXTENSION_SIZE]; /* null terminated extensions with '.' */
|
||||
char authorstr[GIMEX_AUTHORSTR_SIZE]; /* name of gimex module author */
|
||||
char versionstr[GIMEX_VERSIONSTR_SIZE]; /* version number of gimex module ie 1.00 */
|
||||
char shorttypestr[GIMEX_SHORTTYPESTR_SIZE]; /* 3 or 4 character type string ie TGA */
|
||||
char wordtypestr[GIMEX_WORDTYPESTR_SIZE]; /* single word type string ie Targa */
|
||||
char longtypestr[GIMEX_LONGTYPESTR_SIZE]; /* full name of data format ie True Vision Targa */
|
||||
unsigned int maxalphabits:8; /* maximum supported number of bits in alpha channel */
|
||||
unsigned int maxredbits :8; /* maximum supported number of bits in red channel */
|
||||
unsigned int maxgreenbits:8; /* maximum supported number of bits in green channel */
|
||||
unsigned int maxbluebits :8; /* maximum supported number of bits in blue channel */
|
||||
unsigned int maxwidth; /* maximum width in pixels */
|
||||
unsigned int maxheight; /* maximum height in pixels */
|
||||
unsigned int alignwidth; /* width must be multiple of this in pixels */
|
||||
unsigned int alignheight; /* height must be multiple of this in pixels */
|
||||
unsigned int pad2[4];
|
||||
} GABOUT;
|
||||
|
||||
/* Bitmap structure (optional) */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GINFO *ginfo;
|
||||
void *image;
|
||||
int rowbytes;
|
||||
} GBITMAP;
|
||||
|
||||
#ifndef GMAKEID
|
||||
#define GMAKEID(a,b,c,d) (((int)(a)<<24)|((int)(b)<<16)|((int)(c)<<8)|(int)(d))
|
||||
#endif
|
||||
|
||||
#ifndef gmin
|
||||
#define gmin(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef gmax
|
||||
#define gmax(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#if !defined(GCALL)
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#define GCALL __stdcall
|
||||
#else
|
||||
#define GCALL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(__cplusplus) && !defined(bool)
|
||||
#define bool bool
|
||||
typedef enum{ False=0x0, True=0x1}bool;
|
||||
#endif
|
||||
|
||||
typedef struct GFUNCTIONS
|
||||
{
|
||||
GABOUT * (GCALL * GIMEX_about)(void);
|
||||
int (GCALL * GIMEX_is)(GSTREAM *g);
|
||||
int (GCALL * GIMEX_open)(GINSTANCE **gx, GSTREAM *g, const char *pathname,bool framecountflag);
|
||||
GINFO * (GCALL * GIMEX_info)(GINSTANCE *gx, int framenum);
|
||||
int (GCALL * GIMEX_read)(GINSTANCE *gx, GINFO *ginfo, char *dest, int rowbytes);
|
||||
int (GCALL * GIMEX_close)(GINSTANCE *gx);
|
||||
int (GCALL * GIMEX_wopen)(GINSTANCE **gx, GSTREAM *g, const char *pathname, int numframes);
|
||||
int (GCALL * GIMEX_write)(GINSTANCE *gx, const GINFO *ginfo, char *source, int rowbytes);
|
||||
int (GCALL * GIMEX_wclose)(GINSTANCE *gx);
|
||||
} GFUNCTIONS;
|
||||
|
||||
extern struct GFUNCTIONS gfunctions[];
|
||||
|
||||
/****************************************************************************/
|
||||
/* Gimex Module Example Prototypes */
|
||||
/****************************************************************************/
|
||||
|
||||
/* valid values to be passed to framecountflag parameter for the GIMEX_open function */
|
||||
#ifdef __cplusplus
|
||||
#define GIMEX_FRAMECOUNT true
|
||||
#define GIMEX_NOFRAMECOUNT false
|
||||
#else
|
||||
#define GIMEX_FRAMECOUNT 0x1
|
||||
#define GIMEX_NOFRAMECOUNT 0x0
|
||||
#endif
|
||||
/* Information Functions */
|
||||
|
||||
GABOUT *GCALL GIMEX_about(void);
|
||||
int GCALL GIMEX_is(GSTREAM *g);
|
||||
|
||||
/* Import Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
int GCALL GIMEX_open(GINSTANCE **gx, GSTREAM *g, const char *pathname, bool framecountflag=GIMEX_FRAMECOUNT);
|
||||
#else
|
||||
int GCALL GIMEX_open(GINSTANCE **gx, GSTREAM *g, const char *pathname, bool framecountflag);
|
||||
#endif
|
||||
GINFO * GCALL GIMEX_info(GINSTANCE *gx, int framenum);
|
||||
bool GCALL GIMEX_read(GINSTANCE *gx, const GINFO *ginfo, void *dest, int rowbytes);
|
||||
bool GCALL GIMEX_close(GINSTANCE *gx);
|
||||
|
||||
/* Example Export Functions */
|
||||
|
||||
bool GCALL GIMEX_wopen(GINSTANCE **gx, GSTREAM *g, const char *pathname, int numframes);
|
||||
bool GCALL GIMEX_write(GINSTANCE *gx, const GINFO *ginfo, const void *source, int rowbytes);
|
||||
bool GCALL GIMEX_wclose(GINSTANCE *gx);
|
||||
|
||||
/****************************************************************************/
|
||||
/* Application Module Prototypes */
|
||||
/****************************************************************************/
|
||||
|
||||
/* File Stream Functions */
|
||||
|
||||
GSTREAM * GCALL gopen(const char *pathname);
|
||||
GSTREAM * GCALL gwopen(const char *pathname);
|
||||
bool GCALL gclose(GSTREAM *g);
|
||||
int GCALL gread(GSTREAM *g, void *buf, int size);
|
||||
int GCALL gwrite(GSTREAM *g, const void *buf, int size);
|
||||
bool GCALL gseek(GSTREAM *g, GPOS offset);
|
||||
GPOS GCALL glen(GSTREAM *g);
|
||||
GPOS GCALL gtell(GSTREAM *g);
|
||||
|
||||
/* Memory Functions */
|
||||
|
||||
#if !defined(galloc)
|
||||
#include <stdlib.h>
|
||||
#define galloc malloc
|
||||
//void * GCALL galloc(int size);
|
||||
#endif
|
||||
//bool GCALL gfree(void *memptr);
|
||||
#define gfree free
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
/* Inline C++ (cross platform) */
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4514) // unreferenced inline function has been removed
|
||||
#endif
|
||||
|
||||
/* get motorola memory */
|
||||
static __inline unsigned int ggetm(const void *src, int bytes)
|
||||
{
|
||||
if (bytes==1)
|
||||
return (unsigned int) *(const unsigned char *) src;
|
||||
#if defined(__APPLE__) || (defined(__MWERKS__) && defined(__PPCGEKKO__))
|
||||
else if (bytes==2)
|
||||
return (unsigned int) *(const unsigned short *) src;
|
||||
else if (bytes==4)
|
||||
return (unsigned int) *(const unsigned int *) src;
|
||||
#else
|
||||
else if (bytes==2)
|
||||
return (((unsigned int) *(const unsigned char *) src)<<8) | (((unsigned int) *((const unsigned char *) src+1)));
|
||||
else if (bytes==4)
|
||||
return (((unsigned int) *(const unsigned char *) src)<<24) | (((unsigned int) *((const unsigned char *) src+1))<<16) | (((unsigned int) *((const unsigned char *) src+2))<<8) | (((unsigned int) *((const unsigned char *) src+3)));
|
||||
#endif
|
||||
else if (bytes==3)
|
||||
return (((unsigned int) *(const unsigned char *) src)<<16) | (((unsigned int) *((const unsigned char *) src+1))<<8) | (((unsigned int) *((const unsigned char *) src+2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get intel memory */
|
||||
|
||||
static __inline unsigned int ggeti(const void *src, int bytes)
|
||||
{
|
||||
if (bytes==1)
|
||||
return (unsigned int) *(const unsigned char *) src;
|
||||
#if defined(_MSC_VER) || defined(__i386__)
|
||||
else if (bytes==2)
|
||||
return (unsigned int) *(const unsigned short *) src;
|
||||
else if (bytes==4)
|
||||
return (unsigned int) *(const unsigned int *) src;
|
||||
#else
|
||||
else if (bytes==2)
|
||||
return (((unsigned int) *((const unsigned char *) src+1))<<8) | (((unsigned int) *(const unsigned char *) src+0));
|
||||
else if (bytes==4)
|
||||
return (((unsigned int) *((const unsigned char *) src+3))<<24) | (((unsigned int) *((const unsigned char *) src+2))<<16) | (((unsigned int) *((const unsigned char *) src+1))<<8) | (((unsigned int) *(const unsigned char *) src+0));
|
||||
#endif
|
||||
else if (bytes==3)
|
||||
return (((unsigned int) *((const unsigned char *) src+2))<<16) | (((unsigned int) *((const unsigned char *) src+1))<<8) | (((unsigned int) *(const unsigned char *) src+0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* put motorolla memory */
|
||||
|
||||
static __inline void gputm(void *dst, unsigned int data, int bytes)
|
||||
{
|
||||
if (bytes==1)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) data;
|
||||
}
|
||||
#if defined(__APPLE__) || (defined(__MWERKS__) && defined(__PPCGEKKO__))
|
||||
else if (bytes==2)
|
||||
{
|
||||
((unsigned short *) dst)[0] = (unsigned short) data;
|
||||
}
|
||||
else if (bytes==4)
|
||||
{
|
||||
((unsigned int *) dst)[0] = (unsigned int) data;
|
||||
}
|
||||
#else
|
||||
else if (bytes==2)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) (data>>8);
|
||||
((unsigned char *) dst)[1] = (unsigned char) data;
|
||||
}
|
||||
else if (bytes==4)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) (data>>24);
|
||||
((unsigned char *) dst)[1] = (unsigned char) (data>>16);
|
||||
((unsigned char *) dst)[2] = (unsigned char) (data>>8);
|
||||
((unsigned char *) dst)[3] = (unsigned char) data;
|
||||
}
|
||||
#endif
|
||||
else if (bytes==3)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) (data>>16);
|
||||
((unsigned char *) dst)[1] = (unsigned char) (data>>8);
|
||||
((unsigned char *) dst)[2] = (unsigned char) data;
|
||||
}
|
||||
}
|
||||
|
||||
/* put intel memory */
|
||||
|
||||
static __inline void gputi(void *dst, unsigned int data, int bytes)
|
||||
{
|
||||
if (bytes==1)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) data;
|
||||
}
|
||||
#if defined(_MSC_VER) || defined(__i386__)
|
||||
else if (bytes==2)
|
||||
{
|
||||
((unsigned short *) dst)[0] = (unsigned short) data;
|
||||
}
|
||||
else if (bytes==4)
|
||||
{
|
||||
((unsigned int *) dst)[0] = (unsigned int) data;
|
||||
}
|
||||
#else
|
||||
else if (bytes==2)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) data;
|
||||
((unsigned char *) dst)[1] = (unsigned char) (data>>8);
|
||||
}
|
||||
else if (bytes==4)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) data;
|
||||
((unsigned char *) dst)[1] = (unsigned char) (data>>8);
|
||||
((unsigned char *) dst)[2] = (unsigned char) (data>>16);
|
||||
((unsigned char *) dst)[3] = (unsigned char) (data>>24);
|
||||
}
|
||||
#endif
|
||||
else if (bytes==3)
|
||||
{
|
||||
((unsigned char *) dst)[0] = (unsigned char) data;
|
||||
((unsigned char *) dst)[1] = (unsigned char) (data>>8);
|
||||
((unsigned char *) dst)[2] = (unsigned char) (data>>16);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __GIMEX_H */
|
||||
|
||||
/* END ABSTRACT */
|
88
Generals/Code/Libraries/Source/Compression/EAC/huffabout.cpp
Normal file
88
Generals/Code/Libraries/Source/Compression/EAC/huffabout.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
/* ABSTRACT */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Huffman - Huffman with Runlength Codex */
|
||||
/* */
|
||||
/* by FrANK G. Barchard, EAC */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version Date SE History: */
|
||||
/* ------- ---- -- -------- */
|
||||
/* 1.00 950108 FB based on huff and ref codex */
|
||||
/* 1.01 950316 FB delta huff and delta delta huff */
|
||||
/* 1.02 950317 FB quick table version (used in wing3) */
|
||||
/* 1.03 950626 FB allocate context instead of on stack */
|
||||
/* 1.04 010608 ID forgot to undelta big size buffer fix */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Module Notes: */
|
||||
/* ------------- */
|
||||
/* Reentrant */
|
||||
/* Files: hufread.c hufwrite.c hufcodex.h */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Format Notes: */
|
||||
/* ------------- */
|
||||
/* *30fb fb6 huff 6.1 EOF only huff */
|
||||
/* *31fb fb6 huff 6.1 ' ' ' composite */
|
||||
/* *32fb fb6 huff 6.1 EOF only speed */
|
||||
/* *33fb fb6 huff 6.1 ' ' ' composite */
|
||||
/* *34fb fb6 huff 6.1 EOF only acceleration */
|
||||
/* *35fb fb6 huff 6.1 ' ' ' composite */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* END ABSTRACT */
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "huffcodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Information Functions */
|
||||
/****************************************************************/
|
||||
|
||||
CODEXABOUT *GCALL HUFF_about(void)
|
||||
{
|
||||
CODEXABOUT *info;
|
||||
|
||||
info = (CODEXABOUT *) galloc(sizeof(CODEXABOUT));
|
||||
if (info)
|
||||
{
|
||||
memset(info, 0, sizeof(CODEXABOUT));
|
||||
|
||||
info->signature = QMAKEID('H','U','F','F');
|
||||
info->size = sizeof(CODEXABOUT);
|
||||
info->version = 200; /* codex version number (200) */
|
||||
info->decode = 1; /* supports decoding */
|
||||
info->encode = 1; /* supports encoding */
|
||||
info->size32 = 0; /* supports 32 bit size field */
|
||||
strcpy(info->versionstr, "1.04"); /* version # */
|
||||
strcpy(info->shorttypestr, "huff"); /* type */
|
||||
strcpy(info->longtypestr, "Huffman"); /* longtype */
|
||||
}
|
||||
return(info);
|
||||
}
|
||||
|
74
Generals/Code/Libraries/Source/Compression/EAC/huffcodex.h
Normal file
74
Generals/Code/Libraries/Source/Compression/EAC/huffcodex.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved. */
|
||||
|
||||
#ifndef __HUFCODEX
|
||||
#define __HUFCODEX 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __CODEX_H
|
||||
#error "Include codex.h before huffcodex.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* HUF Codex */
|
||||
/****************************************************************/
|
||||
|
||||
/* Information Functions */
|
||||
|
||||
CODEXABOUT *GCALL HUFF_about(void);
|
||||
bool GCALL HUFF_is(const void *compresseddata);
|
||||
|
||||
/* Decode Functions */
|
||||
|
||||
int GCALL HUFF_size(const void *compresseddata);
|
||||
#ifdef __cplusplus
|
||||
int GCALL HUFF_decode(void *dest, const void *compresseddata, int *compressedsize=0);
|
||||
#else
|
||||
int GCALL HUFF_decode(void *dest, const void *compresseddata, int *compressedsize);
|
||||
#endif
|
||||
|
||||
/* Encode Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
int GCALL HUFF_encode(void *compresseddata, const void *source, int sourcesize, int *opts=0);
|
||||
#else
|
||||
int GCALL HUFF_encode(void *compresseddata, const void *source, int sourcesize, int *opts);
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* Internal */
|
||||
/****************************************************************/
|
||||
|
||||
#ifndef qmin
|
||||
#define qmin(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef qmax
|
||||
#define qmax(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
570
Generals/Code/Libraries/Source/Compression/EAC/huffdecode.cpp
Normal file
570
Generals/Code/Libraries/Source/Compression/EAC/huffdecode.cpp
Normal file
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
#ifndef __HUFREAD
|
||||
#define __HUFREAD 1
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "huffcodex.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push,1)
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* Internal Functions */
|
||||
/****************************************************************/
|
||||
|
||||
struct HuffDecodeContext
|
||||
{
|
||||
unsigned char *s;
|
||||
int bitsleft;
|
||||
unsigned int bits;
|
||||
};
|
||||
|
||||
/****************************************************************/
|
||||
/* Huffman Unpacker */
|
||||
/****************************************************************/
|
||||
|
||||
static int ZERO=0;
|
||||
|
||||
#define GET16BITS() \
|
||||
bitsunshifted = qs[0] | (bitsunshifted << 8);\
|
||||
bitsunshifted = qs[1] | (bitsunshifted << 8);\
|
||||
qs += 2;
|
||||
|
||||
|
||||
#define SQgetbits(v,n)\
|
||||
if (n) \
|
||||
{ \
|
||||
v = bits >> (32-(n));\
|
||||
bits <<= (n);\
|
||||
bitsleft -= (n);\
|
||||
} \
|
||||
\
|
||||
if (bitsleft<0)\
|
||||
{\
|
||||
GET16BITS() \
|
||||
\
|
||||
bits = bitsunshifted<<(-bitsleft);\
|
||||
bitsleft += 16;\
|
||||
}
|
||||
|
||||
|
||||
#define SQgetnum(v) \
|
||||
if ((int)bits<0)\
|
||||
{\
|
||||
SQgetbits(v,3);\
|
||||
v -= 4;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
int n;\
|
||||
unsigned int v1;\
|
||||
\
|
||||
if (bits>>16)\
|
||||
{\
|
||||
n=2;\
|
||||
do\
|
||||
{\
|
||||
bits <<= 1; \
|
||||
++n;\
|
||||
}\
|
||||
while ((int)bits>=0);\
|
||||
bits <<= 1;\
|
||||
bitsleft -= (n-1);\
|
||||
SQgetbits(v,ZERO);\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
n=2;\
|
||||
do\
|
||||
{\
|
||||
++n;\
|
||||
SQgetbits(v,1);\
|
||||
}\
|
||||
while (!v);\
|
||||
}\
|
||||
if (n>16)\
|
||||
{\
|
||||
SQgetbits(v,n-16);\
|
||||
SQgetbits(v1,16);\
|
||||
v = (v1|(v<<16))+(1<<n)-4;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
SQgetbits(v,n);\
|
||||
v = (v+(1<<n)-4);\
|
||||
}\
|
||||
}
|
||||
|
||||
/* note: requires 'amt' be a multiple of 16 */
|
||||
#define SQmemset(ptr, val, amt) \
|
||||
{\
|
||||
int i = amt/16;\
|
||||
int intval = (val<<24)|(val<<16)|(val<<8)|val;\
|
||||
int* lptr = (int*)ptr;\
|
||||
\
|
||||
while (i)\
|
||||
{\
|
||||
lptr[0] = intval;\
|
||||
lptr[1] = intval;\
|
||||
lptr[2] = intval;\
|
||||
lptr[3] = intval;\
|
||||
lptr += 4;\
|
||||
--i;\
|
||||
}\
|
||||
}\
|
||||
|
||||
static int HUFF_decompress(unsigned char *packbuf, unsigned char *unpackbuf)
|
||||
{
|
||||
unsigned int type;
|
||||
unsigned char clue;
|
||||
int ulen;
|
||||
unsigned int cmp;
|
||||
int bitnum=0;
|
||||
int cluelen=0;
|
||||
unsigned char *qs;
|
||||
unsigned char *qd;
|
||||
unsigned int bits;
|
||||
unsigned int bitsunshifted=0;
|
||||
int numbits;
|
||||
int bitsleft;
|
||||
unsigned int v;
|
||||
|
||||
qs = packbuf;
|
||||
qd = unpackbuf;
|
||||
ulen = 0L;
|
||||
|
||||
if (qs)
|
||||
{
|
||||
{
|
||||
int mostbits;
|
||||
int i;
|
||||
int bitnumtbl[16];
|
||||
unsigned int deltatbl[16];
|
||||
unsigned int cmptbl[16];
|
||||
unsigned char codetbl[256];
|
||||
unsigned char quickcodetbl[256];
|
||||
unsigned char quicklentbl[256];
|
||||
|
||||
bitsleft = -16; /* init bit stream */
|
||||
bits = 0;
|
||||
SQgetbits(v,ZERO);
|
||||
|
||||
SQgetbits(type,16);
|
||||
|
||||
if (type&0x8000) /* 4 byte size field */
|
||||
{
|
||||
/* (skip nothing for 0x30fb) */
|
||||
if (type&0x100) /* skip ulen */
|
||||
{
|
||||
SQgetbits(v,16);
|
||||
SQgetbits(v,16);
|
||||
}
|
||||
type &= ~0x100;
|
||||
|
||||
SQgetbits(v,16); /* unpack len */
|
||||
SQgetbits(ulen,16);
|
||||
ulen |= (v<<16);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (skip nothing for 0x30fb) */
|
||||
if (type&0x100) /* skip ulen */
|
||||
{
|
||||
SQgetbits(v,8);
|
||||
SQgetbits(v,16);
|
||||
}
|
||||
type &= ~0x100;
|
||||
|
||||
SQgetbits(v,8); /* unpack len */
|
||||
SQgetbits(ulen,16);
|
||||
ulen |= (v<<16);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
int numchars;
|
||||
|
||||
{
|
||||
unsigned int basecmp;
|
||||
|
||||
{
|
||||
unsigned int t;
|
||||
SQgetbits(t,8); /* clue byte */
|
||||
clue = (unsigned char)t;
|
||||
}
|
||||
|
||||
numchars = 0;
|
||||
numbits = 1;
|
||||
basecmp = (unsigned int) 0;
|
||||
|
||||
/* decode bitnums */
|
||||
|
||||
do
|
||||
{
|
||||
basecmp <<= 1;
|
||||
deltatbl[numbits] = basecmp-numchars;
|
||||
|
||||
SQgetnum(bitnum); /* # of codes of n bits */
|
||||
bitnumtbl[numbits] = bitnum;
|
||||
|
||||
numchars += bitnum;
|
||||
basecmp += bitnum;
|
||||
|
||||
cmp = 0;
|
||||
if (bitnum) /* left justify cmp */
|
||||
cmp = (basecmp << (16-numbits) & 0xffff);
|
||||
|
||||
cmptbl[numbits++] = cmp;
|
||||
|
||||
}
|
||||
while (!bitnum || cmp); /* n+1 bits in cmp? */
|
||||
}
|
||||
cmptbl[numbits-1] = 0xffffffff; /* force match on most bits */
|
||||
|
||||
mostbits = numbits-1;
|
||||
|
||||
/* decode leapfrog code table */
|
||||
|
||||
{
|
||||
signed char leap[256];
|
||||
unsigned char nextchar;
|
||||
|
||||
SQmemset(leap,0,256);
|
||||
nextchar = (unsigned char) -1;
|
||||
|
||||
for (i=0;i<numchars;++i)
|
||||
{
|
||||
int leapdelta=0;
|
||||
|
||||
SQgetnum(leapdelta);
|
||||
++leapdelta;
|
||||
|
||||
do
|
||||
{
|
||||
++nextchar;
|
||||
if (!leap[nextchar])
|
||||
--leapdelta;
|
||||
} while (leapdelta);
|
||||
|
||||
leap[nextchar] = 1;
|
||||
codetbl[i] = nextchar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* Make fast 8 tables */
|
||||
/****************************************************************/
|
||||
|
||||
SQmemset(quicklentbl,64,256);
|
||||
|
||||
{
|
||||
int bits;
|
||||
int bitnum;
|
||||
int numbitentries;
|
||||
int nextcode;
|
||||
int nextlen;
|
||||
int i;
|
||||
unsigned char *codeptr;
|
||||
unsigned char *quickcodeptr;
|
||||
unsigned char *quicklenptr;
|
||||
|
||||
codeptr = codetbl;
|
||||
quickcodeptr = quickcodetbl;
|
||||
quicklenptr = quicklentbl;
|
||||
|
||||
for (bits=1; bits<=mostbits; ++bits)
|
||||
{
|
||||
bitnum = bitnumtbl[bits];
|
||||
if (bits>=9)
|
||||
break;
|
||||
numbitentries = 1<<(8-bits);
|
||||
|
||||
while (bitnum--)
|
||||
{
|
||||
nextcode = *codeptr++;
|
||||
nextlen = bits;
|
||||
if (nextcode==clue)
|
||||
{
|
||||
cluelen = bits;
|
||||
nextlen = 96; /* will force out of main loop */
|
||||
}
|
||||
for (i=0; i<numbitentries; ++i)
|
||||
{
|
||||
*quickcodeptr++ = (unsigned char) nextcode;
|
||||
*quicklenptr++ = (unsigned char) nextlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* Main decoder */
|
||||
/****************************************************************/
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned char *quickcodeptr = quickcodetbl;
|
||||
unsigned char *quicklenptr = quicklentbl;
|
||||
|
||||
goto nextloop;
|
||||
|
||||
/* quick 8 fetch */
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
*qd++ = quickcodeptr[bits>>24];
|
||||
GET16BITS();
|
||||
bits = bitsunshifted<<(16-bitsleft);
|
||||
|
||||
/* quick 8 decode */
|
||||
|
||||
nextloop:
|
||||
numbits = quicklenptr[bits>>24];
|
||||
bitsleft -= numbits;
|
||||
|
||||
if (bitsleft>=0)
|
||||
{
|
||||
do
|
||||
{
|
||||
*qd++ = quickcodeptr[bits>>24];
|
||||
bits <<= numbits;
|
||||
|
||||
numbits = quicklenptr[bits>>24];
|
||||
bitsleft -= numbits;
|
||||
if (bitsleft<0) break;
|
||||
*qd++ = quickcodeptr[bits>>24];
|
||||
bits <<= numbits;
|
||||
|
||||
numbits = quicklenptr[bits>>24];
|
||||
bitsleft -= numbits;
|
||||
if (bitsleft<0) break;
|
||||
*qd++ = quickcodeptr[bits>>24];
|
||||
bits <<= numbits;
|
||||
|
||||
numbits = quicklenptr[bits>>24];
|
||||
bitsleft -= numbits;
|
||||
if (bitsleft<0) break;
|
||||
*qd++ = quickcodeptr[bits>>24];
|
||||
bits <<= numbits;
|
||||
|
||||
numbits = quicklenptr[bits>>24];
|
||||
bitsleft -= numbits;
|
||||
|
||||
} while (bitsleft>=0);
|
||||
}
|
||||
bitsleft += 16;
|
||||
|
||||
} while (bitsleft>=0); /* would fetching 16 bits do it? */
|
||||
|
||||
bitsleft = bitsleft-16+numbits; /* back to normal */
|
||||
|
||||
/****************************************************************/
|
||||
/* 16 bit decoder */
|
||||
/****************************************************************/
|
||||
|
||||
{
|
||||
unsigned char code;
|
||||
|
||||
|
||||
if (numbits!=96)
|
||||
{
|
||||
cmp = (unsigned int) (bits>>16); /* 16 bit left justified compare */
|
||||
|
||||
numbits = 8;
|
||||
do
|
||||
{
|
||||
++numbits;
|
||||
}
|
||||
while (cmp>=cmptbl[numbits]);
|
||||
}
|
||||
else
|
||||
numbits = cluelen;
|
||||
|
||||
|
||||
cmp = bits >> (32-(numbits));
|
||||
bits <<= (numbits);
|
||||
bitsleft -= (numbits);
|
||||
|
||||
code = codetbl[cmp-deltatbl[numbits]]; /* the code */
|
||||
|
||||
if (code!=clue && bitsleft>=0)
|
||||
{
|
||||
*qd++ = code;
|
||||
goto nextloop;
|
||||
}
|
||||
|
||||
if (bitsleft<0)
|
||||
{
|
||||
GET16BITS();
|
||||
bits = bitsunshifted<<-bitsleft;
|
||||
bitsleft += 16;
|
||||
}
|
||||
|
||||
if (code!=clue)
|
||||
{
|
||||
*qd++ = code;
|
||||
goto nextloop;
|
||||
}
|
||||
|
||||
/* handle clue */
|
||||
|
||||
{
|
||||
int runlen=0;
|
||||
unsigned char *d=qd;
|
||||
unsigned char *dest;
|
||||
|
||||
SQgetnum(runlen);
|
||||
if (runlen) /* runlength sequence */
|
||||
{
|
||||
dest = d+runlen;
|
||||
code = *(d-1);
|
||||
do
|
||||
{
|
||||
*d++ = code;
|
||||
} while (d<dest);
|
||||
|
||||
qd = d;
|
||||
goto nextloop;
|
||||
}
|
||||
}
|
||||
|
||||
SQgetbits(v,1); /* End Of File */
|
||||
if (v)
|
||||
break;
|
||||
|
||||
{
|
||||
unsigned int t;
|
||||
SQgetbits(t,8); /* explicite byte */
|
||||
code = (unsigned char)t;
|
||||
}
|
||||
*qd++ = code;
|
||||
goto nextloop;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Undelta */
|
||||
/****************************************************************/
|
||||
|
||||
{
|
||||
int i;
|
||||
int nextchar;
|
||||
|
||||
if (type==0x32fb || type==0xb2fb) /* deltaed? */
|
||||
{
|
||||
i = 0;
|
||||
qd = unpackbuf;
|
||||
while (qd<unpackbuf+ulen)
|
||||
{
|
||||
i += (int) *qd;
|
||||
*qd++ = (unsigned char) i;
|
||||
}
|
||||
}
|
||||
else if (type==0x34fb || type==0xb4fb) /* accelerated? */
|
||||
{
|
||||
|
||||
i = 0;
|
||||
nextchar = 0;
|
||||
qd = unpackbuf;
|
||||
while (qd<unpackbuf+ulen)
|
||||
{
|
||||
i += (int) *qd;
|
||||
nextchar += i;
|
||||
*qd++ = (unsigned char) nextchar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(ulen);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* Information Functions */
|
||||
/****************************************************************/
|
||||
|
||||
/* check for reasonable header: */
|
||||
/* 30fb..35fb header */
|
||||
|
||||
bool GCALL HUFF_is(const void *compresseddata)
|
||||
{
|
||||
bool ok=false;
|
||||
int packtype=ggetm(compresseddata,2);
|
||||
|
||||
if (packtype==0x30fb
|
||||
|| packtype==0x31fb
|
||||
|| packtype==0x32fb
|
||||
|| packtype==0x33fb
|
||||
|| packtype==0x34fb
|
||||
|| packtype==0x35fb
|
||||
|| packtype==0xb0fb
|
||||
|| packtype==0xb1fb
|
||||
|| packtype==0xb2fb
|
||||
|| packtype==0xb3fb
|
||||
|| packtype==0xb4fb
|
||||
|| packtype==0xb5fb)
|
||||
ok = true;
|
||||
|
||||
return(ok);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Decode Functions */
|
||||
/****************************************************************/
|
||||
|
||||
int GCALL HUFF_size(const void *compresseddata)
|
||||
{
|
||||
int len=0;
|
||||
int packtype=ggetm(compresseddata,2);
|
||||
int ssize=(packtype&0x8000)?4:3;
|
||||
|
||||
if (packtype&0x100) /* 31fb 33fb 35fb */
|
||||
{
|
||||
len = ggetm((char *)compresseddata+2+ssize,ssize);
|
||||
}
|
||||
else /* 30fb 32fb 34fb */
|
||||
{
|
||||
len = ggetm((char *)compresseddata+2,ssize);
|
||||
}
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
int GCALL HUFF_decode(void *dest, const void *compresseddata, int *compressedsize)
|
||||
{
|
||||
return(HUFF_decompress((unsigned char *)compresseddata, (unsigned char *)dest));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1227
Generals/Code/Libraries/Source/Compression/EAC/huffencode.cpp
Normal file
1227
Generals/Code/Libraries/Source/Compression/EAC/huffencode.cpp
Normal file
File diff suppressed because it is too large
Load diff
105
Generals/Code/Libraries/Source/Compression/EAC/refabout.cpp
Normal file
105
Generals/Code/Libraries/Source/Compression/EAC/refabout.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
/* ABSTRACT */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* RefPack - Backward Reference Codex */
|
||||
/* */
|
||||
/* by FrANK G. Barchard, EAC */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version Date SE History: */
|
||||
/* ------- ---- -- -------- */
|
||||
/* 0.10 941010 FB First codex prototype module */
|
||||
/* 0.90 941019 FB #includable */
|
||||
/* 1.00 950108 FB frozen API at 1.00 */
|
||||
/* 1.01 010426 FB 32 size field */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Module Notes: */
|
||||
/* ------------- */
|
||||
/* used hash table and link table for speed */
|
||||
/* Reentrant */
|
||||
/* Files: refread.c refwrite.c refcodex.h (refmatch.asm pc) */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Format Notes: */
|
||||
/* ------------- */
|
||||
/* refpack is a sliding window (131k) lzss method, with byte */
|
||||
/* oriented coding. */
|
||||
/* */
|
||||
/* huff fb6 style header: */
|
||||
/* *10fb fb6 refpack 1.0 reference pack */
|
||||
/* *90fb fb6 refpack 1.01 32 bit reference pack */
|
||||
/* */
|
||||
/* */
|
||||
/* header: */
|
||||
/* [10fb] [totalunpacksize] [nextunpacksize] */
|
||||
/* 2 3 3 */
|
||||
/* [90fb] [totalunpacksize] [nextunpacksize] */
|
||||
/* 2 4 4 */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* format is: */
|
||||
/* ---------- */
|
||||
/* 0ffnnndd_ffffffff short ref, f=0..1023,n=3..10,d=0..3 */
|
||||
/* 10nnnnnn_ddffffff_ffffffff int ref, f=0..16384,n=4..67,d=0..3 */
|
||||
/* 110fnndd_f.._f.._nnnnnnnn very int,f=0..131071,n=5..1028,d=0..3*/
|
||||
/* 111ddddd literal, d=4..112 */
|
||||
/* 111111dd eof, d=0..3 */
|
||||
/* */
|
||||
/*------------------------------------------------------------------*/
|
||||
/* END ABSTRACT */
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "refcodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Information Functions */
|
||||
/****************************************************************/
|
||||
|
||||
CODEXABOUT *GCALL REF_about(void)
|
||||
{
|
||||
CODEXABOUT *info;
|
||||
|
||||
info = (CODEXABOUT *) galloc(sizeof(CODEXABOUT));
|
||||
if (info)
|
||||
{
|
||||
memset(info, 0, sizeof(CODEXABOUT));
|
||||
|
||||
info->signature = QMAKEID(0,'R','E','F');
|
||||
info->size = sizeof(CODEXABOUT);
|
||||
info->version = 200; /* codex version number (200) */
|
||||
info->decode = 1; /* supports decoding */
|
||||
info->encode = 1; /* supports encoding */
|
||||
info->size32 = 1; /* supports 32 bit size field */
|
||||
strcpy(info->versionstr, "1.01"); /* version # */
|
||||
strcpy(info->shorttypestr, "ref"); /* type */
|
||||
strcpy(info->longtypestr, "Refpack"); /* longtype */
|
||||
}
|
||||
return(info);
|
||||
}
|
||||
|
74
Generals/Code/Libraries/Source/Compression/EAC/refcodex.h
Normal file
74
Generals/Code/Libraries/Source/Compression/EAC/refcodex.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved. */
|
||||
|
||||
#ifndef __REFCODEX
|
||||
#define __REFCODEX 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __CODEX_H
|
||||
#error "Include codex.h before refcodex.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* REF Codex */
|
||||
/****************************************************************/
|
||||
|
||||
/* Information Functions */
|
||||
|
||||
CODEXABOUT *GCALL REF_about(void);
|
||||
bool GCALL REF_is(const void *compresseddata);
|
||||
|
||||
/* Decode Functions */
|
||||
|
||||
int GCALL REF_size(const void *compresseddata);
|
||||
#ifdef __cplusplus
|
||||
int GCALL REF_decode(void *dest, const void *compresseddata, int *compressedsize=0);
|
||||
#else
|
||||
int GCALL REF_decode(void *dest, const void *compresseddata, int *compressedsize);
|
||||
#endif
|
||||
|
||||
/* Encode Functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
int GCALL REF_encode(void *compresseddata, const void *source, int sourcesize, int *opts=0);
|
||||
#else
|
||||
int GCALL REF_encode(void *compresseddata, const void *source, int sourcesize, int *opts);
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* Internal */
|
||||
/****************************************************************/
|
||||
|
||||
#ifndef qmin
|
||||
#define qmin(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef qmax
|
||||
#define qmax(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
186
Generals/Code/Libraries/Source/Compression/EAC/refdecode.cpp
Normal file
186
Generals/Code/Libraries/Source/Compression/EAC/refdecode.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
#ifndef __REFREAD
|
||||
#define __REFREAD 1
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "refcodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Information Functions */
|
||||
/****************************************************************/
|
||||
|
||||
/* check for reasonable header: */
|
||||
/* 10fb header */
|
||||
|
||||
bool GCALL REF_is(const void *compresseddata)
|
||||
{
|
||||
bool ok=false;
|
||||
int packtype=ggetm(compresseddata,2);
|
||||
|
||||
if (packtype==0x10fb
|
||||
|| packtype==0x11fb
|
||||
|| packtype==0x90fb
|
||||
|| packtype==0x91fb)
|
||||
ok = true;
|
||||
|
||||
return(ok);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Decode Functions */
|
||||
/****************************************************************/
|
||||
|
||||
int GCALL REF_size(const void *compresseddata)
|
||||
{
|
||||
int len=0;
|
||||
int packtype=ggetm(compresseddata,2);
|
||||
int ssize=(packtype&0x8000)?4:3;
|
||||
|
||||
if (packtype&0x100) /* 11fb */
|
||||
{
|
||||
len = ggetm((char *)compresseddata+2+ssize,ssize);
|
||||
}
|
||||
else /* 10fb */
|
||||
{
|
||||
len = ggetm((char *)compresseddata+2,ssize);
|
||||
}
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
int GCALL REF_decode(void *dest, const void *compresseddata, int *compressedsize)
|
||||
{
|
||||
unsigned char *s;
|
||||
unsigned char *ref;
|
||||
unsigned char *d;
|
||||
unsigned char first;
|
||||
unsigned char second;
|
||||
unsigned char third;
|
||||
unsigned char forth;
|
||||
unsigned int run;
|
||||
unsigned int type;
|
||||
int ulen;
|
||||
|
||||
s = (unsigned char *) compresseddata;
|
||||
d = (unsigned char *) dest;
|
||||
ulen = 0L;
|
||||
|
||||
if (s)
|
||||
{
|
||||
type = *s++;
|
||||
type = (type<<8) + *s++;
|
||||
|
||||
if (type&0x8000) /* 4 byte size field */
|
||||
{
|
||||
if (type&0x100) /* skip ulen */
|
||||
s += 4;
|
||||
|
||||
ulen = *s++;
|
||||
ulen = (ulen<<8) + *s++;
|
||||
ulen = (ulen<<8) + *s++;
|
||||
ulen = (ulen<<8) + *s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type&0x100) /* skip ulen */
|
||||
s += 3;
|
||||
|
||||
ulen = *s++;
|
||||
ulen = (ulen<<8) + *s++;
|
||||
ulen = (ulen<<8) + *s++;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
first = *s++;
|
||||
if (!(first&0x80)) /* short form */
|
||||
{
|
||||
second = *s++;
|
||||
run = first&3;
|
||||
while (run--)
|
||||
*d++ = *s++;
|
||||
ref = d-1 - (((first&0x60)<<3) + second);
|
||||
run = ((first&0x1c)>>2)+3-1;
|
||||
do
|
||||
{
|
||||
*d++ = *ref++;
|
||||
} while (run--);
|
||||
continue;
|
||||
}
|
||||
if (!(first&0x40)) /* int form */
|
||||
{
|
||||
second = *s++;
|
||||
third = *s++;
|
||||
run = second>>6;
|
||||
while (run--)
|
||||
*d++ = *s++;
|
||||
|
||||
ref = d-1 - (((second&0x3f)<<8) + third);
|
||||
|
||||
run = (first&0x3f)+4-1;
|
||||
do
|
||||
{
|
||||
*d++ = *ref++;
|
||||
} while (run--);
|
||||
continue;
|
||||
}
|
||||
if (!(first&0x20)) /* very int form */
|
||||
{
|
||||
second = *s++;
|
||||
third = *s++;
|
||||
forth = *s++;
|
||||
run = first&3;
|
||||
while (run--)
|
||||
*d++ = *s++;
|
||||
|
||||
ref = d-1 - (((first&0x10)>>4<<16) + (second<<8) + third);
|
||||
|
||||
run = ((first&0x0c)>>2<<8) + forth + 5-1;
|
||||
do
|
||||
{
|
||||
*d++ = *ref++;
|
||||
} while (run--);
|
||||
continue;
|
||||
}
|
||||
run = ((first&0x1f)<<2)+4; /* literal */
|
||||
if (run<=112)
|
||||
{
|
||||
while (run--)
|
||||
*d++ = *s++;
|
||||
continue;
|
||||
}
|
||||
run = first&3; /* eof (+0..3 literal) */
|
||||
while (run--)
|
||||
*d++ = *s++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (compressedsize)
|
||||
*compressedsize = (int)((char *)s-(char *)compresseddata);
|
||||
return(ulen);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
264
Generals/Code/Libraries/Source/Compression/EAC/refencode.cpp
Normal file
264
Generals/Code/Libraries/Source/Compression/EAC/refencode.cpp
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
|
||||
|
||||
#ifndef __REFWRITE
|
||||
#define __REFWRITE 1
|
||||
|
||||
#include <string.h>
|
||||
#include "codex.h"
|
||||
#include "refcodex.h"
|
||||
|
||||
/****************************************************************/
|
||||
/* Internal Functions */
|
||||
/****************************************************************/
|
||||
|
||||
static unsigned int matchlen(unsigned char *s,unsigned char *d, unsigned int maxmatch)
|
||||
{
|
||||
unsigned int current;
|
||||
|
||||
for (current=0; current<maxmatch && *s++==*d++; ++current)
|
||||
;
|
||||
|
||||
return(current);
|
||||
}
|
||||
|
||||
#define HASH(cptr) (int)((((unsigned int)(unsigned char)cptr[0]<<8) | ((unsigned int)(unsigned char)cptr[2])) ^ ((unsigned int)(unsigned char)cptr[1]<<4))
|
||||
|
||||
static int refcompress(unsigned char *from, int len, unsigned char *dest, int maxback, int quick)
|
||||
{
|
||||
unsigned int tlen;
|
||||
unsigned int tcost;
|
||||
// unsigned int ccost; // context cost
|
||||
unsigned int run;
|
||||
unsigned int toffset;
|
||||
unsigned int boffset;
|
||||
unsigned int blen;
|
||||
unsigned int bcost;
|
||||
unsigned int mlen;
|
||||
unsigned char *tptr;
|
||||
unsigned char *cptr;
|
||||
unsigned char *to;
|
||||
unsigned char *rptr;
|
||||
int countliterals=0;
|
||||
int countshort=0;
|
||||
int countint=0;
|
||||
int countvint=0;
|
||||
int hash;
|
||||
int hoffset;
|
||||
int minhoffset;
|
||||
int i;
|
||||
int *link;
|
||||
int *hashtbl;
|
||||
|
||||
to = dest;
|
||||
run = 0;
|
||||
cptr = rptr = from;
|
||||
|
||||
if ((unsigned int)maxback > (unsigned int)131071)
|
||||
maxback = 131071;
|
||||
|
||||
hashtbl = (int *) galloc(65536L*sizeof(int));
|
||||
if (!hashtbl)
|
||||
return(0);
|
||||
link = (int *) galloc(131072L*sizeof(int));
|
||||
if (!link)
|
||||
return(0);
|
||||
|
||||
memset(hashtbl,-1,65536L*sizeof(int));
|
||||
|
||||
len -= 4;
|
||||
while (len>=0)
|
||||
{
|
||||
boffset = 0;
|
||||
blen = 2;
|
||||
bcost = 2;
|
||||
// ccost = 0;
|
||||
mlen = qmin(len,1028);
|
||||
tptr=cptr-1;
|
||||
hash = HASH(cptr);
|
||||
hoffset = hashtbl[hash];
|
||||
minhoffset = qmax(cptr-from-131071,0);
|
||||
|
||||
|
||||
if (hoffset>=minhoffset)
|
||||
{
|
||||
do
|
||||
{
|
||||
tptr = from+hoffset;
|
||||
if (cptr[blen]==tptr[blen])
|
||||
{
|
||||
tlen = matchlen(cptr,tptr,mlen);
|
||||
if (tlen > blen)
|
||||
{
|
||||
toffset = (cptr-1)-tptr;
|
||||
if (toffset<1024 && tlen<=10) /* two byte int form */
|
||||
tcost = 2;
|
||||
else if (toffset<16384 && tlen<=67) /* three byte int form */
|
||||
tcost = 3;
|
||||
else /* four byte very int form */
|
||||
tcost = 4;
|
||||
|
||||
if (tlen-tcost+4 > blen-bcost+4)
|
||||
{
|
||||
blen = tlen;
|
||||
bcost = tcost;
|
||||
boffset = toffset;
|
||||
if (blen>=1028) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ((hoffset = link[hoffset&131071]) >= minhoffset);
|
||||
}
|
||||
|
||||
// ccost = 0;
|
||||
// if ((run<4) && ((run+blen)>=4))
|
||||
// ccost = 1; // extra packet cost to switch out of literal into reference
|
||||
|
||||
// if (bcost>blen || (blen<=2 && bcost==blen && !ccost) || (len<4))
|
||||
if (bcost>=blen || len<4)
|
||||
{
|
||||
hoffset = (cptr-from);
|
||||
link[hoffset&131071] = hashtbl[hash];
|
||||
hashtbl[hash] = hoffset;
|
||||
|
||||
++run;
|
||||
++cptr;
|
||||
--len;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (run>3) /* literal block of data */
|
||||
{
|
||||
tlen = qmin(112,run&~3);
|
||||
run -= tlen;
|
||||
*to++ = (unsigned char) (0xe0+(tlen>>2)-1);
|
||||
memcpy(to,rptr,tlen);
|
||||
rptr += tlen;
|
||||
to += tlen;
|
||||
++countliterals;
|
||||
}
|
||||
if (bcost==2) /* two byte int form */
|
||||
{
|
||||
*to++ = (unsigned char) (((boffset>>8)<<5) + ((blen-3)<<2) + run);
|
||||
*to++ = (unsigned char) boffset;
|
||||
++countshort;
|
||||
}
|
||||
else if (bcost==3) /* three byte int form */
|
||||
{
|
||||
*to++ = (unsigned char) (0x80 + (blen-4));
|
||||
*to++ = (unsigned char) ((run<<6) + (boffset>>8));
|
||||
*to++ = (unsigned char) boffset;
|
||||
++countint;
|
||||
}
|
||||
else /* four byte very int form */
|
||||
{
|
||||
*to++ = (unsigned char) (0xc0 + ((boffset>>16)<<4) + (((blen-5)>>8)<<2) + run);
|
||||
*to++ = (unsigned char) (boffset>>8);
|
||||
*to++ = (unsigned char) (boffset);
|
||||
*to++ = (unsigned char) (blen-5);
|
||||
++countvint;
|
||||
}
|
||||
if (run)
|
||||
{
|
||||
memcpy(to, rptr, run);
|
||||
to += run;
|
||||
run = 0;
|
||||
}
|
||||
|
||||
if (quick)
|
||||
{
|
||||
hoffset = (cptr-from);
|
||||
link[hoffset&131071] = hashtbl[hash];
|
||||
hashtbl[hash] = hoffset;
|
||||
cptr += blen;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < (int)blen; ++i)
|
||||
{
|
||||
hash = HASH(cptr);
|
||||
hoffset = (cptr-from);
|
||||
link[hoffset&131071] = hashtbl[hash];
|
||||
hashtbl[hash] = hoffset;
|
||||
++cptr;
|
||||
}
|
||||
}
|
||||
|
||||
rptr = cptr;
|
||||
len -= blen;
|
||||
}
|
||||
}
|
||||
len += 4;
|
||||
run += len;
|
||||
while (run>3) /* no match at end, use literal */
|
||||
{
|
||||
tlen = qmin(112,run&~3);
|
||||
run -= tlen;
|
||||
*to++ = (unsigned char) (0xe0+(tlen>>2)-1);
|
||||
memcpy(to,rptr,tlen);
|
||||
rptr += tlen;
|
||||
to += tlen;
|
||||
}
|
||||
|
||||
*to++ = (unsigned char) (0xfc+run); /* end of stream command + 0..3 literal */
|
||||
if (run)
|
||||
{
|
||||
memcpy(to,rptr,run);
|
||||
to += run;
|
||||
}
|
||||
|
||||
gfree(link);
|
||||
gfree(hashtbl);
|
||||
return(to-dest);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Encode Function */
|
||||
/****************************************************************/
|
||||
|
||||
int GCALL REF_encode(void *compresseddata, const void *source, int sourcesize, int *opts)
|
||||
{
|
||||
int maxback=131072;
|
||||
int quick=0;
|
||||
int plen;
|
||||
int hlen;
|
||||
|
||||
|
||||
/* simple fb6 header */
|
||||
|
||||
if (sourcesize>0xffffff) // 32 bit header required
|
||||
{
|
||||
gputm(compresseddata, (unsigned int) 0x90fb, 2);
|
||||
gputm((char *)compresseddata+2, (unsigned int) sourcesize, 4);
|
||||
hlen = 6L;
|
||||
}
|
||||
else
|
||||
{
|
||||
gputm(compresseddata, (unsigned int) 0x10fb, 2);
|
||||
gputm((char *)compresseddata+2, (unsigned int) sourcesize, 3);
|
||||
hlen = 5L;
|
||||
}
|
||||
plen = hlen+refcompress((unsigned char *)source, sourcesize, (unsigned char *)compresseddata+hlen, maxback, quick);
|
||||
return(plen);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
4
Generals/Code/Libraries/Source/Compression/LZHCompress/CompLibHeader/.gitignore
vendored
Normal file
4
Generals/Code/Libraries/Source/Compression/LZHCompress/CompLibHeader/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
4
Generals/Code/Libraries/Source/Compression/LZHCompress/CompLibSource/.gitignore
vendored
Normal file
4
Generals/Code/Libraries/Source/Compression/LZHCompress/CompLibSource/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// compress.c
|
||||
// Compress interface for packets and files
|
||||
// Author: Jeff Brown, January 1999
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "Lib/basetype.h"
|
||||
#include "Noxcompress.h"
|
||||
#include "CompLibHeader/lzhl.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
#define BLOCKSIZE 500000
|
||||
#define NoxRead fread
|
||||
#define DbgMalloc malloc
|
||||
#define DbgFree free
|
||||
#define DEBUG_LOG(x) {}
|
||||
|
||||
Bool DecompressFile (char *infile, char *outfile)
|
||||
{
|
||||
UnsignedInt rawSize = 0, compressedSize = 0;
|
||||
FILE *inFilePtr = NULL;
|
||||
FILE *outFilePtr= NULL;
|
||||
char *inBlock = NULL;
|
||||
char *outBlock = NULL;
|
||||
LZHL_DHANDLE decompress;
|
||||
Int ok = 0;
|
||||
UnsignedInt srcSz, dstSz;
|
||||
|
||||
// Parameter checking
|
||||
|
||||
if (( infile == NULL ) || ( outfile == NULL ))
|
||||
return FALSE;
|
||||
|
||||
inFilePtr = fopen( infile, "rb" );
|
||||
if ( inFilePtr )
|
||||
{
|
||||
// Allocate the appropriate amount of memory
|
||||
// Get compressed size of file.
|
||||
fseek( inFilePtr, 0, SEEK_END );
|
||||
compressedSize = ftell( inFilePtr );
|
||||
fseek( inFilePtr, 0, SEEK_SET );
|
||||
|
||||
compressedSize -= sizeof(UnsignedInt);
|
||||
|
||||
// Get uncompressed size. Don't worry about endian,
|
||||
// this is always INTEL baby!
|
||||
NoxRead(&rawSize, 1, sizeof(UnsignedInt), inFilePtr);
|
||||
|
||||
// This is ick, but allocate a BIIIIG chunk o' memory x 2
|
||||
inBlock = (char *) DbgMalloc( compressedSize );
|
||||
outBlock= (char *) DbgMalloc( rawSize );
|
||||
|
||||
if (( inBlock == NULL ) || ( outBlock == NULL ))
|
||||
return FALSE;
|
||||
|
||||
// Read in a big chunk o file
|
||||
NoxRead(inBlock, 1, compressedSize, inFilePtr);
|
||||
|
||||
fclose(inFilePtr);
|
||||
|
||||
// Decompress
|
||||
srcSz = compressedSize;
|
||||
dstSz = rawSize;
|
||||
|
||||
// Just Do it!
|
||||
decompress = LZHLCreateDecompressor();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ok = LZHLDecompress( decompress, outBlock + rawSize - dstSz, &dstSz,
|
||||
inBlock + compressedSize - srcSz, &srcSz);
|
||||
|
||||
if ( !ok )
|
||||
break;
|
||||
|
||||
if (srcSz <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_LOG(("Decompressed %s to %s, output size = %d\n", infile, outfile, rawSize));
|
||||
|
||||
LZHLDestroyDecompressor(decompress);
|
||||
outFilePtr = fopen(outfile, "wb");
|
||||
if (outFilePtr)
|
||||
{
|
||||
fwrite (outBlock, rawSize, 1, outFilePtr);
|
||||
fclose(outFilePtr);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
// Clean up this mess
|
||||
DbgFree(inBlock);
|
||||
DbgFree(outBlock);
|
||||
return TRUE;
|
||||
|
||||
} // End of if fileptr
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Bool CompressFile (char *infile, char *outfile)
|
||||
{
|
||||
UnsignedInt rawSize = 0;
|
||||
UnsignedInt compressedSize = 0, compressed = 0, i = 0;
|
||||
FILE *inFilePtr = NULL;
|
||||
FILE *outFilePtr= NULL;
|
||||
char *inBlock = NULL;
|
||||
char *outBlock = NULL;
|
||||
LZHL_CHANDLE compressor;
|
||||
UnsignedInt blocklen;
|
||||
|
||||
// Parameter checking
|
||||
|
||||
if (( infile == NULL ) || ( outfile == NULL ))
|
||||
return FALSE;
|
||||
|
||||
// Allocate the appropriate amount of memory
|
||||
inFilePtr = fopen( infile, "rb" );
|
||||
if ( inFilePtr )
|
||||
{
|
||||
// Get size of file.
|
||||
fseek( inFilePtr, 0, SEEK_END );
|
||||
rawSize = ftell( inFilePtr );
|
||||
fseek( inFilePtr, 0, SEEK_SET );
|
||||
|
||||
// This is ick, but allocate a BIIIIG chunk o' memory x 2
|
||||
inBlock = (char *) DbgMalloc(rawSize);
|
||||
outBlock= (char *) DbgMalloc( LZHLCompressorCalcMaxBuf( rawSize ));
|
||||
|
||||
if (( inBlock == NULL ) || ( outBlock == NULL ))
|
||||
return FALSE;
|
||||
|
||||
// Read in a big chunk o file
|
||||
NoxRead(inBlock, 1, rawSize, inFilePtr);
|
||||
|
||||
fclose(inFilePtr);
|
||||
|
||||
// Compress
|
||||
compressor = LZHLCreateCompressor();
|
||||
for ( i = 0; i < rawSize; i += BLOCKSIZE )
|
||||
{
|
||||
blocklen = min((UnsignedInt)BLOCKSIZE, rawSize - i);
|
||||
compressed = LZHLCompress(compressor, outBlock + compressedSize, inBlock + i, blocklen);
|
||||
compressedSize += compressed;
|
||||
}
|
||||
|
||||
LZHLDestroyCompressor(compressor);
|
||||
|
||||
outFilePtr = fopen(outfile, "wb");
|
||||
if (outFilePtr)
|
||||
{
|
||||
// write out the uncompressed size first.
|
||||
fwrite(&rawSize, sizeof(UnsignedInt), 1, outFilePtr);
|
||||
fwrite(outBlock, compressedSize, 1, outFilePtr);
|
||||
fclose(outFilePtr);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
// Clean up
|
||||
DbgFree(inBlock);
|
||||
DbgFree(outBlock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool CompressPacket (char *inPacket, char *outPacket)
|
||||
{
|
||||
// Parameter checking
|
||||
|
||||
if (( inPacket == NULL ) || ( outPacket == NULL ))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Bool DecompressPacket (char *inPacket, char *outPacket)
|
||||
{
|
||||
// Parameter checking
|
||||
|
||||
if (( inPacket == NULL ) || ( outPacket == NULL ))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
UnsignedInt CalcNewSize (UnsignedInt rawSize)
|
||||
{
|
||||
return LZHLCompressorCalcMaxBuf(rawSize);
|
||||
}
|
||||
|
||||
Bool DecompressMemory (void *inBufferVoid, Int inSize, void *outBufferVoid, Int& outSize)
|
||||
{
|
||||
UnsignedByte *inBuffer = (UnsignedByte *)inBufferVoid;
|
||||
UnsignedByte *outBuffer = (UnsignedByte *)outBufferVoid;
|
||||
UnsignedInt rawSize = 0, compressedSize = 0;
|
||||
LZHL_DHANDLE decompress;
|
||||
Int ok = 0;
|
||||
UnsignedInt srcSz, dstSz;
|
||||
|
||||
// Parameter checking
|
||||
|
||||
if (( inBuffer == NULL ) || ( outBuffer == NULL ) || ( inSize < 4 ) || ( outSize == 0 ))
|
||||
return FALSE;
|
||||
|
||||
// Get compressed size of file.
|
||||
compressedSize = inSize;
|
||||
|
||||
// Get uncompressed size.
|
||||
rawSize = outSize;
|
||||
|
||||
// Decompress
|
||||
srcSz = compressedSize;
|
||||
dstSz = rawSize;
|
||||
|
||||
// Just Do it!
|
||||
decompress = LZHLCreateDecompressor();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ok = LZHLDecompress( decompress, outBuffer + rawSize - dstSz, &dstSz,
|
||||
inBuffer + compressedSize - srcSz, &srcSz);
|
||||
|
||||
if ( !ok )
|
||||
break;
|
||||
|
||||
if (srcSz <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
LZHLDestroyDecompressor(decompress);
|
||||
|
||||
outSize = rawSize;
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
Bool CompressMemory (void *inBufferVoid, Int inSize, void *outBufferVoid, Int& outSize)
|
||||
{
|
||||
UnsignedByte *inBuffer = (UnsignedByte *)inBufferVoid;
|
||||
UnsignedByte *outBuffer = (UnsignedByte *)outBufferVoid;
|
||||
UnsignedInt rawSize = 0;
|
||||
UnsignedInt compressedSize = 0, compressed = 0, i = 0;
|
||||
LZHL_CHANDLE compressor;
|
||||
UnsignedInt blocklen;
|
||||
|
||||
// Parameter checking
|
||||
|
||||
if (( inBuffer == NULL ) || ( outBuffer == NULL ) || ( inSize < 4 ) || ( outSize == 0 ))
|
||||
return FALSE;
|
||||
|
||||
rawSize = inSize;
|
||||
|
||||
// Compress
|
||||
compressor = LZHLCreateCompressor();
|
||||
for ( i = 0; i < rawSize; i += BLOCKSIZE )
|
||||
{
|
||||
blocklen = min((UnsignedInt)BLOCKSIZE, rawSize - i);
|
||||
compressed = LZHLCompress(compressor, outBuffer + compressedSize, inBuffer + i, blocklen);
|
||||
compressedSize += compressed;
|
||||
}
|
||||
|
||||
LZHLDestroyCompressor(compressor);
|
||||
|
||||
outSize = compressedSize;
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// compress.h
|
||||
// Compress/Decompression header.
|
||||
// Author: Jeff Brown, January 1999
|
||||
|
||||
|
||||
#ifndef __compress_h
|
||||
#define __compress_h
|
||||
|
||||
#define MAP_EXTENSION ".map"
|
||||
#define LZH_EXTENSION ".nxz"
|
||||
#define RUL_EXTENSION ".rul"
|
||||
|
||||
Bool DecompressFile (char *infile, char *outfile);
|
||||
Bool CompressFile (char *infile, char *outfile);
|
||||
Bool CompressPacket (char *inPacket, char *outPacket);
|
||||
Bool DecompressPacket (char *inPacket, char *outPacket);
|
||||
UnsignedInt CalcNewSize (UnsignedInt rawSize);
|
||||
|
||||
Bool DecompressMemory (void *inBufferVoid, Int inSize, void *outBufferVoid, Int& outSize);
|
||||
Bool CompressMemory (void *inBufferVoid, Int inSize, void *outBufferVoid, Int& outSize);
|
||||
|
||||
#endif __compress_h
|
4
Generals/Code/Libraries/Source/Compression/ZLib/.gitignore
vendored
Normal file
4
Generals/Code/Libraries/Source/Compression/ZLib/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
Reference in a new issue