Here are some recent updated versions of some code:
Starting with TA3D_Platform.h
Code: Select all
/*
** File: TA3D_Platform.h
** Notes:
** Cire: Defines the type of platform that we are compling the executable for
** I placed this here so that .h files may include it should they need to
** do anything that requires them to see what type of platform we are working
** with.
** Since this is included within stdafx.h, and all cpp files MUST include
** stdafx.h, there should be no need to directly include this within cpp files.
** This file also specifies variable types, which might be size related. It prevents
** any clashes or at least it should. All other files should use these at all
** times when possible.
** Finally this file also includes stl libs for cstdio, cstdlib, and string which
** probably will be common in many .h files.
*/
#pragma once
// Cire:
// We probably should think about all the platforms and define these
// right away so we know what we are working with. I figure that
// each platform probably should have a 32 bit/64 bit defination
// to reduce the chances of standard variable size clashes. The exception
// is windows because it has 'specific' m$ variable types which will prevent
// an size issues.
#define TA3D_PLATFORM_WINDOWS
#undef TA3D_PLATFORM_LINUX
#undef TA3D_PLATFORM_MAC
#if defined TA3D_PLATFORM_WINDOWS
// 64-bit ints. please note that these are NOT very portable, mainly in the
// stuff you can do with them (aside from standard arithmetic operators) or
// how they are stored. only use them if you REALLY need really big numbers!
// For example, in Win32 (at least w/ VC++6) you can not type-cast from a
// unsigned __int64 (uint64) to a double. You can only use a signed __int64
// (sint64). The Intel compiler does not have this problem.
typedef unsigned __int64 uint64;
typedef signed __int64 sint64;
// 32-bit ints, guaranteed to be 4 bytes in size
typedef unsigned __int32 uint32;
typedef signed __int32 sint32;
// 16-bit ints, guaranteed to be 2 bytes in size
typedef unsigned __int16 uint16;
typedef signed __int16 sint16;
// 8-bit ints, guaranteed to be 1 byte in size
typedef unsigned __int8 uint8;
typedef signed __int8 sint8;
#elif defined TA3D_PLATFORM_LINUX
#elif defined TA3D_PLATFORM_MAC
#else
#error TA3D: platform is unkown, please fix by defining correct platform in TA3D_Platform.h
#endif
// Cire:
// Now lets get stl libs
#include <cstdio>
#include <string>
#include <cstdlib>
#include <map>
// Cire:
// string and wstring typedefs to make life easier.
typedef std::string String;
typedef std::wstring WString;
// Cire:
// Since byte seems to be common throughout the project we'll typedef here.
typedef uint8 byte;
typedef unsigned char uchar;
typedef signed char schar;
// Floating point types, defined for consistencies sakes.
typedef float real32;
typedef double real64;
// Common math related macros
// Pi, our favorite number
#undef PI
#define PI 3.141592653589793238462643383279502884197169399375105
// Square root of 2
#undef SQRT2
#define SQRT2 1.414213562373095048801688724209698078569671875376948
// Square root of 2 over 2
#undef SQRT2OVER2
#define SQRT2OVER2 0.707106781186547524400844362104849039284835937688474
// Square root of 3
#undef SQRT3
#define SQRT3 1.732050807568877293527446341505872366942805253810381
// Square root of 3 over 2
#undef SQRT3OVER2
#define SQRT3OVER2 0.866025403784438646763723170752936183471402626905190
// The natural number "e"
#undef NAT_E
#define NAT_E 2.718281828459045235360287471352662497757247093699959
// Some useful math and template functions
static __forceinline float Deg2Rad (float Deg) { return (Deg * 0.017453292f); }
static __forceinline double Deg2Rad (double Deg) { return (Deg * 0.017453292); }
static __forceinline float Rad2Deg (float Rad) { return (Rad * 57.29578122f); }
static __forceinline double Rad2Deg (double Rad) { return (Rad * 57.29578122); }
// Min/max macros.
// Normally #defined by a Win32 header file
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
template<class T> static void Swap (T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
return;
}
// bit field mask operation macros
template<class T> static void SetMask (T &var, T &mask)
{
var |= mask;
return;
}
template<class T> static void UnsetMask (T &var, T &mask)
{
var |= ~mask;
return;
}
// ordinal bit manipulation macros (least significant bit = bit "0")
template<class T> static T Bit (T &bit)
{
return (1 << bit);
}
template<class T> static void SetBit (T &var, T &bit)
{
return (SetMask (var, Bit(bit)));
}
template<class T> static void UnsetBit (T &var, T &bit)
{
return (UnsetMask (var, Bit(bit)));
}
// Returns -1/1/0 for sign of a variable
template<class T> static T Sign (T x)
{
if( x > 0 )
return (1);
else if( x < 0 )
return (-1);
return (0);
}
Next stdAfx.h, it is to be compiled under linux with -x option (It will generate Precompiled headers (PCH). It is to be the FIRST include in every cpp file. It also has the very first openings of our namespace for TA3D, with some constants contains for variable min/max, as well as a few utility functions, which may be moved later to a utils namespace, and within its own file.
Code: Select all
/*
** File: stdafx.h
** Notes:
** Cire: stdafx.h and stdafx.cpp will generate a pch file
** (pre compiled headers), all other cpp files MUST include
** this file, thier should be no need of any other cpp/h file
** to include anything within this file. Its goal is to include
** everything that should be global to the project, as well
** as platform specific setups and configurations.
*/
#pragma once
// First things first is we will need to know what platform we are building for.
#include "TA3D_Platform.h"
#if defined TA3D_PLATFORM_WINDOWS
// Cire:
// I had to setup a pragma on c4312 warnings, because algero include
// was generating alot of compiler noise.
#pragma warning( disable : 4312 )
// Cire:
// The below definations, make it so that we do not need to run fix
// on allegro, to set proper platform, I'am not entirely sure how
// other platfroms wana handle this so I just left it as including
// allgero directly.
#define ALLEGRO_MSVC
// Cire:
// Since algero include will include windows headers for us, we probably
// should make sure that when it does it excludes rarely used crap
// from windows headers.
#define WIN32_LEAN_AND_MEAN
#include <allegro.h> // in allegro
// Cire:
// Since we disabled 4312, we probably should set it back to its
// default state.
#pragma warning( default : 4312 )
#else
// Cire:
// Other platfroms may wish to adjust how allegro is included, for
// now its this way.
#include <allegro.h>
#endif
// Cire:
// Now to include allegro openGL support.
#include <alleggl.h>
// Cire:
// Malloc should not be platform specfic right???
#include <malloc.h>
#if defined TA3D_PLATFORM_WINDOWS
// Cire:
// The below definations are my way of dealing with 2005 deperation
// by pretty much redirecting them to proper secure methods, kludgy i know but
// it works.
#define strcasecmp(x,xx) _stricmp( x, xx )
#define strcat(x,xx) strcat_s(x, sizeof(x), xx )
#define strdup(x) _strdup( x )
#define vsprintf(x,xx,xxx) vsprintf_s( x, sizeof(x), xx, xxx )
#endif
namespace TA3D
{
// Some useful string manipulation routines
static String Lowercase( const String &sstring )
{
String Return;
Return.resize (sstring.length());
for( uint32 i = 0; i < sstring.length(); i++)
Return[i] = tolower (sstring[i]);
return (Return);
}
static String Uppercase( const String &sstring )
{
String Return;
Return.resize (sstring.length());
for( uint32 i = 0; i < sstring.length(); i++)
Return[i] = toupper (sstring[i]);
return (Return);
}
// Now that the types are defined, create min/max constants
const uint64 uint64max = 0xffffffffffffffff;
const uint64 uint64min = 0;
const sint64 sint64max = 0x7fffffffffffffff;
const sint64 sint64min = (-9223372036854775807i64 - 1);
const uint32 uint32max = 0xffffffff;
const uint32 uint32min = 0;
const sint32 sint32max = 0x7fffffff;
const sint32 sint32min = (-2147483647i32 - 1);
const uint16 uint16max = 0xffff;
const uint16 uint16min = 0;
const sint16 sint16max = 0x7fff;
const sint16 sint16min = -0x8000;
const uint8 uint8max = 0xff;
const uint8 uint8min = 0;
const sint8 sint8max = 0x7f;
const sint8 sint8min = -0x80;
const uchar ucharmax = 0xff;
const uchar ucharmin = 0;
const schar scharmax = 0x7f;
const schar scharmin = -0x80;
} // namespace TA3D
Next up stdafx.cpp, it does nothing but really include stdafx.h and possibly any other global headers, compile with -x option under gcc linux, vc should set this file to generate pch via stdafx.h.
Code: Select all
/*
** File: stdafx.cpp
** Notes:
** Cire: stdafx.h and stdafx.cpp will generate a pch file
** (pre compiled headers). Its goal is to include
** everything that should be global to the project, as well
** as platform specific setups and configurations.
*/
#include "stdafx.h"
Next we have an error handling module. (unfinished, needs reference to a global debugger, which we will add soon.
TA3D_Exception.h
Code: Select all
/*
** File: TA3D_Exception.h
** Notes:
** Cire: This file should be used to handle errors. It is rather simple to use and
** provides methods for tossing an exception and figuring out where it came
** from, as well as who it went through.
** To guard a block of code, with the error to be caught by anybody higher-up:
** guard (Action);
** ...
** unguard;
** If something happens between the guard and unguard, someone will eventually
** catch it and display an error, or act on it.
**
** To catch errors from lower blocks of code, do as above but put catches in
** for uchar*, cException*, and any other types (including ...) that you
** need.
*/
#pragma once
namespace TA3D
{
namespace EXCEPTION
{
// prototypes: internal use only.
extern void IncrementIndent(void);
extern void DecrementIndent(void);
extern uint32 GetIndentLevel(void);
// Use this to throw a nice, more useful debugging string
// Be sure to SetExceptionStatus (false) if you handle an exception.
// Don't worry about manually setting it to true though.
extern void __cdecl ThrowFatal( const char *Format, ... );
extern bool IsExceptionInProgress (void);
extern void SetExceptionStatus (bool E);
#ifdef DEBUG
extern void __cdecl GlobalDebuggerPrintf( const char *Format, ... );
#define dprintf GlobalDebuggerPrintf
#else
#define dprintf //
#endif
// In debug builds, let unhandled errors (referencing bad pointer, etc.) crash
// and give us debugger control. Otherwise, for release builds, give us a
// stack trace. This is used in the unguard macro below.
#ifdef DEBUG
#define UNKNOWN_ERROR_CATCH
#else
#define UNKNOWN_ERROR_CATCH \
catch (...) \
{ \
DecrementIndent (); \
dprintf ("Tossing Unhandled Exception (%s)\n", __GUARD__BLOCK__NAME__); \
SetExceptionStatus (true); \
throw (new cException (__GUARD__BLOCK__NAME__, "Unhandled Exception"));\
}
#endif
// Used for both debug and release builds
#define guard(name) \
{ \
static char *__GUARD__BLOCK__NAME__ = #name; \
dprintf ("Guard: %s\n", __GUARD__BLOCK__NAME__); \
IncrementIndent (); \
try \
{
// Don't need to use this if using unguard. Use this if using
// guardcatch, et. al.
#define guardend \
DecrementIndent (); \
dprintf ("Unguard: %s\n", __GUARD__BLOCK__NAME__); \
}
#define unguard \
} \
catch (cException *E) \
{ \
E->AddTosser (__GUARD__BLOCK__NAME__); \
DecrementIndent (); \
dprintf ("Tossing exception higher (%s)\n", __GUARD__BLOCK__NAME__); \
SetExceptionStatus (true); \
throw (E); \
} \
catch (string ErrorName) \
{ \
DecrementIndent (); \
dprintf ("Tossing string higher as exception (%s)\n", __GUARD__BLOCK__NAME__); \
SetExceptionStatus (true); \
throw (new cException (__GUARD__BLOCK__NAME__, ErrorName)); \
} \
UNKNOWN_ERROR_CATCH \
guardend;
// Use if you want to handle ExceptionD yourself
#define guardcatch(varname) \
} \
catch (cException *varname) \
#ifdef TA3D_SUPERGUARD
#define sguard(a) guard(a)
#define sunguard unguard
#else
#define sguard(a)
#define sunguard
#endif
// Convenience macro
#define SAFETRY(cmd) { guard (cmd); cmd; unguard; }
// Will eat any exceptions caused by a piece of code
#define IMPUNITY(cmd) { try { cmd; } catch (...) { } }
// Disable exception handling and save executable size (and speed?)
#ifdef TA3D_NOGUARD
#undef guard
#define guard(x)
#undef unguard
#define unguard
#undef guardend
#define guardend
#undef guardcatch
#define guardcatch(varname) cException *varname = NULL; if (false)
#endif // TA3D_NOGUARD
// The actual exception class
class cException
{
public:
cException( const String _Instigator, const String _ErrorName )
{
Instigator = _Instigator;
ErrorName = _ErrorName;
TossList = "";
return;
}
void AddTosser( const String Tosser )
{
TossList += " <- " + Tosser;
return;
}
const String GetInstigator (void) { return (Instigator); }
const String GetTossList (void) { return (TossList); }
const String GetErrorName (void) { return (ErrorName); }
private:
String Instigator;
String TossList;
String ErrorName;
}; // class cException
} // namespace EXCEPTION
} // namespace TA3D
and the cpp file TA3D_Exception.cpp
Code: Select all
/*
** File: TA3D_Exception.cpp
** Notes:
** Cire: See notes in TA3D_Exception.h
*/
#include "StdAfx.h"
#include "TA3D_Exception.h"
namespace TA3D
{
namespace EXCEPTION
{
static bool ExceptionStatus = false;
static uint32 IndentLevel = 0;
bool IsExceptionInProgress (void)
{
return (ExceptionStatus);
}
void SetExceptionStatus (bool E)
{
ExceptionStatus = E;
return;
}
void IncrementIndent (void)
{
IndentLevel++;
return;
}
void DecrementIndent (void)
{
if (IndentLevel != 0)
IndentLevel--;
return;
}
uint32 GetIndentLevel (void)
{
return (IndentLevel);
}
void __cdecl ThrowFatal( const char *Format, ... )
{
char Buffer[2000];
String BufferToss;
va_list marker;
va_start (marker, Format);
vsprintf (Buffer, Format, marker);
va_end (marker);
dprintf ("Throwing error string -> %s\n", Buffer);
BufferToss = String(Buffer);
SetExceptionStatus (true);
throw (BufferToss);
return;
}
// TODO: output to global debugger.
void __cdecl GlobalDebuggerPrintf (const char *Format, ...)
{
char Buffer[2000];
va_list marker;
// if (GlobalDebugger == NULL)
// return;
va_start (marker, Format);
vsprintf (Buffer, Format, marker);
va_end (marker);
// GlobalDebugger->DebugPrintf (Buffer);
return;
}
} // namespace EXCEPTION
} // namespace TA3D
Finally new HPI handler code, begining with
TA3D_hpi.h
Code: Select all
/*
** File: TA3D_hpi.h
** Notes:
** Cire: The original author of most of this code is Joe D, aka Kingbot
** I modified it to be more complain with C++ as it was mostly
** C based. I wrapped it neatly in a class, and exposed only
** those methods that the game engine need to access.
** TODO: If this is to be accessed by multiple threads it should be
** rewritten as it currently can not handle multiple calls.
** HPIITEM might be expanded to keep a reference track of
** how many times it gets asked to decode some file, if it
** reaches some point it might just keep that 'data' in its
** self and return it instead of having to decode each time.
*/
#pragma once
namespace TA3D
{
namespace UTILS
{
namespace HPI
{
#define HEX_HAPI 0x49504148
#define HPI_V1 0x00010000
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
class cHPIHandler
{
// Member Declarations:
private:
#pragma pack(1) // Byte alignment.
struct HPIVERSION
{
sint32 HPIMarker; /* Must be HEX_HAPI */
sint32 Version; /* Must be HPI_V1 */
};
struct HPIHEADER
{
sint32 DirectorySize; /* Directory size */
sint32 Key; /* Decode key */
sint32 Start; /* Directory offset */
};
struct HPIENTRY
{
sint32 NameOffset;
sint32 CountOffset;
sint8 Flag;
};
struct HPICHUNK
{
sint32 Marker; /* always 0x48535153 (SQSH) */
sint8 Unknown1; /* I have no idea what these mean */
sint8 CompMethod; /* 1 = lz77, 2 = zlib */
sint8 Encrypt; /* Is the chunk encrypted? */
sint32 CompressedSize; /* the length of the compressed data */
sint32 DecompressedSize; /* the length of the decompressed data */
sint32 Checksum; /* check sum */
};
struct HPIFILEDATA
{
HPIHEADER H1;
sint8 Key;
std::string HPIFileName;
sint8 *Directory;
FILE *HPIFile;
};
struct HPIITEM
{
HPIFILEDATA *hfd;
HPIENTRY *E1;
sint32 IsDir;
sint8 *Name;
sint32 Size;
};
#pragma pack()
// Member Functions:
private:
void AddArchive( const std::string &FileName );
void LocateAndReadFiles( const std::string &Path, const std::string &FileSearch );
void ProcessRoot( HPIFILEDATA *hfd, const std::string &StartPath, sint32 offset );
void ProcessSubDir( HPIITEM *hi );
void *GetMem( sint32 size, sint32 zero );
sint32 ReadAndDecrypt( sint32 fpos, byte *buff, sint32 buffsize );
sint32 ZLibDecompress( byte *out, byte *in, HPICHUNK *Chunk );
sint32 LZ77Decompress( byte *out, byte *in, HPICHUNK *Chunk );
sint32 Decompress( byte *out, byte *in, HPICHUNK *Chunk );
void CloseTheFile( HPIFILEDATA *hfd );
void cHPIHandler::CloseCurrentFile( void );
byte *cHPIHandler::DecodeFileToMem( HPIITEM *hi );
public:
void SearchDirForArchives( const std::string &Path );
// constructors:
cHPIHandler::cHPIHandler() { HPIInfo=NULL; }
cHPIHandler::cHPIHandler( const std::string &Path )
{
HPIInfo=NULL;
SearchDirForArchives( Path );
}
// DeConstructor
~cHPIHandler();
void ShowArchive(); // for debug only we don't need it.
unsigned char * PullFromHPI( const std::string &FileName );
// Member Variables:
private:
HPIFILEDATA *HPIInfo;
std::string cDir;
typedef std::map< std::string, HPIITEM *> HPIARCHIVE;
HPIARCHIVE m_Archive;
}; // class cHPIHandler;
} // namespace HPI
} // namespace utils
} // namespace TA3D
Now the TA3D_hpp.cpp, please note that while this is useable it is NOT finished, there are several memory leaks in it. Also since I last changed it to use 'size' specific types in platforms I havn't tested it to see if it functions correctly, a bit of debugging may be needed.
TA3D_hpp.cpp
Code: Select all
/*
** File: TA3D_hpi.cpp
** Notes:
** Cire: See notes in TA3D_hpp.h
*/
#include "stdafx.h"
#include "TA3D_hpi.h"
#if defined TA3D_PLATFORM_WINDOWS
#include "tools/win32/include/zlib.h"
#pragma comment(lib, "tools/win32/libs/zlib.lib")
//#elif
// otherplatform includes for zlib.
#endif
using namespace std;
using namespace TA3D;
using namespace TA3D::UTILS::HPI;
void * cHPIHandler::GetMem( sint32 size, sint32 zero )
{
void *result;
if( zero )
result = calloc( size, 1 );
else
result = malloc( size );
/*
TODO: Global DEBUGGER NOTIFICATION HERE.
if( !result )
GlobalDebugger->Failed to alloc memory for hpi
*/
return result;
}
int cHPIHandler::ReadAndDecrypt( sint32 fpos, byte *buff, sint32 buffsize)
{
sint32 count, tkey, result;
fseek(HPIInfo->HPIFile, fpos, SEEK_SET);
result = (sint32)fread(buff, buffsize, 1, HPIInfo->HPIFile);
if (HPIInfo->Key)
{
for (count = 0; count < buffsize; count++)
{
tkey = (fpos + count) ^ HPIInfo->Key;
buff[count] = tkey ^ ~buff[count];
}
}
return result;
}
int cHPIHandler::ZLibDecompress( byte *out, byte *in, HPICHUNK *Chunk)
{
z_stream zs;
sint32 result;
zs.next_in = in;
zs.avail_in = Chunk->CompressedSize;
zs.total_in = 0;
zs.next_out = out;
zs.avail_out = Chunk->DecompressedSize;
zs.total_out = 0;
zs.msg = NULL;
zs.state = NULL;
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = NULL;
zs.data_type = Z_BINARY;
zs.adler = 0;
zs.reserved = 0;
result = inflateInit(&zs);
if (result != Z_OK) {
//printf("Error on inflateInit %d\nMessage: %s\n", result, zs.msg);
return 0;
}
result = inflate(&zs, Z_FINISH);
if (result != Z_STREAM_END) {
//printf("Error on inflate %d\nMessage: %s\n", result, zs.msg);
zs.total_out = 0;
}
result = inflateEnd(&zs);
if (result != Z_OK) {
//printf("Error on inflateEnd %d\nMessage: %s\n", result, zs.msg);
return 0;
}
return zs.total_out;
}
sint32 cHPIHandler::LZ77Decompress( byte *out, byte *in, HPICHUNK *Chunk)
{
sint32 x, work1, work2, work3, inptr, outptr, done, DPtr;
schar DBuff[4096];
done = 0;
inptr = 0;
outptr = 0;
work1 = 1;
work2 = 1;
work3 = in[inptr++];
while (!done)
{
if ((work2 & work3) == 0)
{
out[outptr++] = in[inptr];
DBuff[work1] = in[inptr];
work1 = (work1 + 1) & 0xFFF;
inptr++;
}
else
{ int
count = *((uint16 *) (in+inptr));
inptr += 2;
DPtr = count >> 4;
if (DPtr == 0)
return outptr;
else
{
count = (count & 0x0f) + 2;
if (count >= 0)
{
for (x = 0; x < count; x++)
{
out[outptr++] = DBuff[DPtr];
DBuff[work1] = DBuff[DPtr];
DPtr = (DPtr + 1) & 0xFFF;
work1 = (work1 + 1) & 0xFFF;
}
}
}
}
work2 *= 2;
if (work2 & 0x0100)
{
work2 = 1;
work3 = in[inptr++];
}
}
return outptr;
}
sint32 cHPIHandler::Decompress( byte *out, byte *in, HPICHUNK *Chunk )
{
sint32 x, Checksum;
Checksum = 0;
for (x = 0; x < Chunk->CompressedSize; x++) {
Checksum += (byte) in[x];
if (Chunk->Encrypt)
in[x] = (in[x] - x) ^ x;
}
if (Chunk->Checksum != Checksum)
{
// GlobalDebugger-> Checksum error! Calculated: 0x%X Actual: 0x%X\n", Checksum, Chunk->Checksum);
return 0;
}
switch (Chunk->CompMethod) {
case 1 : return LZ77Decompress(out, in, Chunk);
case 2 : return ZLibDecompress(out, in, Chunk);
default : return 0;
}
}
byte *cHPIHandler::DecodeFileToMem(HPIITEM *hi)
{
sint32 DeCount,DeLen, x, WriteSize, WritePtr, Offset, Length, FileFlag, *DeSize;
byte *DeBuff, *WriteBuff;
HPIENTRY *Entry;
HPICHUNK *Chunk;
if (!hi)
return NULL;
Entry = hi->E1;
Offset = *((sint32 *) (HPIInfo->Directory + Entry->CountOffset));
Length = *((sint32 *) (HPIInfo->Directory + Entry->CountOffset + 4));
FileFlag = *(HPIInfo->Directory + Entry->CountOffset + 8);
WriteBuff = (byte *)GetMem(Length+1, 0);
if (!WriteBuff)
{
// NO NEED to global deubber this, get meme shoulda done it for us.
return NULL;
}
WriteBuff[Length] = 0;
if (FileFlag) {
DeCount = Length / 65536;
if (Length % 65536)
DeCount++;
DeLen = DeCount * sizeof(sint32);
DeSize = (sint32 *)GetMem(DeLen, 0);
ReadAndDecrypt(Offset, (byte *) DeSize, DeLen);
Offset += DeLen;
WritePtr = 0;
for (x = 0; x < DeCount; x++) {
Chunk = (HPICHUNK *)GetMem(DeSize[x], 0);
ReadAndDecrypt(Offset, (byte *) Chunk, DeSize[x]);
Offset += DeSize[x];
DeBuff = (byte *) (Chunk+1);
WriteSize = Decompress(WriteBuff+WritePtr, DeBuff, Chunk);
WritePtr += WriteSize;
free(Chunk);
}
free(DeSize);
}
else {
// file not compressed
ReadAndDecrypt(Offset, WriteBuff, Length);
}
return WriteBuff;
}
void cHPIHandler::CloseTheFile(HPIFILEDATA *hfd)
{
if (!hfd)
return;
if (hfd->Directory)
{
free(hfd->Directory);
hfd->Directory = NULL;
}
if (hfd->HPIFile)
fclose(hfd->HPIFile);
hfd->HPIFile = NULL;
}
void cHPIHandler::CloseCurrentFile( void )
{
if (HPIInfo)
CloseTheFile(HPIInfo);
}
void cHPIHandler::ProcessSubDir( HPIITEM *hi )
{
sint32 *FileCount, *FileLength, *EntryOffset, *Entries, count;
schar *Name;
HPIENTRY *Base, *Entry;
HPIITEM *li;
Base = hi->E1;
if (Base)
Entries = (sint32 *) (HPIInfo->Directory + Base->CountOffset);
else
Entries = (sint32 *) (HPIInfo->Directory + hi->hfd->H1.Start);
EntryOffset = Entries + 1;
Entry = (HPIENTRY *) (HPIInfo->Directory + *EntryOffset);
for (count = 0; count < *Entries; count++) {
Name = HPIInfo->Directory + Entry->NameOffset;
FileCount = (sint32 *) (HPIInfo->Directory + Entry->CountOffset);
FileLength = FileCount + 1;
li = (HPIITEM *)GetMem(sizeof(HPIITEM), 1);
li->hfd = hi->hfd;
li->Name = Name;
li->E1 = Entry;
if (Entry->Flag == 1)
{
li->Size = 0;
li->IsDir = 1;
}
else
{
li->Size = *FileLength;
li->IsDir = 0;
}
if (Entry->Flag == 1)
{
std::string sDir = cDir;
cDir += (char *)Name;
cDir += "\\";
ProcessSubDir( li );
cDir = sDir;
} else {
std::string f = cDir + (char *)Name;
m_Archive[f] = li; // memory leak here FIX!!!
}
Entry++;
}
}
void cHPIHandler::ProcessRoot(HPIFILEDATA *hfd, const std::string &StartPath, sint32 offset )
{
sint32 *Entries, *FileCount, *EntryOffset;
schar *Name;
std::string MyPath;
HPIInfo = hfd;
Entries = (sint32 *)(hfd->Directory + offset);
EntryOffset = Entries + 1;
HPIENTRY *Entry = (HPIENTRY *)(hfd->Directory + *EntryOffset);
for( sint32 count = 0; count < *Entries; count++ )
{
Name = hfd->Directory + Entry->NameOffset;
FileCount = (sint32 *) (hfd->Directory + Entry->CountOffset);
if (Entry->Flag == 1)
{
MyPath = StartPath;
if( MyPath.length() )
MyPath += "\\";
MyPath += (char *)Name;
cDir = MyPath + "\\";
// printf( "%s\n", MyPath.c_str() );
HPIITEM *hi = (HPIITEM *)GetMem(sizeof(HPIITEM), 1);
hi->hfd = hfd;
hi->IsDir = 1;
hi->Size = 0;
hi->Name = Name;
hi->E1 = Entry;
ProcessSubDir( hi );
}
Entry++;
}
}
// start new code.
void cHPIHandler::AddArchive( const std::string &FileName )
{
HPIFILEDATA *hfd = (HPIFILEDATA *)GetMem(sizeof(HPIFILEDATA), 1);
if (!hfd)
return; // No Need to generate error here as getmem already did it.
hfd->HPIFileName = FileName;
errno_t err;
if( (err = fopen_s( &hfd->HPIFile, hfd->HPIFileName.c_str(), "rb" )) != 0 )
{
CloseTheFile(hfd);
free(hfd);
// GlobalDebugger-> Failed to open hpi file for reading.
return;
}
HPIVERSION hv;
fread(&hv, sizeof(HPIVERSION), 1, hfd->HPIFile);
if( hv.Version != HPI_V1 || hv.HPIMarker != HEX_HAPI )
{
// No need to generate error I don't think, just wasn't an
// hpi archive we were interested in, possibly packed with
// version 2, or was a save file.
CloseTheFile(hfd);
free(hfd);
hfd = NULL;
}
fread(&hfd->H1, sizeof(HPIHEADER), 1, hfd->HPIFile);
if (hfd->H1.Key)
hfd->Key = ~((hfd->H1.Key * 4) | (hfd->H1.Key >> 6));
else
hfd->Key = 0;
int start = hfd->H1.Start;
int size = hfd->H1.DirectorySize;
hfd->Directory = (sint8 *)GetMem(size, 1);
HPIInfo = hfd;
ReadAndDecrypt(start, (byte *)hfd->Directory + start, size - start);
cDir = "";
ProcessRoot(hfd, "", start);
}
void cHPIHandler::LocateAndReadFiles( const std::string &Path, const std::string &FileSearch )
{
al_ffblk search;
if( al_findfirst(FileSearch.c_str(), &search, FA_RDONLY | FA_ARCH ) ==0 )
{
do
{
AddArchive( Path + search.name );
} while( al_findnext( &search ) == 0 );
al_findclose(&search);
}
}
void cHPIHandler::SearchDirForArchives( const std::string &Path )
{
schar ext[4][6] = { "*.ufo", "*.hpi", "*.ccx", "*.gp3" };
for( uint32 i = 0; i < 4; i++ )
LocateAndReadFiles( Path, Path + (char *)ext[i] );
}
cHPIHandler::~cHPIHandler()
{
// TODO: CLEANUP!!!!
}
void cHPIHandler::ShowArchive()
{
for(HPIARCHIVE::iterator iter = m_Archive.begin(); iter != m_Archive.end(); iter++)
{
printf( "(arch)%s\n", (*iter).first.c_str() );
}
}
unsigned char *cHPIHandler::PullFromHPI( const std::string &FileName )
{
HPIARCHIVE::const_iterator iterFind = m_Archive.find( FileName );
if( iterFind != m_Archive.end() )
{
HPIITEM *hi = hi = iterFind->second;
return DecodeFileToMem( hi );
}
return NULL;
}
I'll now wait for the latest source releases before contininug. My next goals for next week will include a global debugger, perhaps implementing new sound/music support via discuessed fmod, and perhaps serveral class optionations to other areas, as well i'll work on finishing this ta3d_hpi.cpp file, and a few others.
Unless zuff or someone else specifically assings me to another element, I plan on keeping slowly rewritting most of the engine to be cpp complain and optomizing. Since we now have platform specific typecasing I also plan on enahcing win32 support and perhaps adding a feature or two myself if its cool with the team.
++Cire.