diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index ff744e8757..dfe07bdbbb 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -175,21 +175,15 @@ 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. */ - 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; - 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 90b99ec44b..03344fe579 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -426,9 +426,9 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd /* 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. */ - GRFTextWrapper *unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); - if (unknown_name != nullptr && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { - AddGRFTextToList(&unknown_name->text, name); + GRFTextWrapper unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); + if (unknown_name && strcmp(GetGRFStringFromGRFText(unknown_name), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { + AddGRFTextToList(unknown_name, name); } } } @@ -441,21 +441,13 @@ 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 */ - 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->Release(); config->name = f->name; - config->name->AddRef(); - config->info->Release(); config->info = f->info; - config->info->AddRef(); - config->url->Release(); config->url = f->url; - config->url->AddRef(); } SetBit(config->flags, GCF_COPY); } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index c1b8364811..4ada53a0a4 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -6720,11 +6720,11 @@ static void ScanInfo(ByteReader *buf) /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ if (GB(grfid, 0, 8) == 0xFF) SetBit(_cur.grfconfig->flags, GCF_SYSTEM); - AddGRFTextToList(&_cur.grfconfig->name->text, 0x7F, grfid, false, name); + AddGRFTextToList(_cur.grfconfig->name, 0x7F, grfid, false, name); if (buf->HasData()) { const char *info = buf->ReadString(); - AddGRFTextToList(&_cur.grfconfig->info->text, 0x7F, grfid, true, info); + AddGRFTextToList(_cur.grfconfig->info, 0x7F, grfid, true, info); } /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */ @@ -7806,21 +7806,21 @@ 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->text, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur.grfconfig->name, langid, _cur.grfconfig->ident.grfid, false, 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->text, langid, _cur.grfconfig->ident.grfid, true, str); + AddGRFTextToList(_cur.grfconfig->info, langid, _cur.grfconfig->ident.grfid, true, str); return true; } /** Callback function for 'INFO'->'URL_' to set the newgrf url. */ static bool ChangeGRFURL(byte langid, const char *str) { - AddGRFTextToList(&_cur.grfconfig->url->text, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur.grfconfig->url, langid, _cur.grfconfig->ident.grfid, false, str); return true; } @@ -7922,14 +7922,14 @@ static GRFParameterInfo *_cur_parameter; ///< The parameter which info is curren /** Callback function for 'INFO'->'PARAM'->param_num->'NAME' to set the name of a parameter. */ static bool ChangeGRFParamName(byte langid, const char *str) { - AddGRFTextToList(&_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str); return true; } /** Callback function for 'INFO'->'PARAM'->param_num->'DESC' to set the description of a parameter. */ static bool ChangeGRFParamDescription(byte langid, const char *str) { - AddGRFTextToList(&_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str); + AddGRFTextToList(_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str); return true; } @@ -8113,12 +8113,12 @@ static bool ChangeGRFParamValueNames(ByteReader *buf) byte langid = buf->ReadByte(); const char *name_string = buf->ReadString(); - std::pair *val_name = _cur_parameter->value_names.Find(id); + std::pair *val_name = _cur_parameter->value_names.Find(id); if (val_name != _cur_parameter->value_names.End()) { - AddGRFTextToList(&val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string); + AddGRFTextToList(val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string); } else { - GRFText *list = nullptr; - AddGRFTextToList(&list, langid, _cur.grfconfig->ident.grfid, false, name_string); + GRFTextList list; + AddGRFTextToList(list, langid, _cur.grfconfig->ident.grfid, false, name_string); _cur_parameter->value_names.Insert(id, list); } diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 605bceca5b..8452d08299 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -21,23 +21,13 @@ #include "textfile_gui.h" #include "thread.h" #include "newgrf_config.h" +#include "newgrf_text.h" #include "fileio_func.h" #include "fios.h" #include "safeguards.h" -/** Create a new GRFTextWrapper. */ -GRFTextWrapper::GRFTextWrapper() : - text(nullptr) -{ -} - -/** Cleanup a GRFTextWrapper object. */ -GRFTextWrapper::~GRFTextWrapper() -{ - CleanUpGRFText(this->text); -} /** * Create a new GRFConfig. @@ -45,15 +35,9 @@ GRFTextWrapper::~GRFTextWrapper() * is copied so the original string isn't needed after the constructor. */ GRFConfig::GRFConfig(const char *filename) : - name(new GRFTextWrapper()), - info(new GRFTextWrapper()), - url(new GRFTextWrapper()), num_valid_params(lengthof(param)) { if (filename != nullptr) this->filename = stredup(filename); - this->name->AddRef(); - this->info->AddRef(); - this->url->AddRef(); } /** @@ -79,9 +63,6 @@ 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 != nullptr) this->filename = stredup(config.filename); - this->name->AddRef(); - this->info->AddRef(); - this->url->AddRef(); if (config.error != nullptr) this->error = new GRFError(*config.error); for (uint i = 0; i < config.param_info.size(); i++) { if (config.param_info[i] == nullptr) { @@ -100,9 +81,6 @@ GRFConfig::~GRFConfig() free(this->filename); delete this->error; } - this->name->Release(); - this->info->Release(); - this->url->Release(); for (uint i = 0; i < this->param_info.size(); i++) delete this->param_info[i]; } @@ -125,7 +103,7 @@ void GRFConfig::CopyParams(const GRFConfig &src) */ const char *GRFConfig::GetName() const { - const char *name = GetGRFStringFromGRFText(this->name->text); + const char *name = GetGRFStringFromGRFText(this->name); return StrEmpty(name) ? this->filename : name; } @@ -135,7 +113,7 @@ const char *GRFConfig::GetName() const */ const char *GRFConfig::GetDescription() const { - return GetGRFStringFromGRFText(this->info->text); + return GetGRFStringFromGRFText(this->info); } /** @@ -144,7 +122,7 @@ const char *GRFConfig::GetDescription() const */ const char *GRFConfig::GetURL() const { - return GetGRFStringFromGRFText(this->url->text); + return GetGRFStringFromGRFText(this->url); } /** Set the default value for all parameters as specified by action14. */ @@ -232,8 +210,8 @@ GRFError::~GRFError() * @param nr The newgrf parameter that is changed. */ GRFParameterInfo::GRFParameterInfo(uint nr) : - name(nullptr), - desc(nullptr), + name(), + desc(), type(PTYPE_UINT_ENUM), min_value(0), max_value(UINT32_MAX), @@ -241,6 +219,7 @@ GRFParameterInfo::GRFParameterInfo(uint nr) : param_nr(nr), first_bit(0), num_bit(32), + value_names(), complete_labels(false) {} @@ -250,8 +229,8 @@ GRFParameterInfo::GRFParameterInfo(uint nr) : * @param info The GRFParameterInfo object to make a copy of. */ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : - name(DuplicateGRFText(info.name)), - desc(DuplicateGRFText(info.desc)), + name(info.name), + desc(info.desc), type(info.type), min_value(info.min_value), max_value(info.max_value), @@ -259,23 +238,9 @@ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : param_nr(info.param_nr), first_bit(info.first_bit), num_bit(info.num_bit), + value_names(info.value_names), complete_labels(info.complete_labels) { - for (uint i = 0; i < info.value_names.size(); i++) { - std::pair *data = info.value_names.data() + i; - this->value_names.Insert(data->first, DuplicateGRFText(data->second)); - } -} - -/** Cleanup all parameter info. */ -GRFParameterInfo::~GRFParameterInfo() -{ - CleanUpGRFText(this->name); - CleanUpGRFText(this->desc); - for (uint i = 0; i < this->value_names.size(); i++) { - std::pair *data = this->value_names.data() + i; - CleanUpGRFText(data->second); - } } /** @@ -598,12 +563,8 @@ compatible_grf: free(c->filename); c->filename = stredup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); - c->name->Release(); c->name = f->name; - c->name->AddRef(); - c->info->Release(); c->info = f->name; - c->info->AddRef(); c->error = nullptr; c->version = f->version; c->min_loadable_version = f->min_loadable_version; @@ -686,7 +647,7 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const _modal_progress_paint_mutex.lock(); const char *name = nullptr; - if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name->text); + if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name); if (name == nullptr) name = c->filename; UpdateNewGRFScanStatus(this->num_scanned, name); @@ -820,8 +781,12 @@ 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; ///< The next unknown GRF. - GRFTextWrapper *name; ///< Name of the GRF. + GRFTextWrapper name; ///< Name of the GRF. + + UnknownGRF() = default; + UnknownGRF(const UnknownGRF &other) = default; + UnknownGRF(UnknownGRF &&other) = default; + UnknownGRF(uint32 grfid, const uint8 *_md5sum) : GRFIdentifier(grfid, _md5sum), name(new GRFTextList) {} }; /** @@ -841,30 +806,24 @@ struct UnknownGRF : public GRFIdentifier { * and MD5 checksum or nullptr when it does not exist and create is false. * This value must NEVER be freed by the caller. */ -GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) +GRFTextWrapper FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) { - UnknownGRF *grf; - static UnknownGRF *unknown_grfs = nullptr; + static std::vector unknown_grfs; - for (grf = unknown_grfs; grf != nullptr; grf = grf->next) { - if (grf->grfid == grfid) { - if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name; + for (const auto &grf : unknown_grfs) { + if (grf.grfid == grfid) { + if (memcmp(md5sum, grf.md5sum, sizeof(grf.md5sum)) == 0) return grf.name; } } if (!create) return nullptr; - grf = CallocT(1); - grf->grfid = grfid; - grf->next = unknown_grfs; - grf->name = new GRFTextWrapper(); - grf->name->AddRef(); + unknown_grfs.emplace_back(grfid, md5sum); + UnknownGRF &grf = unknown_grfs.back(); - AddGRFTextToList(&grf->name->text, UNKNOWN_GRF_NAME_PLACEHOLDER); - memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum)); + AddGRFTextToList(grf.name, UNKNOWN_GRF_NAME_PLACEHOLDER); - unknown_grfs = grf; - return grf->name; + return grf.name; } /** diff --git a/src/newgrf_config.h b/src/newgrf_config.h index 8c3b2ecdf4..2c8a8559dd 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -16,6 +16,7 @@ #include "misc/countedptr.hpp" #include "fileio_type.h" #include "textfile_type.h" +#include "newgrf_text.h" /** GRF config bit flags */ enum GCF_Flags { @@ -83,6 +84,16 @@ struct GRFIdentifier { uint32 grfid; ///< GRF ID (defined by Action 0x08) uint8 md5sum[16]; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF) + GRFIdentifier() = default; + GRFIdentifier(const GRFIdentifier &other) = default; + GRFIdentifier(GRFIdentifier &&other) = default; + GRFIdentifier(uint32 grfid, const uint8 *md5sum) : grfid(grfid) + { + MemCpyT(this->md5sum, md5sum, lengthof(this->md5sum)); + } + + GRFIdentifier& operator =(const GRFIdentifier &other) = default; + /** * Does the identification match the provided values? * @param grfid Expected grfid. @@ -121,9 +132,8 @@ enum GRFParameterType { struct GRFParameterInfo { GRFParameterInfo(uint nr); GRFParameterInfo(GRFParameterInfo &info); - ~GRFParameterInfo(); - struct GRFText *name; ///< The name of this parameter - struct GRFText *desc; ///< The description of this parameter + GRFTextList name; ///< The name of this parameter + GRFTextList desc; ///< The description of this parameter GRFParameterType type; ///< The type of this parameter uint32 min_value; ///< The minimal value this parameter can have uint32 max_value; ///< The maximal value of this parameter @@ -131,7 +141,7 @@ struct GRFParameterInfo { byte param_nr; ///< GRF parameter to store content in byte first_bit; ///< First bit to use in the GRF parameter byte num_bit; ///< Number of bits to use for this parameter - SmallMap value_names; ///< Names for each value. + SmallMap value_names; ///< Names for each value. bool complete_labels; ///< True if all values have a label. uint32 GetValue(struct GRFConfig *config) const; @@ -139,14 +149,6 @@ struct GRFParameterInfo { void Finalize(); }; -/** 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 = nullptr); @@ -156,9 +158,9 @@ 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 - GRFTextWrapper *name; ///< NOSAVE: GRF name (Action 0x08) - GRFTextWrapper *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) - GRFTextWrapper *url; ///< NOSAVE: URL belonging to this GRF. + GRFTextWrapper name; ///< NOSAVE: GRF name (Action 0x08) + GRFTextWrapper info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) + GRFTextWrapper url; ///< NOSAVE: URL belonging to this GRF. 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 @@ -229,7 +231,7 @@ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFC /** For communication about GRFs over the network */ #define UNKNOWN_GRF_NAME_PLACEHOLDER "" -GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); +GRFTextWrapper FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); void UpdateNewGRFScanStatus(uint num, const char *name); bool UpdateNewGRFConfigPalette(int32 p1 = 0); diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 1345119446..4f1a6ffd49 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -60,89 +60,6 @@ enum GRFExtendedLanguages { GRFLX_UNSPECIFIED = 0x7F, }; -/** - * Element of the linked list. - * Each of those elements represent the string, - * but according to a different lang. - */ -struct GRFText { -public: - /** - * Allocate, and assign a new GRFText with the given text. - * As these strings can have string terminations in them, e.g. - * due to "choice lists" we (sometimes) cannot rely on detecting - * the length by means of strlen. Also, if the length of already - * known not scanning the whole string is more efficient. - * @param langid The language of the text. - * @param text The text to store in the new GRFText. - * @param len The length of the text. - */ - static GRFText *New(byte langid, const char *text, size_t len) - { - return new (len) GRFText(langid, text, len); - } - - /** - * Create a copy of this GRFText. - * @param orig the grftext to copy. - * @return an exact copy of the given text. - */ - static GRFText *Copy(GRFText *orig) - { - return GRFText::New(orig->langid, orig->text, orig->len); - } - - /** - * Helper allocation function to disallow something. - * Don't allow simple 'news'; they wouldn't have enough memory. - * @param size the amount of space not to allocate. - */ - void *operator new(size_t size) - { - NOT_REACHED(); - } - - /** - * Free the memory we allocated. - * @param p memory to free. - */ - void operator delete(void *p) - { - free(p); - } -private: - /** - * Actually construct the GRFText. - * @param langid_ The language of the text. - * @param text_ The text to store in this GRFText. - * @param len_ The length of the text to store. - */ - GRFText(byte langid_, const char *text_, size_t len_) : next(nullptr), len(len_), langid(langid_) - { - /* We need to use memcpy instead of strcpy due to - * the possibility of "choice lists" and therefore - * intermediate string terminators. */ - memcpy(this->text, text_, len); - } - - /** - * Allocate memory for this class. - * @param size the size of the instance - * @param extra the extra memory for the text - * @return the requested amount of memory for both the instance and the text - */ - void *operator new(size_t size, size_t extra) - { - return MallocT(size + extra); - } - -public: - GRFText *next; ///< The next GRFText in this chain. - size_t len; ///< The length of the stored string, used for copying. - byte langid; ///< The language associated with this GRFText. - char text[]; ///< The actual (translated) text. -}; - /** * Holder of the above structure. @@ -153,7 +70,7 @@ struct GRFTextEntry { uint32 grfid; uint16 stringid; StringID def_string; - GRFText *textholder; + GRFTextList textholder; }; @@ -576,26 +493,23 @@ string_end: } /** - * Add a GRFText to a GRFText list. + * Add a new text to a GRFText list. * @param list The list where the text should be added to. - * @param text_to_add The GRFText to add to the list. + * @param langid The The language of the new text. + * @param text_to_add The text to add to the list. */ -void AddGRFTextToList(GRFText **list, GRFText *text_to_add) +static void AddGRFTextToList(GRFTextList &list, byte langid, const std::string &text_to_add) { - GRFText **ptext, *text; - /* Loop through all languages and see if we can replace a string */ - for (ptext = list; (text = *ptext) != nullptr; ptext = &text->next) { - if (text->langid == text_to_add->langid) { - text_to_add->next = text->next; - *ptext = text_to_add; - delete text; + for (auto &text : list) { + if (text.langid == langid) { + text.text = text_to_add; return; } } /* If a string wasn't replaced, then we must append the new string */ - *ptext = text_to_add; + list.push_back(GRFText{ langid, text_to_add }); } /** @@ -607,14 +521,29 @@ void AddGRFTextToList(GRFText **list, GRFText *text_to_add) * @param text_to_add The text to add to the list. * @note All text-codes will be translated. */ -void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) +void AddGRFTextToList(GRFTextList &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) { int len; char *translatedtext = TranslateTTDPatchCodes(grfid, langid, allow_newlines, text_to_add, &len); - GRFText *newtext = GRFText::New(langid, translatedtext, len); + std::string newtext(translatedtext, len); free(translatedtext); - AddGRFTextToList(list, newtext); + AddGRFTextToList(list, langid, newtext); +} + +/** + * Add a string to a GRFText list. + * @param list The list where the text should be added to. + * @param langid The language of the new text. + * @param grfid The grfid where this string is defined. + * @param allow_newlines Whether newlines are allowed in this string. + * @param text_to_add The text to add to the list. + * @note All text-codes will be translated. + */ +void AddGRFTextToList(GRFTextWrapper &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) +{ + if (!list) list.reset(new GRFTextList()); + AddGRFTextToList(*list, langid, grfid, allow_newlines, text_to_add); } /** @@ -623,25 +552,10 @@ void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool all * @param list The list where the text should be added to. * @param text_to_add The text to add to the list. */ -void AddGRFTextToList(struct GRFText **list, const char *text_to_add) +void AddGRFTextToList(GRFTextWrapper &list, const char *text_to_add) { - AddGRFTextToList(list, GRFText::New(0x7F, text_to_add, strlen(text_to_add) + 1)); -} - -/** - * Create a copy of this GRFText list. - * @param orig The GRFText list to copy. - * @return A duplicate of the given GRFText. - */ -GRFText *DuplicateGRFText(GRFText *orig) -{ - GRFText *newtext = nullptr; - GRFText **ptext = &newtext; - for (; orig != nullptr; orig = orig->next) { - *ptext = GRFText::Copy(orig); - ptext = &(*ptext)->next; - } - return newtext; + if (!list) list.reset(new GRFTextList()); + AddGRFTextToList(*list, GRFLX_UNSPECIFIED, std::string(text_to_add)); } /** @@ -681,22 +595,20 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool ne int len; translatedtext = TranslateTTDPatchCodes(grfid, langid_to_add, allow_newlines, text_to_add, &len); - - GRFText *newtext = GRFText::New(langid_to_add, translatedtext, len); - + std::string newtext(translatedtext, len); free(translatedtext); /* If we didn't find our stringid and grfid in the list, allocate a new id */ if (id == _num_grf_texts) _num_grf_texts++; - if (_grf_text[id].textholder == nullptr) { + if (_grf_text[id].textholder.empty()) { _grf_text[id].grfid = grfid; _grf_text[id].stringid = stringid; _grf_text[id].def_string = def_string; } - AddGRFTextToList(&_grf_text[id].textholder, newtext); + AddGRFTextToList(_grf_text[id].textholder, langid_to_add, newtext); - grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s' (%X)", id, grfid, stringid, newtext->langid, newtext->text, MakeStringID(TEXT_TAB_NEWGRF_START, id)); + grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s' (%X)", id, grfid, stringid, langid_to_add, newtext.c_str(), MakeStringID(TEXT_TAB_NEWGRF_START, id)); return MakeStringID(TEXT_TAB_NEWGRF_START, id); } @@ -721,26 +633,38 @@ StringID GetGRFStringID(uint32 grfid, StringID stringid) * current language it is returned, otherwise the default translation * is returned. If there is neither a default nor a translation for the * current language nullptr is returned. - * @param text The GRFText to get the string from. + * @param text_list The GRFTextList to get the string from. */ -const char *GetGRFStringFromGRFText(const GRFText *text) +const char *GetGRFStringFromGRFText(const GRFTextList &text_list) { const char *default_text = nullptr; /* Search the list of lang-strings of this stringid for current lang */ - for (; text != nullptr; text = text->next) { - if (text->langid == _currentLangID) return text->text; + for (const auto &text : text_list) { + if (text.langid == _currentLangID) return text.text.c_str(); /* If the current string is English or American, set it as the * fallback language if the specific language isn't available. */ - if (text->langid == GRFLX_UNSPECIFIED || (default_text == nullptr && (text->langid == GRFLX_ENGLISH || text->langid == GRFLX_AMERICAN))) { - default_text = text->text; + if (text.langid == GRFLX_UNSPECIFIED || (default_text == nullptr && (text.langid == GRFLX_ENGLISH || text.langid == GRFLX_AMERICAN))) { + default_text = text.text.c_str(); } } return default_text; } +/** + * Get a C-string from a GRFText-list. If there is a translation for the + * current language it is returned, otherwise the default translation + * is returned. If there is neither a default nor a translation for the + * current language nullptr is returned. + * @param text The GRFTextList to get the string from. + */ +const char *GetGRFStringFromGRFText(const GRFTextWrapper &text) +{ + return text ? GetGRFStringFromGRFText(*text) : nullptr; +} + /** * Get a C-string from a stringid set by a newgrf. */ @@ -782,19 +706,6 @@ bool CheckGrfLangID(byte lang_id, byte grf_version) return (lang_id == _currentLangID || lang_id == GRFLX_UNSPECIFIED); } -/** - * Delete all items of a linked GRFText list. - * @param grftext the head of the list to delete - */ -void CleanUpGRFText(GRFText *grftext) -{ - while (grftext != nullptr) { - GRFText *grftext2 = grftext->next; - delete grftext; - grftext = grftext2; - } -} - /** * House cleaning. * Remove all strings and reset the text counter. @@ -804,10 +715,9 @@ void CleanUpStrings() uint id; for (id = 0; id < _num_grf_texts; id++) { - CleanUpGRFText(_grf_text[id].textholder); _grf_text[id].grfid = 0; _grf_text[id].stringid = 0; - _grf_text[id].textholder = nullptr; + _grf_text[id].textholder.clear(); } _num_grf_texts = 0; diff --git a/src/newgrf_text.h b/src/newgrf_text.h index 709f4dd244..bdd1f1bc95 100644 --- a/src/newgrf_text.h +++ b/src/newgrf_text.h @@ -14,26 +14,39 @@ #include "strings_type.h" #include "core/smallvec_type.hpp" #include "table/control_codes.h" +#include +#include +#include /** This character, the thorn ('รพ'), indicates a unicode string to NFO. */ static const WChar NFO_UTF8_IDENTIFIER = 0x00DE; +/** A GRF text with associated language ID. */ +struct GRFText { + byte langid; ///< The language associated with this GRFText. + std::string text; ///< The actual (translated) text. +}; + +/** A GRF text with a list of translations. */ +typedef std::vector GRFTextList; +/** Reference counted wrapper around a GRFText pointer. */ +typedef std::shared_ptr GRFTextWrapper; + StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string); StringID GetGRFStringID(uint32 grfid, StringID stringid); -const char *GetGRFStringFromGRFText(const struct GRFText *text); +const char *GetGRFStringFromGRFText(const GRFTextList &text_list); +const char *GetGRFStringFromGRFText(const GRFTextWrapper &text); const char *GetGRFStringPtr(uint16 stringid); void CleanUpStrings(); void SetCurrentGrfLangID(byte language_id); char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen = nullptr, StringControlCode byte80 = SCC_NEWGRF_PRINT_WORD_STRING_ID); -struct GRFText *DuplicateGRFText(struct GRFText *orig); -void AddGRFTextToList(struct GRFText **list, struct GRFText *text_to_add); -void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); -void AddGRFTextToList(struct GRFText **list, const char *text_to_add); -void CleanUpGRFText(struct GRFText *grftext); +void AddGRFTextToList(GRFTextList &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); +void AddGRFTextToList(GRFTextWrapper &list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); +void AddGRFTextToList(GRFTextWrapper &list, const char *text_to_add); bool CheckGrfLangID(byte lang_id, byte grf_version); -void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values = nullptr); +void StartTextRefStackUsage(const struct GRFFile *grffile, byte numEntries, const uint32 *values = nullptr); void StopTextRefStackUsage(); void RewindTextRefStack(); bool UsingNewGRFTextStack();