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-861f7616d084master
parent
54ae7cda3a
commit
3eabf084ad
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
110
src/scriptobj.c
110
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;
|
||||
memcpy(pBuffer + sizeof(len), idStr, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*((UDWORD*)pBuffer) = strID;
|
||||
}
|
||||
}
|
||||
endian_udword((UDWORD*)pBuffer);
|
||||
}
|
||||
*pSize = sizeof(UDWORD);
|
||||
*pSize = sizeof(len) + len;
|
||||
break;
|
||||
}
|
||||
case ST_LEVEL:
|
||||
if (psVal->v.sval != NULL)
|
||||
{
|
||||
|
@ -1190,14 +1181,30 @@ BOOL scrValDefLoad(SDWORD version, INTERP_VAL *psVal, char *pBuffer, UDWORD size
|
|||
}
|
||||
break;
|
||||
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);
|
||||
endian_udword(&id);
|
||||
|
||||
if (id == UDWORD_MAX)
|
||||
{
|
||||
psVal->v.sval = '\0';
|
||||
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)
|
||||
{
|
||||
|
@ -1206,6 +1213,71 @@ BOOL scrValDefLoad(SDWORD version, INTERP_VAL *psVal, char *pBuffer, UDWORD size
|
|||
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);
|
||||
if (!psVal->v.sval)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue