1
0
Fork 0

Codefix #13872: Use StringConsumer in TranslateTTDPatchCodes.

pull/14000/head
frosch 2025-03-28 16:18:24 +01:00 committed by frosch
parent 069edc1a4b
commit 98efd3c96e
1 changed files with 21 additions and 37 deletions

View File

@ -28,6 +28,7 @@
#include "debug.h" #include "debug.h"
#include "core/alloc_type.hpp" #include "core/alloc_type.hpp"
#include "core/string_builder.hpp" #include "core/string_builder.hpp"
#include "core/string_consumer.hpp"
#include "language.h" #include "language.h"
#include "table/strings.h" #include "table/strings.h"
@ -238,17 +239,10 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
/* Empty input string? Nothing to do here. */ /* Empty input string? Nothing to do here. */
if (str.empty()) return {}; if (str.empty()) return {};
std::string_view::const_iterator src = str.cbegin(); StringConsumer consumer(str);
/* Is this an unicode string? */ /* Is this an unicode string? */
bool unicode = false; bool unicode = consumer.ReadUtf8If(NFO_UTF8_IDENTIFIER);
char32_t marker;
size_t len = Utf8Decode(&marker, &*src);
if (marker == NFO_UTF8_IDENTIFIER) {
unicode = true;
src += len;
}
/* Helper variable for a possible (string) mapping of plural/gender and cases. */ /* Helper variable for a possible (string) mapping of plural/gender and cases. */
std::optional<UnmappedChoiceList> mapping_pg, mapping_c; std::optional<UnmappedChoiceList> mapping_pg, mapping_c;
@ -256,29 +250,27 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
std::string dest; std::string dest;
StringBuilder builder(dest); StringBuilder builder(dest);
while (src != str.cend()) { while (consumer.AnyBytesLeft()) {
char32_t c; char32_t c;
if (auto u = unicode ? consumer.TryReadUtf8() : std::nullopt; u.has_value()) {
if (unicode && Utf8EncodedCharLen(*src) != 0) { c = *u;
c = Utf8Consume(src);
/* 'Magic' range of control codes. */ /* 'Magic' range of control codes. */
if (GB(c, 8, 8) == 0xE0) { if (0xE000 <= c && c <= 0xE0FF) {
c = GB(c, 0, 8); c -= 0xE000;
} else if (c >= 0x20) { } else if (c >= 0x20) {
if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?'; if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
builder.PutUtf8(c); builder.PutUtf8(c);
continue; continue;
} }
} else { } else {
c = static_cast<uint8_t>(*src++); c = consumer.ReadUint8(); // read as unsigned, otherwise integer promotion breaks it
} }
assert(c <= 0xFF);
if (c == '\0') break; if (c == '\0') break;
switch (c) { switch (c) {
case 0x01: case 0x01:
if (*src == '\0') goto string_end; consumer.SkipUint8();
src++;
builder.PutChar(' '); builder.PutChar(' ');
break; break;
case 0x0A: break; case 0x0A: break;
@ -292,8 +284,8 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
case 0x0E: builder.PutUtf8(SCC_TINYFONT); break; case 0x0E: builder.PutUtf8(SCC_TINYFONT); break;
case 0x0F: builder.PutUtf8(SCC_BIGFONT); break; case 0x0F: builder.PutUtf8(SCC_BIGFONT); break;
case 0x1F: case 0x1F:
if (src[0] == '\0' || src[1] == '\0') goto string_end; consumer.SkipUint8();
src += 2; consumer.SkipUint8();
builder.PutChar(' '); builder.PutChar(' ');
break; break;
case 0x7B: case 0x7B:
@ -304,10 +296,7 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
case 0x80: builder.PutUtf8(byte80); break; case 0x80: builder.PutUtf8(byte80); break;
case 0x81: case 0x81:
{ {
if (src[0] == '\0' || src[1] == '\0') goto string_end; uint16_t string = consumer.ReadUint16LE();
uint16_t string;
string = static_cast<uint8_t>(*src++);
string |= static_cast<uint8_t>(*src++) << 8;
builder.PutUtf8(SCC_NEWGRF_STRINL); builder.PutUtf8(SCC_NEWGRF_STRINL);
builder.PutUtf8(MapGRFStringID(grfid, GRFStringID{string})); builder.PutUtf8(MapGRFStringID(grfid, GRFStringID{string}));
break; break;
@ -337,7 +326,7 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
case 0x98: builder.PutUtf8(SCC_BLACK); break; case 0x98: builder.PutUtf8(SCC_BLACK); break;
case 0x9A: case 0x9A:
{ {
int code = *src++; uint8_t code = consumer.ReadUint8();
switch (code) { switch (code) {
case 0x00: goto string_end; case 0x00: goto string_end;
case 0x01: builder.PutUtf8(SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; case 0x01: builder.PutUtf8(SCC_NEWGRF_PRINT_QWORD_CURRENCY); break;
@ -350,9 +339,7 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
* support this. As such it is not implemented in OpenTTD. */ * support this. As such it is not implemented in OpenTTD. */
case 0x03: case 0x03:
{ {
if (src[0] == '\0' || src[1] == '\0') goto string_end; uint16_t tmp = consumer.ReadUint16LE();
uint16_t tmp = static_cast<uint8_t>(*src++);
tmp |= static_cast<uint8_t>(*src++) << 8;
builder.PutUtf8(SCC_NEWGRF_PUSH_WORD); builder.PutUtf8(SCC_NEWGRF_PUSH_WORD);
builder.PutUtf8(tmp); builder.PutUtf8(tmp);
break; break;
@ -367,9 +354,8 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
case 0x0E: case 0x0E:
case 0x0F: case 0x0F:
{ {
if (str[0] == '\0') goto string_end;
const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id); const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id);
int index = *src++; int index = consumer.ReadUint8();
int mapped = lm != nullptr ? lm->GetMapping(index, code == 0x0E) : -1; int mapped = lm != nullptr ? lm->GetMapping(index, code == 0x0E) : -1;
if (mapped >= 0) { if (mapped >= 0) {
builder.PutUtf8(code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE); builder.PutUtf8(code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE);
@ -380,14 +366,13 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
case 0x10: case 0x10:
case 0x11: case 0x11:
if (str[0] == '\0') goto string_end;
if (!mapping_pg.has_value() && !mapping_c.has_value()) { if (!mapping_pg.has_value() && !mapping_c.has_value()) {
if (code == 0x10) src++; // Skip the index if (code == 0x10) consumer.SkipUint8(); // Skip the index
GrfMsg(1, "choice list {} marker found when not expected", code == 0x10 ? "next" : "default"); GrfMsg(1, "choice list {} marker found when not expected", code == 0x10 ? "next" : "default");
break; break;
} else { } else {
auto &mapping = mapping_pg ? mapping_pg : mapping_c; auto &mapping = mapping_pg ? mapping_pg : mapping_c;
int index = (code == 0x10 ? *src++ : 0); int index = (code == 0x10 ? consumer.ReadUint8() : 0);
if (mapping->strings.find(index) != mapping->strings.end()) { if (mapping->strings.find(index) != mapping->strings.end()) {
GrfMsg(1, "duplicate choice list string, ignoring"); GrfMsg(1, "duplicate choice list string, ignoring");
} else { } else {
@ -416,14 +401,13 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all
case 0x14: case 0x14:
case 0x15: { case 0x15: {
auto &mapping = code == 0x14 ? mapping_c : mapping_pg; auto &mapping = code == 0x14 ? mapping_c : mapping_pg;
if (src[0] == '\0') goto string_end;
/* Case mapping can have nested plural/gender mapping. Otherwise nesting is invalid. */ /* Case mapping can have nested plural/gender mapping. Otherwise nesting is invalid. */
if (mapping.has_value() || mapping_pg.has_value()) { if (mapping.has_value() || mapping_pg.has_value()) {
GrfMsg(1, "choice lists can't be stacked, it's going to get messy now..."); GrfMsg(1, "choice lists can't be stacked, it's going to get messy now...");
if (code != 0x14) src++; if (code != 0x14) consumer.SkipUint8();
} else { } else {
static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST }; static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST };
mapping.emplace(mp[code - 0x13], code == 0x14 ? 0 : *src++); mapping.emplace(mp[code - 0x13], code == 0x14 ? 0 : consumer.ReadUint8());
} }
break; break;
} }