2007-01-15 12:09:25 -08:00
|
|
|
/*
|
|
|
|
This file is part of Warzone 2100.
|
|
|
|
Copyright (C) 1999-2004 Eidos Interactive
|
|
|
|
Copyright (C) 2005-2007 Warzone Resurrection Project
|
|
|
|
|
|
|
|
Warzone 2100 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 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
2007-06-28 10:47:08 -07:00
|
|
|
/*
|
|
|
|
* FrameResource.c
|
|
|
|
*
|
|
|
|
* Framework Resource file processing functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
2007-02-19 06:10:44 -08:00
|
|
|
#include <ctype.h>
|
2007-06-28 10:47:08 -07:00
|
|
|
#include "frame.h"
|
|
|
|
#include "frameresource.h"
|
|
|
|
#include "resly.h"
|
2007-07-16 10:19:47 -07:00
|
|
|
#include <physfs.h>
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
// Local prototypes
|
|
|
|
static RES_TYPE *psResTypes=NULL;
|
|
|
|
|
|
|
|
/* The initial resource directory and the current resource directory */
|
2007-08-21 05:59:05 -07:00
|
|
|
char aResDir[PATH_MAX];
|
|
|
|
char aCurrResDir[PATH_MAX];
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
// the current resource block ID
|
2007-10-15 11:09:18 -07:00
|
|
|
static SDWORD resBlockID;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
// prototypes
|
|
|
|
static void ResetResourceFile(void);
|
|
|
|
|
|
|
|
// callback to resload screen.
|
|
|
|
static RESLOAD_CALLBACK resLoadCallback=NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/* set the callback function for the res loader*/
|
2006-09-13 02:09:05 -07:00
|
|
|
void resSetLoadCallback(RESLOAD_CALLBACK funcToCall)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
resLoadCallback = funcToCall;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do the callback for the resload display function */
|
2007-04-08 14:39:24 -07:00
|
|
|
static inline void resDoResLoadCallback(void)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
if(resLoadCallback)
|
|
|
|
{
|
|
|
|
resLoadCallback();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialise the resource module */
|
|
|
|
BOOL resInitialise(void)
|
|
|
|
{
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( psResTypes == NULL,
|
|
|
|
"resInitialise: resource module hasn't been shut down??" );
|
2007-06-28 10:47:08 -07:00
|
|
|
psResTypes = NULL;
|
|
|
|
resBlockID = 0;
|
|
|
|
resLoadCallback = NULL;
|
|
|
|
|
|
|
|
ResetResourceFile();
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Shutdown the resource module */
|
|
|
|
void resShutDown(void)
|
|
|
|
{
|
|
|
|
if (psResTypes != NULL) {
|
|
|
|
debug(LOG_WZ, "resShutDown: warning resources still allocated");
|
|
|
|
resReleaseAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// set the base resource directory
|
2007-10-27 09:12:00 -07:00
|
|
|
void resSetBaseDir(const char* pResDir)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(aResDir, pResDir, sizeof(aResDir));
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse the res file */
|
2007-12-10 15:15:46 -08:00
|
|
|
BOOL resLoad(const char *pResFile, SDWORD blockID)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2006-08-12 09:52:37 -07:00
|
|
|
char *pBuffer;
|
2007-06-28 10:47:08 -07:00
|
|
|
UDWORD size;
|
|
|
|
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(aCurrResDir, aResDir, sizeof(aCurrResDir));
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
// Note the block id number
|
|
|
|
resBlockID = blockID;
|
|
|
|
|
|
|
|
debug(LOG_WZ, "resLoad: loading %s", pResFile);
|
|
|
|
|
2006-02-18 10:54:37 -08:00
|
|
|
// Load the RES file; allocate memory for a wrf, and load it
|
2007-06-14 12:21:52 -07:00
|
|
|
if (!loadFile(pResFile, &pBuffer, &size))
|
|
|
|
{
|
2007-06-28 10:47:08 -07:00
|
|
|
debug(LOG_ERROR, "resLoad: failed to load %s", pResFile);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// and parse it
|
|
|
|
resSetInputBuffer(pBuffer, size);
|
2007-06-14 12:21:52 -07:00
|
|
|
if (res_parse() != 0)
|
|
|
|
{
|
2007-06-28 10:47:08 -07:00
|
|
|
debug(LOG_ERROR, "resLoad: failed to parse %s", pResFile);
|
2007-06-14 12:21:52 -07:00
|
|
|
free(pBuffer);
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-04-15 03:43:05 -07:00
|
|
|
free(pBuffer);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Allocate a RES_TYPE structure */
|
2007-04-08 10:15:56 -07:00
|
|
|
static RES_TYPE* resAlloc(const char *pType)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
RES_TYPE *psT;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Check for a duplicate type
|
|
|
|
for(psT = psResTypes; psT; psT = psT->psNext)
|
|
|
|
{
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( strcmp(psT->aType, pType) != 0,
|
|
|
|
"resAlloc: Duplicate function for type: %s", pType );
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Allocate the memory
|
2007-04-15 03:43:05 -07:00
|
|
|
psT = (RES_TYPE *)malloc(sizeof(RES_TYPE));
|
2007-06-28 10:47:08 -07:00
|
|
|
if (!psT)
|
|
|
|
{
|
2006-08-22 07:28:49 -07:00
|
|
|
debug( LOG_ERROR, "resAlloc: Out of memory" );
|
|
|
|
abort();
|
2007-04-08 10:15:56 -07:00
|
|
|
return NULL;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// setup the structure
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(psT->aType, pType, sizeof(psT->aType));
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
psT->HashedType=HashString(psT->aType); // store a hased version for super speed !
|
|
|
|
|
|
|
|
psT->psRes = NULL;
|
|
|
|
|
2007-04-08 10:15:56 -07:00
|
|
|
return psT;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Add a buffer load function for a file type */
|
2006-11-03 13:35:50 -08:00
|
|
|
BOOL resAddBufferLoad(const char *pType, RES_BUFFERLOAD buffLoad,
|
2007-06-28 10:47:08 -07:00
|
|
|
RES_FREE release)
|
|
|
|
{
|
2007-04-08 10:15:56 -07:00
|
|
|
RES_TYPE *psT = resAlloc(pType);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 10:15:56 -07:00
|
|
|
if (!psT)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
psT->buffLoad = buffLoad;
|
2007-04-08 14:39:24 -07:00
|
|
|
psT->fileLoad = NULL;
|
|
|
|
psT->release = release;
|
|
|
|
|
|
|
|
psT->psNext = psResTypes;
|
|
|
|
psResTypes = psT;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Add a file name load function for a file type */
|
|
|
|
BOOL resAddFileLoad(const char *pType, RES_FILELOAD fileLoad,
|
|
|
|
RES_FREE release)
|
|
|
|
{
|
|
|
|
RES_TYPE *psT = resAlloc(pType);
|
|
|
|
|
|
|
|
if (!psT)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
psT->buffLoad = NULL;
|
|
|
|
psT->fileLoad = fileLoad;
|
2007-06-28 10:47:08 -07:00
|
|
|
psT->release = release;
|
|
|
|
|
|
|
|
psT->psNext = psResTypes;
|
|
|
|
psResTypes = psT;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a string lower case
|
2006-11-03 13:35:50 -08:00
|
|
|
void resToLower(char *pStr)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
while (*pStr != 0)
|
|
|
|
{
|
|
|
|
if (isupper(*pStr))
|
|
|
|
{
|
2006-11-03 13:35:50 -08:00
|
|
|
*pStr = (char)(*pStr - (char)('A' - 'a'));
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
pStr += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-21 05:59:05 -07:00
|
|
|
static char LastResourceFilename[PATH_MAX];
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-07-25 15:37:48 -07:00
|
|
|
/*!
|
|
|
|
* Returns the filename of the last resource file loaded
|
|
|
|
* The filename is always null terminated
|
|
|
|
*/
|
|
|
|
const char *GetLastResourceFilename(void)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-25 15:37:48 -07:00
|
|
|
return LastResourceFilename;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
2007-07-25 15:37:48 -07:00
|
|
|
/*!
|
|
|
|
* Set the resource name of the last resource file loaded
|
|
|
|
*/
|
|
|
|
void SetLastResourceFilename(const char *pName)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(LastResourceFilename, pName, sizeof(LastResourceFilename));
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Structure for each file currently in use in the resource ... probably only going to be one ... but we will handle upto MAXLOADEDRESOURCE
|
|
|
|
typedef struct
|
|
|
|
{
|
2006-08-12 09:52:37 -07:00
|
|
|
char *pBuffer; // a pointer to the data
|
2007-06-28 10:47:08 -07:00
|
|
|
UDWORD size; // number of bytes
|
|
|
|
UBYTE type; // what type of resource is it
|
2006-02-18 10:54:37 -08:00
|
|
|
} RESOURCEFILE;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
#define RESFILETYPE_EMPTY (0) // empty entry
|
|
|
|
#define RESFILETYPE_PC_SBL (1) // Johns SBL stuff
|
|
|
|
#define RESFILETYPE_LOADED (2) // Loaded from a file (!)
|
|
|
|
#define RESFILETYPE_WDGPTR (3) // A pointer from the WDG cache
|
|
|
|
|
|
|
|
|
|
|
|
#define MAXLOADEDRESOURCES (6)
|
|
|
|
static RESOURCEFILE LoadedResourceFiles[MAXLOADEDRESOURCES];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clear out the resource list ... needs to be called during init.
|
|
|
|
static void ResetResourceFile(void)
|
|
|
|
{
|
|
|
|
UWORD i;
|
|
|
|
|
|
|
|
for (i=0;i<MAXLOADEDRESOURCES;i++)
|
|
|
|
{
|
|
|
|
LoadedResourceFiles[i].type=RESFILETYPE_EMPTY;
|
2006-02-18 10:54:37 -08:00
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns an empty resource entry or -1 if none exsist
|
2006-09-19 11:45:48 -07:00
|
|
|
static SDWORD FindEmptyResourceFile(void)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
UWORD i;
|
|
|
|
for (i=0;i<MAXLOADEDRESOURCES ;i++ )
|
|
|
|
{
|
|
|
|
if (LoadedResourceFiles[i].type==RESFILETYPE_EMPTY)
|
|
|
|
return(i);
|
2006-02-18 10:54:37 -08:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
return(-1); // ERROR
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get a resource data file ... either loads it or just returns a pointer
|
2006-09-19 11:45:48 -07:00
|
|
|
static BOOL RetreiveResourceFile(char *ResourceName, RESOURCEFILE **NewResource)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
SDWORD ResID;
|
|
|
|
RESOURCEFILE *ResData;
|
|
|
|
UDWORD size;
|
2006-08-12 09:52:37 -07:00
|
|
|
char *pBuffer;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
ResID=FindEmptyResourceFile();
|
|
|
|
if (ResID==-1) return(FALSE); // all resource files are full
|
|
|
|
|
|
|
|
ResData= &LoadedResourceFiles[ResID];
|
|
|
|
*NewResource=ResData;
|
|
|
|
|
|
|
|
// This is needed for files that do not fit in the WDG cache ... (VAB file for example)
|
2006-08-12 09:52:37 -07:00
|
|
|
if (!loadFile(ResourceName, &pBuffer, &size))
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ResData->type=RESFILETYPE_LOADED;
|
|
|
|
ResData->size=size;
|
|
|
|
ResData->pBuffer=pBuffer;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Free up the file depending on what type it is
|
2006-09-19 11:45:48 -07:00
|
|
|
static void FreeResourceFile(RESOURCEFILE *OldResource)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
switch (OldResource->type)
|
2007-06-14 12:21:52 -07:00
|
|
|
{
|
2007-06-28 10:47:08 -07:00
|
|
|
case RESFILETYPE_LOADED:
|
2007-04-15 03:43:05 -07:00
|
|
|
free(OldResource->pBuffer);
|
2007-06-14 12:21:52 -07:00
|
|
|
OldResource->pBuffer = NULL;
|
2007-06-28 10:47:08 -07:00
|
|
|
break;
|
2007-06-14 12:21:52 -07:00
|
|
|
|
2007-04-07 06:23:14 -07:00
|
|
|
default:
|
|
|
|
debug(LOG_WARNING, "resource not freed");
|
2007-06-14 12:21:52 -07:00
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
|
|
|
|
// Remove from the list
|
2006-02-18 10:54:37 -08:00
|
|
|
OldResource->type=RESFILETYPE_EMPTY;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
static inline RES_DATA* resDataInit(const char *DebugName, UDWORD DataIDHash, void *pData, UDWORD BlockID)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-10-24 09:54:53 -07:00
|
|
|
// Allocate memory to hold the RES_DATA structure plus the identifying string
|
|
|
|
RES_DATA* psRes = malloc(sizeof(RES_DATA) + strlen(DebugName) + 1);
|
2007-04-08 14:39:24 -07:00
|
|
|
if (!psRes)
|
|
|
|
{
|
|
|
|
debug(LOG_ERROR, "resDataInit: Out of memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-10-29 10:53:37 -07:00
|
|
|
// Initialize the pointer for our ID string
|
2007-10-24 09:54:53 -07:00
|
|
|
psRes->aID = (char*)(psRes + 1);
|
2007-07-25 15:37:48 -07:00
|
|
|
|
2007-10-24 09:54:53 -07:00
|
|
|
// Copy over the identifying string
|
2007-07-25 15:37:48 -07:00
|
|
|
strcpy((char*)psRes->aID, DebugName);
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
psRes->pData = pData;
|
2006-12-02 05:06:56 -08:00
|
|
|
psRes->blockID = BlockID;
|
2007-04-08 14:39:24 -07:00
|
|
|
psRes->HashedID = DataIDHash;
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
psRes->usage = 0;
|
2007-04-08 14:39:24 -07:00
|
|
|
|
|
|
|
return psRes;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-29 16:33:21 -07:00
|
|
|
#ifdef ENABLE_NLS
|
2007-07-16 10:19:47 -07:00
|
|
|
/*!
|
|
|
|
* Return the language part of the selected locale
|
|
|
|
*/
|
|
|
|
static WZ_DECL_CONST const char* getLanguage(void)
|
|
|
|
{
|
|
|
|
static char language[4] = { '\0' }; // ISO639 language code has to fit in!
|
|
|
|
static BOOL haveLanguage = FALSE;
|
|
|
|
|
|
|
|
if ( ! haveLanguage ) // only get language name once for speed optimization
|
|
|
|
{
|
|
|
|
char *localeName = setlocale(LC_MESSAGES, NULL);
|
|
|
|
char *delim = NULL;
|
|
|
|
|
|
|
|
haveLanguage = TRUE;
|
|
|
|
|
|
|
|
if ( !localeName )
|
|
|
|
{
|
|
|
|
return language; // Return empty string on errors
|
|
|
|
}
|
|
|
|
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(language, localeName, sizeof(language));
|
2007-07-16 10:19:47 -07:00
|
|
|
|
|
|
|
delim = strchr(language, '_');
|
|
|
|
|
|
|
|
if ( !delim )
|
|
|
|
{
|
|
|
|
delim = strchr(language, '.');
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( delim )
|
|
|
|
{
|
|
|
|
*delim = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return language;
|
|
|
|
}
|
2007-07-29 16:33:21 -07:00
|
|
|
#endif // ENABLE_NLS
|
2007-07-16 10:19:47 -07:00
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* check if given file exists in a locale dependend subdir
|
|
|
|
* if so, modify given fileName to hold the locale dep. file,
|
|
|
|
* else do not change given fileName
|
2007-10-27 09:12:00 -07:00
|
|
|
* \param fileName[out] must be at least MAX_PATH bytes large
|
2007-07-16 10:19:47 -07:00
|
|
|
*/
|
|
|
|
static void makeLocaleFile(char fileName[]) // given string must have MAX_PATH size
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_NLS
|
|
|
|
const char * language = getLanguage();
|
2007-08-21 05:59:05 -07:00
|
|
|
char localeFile[PATH_MAX];
|
2007-07-16 10:19:47 -07:00
|
|
|
|
|
|
|
if ( language[0] == '\0' || // could not get language
|
2007-08-21 05:59:05 -07:00
|
|
|
strlen(fileName) + strlen(language) + 1 >= PATH_MAX )
|
2007-07-16 10:19:47 -07:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-28 04:35:26 -07:00
|
|
|
snprintf(localeFile, sizeof(localeFile), "locale/%s/%s", language, fileName);
|
2007-07-16 10:19:47 -07:00
|
|
|
|
|
|
|
if ( PHYSFS_exists(localeFile) )
|
|
|
|
{
|
2007-10-27 09:12:00 -07:00
|
|
|
strlcpy(fileName, localeFile, sizeof(localeFile));
|
2007-07-16 10:19:47 -07:00
|
|
|
debug(LOG_WZ, "Found translated file: %s", fileName);
|
|
|
|
}
|
|
|
|
#endif // ENABLE_NLS
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-25 15:37:48 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Call the load function (registered in data.c)
|
|
|
|
* for this filetype
|
|
|
|
*/
|
2007-04-08 14:39:24 -07:00
|
|
|
BOOL resLoadFile(const char *pType, const char *pFile)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
RES_TYPE *psT;
|
|
|
|
void *pData;
|
|
|
|
RES_DATA *psRes;
|
2007-08-21 05:59:05 -07:00
|
|
|
char aFileName[PATH_MAX];
|
2007-07-25 15:37:48 -07:00
|
|
|
UDWORD HashedName, HashedType = HashString(pType);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
// Find the resource-type
|
|
|
|
for(psT = psResTypes; psT != NULL; psT = psT->psNext )
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-04-08 14:39:24 -07:00
|
|
|
if (psT->HashedType == HashedType)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
2007-07-25 15:37:48 -07:00
|
|
|
if (psT == NULL)
|
|
|
|
{
|
2007-04-08 14:39:24 -07:00
|
|
|
debug(LOG_WZ, "resLoadFile: Unknown type: %s", pType);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
// Check for duplicates
|
|
|
|
HashedName = HashStringIgnoreCase(pFile);
|
2007-07-25 15:37:48 -07:00
|
|
|
for (psRes = psT->psRes; psRes; psRes = psRes->psNext)
|
|
|
|
{
|
|
|
|
if(psRes->HashedID == HashedName)
|
|
|
|
{
|
2007-04-08 14:39:24 -07:00
|
|
|
debug(LOG_WZ, "resLoadFile: Duplicate file name: %s (hash %x) for type %s",
|
|
|
|
pFile, HashedName, psT->aType);
|
|
|
|
// assume that they are actually both the same and silently fail
|
|
|
|
// lovely little hack to allow some files to be loaded from disk (believe it or not!).
|
|
|
|
return TRUE;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2007-04-08 14:39:24 -07:00
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
// Create the file name
|
2007-08-21 05:59:05 -07:00
|
|
|
if (strlen(aCurrResDir) + strlen(pFile) + 1 >= PATH_MAX)
|
2007-07-25 15:37:48 -07:00
|
|
|
{
|
2007-04-08 14:39:24 -07:00
|
|
|
debug(LOG_ERROR, "resLoadFile: Filename too long!! %s%s", aCurrResDir, pFile);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2007-10-27 08:47:17 -07:00
|
|
|
strlcpy(aFileName, aCurrResDir, sizeof(aFileName));
|
|
|
|
strlcat(aFileName, pFile, sizeof(aFileName));
|
2007-04-08 14:39:24 -07:00
|
|
|
|
2007-07-16 10:19:47 -07:00
|
|
|
makeLocaleFile(aFileName); // check for translated file
|
|
|
|
|
2007-07-25 15:37:48 -07:00
|
|
|
SetLastResourceFilename(pFile); // Save the filename in case any routines need it
|
2007-04-08 14:39:24 -07:00
|
|
|
|
|
|
|
// load the resource
|
|
|
|
if (psT->buffLoad)
|
|
|
|
{
|
|
|
|
RESOURCEFILE *Resource;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
// Load the file in a buffer
|
2007-07-25 15:37:48 -07:00
|
|
|
if (!RetreiveResourceFile(aFileName, &Resource))
|
|
|
|
{
|
2007-04-08 14:39:24 -07:00
|
|
|
debug(LOG_ERROR, "resLoadFile: Unable to retreive resource - %s", aFileName);
|
|
|
|
return(FALSE);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
// Now process the buffer data
|
|
|
|
if (!psT->buffLoad(Resource->pBuffer, Resource->size, &pData))
|
|
|
|
{
|
|
|
|
FreeResourceFile(Resource);
|
|
|
|
psT->release( pData );
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
FreeResourceFile(Resource);
|
|
|
|
}
|
|
|
|
else if(psT->fileLoad)
|
|
|
|
{
|
|
|
|
// Process data directly from file
|
|
|
|
if (!psT->fileLoad(aFileName, &pData))
|
|
|
|
{
|
|
|
|
psT->release( pData );
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
2007-04-08 14:39:24 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
debug(LOG_ERROR, "resLoadFile: No load functions for this type (%s)", pType);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
resDoResLoadCallback(); // do callback.
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 14:39:24 -07:00
|
|
|
// Set up the resource structure if there is something to store
|
|
|
|
if (pData != NULL)
|
|
|
|
{
|
|
|
|
// LastResourceFilename may have been changed (e.g. by TEXPAGE loading)
|
2007-07-25 15:37:48 -07:00
|
|
|
psRes = resDataInit( GetLastResourceFilename(), HashStringIgnoreCase(GetLastResourceFilename()), pData, resBlockID );
|
2007-04-08 14:39:24 -07:00
|
|
|
if (!psRes)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-04-08 14:39:24 -07:00
|
|
|
psT->release(pData);
|
|
|
|
return FALSE;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2007-04-08 14:39:24 -07:00
|
|
|
|
|
|
|
// Add the resource to the list
|
|
|
|
psRes->psNext = psT->psRes;
|
|
|
|
psT->psRes = psRes;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return the resource for a type and hashedname */
|
2006-11-03 13:35:50 -08:00
|
|
|
void *resGetDataFromHash(const char *pType, UDWORD HashedID)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-29 09:58:16 -07:00
|
|
|
RES_TYPE *psT = NULL;
|
|
|
|
RES_DATA *psRes = NULL;
|
2007-06-28 10:47:08 -07:00
|
|
|
// Find the correct type
|
2007-07-29 09:58:16 -07:00
|
|
|
UDWORD HashedType = HashString(pType);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
for(psT = psResTypes; psT != NULL; psT = psT->psNext )
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
if (psT->HashedType==HashedType)
|
|
|
|
{
|
2007-07-29 09:58:16 -07:00
|
|
|
/* We found it */
|
2007-06-28 10:47:08 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-04-08 08:35:00 -07:00
|
|
|
|
2007-07-29 09:58:16 -07:00
|
|
|
ASSERT( psT != NULL, "resGetDataFromHash: Unknown type: %s", pType );
|
2007-06-28 10:47:08 -07:00
|
|
|
if (psT == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-07-29 09:58:16 -07:00
|
|
|
for(psRes = psT->psRes; psRes != NULL; psRes = psRes->psNext)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-04-08 08:35:00 -07:00
|
|
|
if (psRes->HashedID == HashedID)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-04-08 08:35:00 -07:00
|
|
|
/* We found it */
|
|
|
|
break;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-29 09:58:16 -07:00
|
|
|
ASSERT( psRes != NULL, "resGetDataFromHash: Unknown ID: %0x Type: %s", HashedID, pType );
|
2007-06-28 10:47:08 -07:00
|
|
|
if (psRes == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
psRes->usage += 1;
|
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
return psRes->pData;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return the resource for a type and ID */
|
2006-11-03 13:35:50 -08:00
|
|
|
void *resGetData(const char *pType, const char *pID)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-29 10:17:38 -07:00
|
|
|
void * data = resGetDataFromHash(pType, HashStringIgnoreCase(pID));
|
|
|
|
ASSERT(data != NULL, "resGetData: Unable to find data for %s type %s", pID, pType);
|
|
|
|
return data;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-03 13:35:50 -08:00
|
|
|
BOOL resGetHashfromData(const char *pType, const void *pData, UDWORD *pHash)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
RES_TYPE *psT;
|
|
|
|
RES_DATA *psRes;
|
|
|
|
|
|
|
|
// Find the correct type
|
|
|
|
UDWORD HashedType=HashString(pType);
|
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
for(psT = psResTypes; psT != NULL; psT = psT->psNext )
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
if (psT->HashedType==HashedType)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psT == NULL)
|
|
|
|
{
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( FALSE, "resGetHashfromData: Unknown type: %x", HashedType );
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the resource
|
|
|
|
for(psRes = psT->psRes; psRes; psRes = psRes->psNext)
|
|
|
|
{
|
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
if (psRes->pData == pData)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psRes == NULL)
|
|
|
|
{
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( FALSE, "resGetHashfromData:: couldn't find data for type %x\n", HashedType );
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pHash = psRes->HashedID;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-01-02 16:35:57 -08:00
|
|
|
const char* resGetNamefromData(const char* type, const void *data)
|
|
|
|
{
|
|
|
|
RES_TYPE *psT;
|
|
|
|
RES_DATA *psRes;
|
|
|
|
UDWORD HashedType;
|
|
|
|
|
|
|
|
if (type == NULL || data == NULL)
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the correct type
|
|
|
|
HashedType = HashString(type);
|
|
|
|
|
|
|
|
// Find the resource table for the given type
|
|
|
|
for (psT = psResTypes; psT != NULL; psT = psT->psNext)
|
|
|
|
{
|
|
|
|
if (psT->HashedType == HashedType)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psT == NULL)
|
|
|
|
{
|
|
|
|
ASSERT( FALSE, "resGetHashfromData: Unknown type: %x", HashedType );
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the resource in the resource table
|
|
|
|
for(psRes = psT->psRes; psRes; psRes = psRes->psNext)
|
|
|
|
{
|
|
|
|
if (psRes->pData == data)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psRes == NULL)
|
|
|
|
{
|
|
|
|
ASSERT( FALSE, "resGetHashfromData:: couldn't find data for type %x\n", HashedType );
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return psRes->aID;
|
|
|
|
}
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
/* Simply returns true if a resource is present */
|
2006-11-03 13:35:50 -08:00
|
|
|
BOOL resPresent(const char *pType, const char *pID)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
RES_TYPE *psT;
|
|
|
|
RES_DATA *psRes;
|
|
|
|
|
|
|
|
// Find the correct type
|
|
|
|
UDWORD HashedType=HashString(pType);
|
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
for(psT = psResTypes; psT != NULL; psT = psT->psNext )
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
if (psT->HashedType==HashedType)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bow out if unrecognised type */
|
2007-08-01 08:04:16 -07:00
|
|
|
ASSERT(psT != NULL, "resPresent: Unknown type");
|
2007-06-28 10:47:08 -07:00
|
|
|
if (psT == NULL)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
UDWORD HashedID=HashStringIgnoreCase(pID);
|
2007-08-01 08:04:16 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
for(psRes = psT->psRes; psRes; psRes = psRes->psNext)
|
|
|
|
{
|
|
|
|
if (psRes->HashedID==HashedID)
|
|
|
|
{
|
|
|
|
/* We found it */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Did we find it? */
|
|
|
|
if (psRes != NULL)
|
|
|
|
{
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Release all the resources currently loaded and the resource load functions */
|
|
|
|
void resReleaseAll(void)
|
|
|
|
{
|
2007-07-25 15:37:48 -07:00
|
|
|
RES_TYPE *psT, *psNT;
|
|
|
|
|
|
|
|
resReleaseAllData();
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
for(psT = psResTypes; psT != NULL; psT = psNT)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
2007-07-25 15:37:48 -07:00
|
|
|
psNT = psT->psNext;
|
|
|
|
free(psT);
|
|
|
|
}
|
|
|
|
|
|
|
|
psResTypes = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Release all the resources currently loaded but keep the resource load functions */
|
|
|
|
void resReleaseAllData(void)
|
|
|
|
{
|
|
|
|
RES_TYPE *psT;
|
|
|
|
RES_DATA *psRes, *psNRes;
|
|
|
|
|
|
|
|
for (psT = psResTypes; psT != NULL; psT = psT->psNext)
|
|
|
|
{
|
|
|
|
for(psRes = psT->psRes; psRes != NULL; psRes = psNRes)
|
2007-06-14 12:21:52 -07:00
|
|
|
{
|
|
|
|
if (psRes->usage == 0)
|
|
|
|
{
|
2007-08-01 08:04:16 -07:00
|
|
|
debug(LOG_NEVER, "resReleaseAllData: %s resource: %s(%04x) not used", psT->aType, psRes->aID, psRes->HashedID);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
2007-07-25 15:37:48 -07:00
|
|
|
|
2007-06-14 12:21:52 -07:00
|
|
|
if (psT->release != NULL)
|
|
|
|
{
|
|
|
|
psT->release(psRes->pData);
|
|
|
|
}
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
psNRes = psRes->psNext;
|
2007-04-15 03:43:05 -07:00
|
|
|
free(psRes);
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
2007-07-25 15:37:48 -07:00
|
|
|
psT->psRes = NULL;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// release the data for a particular block ID
|
|
|
|
void resReleaseBlockData(SDWORD blockID)
|
|
|
|
{
|
|
|
|
RES_TYPE *psT, *psNT;
|
|
|
|
RES_DATA *psPRes, *psRes, *psNRes;
|
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
for(psT = psResTypes; psT != NULL; psT = psNT)
|
2007-06-28 10:47:08 -07:00
|
|
|
{
|
|
|
|
psPRes = NULL;
|
|
|
|
for(psRes = psT->psRes; psRes; psRes = psNRes)
|
|
|
|
{
|
2007-06-14 12:21:52 -07:00
|
|
|
ASSERT(psRes != NULL, "resReleaseBlockData: null pointer passed into loop");
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2007-06-14 12:21:52 -07:00
|
|
|
if (psRes->blockID == blockID)
|
|
|
|
{
|
|
|
|
if (psRes->usage == 0)
|
|
|
|
{
|
2007-08-01 08:04:16 -07:00
|
|
|
debug(LOG_NEVER, "resReleaseBlockData: %s resource: %s(%04x) not used", psT->aType, psRes->aID,
|
2007-06-28 10:47:08 -07:00
|
|
|
psRes->HashedID);
|
|
|
|
}
|
|
|
|
if(psT->release != NULL)
|
|
|
|
{
|
2007-04-08 08:35:00 -07:00
|
|
|
psT->release( psRes->pData );
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( FALSE,"resReleaseAllData: NULL release function" );
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
psNRes = psRes->psNext;
|
2007-04-15 03:43:05 -07:00
|
|
|
free(psRes);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
if (psPRes == NULL)
|
|
|
|
{
|
|
|
|
psT->psRes = psNRes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
psPRes->psNext = psNRes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
psPRes = psRes;
|
|
|
|
psNRes = psRes->psNext;
|
|
|
|
}
|
|
|
|
}
|
2007-06-14 12:21:52 -07:00
|
|
|
|
2007-04-08 08:35:00 -07:00
|
|
|
psNT = psT->psNext;
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
}
|