Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View 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

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

View file

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

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

View 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

View 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

View 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

View 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

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

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

View 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

View 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

File diff suppressed because it is too large Load diff

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

View 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

View 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

View 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

View file

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View file

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View file

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

View file

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

View file

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore