Get rid of the ID number cruft in the string resource system:

* At the only place where these ID numbers where used (scrValDefSave and scrValDefLoad), use the key-string instead (e.g. "ZNULLBODY" instead of 17)
 * Rename function strresGetStringByID to strresGetString
 * Increment event save file version to 4 (version of savegame.es files)
 * Reject loading of savegames that need to load non-NULL ST_TEXTSTRING variables from version < 4

NOTE: This may break current savegames of games that use scripts with variables of type TEXTSTRING in them (AFAIK currently only ''some'' campaign and tutorial savegames have these).

This closes ticket:19

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5685 4a71c877-e1ca-e34f-864e-861f7616d084
master
Giel van Schijndel 2008-07-27 23:58:49 +00:00
parent 54ae7cda3a
commit 3eabf084ad
10 changed files with 128 additions and 104 deletions

View File

@ -40,7 +40,6 @@
typedef struct STR_RES typedef struct STR_RES
{ {
struct TREAP_NODE** psIDTreap; ///< The treap to store string identifiers struct TREAP_NODE** psIDTreap; ///< The treap to store string identifiers
int nextID; ///< The next free ID
} STR_RES; } STR_RES;
/* Initialise the string system */ /* Initialise the string system */
@ -53,7 +52,6 @@ STR_RES* strresCreate()
abort(); abort();
return NULL; return NULL;
} }
psRes->nextID = 0;
psRes->psIDTreap = treapCreate(); psRes->psIDTreap = treapCreate();
if (!psRes->psIDTreap) if (!psRes->psIDTreap)
@ -89,19 +87,10 @@ BOOL strresStoreString(STR_RES *psRes, const char* pID, const char* pString)
return false; return false;
} }
return treapAdd(psRes->psIDTreap, pID, pString, psRes->nextID++); return treapAdd(psRes->psIDTreap, pID, pString);
} }
const char* strresGetString(const STR_RES* psRes, const char* ID)
/* Get the string from an ID number */
const char* strresGetString(const STR_RES * psRes, int id)
{
ASSERT(psRes != NULL, "Invalid string resource pointer");
return treapFindByID(psRes->psIDTreap, id);
}
const char* strresGetStringByID(const STR_RES* psRes, const char* ID)
{ {
const char * string; const char * string;
@ -140,9 +129,9 @@ BOOL strresLoad(STR_RES* psRes, const char* fileName)
} }
/* Get the ID number for a string*/ /* Get the ID number for a string*/
int strresGetIDfromString(STR_RES *psRes, const char *pString) const char* strresGetIDfromString(STR_RES *psRes, const char *pString)
{ {
ASSERT(psRes != NULL, "Invalid string res pointer"); ASSERT(psRes != NULL, "Invalid string res pointer");
return treapFindID(psRes->psIDTreap, pString); return treapFindKey(psRes->psIDTreap, pString);
} }

View File

@ -32,9 +32,6 @@ extern struct STR_RES* strresCreate(void);
/* Release a string resource object */ /* Release a string resource object */
extern void strresDestroy(struct STR_RES *psRes); extern void strresDestroy(struct STR_RES *psRes);
/* Get the string from an ID number */
extern const char* strresGetString(const struct STR_RES *psRes, int id);
/** /**
* Retrieve a resource string from its identifier string. * Retrieve a resource string from its identifier string.
* *
@ -43,12 +40,12 @@ extern const char* strresGetString(const struct STR_RES *psRes, int id);
* @return the string associated with the given @c ID string, or NULL if none * @return the string associated with the given @c ID string, or NULL if none
* could be found. * could be found.
*/ */
extern const char* strresGetStringByID(const struct STR_RES* psRes, const char* ID); extern const char* strresGetString(const struct STR_RES* psRes, const char* ID);
/* Load a string resource file */ /* Load a string resource file */
extern BOOL strresLoad(struct STR_RES* psRes, const char* fileName); extern BOOL strresLoad(struct STR_RES* psRes, const char* fileName);
/* Get the ID string for a string */ /* Get the ID string for a string */
extern int strresGetIDfromString(struct STR_RES *psRes, const char *pString); extern const char* strresGetIDfromString(struct STR_RES *psRes, const char *pString);
#endif #endif

View File

