1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2026-01-31 16:14:29 +01:00

Codechange: Encode case/gender/plural choice lists without null termination, only length prefix. (#13876)

This commit is contained in:
frosch
2025-03-25 20:32:40 +01:00
committed by GitHub
parent 25005cff16
commit c105adcd96
3 changed files with 46 additions and 39 deletions

View File

@@ -292,18 +292,14 @@ std::optional<std::string_view> ParseWord(const char **buf)
* CommandByte <ARG#> <NUM> {Length of each string} {each string} */
static void EmitWordList(Buffer *buffer, const std::vector<std::string> &words)
{
/* Maximum word length in bytes, excluding trailing NULL. */
constexpr size_t MAX_WORD_LENGTH = UINT8_MAX - 2;
buffer->AppendByte(static_cast<uint8_t>(words.size()));
for (size_t i = 0; i < words.size(); i++) {
size_t len = words[i].size() + 1;
if (len >= UINT8_MAX) StrgenFatal("WordList {}/{} string '{}' too long, max bytes {}", i + 1, words.size(), words[i], MAX_WORD_LENGTH);
size_t len = words[i].size();
if (len > UINT8_MAX) StrgenFatal("WordList {}/{} string '{}' too long, max bytes {}", i + 1, words.size(), words[i], UINT8_MAX);
buffer->AppendByte(static_cast<uint8_t>(len));
}
for (size_t i = 0; i < words.size(); i++) {
buffer->append(words[i]);
buffer->AppendByte(0);
}
}
@@ -900,11 +896,12 @@ void LanguageWriter::WriteLang(const StringData &data)
_translated = cmdp != &ls->english;
std::optional<size_t> default_case_pos;
if (!ls->translated_cases.empty()) {
/* Need to output a case-switch.
* It has this format
* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
* Each LEN is printed using 2 bytes in big endian order. */
* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <LENDEFAULT> <STRINGDEFAULT>
* Each LEN is printed using 2 bytes in little endian order. */
buffer.AppendUtf8(SCC_SWITCH_CASE);
buffer.AppendByte(static_cast<uint8_t>(ls->translated_cases.size()));
@@ -917,16 +914,25 @@ void LanguageWriter::WriteLang(const StringData &data)
buffer.AppendByte(0);
/* Write string */
PutCommandString(&buffer, c.string.c_str());
buffer.AppendByte(0); // terminate with a zero
/* Fill in the length */
size_t size = buffer.size() - (pos + 2);
buffer[pos + 0] = GB(size, 8, 8);
buffer[pos + 1] = GB(size, 0, 8);
buffer[pos + 0] = GB(size, 0, 8);
buffer[pos + 1] = GB(size, 8, 8);
}
default_case_pos = buffer.size();
buffer.AppendByte(0);
buffer.AppendByte(0);
}
if (!cmdp->empty()) PutCommandString(&buffer, cmdp->c_str());
if (default_case_pos.has_value()) {
size_t size = buffer.size() - (*default_case_pos + 2);
buffer[*default_case_pos + 0] = GB(size, 0, 8);
buffer[*default_case_pos + 1] = GB(size, 8, 8);
}
this->WriteLength(buffer.size());
this->Write(buffer.data(), buffer.size());
buffer.clear();