1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2026-01-17 09:22:42 +01:00

Codechange: Pass unformatted strings from GetStringPtr as std::string_view. (#13871)

This commit is contained in:
frosch
2025-03-23 19:23:31 +01:00
committed by GitHub
parent 234c9fb3bd
commit 5aa4ad5135
8 changed files with 97 additions and 92 deletions

View File

@@ -258,7 +258,7 @@ uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
static void StationGetSpecialString(StringBuilder &builder, StationFacilities x);
static bool GetSpecialNameString(StringBuilder &builder, StringID string, StringParameters &args);
static void FormatString(StringBuilder &builder, const char *str, StringParameters &args, uint case_index = 0, bool game_script = false, bool dry_run = false);
static void FormatString(StringBuilder &builder, std::string_view str, StringParameters &args, uint case_index = 0, bool game_script = false, bool dry_run = false);
/**
* Parse most format codes within a string and write the result to a buffer.
@@ -270,7 +270,7 @@ static void FormatString(StringBuilder &builder, const char *str, StringParamete
* @param game_script True when doing GameScript text processing.
* @param dry_run True when the args' type data is not yet initialized.
*/
static void FormatString(StringBuilder &builder, const char *str, std::span<StringParameter> params, uint case_index = 0, bool game_script = false, bool dry_run = false)
static void FormatString(StringBuilder &builder, std::string_view str, std::span<StringParameter> params, uint case_index = 0, bool game_script = false, bool dry_run = false)
{
StringParameters tmp_params{params};
FormatString(builder, str, tmp_params, case_index, game_script, dry_run);
@@ -291,7 +291,7 @@ struct LanguagePackDeleter {
struct LoadedLanguagePack {
std::unique_ptr<LanguagePack, LanguagePackDeleter> langpack;
std::vector<char *> offsets;
std::vector<std::string_view> strings;
std::array<uint, TEXT_TAB_END> langtab_num; ///< Offset into langpack offs
std::array<uint, TEXT_TAB_END> langtab_start; ///< Offset into langpack offs
@@ -312,7 +312,7 @@ std::string_view GetListSeparator()
return _langpack.list_separator;
}
const char *GetStringPtr(StringID string)
std::string_view GetStringPtr(StringID string)
{
switch (GetStringTab(string)) {
case TEXT_TAB_GAMESCRIPT_START: return GetGameStringPtr(GetStringIndex(string));
@@ -321,8 +321,8 @@ const char *GetStringPtr(StringID string)
case TEXT_TAB_NEWGRF_START: return GetGRFStringPtr(GetStringIndex(string));
default: {
const size_t offset = _langpack.langtab_start[GetStringTab(string)] + GetStringIndex(string).base();
if (offset < _langpack.offsets.size()) return _langpack.offsets[offset];
return nullptr;
if (offset < _langpack.strings.size()) return _langpack.strings[offset];
return "(undefined string)";
}
}
}
@@ -780,16 +780,19 @@ static const char *ParseStringChoice(const char *b, uint form, StringBuilder &bu
{
/* <NUM> {Length of each string} {each string} */
uint n = (uint8_t)*b++;
uint pos, i, mypos = 0;
for (i = pos = 0; i != n; i++) {
size_t form_offset = 0, form_len = 0, total_len = 0;
for (uint i = 0; i != n; i++) {
uint len = (uint8_t)*b++;
if (i == form) mypos = pos;
pos += len;
if (i == form) {
form_offset = total_len;
form_len = len;
}
total_len += len;
}
builder += b + mypos;
return b + pos;
assert(form_len > 0); // len includes a null terminator
builder += std::string_view(b + form_offset, form_len - 1);
return b + total_len;
}
/** Helper for unit conversion. */
@@ -1075,7 +1078,7 @@ static const char *DecodeEncodedString(const char *str, bool game_script, String
* @param args Pointer to extra arguments used by various string codes.
* @param dry_run True when the args' type data is not yet initialized.
*/
static void FormatString(StringBuilder &builder, const char *str_arg, StringParameters &args, uint orig_case_index, bool game_script, bool dry_run)
static void FormatString(StringBuilder &builder, std::string_view str_arg, StringParameters &args, uint orig_case_index, bool game_script, bool dry_run)
{
size_t orig_first_param_offset = args.GetOffset();
@@ -1094,25 +1097,31 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
/* We have to restore the original offset here to to read the correct values. */
args.SetOffset(orig_first_param_offset);
}
char32_t b = '\0';
uint next_substr_case_index = 0;
struct StrStackItem {
const char *str;
const char *end;
size_t first_param_offset;
uint case_index;
StrStackItem(std::string_view view, size_t first_param_offset, uint case_index)
: str(view.data()), end(view.data() + view.size()), first_param_offset(first_param_offset), case_index(case_index)
{}
};
std::stack<StrStackItem, std::vector<StrStackItem>> str_stack;
str_stack.emplace(str_arg, orig_first_param_offset, orig_case_index);
for (;;) {
try {
while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top().str)) == '\0') {
while (!str_stack.empty() && str_stack.top().str >= str_stack.top().end) {
str_stack.pop();
}
if (str_stack.empty()) break;
const char *&str = str_stack.top().str;
const size_t ref_param_offset = str_stack.top().first_param_offset;
const uint case_index = str_stack.top().case_index;
char32_t b = Utf8Consume(&str);
assert(b != 0);
if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
/* We need to pass some stuff as it might be modified. */
@@ -1134,24 +1143,16 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
case SCC_NEWGRF_STRINL: {
StringID substr = Utf8Consume(&str);
const char *ptr = GetStringPtr(substr);
if (ptr == nullptr) {
builder += "(invalid NewGRF string)";
} else {
str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "str"
}
std::string_view ptr = GetStringPtr(substr);
str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "str"
next_substr_case_index = 0;
break;
}
case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
StringID substr = args.GetNextParameter<StringID>();
const char *ptr = GetStringPtr(substr);
if (ptr == nullptr) {
builder += "(invalid NewGRF string)";
} else {
str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "str"
}
std::string_view ptr = GetStringPtr(substr);
str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "str"
next_substr_case_index = 0;
break;
}
@@ -1226,16 +1227,22 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
/* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
* Each LEN is printed using 2 bytes in big endian order. */
uint num = (uint8_t)*str++;
while (num) {
if ((uint8_t)str[0] == case_index) {
/* Found the case, adjust str pointer and continue */
str += 3;
break;
std::optional<std::string_view> found;
for (; num > 0; --num) {
uint8_t index = static_cast<uint8_t>(str[0]);
uint16_t len = (static_cast<uint8_t>(str[1]) << 8) + static_cast<uint8_t>(str[2]);
assert(len > 0); // len includes a null terminator
str += 3;
if (index == case_index) {
/* Found the case */
found.emplace(str, len - 1);
}
/* Otherwise skip to the next case */
str += 3 + (static_cast<uint8_t>(str[1]) << 8) + static_cast<uint8_t>(str[2]);
num--;
str += len;
}
const char *end = str_stack.top().end;
if (!found.has_value()) found.emplace(str, end - str);
str = end;
str_stack.emplace(*found, ref_param_offset, case_index); // this may invalidate "str"
break;
}
@@ -1990,12 +1997,12 @@ bool LanguagePackHeader::IsReasonablyFinished() const
bool ReadLanguagePack(const LanguageMetadata *lang)
{
/* Current language pack */
size_t len = 0;
std::unique_ptr<LanguagePack, LanguagePackDeleter> lang_pack(reinterpret_cast<LanguagePack *>(ReadFileToMem(FS2OTTD(lang->file), len, 1U << 20).release()));
size_t total_len = 0;
std::unique_ptr<LanguagePack, LanguagePackDeleter> lang_pack(reinterpret_cast<LanguagePack *>(ReadFileToMem(FS2OTTD(lang->file), total_len, 1U << 20).release()));
if (!lang_pack) return false;
/* End of read data (+ terminating zero added in ReadFileToMem()) */
const char *end = (char *)lang_pack.get() + len + 1;
const char *end = (char *)lang_pack.get() + total_len + 1;
/* We need at least one byte of lang_pack->data */
if (end <= lang_pack->data || !lang_pack->IsValid()) {
@@ -2015,26 +2022,25 @@ bool ReadLanguagePack(const LanguageMetadata *lang)
}
/* Allocate offsets */
std::vector<char *> offs(count);
std::vector<std::string_view> strings;
/* Fill offsets */
char *s = lang_pack->data;
len = (uint8_t)*s++;
for (uint i = 0; i < count; i++) {
size_t len = static_cast<uint8_t>(*s++);
if (s + len >= end) return false;
if (len >= 0xC0) {
len = ((len & 0x3F) << 8) + (uint8_t)*s++;
len = ((len & 0x3F) << 8) + static_cast<uint8_t>(*s++);
if (s + len >= end) return false;
}
offs[i] = s;
strings.emplace_back(s, len);
s += len;
len = (uint8_t)*s;
*s++ = '\0'; // zero terminate the string
}
assert(strings.size() == count);
_langpack.langpack = std::move(lang_pack);
_langpack.offsets = std::move(offs);
_langpack.strings = std::move(strings);
_langpack.langtab_num = tab_num;
_langpack.langtab_start = tab_start;
@@ -2298,7 +2304,7 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
{
if (this->i >= TEXT_TAB_END) return std::nullopt;
const char *ret = _langpack.offsets[_langpack.langtab_start[this->i] + this->j];
std::string_view ret = _langpack.strings[_langpack.langtab_start[this->i] + this->j];
this->j++;
while (this->i < TEXT_TAB_END && this->j >= _langpack.langtab_num[this->i]) {