@ -39,7 +39,6 @@ typedef struct TREAP_NODE
const char* key; //< The key to sort the node on const char* key; //< The key to sort the node on
unsigned int priority; //< Treap priority unsigned int priority; //< Treap priority
const char* string; //< The string stored in the treap const char* string; //< The string stored in the treap
int id; //< An ID number that can be used to refer to these strings
struct TREAP_NODE *psLeft, *psRight; //< The sub trees struct TREAP_NODE *psLeft, *psRight; //< The sub trees
} TREAP_NODE; } TREAP_NODE;
@ -137,7 +136,7 @@ static void treapAddNode(TREAP_NODE **ppsRoot, TREAP_NODE *psNew)
/* Add an object to a treap /* Add an object to a treap
*/ */
BOOL treapAdd(TREAP_NODE** psTreap, const char* key, const char* string, int id) BOOL treapAdd(TREAP_NODE** psTreap, const char* key, const char* string)
{ {
/* Over-allocate so that we can put the key and the string in the same /* Over-allocate so that we can put the key and the string in the same
* chunck of memory as the TREAP_NODE struct. Which means a single * chunck of memory as the TREAP_NODE struct. Which means a single
@ -156,8 +155,6 @@ BOOL treapAdd(TREAP_NODE** psTreap, const char* key, const char* string, int id)
psNew->key = strcpy((char*)(psNew + 1), key); psNew->key = strcpy((char*)(psNew + 1), key);
psNew->string = strcpy((char*)(psNew + 1) + key_size, string); psNew->string = strcpy((char*)(psNew + 1) + key_size, string);
psNew->id = id;
psNew->priority = rand(); psNew->priority = rand();
psNew->psLeft = NULL; psNew->psLeft = NULL;
psNew->psRight = NULL; psNew->psRight = NULL;
@ -204,64 +201,34 @@ const char* treapFind(TREAP_NODE** psTreap, const char *key)
return treapFindRec(*psTreap, key); return treapFindRec(*psTreap, key);
} }
static const char* treapFindByIDRec(TREAP_NODE const * const psNode, const int id) static const char* treapFindKeyRec(TREAP_NODE const * const psNode, const char * const string)
{ {
const char* str; const char* key;
if (psNode == NULL) if (psNode == NULL)
{ {
return NULL; return NULL;
} }
if (psNode->id == id)
{
return psNode->string;
}
str = treapFindByIDRec(psNode->psLeft, id);
if (str)
{
return str;
}
return treapFindByIDRec(psNode->psRight, id);
}
const char* treapFindByID(TREAP_NODE** psTreap, int id)
{
ASSERT(psTreap != NULL, "Invalid treap pointer!");
return treapFindByIDRec(*psTreap, id);
}
static int treapFindIDRec(TREAP_NODE const * const psNode, const char * const string)
{
int id;
if (psNode == NULL)
{
return -1;
}
if (strcmp(psNode->string, string) == 0) if (strcmp(psNode->string, string) == 0)
{ {
return psNode->id; return psNode->key;
} }
id = treapFindIDRec(psNode->psLeft, string); key = treapFindKeyRec(psNode->psLeft, string);
if (id != -1) if (key)
{ {
return id; return key;
} }
return treapFindIDRec(psNode->psRight, string); return treapFindKeyRec(psNode->psLeft, string);
} }
int treapFindID(TREAP_NODE** psTreap, const char* string) const char* treapFindKey(TREAP_NODE** psTreap, const char* string)
{ {
ASSERT(psTreap != NULL, "Invalid treap pointer!"); ASSERT(psTreap != NULL, "Invalid treap pointer!");
return treapFindIDRec(*psTreap, string); return treapFindKeyRec(*psTreap, string);
} }
/* Recursively free a treap */ /* Recursively free a treap */

View File

@ -45,16 +45,13 @@ extern struct TREAP_NODE** treapCreate(void);
/* Add an object to a treap /* Add an object to a treap
*/ */
extern BOOL treapAdd(struct TREAP_NODE** psTreap, const char *key, const char* string, int id); extern BOOL treapAdd(struct TREAP_NODE** psTreap, const char *key, const char* string);
/* Find an object in a treap */ /* Find an object in a treap */
extern const char* treapFind(struct TREAP_NODE** psTreap, const char *key); extern const char* treapFind(struct TREAP_NODE** psTreap, const char *key);
/** Find the string associated with the given ID number */ /** Find the key associated with the given string number */
extern const char* treapFindByID(struct TREAP_NODE** psTreap, int id); extern const char* treapFindKey(struct TREAP_NODE** psTreap, const char* string);
/** Find the ID number associated with the given string (if any) */
extern int treapFindID(struct TREAP_NODE** psTreap, const char* string);
/* Destroy a treap and release all the memory associated with it */ /* Destroy a treap and release all the memory associated with it */
extern void treapDestroy(struct TREAP_NODE** psTreap); extern void treapDestroy(struct TREAP_NODE** psTreap);

View File

@ -4256,7 +4256,7 @@ const char* getTemplateName(const DROID_TEMPLATE *psTemplate)
/* See if the name has a string resource associated with it by trying /* See if the name has a string resource associated with it by trying
* to get the string resource. * to get the string resource.
*/ */
const char * const pNameID = strresGetStringByID(psStringRes, psTemplate->aName); const char * const pNameID = strresGetString(psStringRes, psTemplate->aName);
// If we couldn't find a string resource, return the name passed in // If we couldn't find a string resource, return the name passed in
if (!pNameID) if (!pNameID)
@ -4287,7 +4287,7 @@ BOOL getDroidResourceName(char *pName)
/* See if the name has a string resource associated with it by trying /* See if the name has a string resource associated with it by trying
* to get the string resource. * to get the string resource.
*/ */
const char * const name = strresGetStringByID(psStringRes, pName); const char * const name = strresGetString(psStringRes, pName);
if (!name) if (!name)
{ {

View File

@ -5166,7 +5166,7 @@ DROID_TEMPLATE *FindDroidTemplate(const char * const name)
DROID_TEMPLATE *Template; DROID_TEMPLATE *Template;
// get the name from the resource associated with it // get the name from the resource associated with it
const char * const nameStr = strresGetStringByID(psStringRes, name); const char * const nameStr = strresGetString(psStringRes, name);
if (!nameStr) if (!nameStr)
{ {
debug( LOG_ERROR, "Cannot find resource for template - %s", name ); debug( LOG_ERROR, "Cannot find resource for template - %s", name );
@ -11662,10 +11662,12 @@ BOOL writeFiresupportDesignators(char *pFileName)
// write the event state to a file on disk // write the event state to a file on disk
static BOOL writeScriptState(char *pFileName) static BOOL writeScriptState(char *pFileName)
{ {
static const int32_t current_event_version = 4;
char *pBuffer; char *pBuffer;
UDWORD fileSize; UDWORD fileSize;
if (!eventSaveState(3, &pBuffer, &fileSize)) if (!eventSaveState(current_event_version, &pBuffer, &fileSize))
{ {
return false; return false;
} }

View File

@ -545,7 +545,7 @@ VIEWDATA *loadViewData(const char *pViewMsgData, UDWORD bufferSize)
pViewMsgData += cnt; pViewMsgData += cnt;
// Get the string from the ID string // Get the string from the ID string
psViewData->ppTextMsg[dataInc] = strresGetStringByID(psStringRes, name); psViewData->ppTextMsg[dataInc] = strresGetString(psStringRes, name);
if (!psViewData->ppTextMsg[dataInc]) if (!psViewData->ppTextMsg[dataInc])
{ {
ASSERT(!"Cannot find string resource", "Cannot find the view data string with id \"%s\"", name); ASSERT(!"Cannot find string resource", "Cannot find the view data string with id \"%s\"", name);
@ -697,7 +697,7 @@ VIEWDATA *loadViewData(const char *pViewMsgData, UDWORD bufferSize)
pViewMsgData += cnt; pViewMsgData += cnt;
// Get the string from the ID string // Get the string from the ID string
psViewReplay->pSeqList[dataInc].ppTextMsg[seqInc] = strresGetStringByID(psStringRes, name); psViewReplay->pSeqList[dataInc].ppTextMsg[seqInc] = strresGetString(psStringRes, name);
if (!psViewReplay->pSeqList[dataInc].ppTextMsg[seqInc]) if (!psViewReplay->pSeqList[dataInc].ppTextMsg[seqInc])
{ {
ASSERT(!"Cannot find string resource", "Cannot find the view data string with id \"%s\"", name); ASSERT(!"Cannot find string resource", "Cannot find the view data string with id \"%s\"", name);

View File

@ -856,29 +856,20 @@ BOOL scrValDefSave(INTERP_VAL *psVal, char *pBuffer, UDWORD *pSize)
*pSize = sizeof(UDWORD); *pSize = sizeof(UDWORD);
break; break;
case ST_TEXTSTRING: case ST_TEXTSTRING:
{
const char * const idStr = psVal->v.sval ? strresGetIDfromString(psStringRes, psVal->v.sval) : NULL;
uint16_t len = idStr ? strlen(idStr) + 1 : 0;
if (pBuffer) if (pBuffer)
{ {
if (psVal->v.sval == NULL) *((uint16_t*)pBuffer) = len;
{ endian_uword((uint16_t*)pBuffer);
*((UDWORD*)pBuffer) = UDWORD_MAX;
}
else
{
const int strID = strresGetIDfromString(psStringRes, psVal->v.sval);
if (strID == -1) memcpy(pBuffer + sizeof(len), idStr, len);
{
*((UDWORD*)pBuffer) = UDWORD_MAX;
} }
else *pSize = sizeof(len) + len;
{
*((UDWORD*)pBuffer) = strID;
}
}
endian_udword((UDWORD*)pBuffer);
}
*pSize = sizeof(UDWORD);
break; break;
}
case ST_LEVEL: case ST_LEVEL:
if (psVal->v.sval != NULL) if (psVal->v.sval != NULL)
{ {
@ -1190,14 +1181,30 @@ BOOL scrValDefLoad(SDWORD version, INTERP_VAL *psVal, char *pBuffer, UDWORD size
} }
break; break;
case ST_TEXTSTRING: case ST_TEXTSTRING:
if (version < 4)
{
if (size != sizeof(UDWORD))
{
debug(LOG_ERROR, "Data size is too small, %u is expected, but %u is provided", (unsigned int)(sizeof(UDWORD)), (unsigned int)size);
return false;
}
id = *((UDWORD*)pBuffer); id = *((UDWORD*)pBuffer);
endian_udword(&id); endian_udword(&id);
if (id == UDWORD_MAX) if (id == UDWORD_MAX)
{ {
psVal->v.sval = '\0'; psVal->v.sval = NULL;
} }
else else
{ {
/* This code is commented out, because it depends on assigning the
* id-th loaded string from the string resources. And from version
* 4 of this file format onward, we do not count strings anymore.
*
* Thus loading of these strings is practically impossible.
*/
#if 0
const char * const str = strresGetString(psStringRes, id); const char * const str = strresGetString(psStringRes, id);
if (!str) if (!str)
{ {
@ -1206,6 +1213,71 @@ BOOL scrValDefLoad(SDWORD version, INTERP_VAL *psVal, char *pBuffer, UDWORD size
return false; return false;
} }
psVal->v.sval = strdup(str);
if (!psVal->v.sval)
{
debug(LOG_ERROR, "Out of memory");
abort();
return false;
}
#else
debug(LOG_ERROR, "Incompatible savegame format version %u, should be at least version 4", (unsigned int)version);
return false;
#endif
}
}
else
{
const char* str;
char* idStr;
uint16_t len;
if (size < sizeof(len))
{
debug(LOG_ERROR, "Data size is too small, %u is expected, but %u is provided", (unsigned int)(sizeof(len)), (unsigned int)size);
return false;
}
len = *((uint16_t*)pBuffer);
endian_uword(&len);
if (size < sizeof(len) + len)
{
debug(LOG_ERROR, "Data size is too small, %u is expected, but %u is provided", (unsigned int)(sizeof(len) + len), (unsigned int)size);
return false;
}
if (len == 0)
{
psVal->v.sval = NULL;
return true;
}
idStr = malloc(len);
if (!idStr)
{
debug(LOG_ERROR, "Out of memory (tried to allocate %u bytes)", (unsigned int)len);
// Don't abort() here, as this might be the result from a bad "len" field in the data
return false;
}
memcpy(idStr, pBuffer + sizeof(len), len);
if (idStr[len - 1] != '\0')
{
debug(LOG_WARNING, "Non-NUL terminated string encountered!");
}
idStr[len - 1] = '\0';
str = strresGetString(psStringRes, idStr);
if (!str)
{
debug(LOG_ERROR, "Couldn't find string with id \"%s\"", idStr);
free(idStr);
return false;
}
free(idStr);
psVal->v.sval = strdup(str); psVal->v.sval = strdup(str);
if (!psVal->v.sval) if (!psVal->v.sval)
{ {

View File

@ -627,7 +627,7 @@ var_init: var_entry TYPE var_value
yyerror("Typemismatch for variable %d", $1); yyerror("Typemismatch for variable %d", $1);
YYABORT; YYABORT;
} }
pString = strresGetStringByID(psStringRes, $3.pString); pString = strresGetString(psStringRes, $3.pString);
if (!pString) if (!pString)
{ {
yyerror("Cannot find the string for id \"%s\"", $3.pString); yyerror("Cannot find the string for id \"%s\"", $3.pString);

View File

@ -2615,7 +2615,7 @@ const char* getName(const char *pNameID)
/* See if the name has a string resource associated with it by trying /* See if the name has a string resource associated with it by trying
* to get the string resource. * to get the string resource.
*/ */
const char * const name = strresGetStringByID(psStringRes, pNameID); const char * const name = strresGetString(psStringRes, pNameID);
if (!name) if (!name)
{ {
debug( LOG_ERROR, "Unable to find string resource for %s", pNameID ); debug( LOG_ERROR, "Unable to find string resource for %s", pNameID );
@ -2819,7 +2819,7 @@ char* allocateName(const char* name)
/* Check whether the given string has a string resource associated with /* Check whether the given string has a string resource associated with
* it. * it.
*/ */
if (!strresGetStringByID(psStringRes, name)) if (!strresGetString(psStringRes, name))
{ {
debug(LOG_ERROR, "Unable to find string resource for %s", name); debug(LOG_ERROR, "Unable to find string resource for %s", name);
abort(); abort();