diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index 3e6db1317f..707c5c36b5 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -182,17 +182,22 @@ void NetworkAfterNewGRFScan() /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already */ - AddGRFTextToList(&c->name, FindUnknownGRFName(c->ident.grfid, c->ident.md5sum, true)); + c->name->Release(); + c->name = FindUnknownGRFName(c->ident.grfid, c->ident.md5sum, true); + c->name->AddRef(); c->status = GCS_NOT_FOUND; /* If we miss a file, we're obviously incompatible */ item->info.compatible = false; } else { - c->filename = f->filename; - CleanUpGRFText(c->name); - c->name = DuplicateGRFText(f->name); - c->info = f->info; - c->status = GCS_UNKNOWN; + c->filename = f->filename; + c->name->Release(); + c->name = f->name; + c->name->AddRef(); + c->info->Release(); + c->info = f->info; + c->info->AddRef(); + c->status = GCS_UNKNOWN; } } } diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 7ed8cae8a6..8a4a6f945a 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -369,7 +369,6 @@ DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_SERVER_NEWGRFS) if (num_grfs > NETWORK_MAX_GRF_COUNT) return; for (i = 0; i < num_grfs; i++) { - char *unknown_name; char name[NETWORK_GRF_NAME_LENGTH]; GRFIdentifier c; @@ -380,12 +379,12 @@ DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_SERVER_NEWGRFS) * and causes problems when showing the NewGRF list. */ if (StrEmpty(name)) continue; - /* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple. + /* Try to find the GRFTextWrapper for the name of this GRF ID and MD5sum tuple. * If it exists and not resolved yet, then name of the fake GRF is * overwritten with the name from the reply. */ - unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); - if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { - ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH); + GRFTextWrapper *unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); + if (unknown_name != NULL && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { + AddGRFTextToList(&unknown_name->text, name); } } } @@ -398,12 +397,18 @@ void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFCo /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already */ - AddGRFTextToList(&config->name, FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true)); + config->name->Release(); + config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); + config->name->AddRef(); config->status = GCS_NOT_FOUND; } else { - config->filename = f->filename; - config->name = DuplicateGRFText(f->name); - config->info = f->info; + config->filename = f->filename; + config->name->Release(); + config->name = f->name; + config->name->AddRef(); + config->info->Release(); + config->info = f->info; + config->info->AddRef(); } SetBit(config->flags, GCF_COPY); } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 1a3e53fbc6..86e92a81f8 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -5382,11 +5382,11 @@ static void ScanInfo(ByteReader *buf) /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ if (GB(grfid, 24, 8) == 0xFF) SetBit(_cur_grfconfig->flags, GCF_SYSTEM); - AddGRFTextToList(&_cur_grfconfig->name, 0x7F, grfid, name); + AddGRFTextToList(&_cur_grfconfig->name->text, 0x7F, grfid, name); if (buf->HasData()) { const char *info = buf->ReadString(); - AddGRFTextToList(&_cur_grfconfig->info, 0x7F, grfid, info); + AddGRFTextToList(&_cur_grfconfig->info->text, 0x7F, grfid, info); } /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */ @@ -6466,14 +6466,14 @@ static void TranslateGRFStrings(ByteReader *buf) /** Callback function for 'INFO'->'NAME' to add a translation to the newgrf name. */ static bool ChangeGRFName(byte langid, const char *str) { - AddGRFTextToList(&_cur_grfconfig->name, langid, _cur_grfconfig->ident.grfid, str); + AddGRFTextToList(&_cur_grfconfig->name->text, langid, _cur_grfconfig->ident.grfid, str); return true; } /** Callback function for 'INFO'->'DESC' to add a translation to the newgrf description. */ static bool ChangeGRFDescription(byte langid, const char *str) { - AddGRFTextToList(&_cur_grfconfig->info, langid, _cur_grfconfig->ident.grfid, str); + AddGRFTextToList(&_cur_grfconfig->info->text, langid, _cur_grfconfig->ident.grfid, str); return true; } diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index aed73655ca..f6e6868034 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -21,15 +21,31 @@ #include "fileio_func.h" #include "fios.h" +/** Create a new GRFTextWrapper. */ +GRFTextWrapper::GRFTextWrapper() : + text(NULL) +{ +} + +/** Cleanup a GRFTextWrapper object. */ +GRFTextWrapper::~GRFTextWrapper() +{ + CleanUpGRFText(this->text); +} + /** * Create a new GRFConfig. * @param filename Set the filename of this GRFConfig to filename. The argument * is copied so the original string isn't needed after the constructor. */ GRFConfig::GRFConfig(const char *filename) : + name(new GRFTextWrapper()), + info(new GRFTextWrapper()), num_valid_params(lengthof(param)) { if (filename != NULL) this->filename = strdup(filename); + this->name->AddRef(); + this->info->AddRef(); } /** @@ -39,6 +55,8 @@ GRFConfig::GRFConfig(const char *filename) : GRFConfig::GRFConfig(const GRFConfig &config) : ZeroedMemoryAllocator(), ident(config.ident), + name(config.name), + info(config.info), version(config.version), min_loadable_version(config.min_loadable_version), flags(config.flags & ~(1 << GCF_COPY)), @@ -52,8 +70,8 @@ GRFConfig::GRFConfig(const GRFConfig &config) : MemCpyT(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum)); MemCpyT(this->param, config.param, lengthof(this->param)); if (config.filename != NULL) this->filename = strdup(config.filename); - this->name = DuplicateGRFText(config.name); - this->info = DuplicateGRFText(config.info); + this->name->AddRef(); + this->info->AddRef(); if (config.error != NULL) this->error = new GRFError(*config.error); for (uint i = 0; i < config.param_info.Length(); i++) { if (config.param_info[i] == NULL) { @@ -67,13 +85,13 @@ GRFConfig::GRFConfig(const GRFConfig &config) : /** Cleanup a GRFConfig object. */ GRFConfig::~GRFConfig() { - /* GCF_COPY as in NOT strdupped/alloced the filename and info */ + /* GCF_COPY as in NOT strdupped/alloced the filename */ if (!HasBit(this->flags, GCF_COPY)) { free(this->filename); - CleanUpGRFText(this->info); delete this->error; } - CleanUpGRFText(this->name); + this->name->Release(); + this->info->Release(); for (uint i = 0; i < this->param_info.Length(); i++) delete this->param_info[i]; } @@ -85,7 +103,7 @@ GRFConfig::~GRFConfig() */ const char *GRFConfig::GetName() const { - const char *name = GetGRFStringFromGRFText(this->name); + const char *name = GetGRFStringFromGRFText(this->name->text); return StrEmpty(name) ? this->filename : name; } @@ -95,7 +113,7 @@ const char *GRFConfig::GetName() const */ const char *GRFConfig::GetDescription() const { - return GetGRFStringFromGRFText(this->info); + return GetGRFStringFromGRFText(this->info->text); } /** Set the default value for all parameters as specified by action14. */ @@ -482,8 +500,12 @@ compatible_grf: free(c->filename); c->filename = strdup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); - if (c->name == NULL) c->name = DuplicateGRFText(f->name); - if (c->info == NULL) c->info = DuplicateGRFText(f->info); + c->name->Release(); + c->name = f->name; + c->name->AddRef(); + c->info->Release(); + c->info = f->name; + c->info->AddRef(); c->error = NULL; c->version = f->version; c->min_loadable_version = f->min_loadable_version; @@ -646,7 +668,7 @@ const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 /** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */ struct UnknownGRF : public GRFIdentifier { UnknownGRF *next; - char name[NETWORK_GRF_NAME_LENGTH]; + GRFTextWrapper *name; }; /** @@ -662,11 +684,11 @@ struct UnknownGRF : public GRFIdentifier { * @param md5sum the MD5 checksum part of the 'unique' GRF identifier * @param create whether to create a new GRFConfig if the GRFConfig did not * exist in the fake list of GRFConfigs. - * @return the GRFConfig with the given GRF ID and MD5 checksum or NULL when - * it does not exist and create is false. This value must NEVER be - * freed by the caller. + * @return The GRFTextWrapper of the name of the GRFConfig with the given GRF ID + * and MD5 checksum or NULL when it does not exist and create is false. + * This value must NEVER be freed by the caller. */ -char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) +GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) { UnknownGRF *grf; static UnknownGRF *unknown_grfs = NULL; @@ -682,7 +704,10 @@ char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) grf = CallocT(1); grf->grfid = grfid; grf->next = unknown_grfs; - strecpy(grf->name, UNKNOWN_GRF_NAME_PLACEHOLDER, lastof(grf->name)); + grf->name = new GRFTextWrapper(); + grf->name->AddRef(); + + AddGRFTextToList(&grf->name->text, UNKNOWN_GRF_NAME_PLACEHOLDER); memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum)); unknown_grfs = grf; diff --git a/src/newgrf_config.h b/src/newgrf_config.h index f6c97c42ca..ad406a9e1e 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -15,6 +15,7 @@ #include "strings_type.h" #include "core/alloc_type.hpp" #include "core/smallmap_type.hpp" +#include "misc/countedptr.hpp" /** GRF config bit flags */ enum GCF_Flags { @@ -129,6 +130,14 @@ struct GRFParameterInfo { void SetValue(struct GRFConfig *config, uint32 value); }; +/** Reference counted wrapper around a GRFText pointer. */ +struct GRFTextWrapper : public SimpleCountedObject { + struct GRFText *text; ///< The actual text + + GRFTextWrapper(); + ~GRFTextWrapper(); +}; + /** Information about GRF, used in the game and (part of it) in savegames */ struct GRFConfig : ZeroedMemoryAllocator { GRFConfig(const char *filename = NULL); @@ -138,8 +147,8 @@ struct GRFConfig : ZeroedMemoryAllocator { GRFIdentifier ident; ///< grfid and md5sum to uniquely identify newgrfs uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded char *filename; ///< Filename - either with or without full path - struct GRFText *name; ///< NOSAVE: GRF name (Action 0x08) - struct GRFText *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) + GRFTextWrapper *name; ///< NOSAVE: GRF name (Action 0x08) + GRFTextWrapper *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) GRFError *error; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B) uint32 version; ///< NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown @@ -198,7 +207,7 @@ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFC #ifdef ENABLE_NETWORK /* For communication about GRFs over the network */ #define UNKNOWN_GRF_NAME_PLACEHOLDER "" -char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); +GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); #endif /* ENABLE_NETWORK */ #endif /* NEWGRF_CONFIG_H */