Codechange: Replace custom linked list for GRF texts with STL vectors and strings.

This commit is contained in:
Michael Lutz 2020-05-17 23:31:47 +02:00
parent f2b40f40aa
commit 43cd892e0c
7 changed files with 131 additions and 261 deletions

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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<uint32, GRFText *> *val_name = _cur_parameter->value_names.Find(id);
std::pair<uint32, GRFTextList> *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);
}

View File

@ -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<uint8>(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum));
MemCpyT<uint32>(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<uint32, GRFText *> *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<uint32, GRFText *> *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<UnknownGRF> 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<UnknownGRF>(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;
}
/**

View File

@ -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<uint32, struct GRFText *> value_names; ///< Names for each value.
SmallMap<uint32, GRFTextList> 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 "<Unknown>"
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);

View File

@ -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<byte>(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;

View File

@ -14,26 +14,39 @@
#include "strings_type.h"
#include "core/smallvec_type.hpp"
#include "table/control_codes.h"
#include <utility>
#include <vector>
#include <string>
/** 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<GRFText> GRFTextList;
/** Reference counted wrapper around a GRFText pointer. */
typedef std::shared_ptr<GRFTextList> 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();