From c1e7c32f070ff8f3aadb2373f543f58333740e70 Mon Sep 17 00:00:00 2001 From: alberth Date: Sat, 24 May 2014 19:12:48 +0000 Subject: (svn r26611) -Feature: Save and load grfid and md5sum of newgrfs in config file (frosch) --- src/settings.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 8 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/settings.cpp b/src/settings.cpp index 11f30c150..5cbdce9d9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1407,6 +1407,40 @@ static void GameLoadConfig(IniFile *ini, const char *grpname) if (item->value != NULL) config->StringToSettings(item->value); } +/** + * Convert a character to a hex nibble value, or \c -1 otherwise. + * @param c Character to convert. + * @return Hex value of the character, or \c -1 if not a hex digit. + */ +static int DecodeHexNibble(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c + 10 - 'A'; + if (c >= 'a' && c <= 'f') return c + 10 - 'a'; + return -1; +} + +/** + * Parse a sequence of characters (supposedly hex digits) into a sequence of bytes. + * After the hex number should be a \c '|' character. + * @param pos First character to convert. + * @param dest [out] Output byte array to write the bytes. + * @param dest_size Number of bytes in \a dest. + * @return Whether reading was successful. + */ +static bool DecodeHexText(char *pos, uint8 *dest, size_t dest_size) +{ + while (dest_size > 0) { + int hi = DecodeHexNibble(pos[0]); + int lo = (hi >= 0) ? DecodeHexNibble(pos[1]) : -1; + if (lo < 0) return false; + *dest++ = (hi << 4) | lo; + pos += 2; + dest_size--; + } + return *pos == '|'; +} + /** * Load a GRF configuration * @param ini The configuration to read from. @@ -1423,16 +1457,41 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati if (group == NULL) return NULL; for (item = group->item; item != NULL; item = item->next) { - GRFConfig *c = new GRFConfig(item->name); + GRFConfig *c = NULL; + + uint8 grfid_buf[4], md5sum[16]; + char *filename = item->name; + bool has_grfid = false; + bool has_md5sum = false; + + /* Try reading "|" and on success, "|". */ + has_grfid = DecodeHexText(filename, grfid_buf, lengthof(grfid_buf)); + if (has_grfid) { + filename += 1 + 2 * lengthof(grfid_buf); + has_md5sum = DecodeHexText(filename, md5sum, lengthof(md5sum)); + if (has_md5sum) filename += 1 + 2 * lengthof(md5sum); + + uint32 grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24); + if (has_md5sum) { + const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, md5sum); + if (s != NULL) c = new GRFConfig(*s); + } + if (c == NULL && !FioCheckFileExists(filename, NEWGRF_DIR)) { + const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID); + if (s != NULL) c = new GRFConfig(*s); + } + } + if (c == NULL) c = new GRFConfig(filename); /* Parse parameters */ if (!StrEmpty(item->value)) { - c->num_params = ParseIntList(item->value, (int*)c->param, lengthof(c->param)); - if (c->num_params == (byte)-1) { - SetDParamStr(0, item->name); + int count = ParseIntList(item->value, (int*)c->param, lengthof(c->param)); + if (count < 0) { + SetDParamStr(0, filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); - c->num_params = 0; + count = 0; } + c->num_params = count; } /* Check if item is valid */ @@ -1449,7 +1508,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN); } - SetDParamStr(0, item->name); + SetDParamStr(0, StrEmpty(filename) ? item->name : filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); delete c; continue; @@ -1459,7 +1518,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati bool duplicate = false; for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) { if (gc->ident.grfid == c->ident.grfid) { - SetDParamStr(0, item->name); + SetDParamStr(0, c->filename); SetDParamStr(1, gc->filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL); duplicate = true; @@ -1557,10 +1616,15 @@ static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *li const GRFConfig *c; for (c = list; c != NULL; c = c->next) { + /* Hex grfid (4 bytes in nibbles), "|", hex md5sum (16 bytes in nibbles), "|", file system path. */ + char key[4 * 2 + 1 + 16 * 2 + 1 + MAX_PATH]; char params[512]; GRFBuildParamList(params, c, lastof(params)); - group->GetItem(c->filename, true)->SetValue(params); + char *pos = key + seprintf(key, lastof(key), "%08X|", BSWAP32(c->ident.grfid)); + pos = md5sumToString(pos, lastof(key), c->ident.md5sum); + seprintf(pos, lastof(key), "|%s", c->filename); + group->GetItem(key, true)->SetValue(params); } } -- cgit v1.2.3-54-g00ecf