From 3eabf084ad98693957a4b19559af45eed1966c17 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Sun, 27 Jul 2008 23:58:49 +0000 Subject: [PATCH] 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 --- lib/framework/strres.c | 19 ++---- lib/framework/strres.h | 7 +-- lib/framework/treap.c | 53 ++++------------- lib/framework/treap.h | 9 +-- src/droid.c | 4 +- src/game.c | 6 +- src/message.c | 4 +- src/scriptobj.c | 124 +++++++++++++++++++++++++++++++--------- src/scriptvals_parser.y | 2 +- src/stats.c | 4 +- 10 files changed, 128 insertions(+), 104 deletions(-) diff --git a/lib/framework/strres.c b/lib/framework/strres.c index d528873d3..6b59e1f46 100644 --- a/lib/framework/strres.c +++ b/lib/framework/strres.c @@ -40,7 +40,6 @@ typedef struct STR_RES { struct TREAP_NODE** psIDTreap; ///< The treap to store string identifiers - int nextID; ///< The next free ID } STR_RES; /* Initialise the string system */ @@ -53,7 +52,6 @@ STR_RES* strresCreate() abort(); return NULL; } - psRes->nextID = 0; psRes->psIDTreap = treapCreate(); if (!psRes->psIDTreap) @@ -89,19 +87,10 @@ BOOL strresStoreString(STR_RES *psRes, const char* pID, const char* pString) return false; } - return treapAdd(psRes->psIDTreap, pID, pString, psRes->nextID++); + return treapAdd(psRes->psIDTreap, pID, pString); } - -/* 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* strresGetString(const STR_RES* psRes, const char* ID) { const char * string; @@ -140,9 +129,9 @@ BOOL strresLoad(STR_RES* psRes, const char* fileName) } /* 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"); - return treapFindID(psRes->psIDTreap, pString); + return treapFindKey(psRes->psIDTreap, pString); } diff --git a/lib/framework/strres.h b/lib/framework/strres.h index b34c9f14c..cdd3d64e9 100644 --- a/lib/framework/strres.h +++ b/lib/framework/strres.h @@ -32,9 +32,6 @@ extern struct STR_RES* strresCreate(void); /* Release a string resource object */ 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. * @@ -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 * 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 */ extern BOOL strresLoad(struct STR_RES* psRes, const char* fileName); /* 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 diff --git a/lib/framework/treap.c b/lib/framework/treap.c index b7001703f..cc6b964d4 100644 --- a/lib/framework/treap.c +++ b/lib/framework/treap.c @@ -39,7 +39,6 @@ typedef struct TREAP_NODE const char* key; //< The key to sort the node on unsigned int priority; //< Treap priority 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 } TREAP_NODE; @@ -137,7 +136,7 @@ static void treapAddNode(TREAP_NODE **ppsRoot, TREAP_NODE *psNew) /* 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 * 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->string = strcpy((char*)(psNew + 1) + key_size, string); - psNew->id = id; - psNew->priority = rand(); psNew->psLeft = NULL; psNew->psRight = NULL; @@ -204,64 +201,34 @@ const char* treapFind(TREAP_NODE** psTreap, const char *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) { 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) { - return psNode->id; + return psNode->key; } - id = treapFindIDRec(psNode->psLeft, string); - if (id != -1) + key = treapFindKeyRec(psNode->psLeft, string); + 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!"); - return treapFindIDRec(*psTreap, string); + return treapFindKeyRec(*psTreap, string); } /* Recursively free a treap */ diff --git a/lib/framework/treap.h b/lib/framework/treap.h index c7986e138..19c2b500a 100644 --- a/lib/framework/treap.h +++ b/lib/framework/treap.h @@ -45,16 +45,13 @@ extern struct TREAP_NODE** treapCreate(void); /* 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 */ extern const char* treapFind(struct TREAP_NODE** psTreap, const char *key); -/** Find the string associated with the given ID number */ -extern const char* treapFindByID(struct TREAP_NODE** psTreap, int id); - -/** Find the ID number associated with the given string (if any) */ -extern int treapFindID(struct TREAP_NODE** psTreap, const char* string); +/** Find the key associated with the given string number */ +extern const char* treapFindKey(struct TREAP_NODE** psTreap, const char* string); /* Destroy a treap and release all the memory associated with it */ extern void treapDestroy(struct TREAP_NODE** psTreap); diff --git a/src/droid.c b/src/droid.c index 30c8376f1..c11997f50 100644 --- a/src/droid.c +++ b/src/droid.c @@ -4256,7 +4256,7 @@ const char* getTemplateName(const DROID_TEMPLATE *psTemplate) /* See if the name has a string resource associated with it by trying * 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 (!pNameID) @@ -4287,7 +4287,7 @@ BOOL getDroidResourceName(char *pName) /* See if the name has a string resource associated with it by trying * to get the string resource. */ - const char * const name = strresGetStringByID(psStringRes, pName); + const char * const name = strresGetString(psStringRes, pName); if (!name) { diff --git a/src/game.c b/src/game.c index 808375067..fa6cb1971 100644 --- a/src/game.c +++ b/src/game.c @@ -5166,7 +5166,7 @@ DROID_TEMPLATE *FindDroidTemplate(const char * const name) DROID_TEMPLATE *Template; // 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) { 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 static BOOL writeScriptState(char *pFileName) { + static const int32_t current_event_version = 4; + char *pBuffer; UDWORD fileSize; - if (!eventSaveState(3, &pBuffer, &fileSize)) + if (!eventSaveState(current_event_version, &pBuffer, &fileSize)) { return false; } diff --git a/src/message.c b/src/message.c index 943d245ac..f801491a9 100644 --- a/src/message.c +++ b/src/message.c @@ -545,7 +545,7 @@ VIEWDATA *loadViewData(const char *pViewMsgData, UDWORD bufferSize) pViewMsgData += cnt; // Get the string from the ID string - psViewData->ppTextMsg[dataInc] = strresGetStringByID(psStringRes, name); + psViewData->ppTextMsg[dataInc] = strresGetString(psStringRes, name); if (!psViewData->ppTextMsg[dataInc]) { 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; // 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]) { ASSERT(!"Cannot find string resource", "Cannot find the view data string with id \"%s\"", name); diff --git a/src/scriptobj.c b/src/scriptobj.c index 9b97d5b55..9abdd80b7 100644 --- a/src/scriptobj.c +++ b/src/scriptobj.c @@ -856,29 +856,20 @@ BOOL scrValDefSave(INTERP_VAL *psVal, char *pBuffer, UDWORD *pSize) *pSize = sizeof(UDWORD); break; 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 (psVal->v.sval == NULL) - { - *((UDWORD*)pBuffer) = UDWORD_MAX; - } - else - { - const int strID = strresGetIDfromString(psStringRes, psVal->v.sval); + *((uint16_t*)pBuffer) = len; + endian_uword((uint16_t*)pBuffer); - if (strID == -1) - { - *((UDWORD*)pBuffer) = UDWORD_MAX; - } - else - { - *((UDWORD*)pBuffer) = strID; - } - } - endian_udword((UDWORD*)pBuffer); + memcpy(pBuffer + sizeof(len), idStr, len); } - *pSize = sizeof(UDWORD); + *pSize = sizeof(len) + len; break; + } case ST_LEVEL: if (psVal->v.sval != NULL) { @@ -1190,22 +1181,103 @@ BOOL scrValDefLoad(SDWORD version, INTERP_VAL *psVal, char *pBuffer, UDWORD size } break; case ST_TEXTSTRING: - id = *((UDWORD *)pBuffer); - endian_udword(&id); - if (id == UDWORD_MAX) + if (version < 4) { - psVal->v.sval = '\0'; + 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); + endian_udword(&id); + + if (id == UDWORD_MAX) + { + psVal->v.sval = NULL; + } + 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); + if (!str) + { + debug(LOG_ERROR, "Couldn't find string with id %u", id); + abort(); + 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 * const str = strresGetString(psStringRes, id); - if (!str) + const char* str; + char* idStr; + uint16_t len; + + if (size < sizeof(len)) { - debug(LOG_ERROR, "Couldn't find string with id %u", id); - abort(); + 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); if (!psVal->v.sval) { diff --git a/src/scriptvals_parser.y b/src/scriptvals_parser.y index ab021468f..eed401584 100644 --- a/src/scriptvals_parser.y +++ b/src/scriptvals_parser.y @@ -627,7 +627,7 @@ var_init: var_entry TYPE var_value yyerror("Typemismatch for variable %d", $1); YYABORT; } - pString = strresGetStringByID(psStringRes, $3.pString); + pString = strresGetString(psStringRes, $3.pString); if (!pString) { yyerror("Cannot find the string for id \"%s\"", $3.pString); diff --git a/src/stats.c b/src/stats.c index 246ff741a..fcf3a574c 100644 --- a/src/stats.c +++ b/src/stats.c @@ -2615,7 +2615,7 @@ const char* getName(const char *pNameID) /* See if the name has a string resource associated with it by trying * to get the string resource. */ - const char * const name = strresGetStringByID(psStringRes, pNameID); + const char * const name = strresGetString(psStringRes, pNameID); if (!name) { 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 * it. */ - if (!strresGetStringByID(psStringRes, name)) + if (!strresGetString(psStringRes, name)) { debug(LOG_ERROR, "Unable to find string resource for %s", name); abort();