mirror of https://github.com/OpenTTD/OpenTTD
Codefix #13872: Use StringConsumer in TranslateTTDPatchCodes.
parent
069edc1a4b
commit
98efd3c96e
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue