1
0
Fork 0

Fix fcf8693c4f: Remove 100 byte limit for parsing string command parameters.

This allows longer parameters to be used in plural and gender commands.

Each individual word list parameter is now limited to 253 bytes, allowing for a trailing NUL and leaving 0xFF reserved.
pull/12950/head
Peter Nelson 2024-09-18 17:08:34 +01:00
parent 66c5a21d8f
commit 5d19b6fd97
No known key found for this signature in database
GPG Key ID: 8EF8F0A467DF75ED
1 changed files with 16 additions and 12 deletions

View File

@ -31,8 +31,7 @@ int _cur_line; ///< The current line we're parsing in the
int _errors, _warnings, _show_todo;
LanguagePackHeader _lang; ///< Header information about a language.
static const ptrdiff_t MAX_COMMAND_PARAM_SIZE = 100; ///< Maximum size of every command block, not counting the name of the command itself
static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei);
static const CmdStruct *ParseCommandString(const char **str, std::string &param, int *argno, int *casei);
/**
* Create a new case.
@ -135,7 +134,7 @@ uint StringData::Version() const
if (ls != nullptr) {
const CmdStruct *cs;
const char *s;
char buf[MAX_COMMAND_PARAM_SIZE];
std::string buf;
int argno;
int casei;
@ -317,8 +316,15 @@ static int TranslateArgumentIdx(int arg, int offset = 0);
static void EmitWordList(Buffer *buffer, const std::vector<const char *> &words, uint nw)
{
/* Maximum word length in bytes, excluding trailing NULL. */
constexpr uint MAX_WORD_LENGTH = UINT8_MAX - 2;
buffer->AppendByte(nw);
for (uint i = 0; i < nw; i++) buffer->AppendByte((uint8_t)strlen(words[i]) + 1);
for (uint i = 0; i < nw; i++) {
size_t len = strlen(words[i]) + 1;
if (len >= UINT8_MAX) StrgenFatal("WordList {}/{} string '{}' too long, max bytes {}", i + 1, nw, words[i], MAX_WORD_LENGTH);
buffer->AppendByte(static_cast<uint8_t>(len));
}
for (uint i = 0; i < nw; i++) {
for (uint j = 0; words[i][j] != '\0'; j++) buffer->AppendByte(words[i][j]);
buffer->AppendByte(0);
@ -442,7 +448,7 @@ static uint ResolveCaseName(const char *str, size_t len)
/* returns nullptr on eof
* else returns command struct */
static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei)
static const CmdStruct *ParseCommandString(const char **str, std::string &param, int *argno, int *casei)
{
const char *s = *str, *start;
char c;
@ -507,11 +513,9 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a
StrgenError("Missing }} from command '{}'", start);
return nullptr;
}
if (s - start == MAX_COMMAND_PARAM_SIZE) FatalError("param command too long");
*param++ = c;
param += c;
}
}
*param = '\0';
*str = s;
@ -532,7 +536,6 @@ StringReader::StringReader(StringData &data, const std::string &file, bool maste
ParsedCommandStruct ExtractCommandString(const char *s, bool)
{
char param[MAX_COMMAND_PARAM_SIZE];
int argno;
int argidx = 0;
int casei;
@ -541,6 +544,7 @@ ParsedCommandStruct ExtractCommandString(const char *s, bool)
for (;;) {
/* read until next command from a. */
std::string param;
const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
if (ar == nullptr) break;
@ -555,7 +559,7 @@ ParsedCommandStruct ExtractCommandString(const char *s, bool)
p.consuming_commands[argidx++] = ar;
} else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them
p.non_consuming_commands.emplace_back(CmdPair{ar, param});
p.non_consuming_commands.emplace_back(CmdPair{ar, std::move(param)});
}
}
@ -835,7 +839,7 @@ static void PutCommandString(Buffer *buffer, const char *str)
continue;
}
char param[MAX_COMMAND_PARAM_SIZE];
std::string param;
int argno;
int casei;
const CmdStruct *cs = ParseCommandString(&str, param, &argno, &casei);
@ -861,7 +865,7 @@ static void PutCommandString(Buffer *buffer, const char *str)
}
}
cs->proc(buffer, param, cs->value);
cs->proc(buffer, param.data(), cs->value);
}
}