mirror of https://github.com/OpenTTD/OpenTTD
Fix fcf8693c4f: Remove 100 byte limit for parsing string command parameters. (#12950)
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/12949/head
parent
66c5a21d8f
commit
25a8abcd8e
|
@ -31,8 +31,7 @@ int _cur_line; ///< The current line we're parsing in the
|
||||||
int _errors, _warnings, _show_todo;
|
int _errors, _warnings, _show_todo;
|
||||||
LanguagePackHeader _lang; ///< Header information about a language.
|
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, std::string ¶m, int *argno, int *casei);
|
||||||
static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new case.
|
* Create a new case.
|
||||||
|
@ -135,7 +134,7 @@ uint StringData::Version() const
|
||||||
if (ls != nullptr) {
|
if (ls != nullptr) {
|
||||||
const CmdStruct *cs;
|
const CmdStruct *cs;
|
||||||
const char *s;
|
const char *s;
|
||||||
char buf[MAX_COMMAND_PARAM_SIZE];
|
std::string buf;
|
||||||
int argno;
|
int argno;
|
||||||
int casei;
|
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)
|
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);
|
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 i = 0; i < nw; i++) {
|
||||||
for (uint j = 0; words[i][j] != '\0'; j++) buffer->AppendByte(words[i][j]);
|
for (uint j = 0; words[i][j] != '\0'; j++) buffer->AppendByte(words[i][j]);
|
||||||
buffer->AppendByte(0);
|
buffer->AppendByte(0);
|
||||||
|
@ -442,7 +448,7 @@ static uint ResolveCaseName(const char *str, size_t len)
|
||||||
|
|
||||||
/* returns nullptr on eof
|
/* returns nullptr on eof
|
||||||
* else returns command struct */
|
* 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 ¶m, int *argno, int *casei)
|
||||||
{
|
{
|
||||||
const char *s = *str, *start;
|
const char *s = *str, *start;
|
||||||
char c;
|
char c;
|
||||||
|
@ -507,11 +513,9 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a
|
||||||
StrgenError("Missing }} from command '{}'", start);
|
StrgenError("Missing }} from command '{}'", start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (s - start == MAX_COMMAND_PARAM_SIZE) FatalError("param command too long");
|
param += c;
|
||||||
*param++ = c;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*param = '\0';
|
|
||||||
|
|
||||||
*str = s;
|
*str = s;
|
||||||
|
|
||||||
|
@ -532,7 +536,6 @@ StringReader::StringReader(StringData &data, const std::string &file, bool maste
|
||||||
|
|
||||||
ParsedCommandStruct ExtractCommandString(const char *s, bool)
|
ParsedCommandStruct ExtractCommandString(const char *s, bool)
|
||||||
{
|
{
|
||||||
char param[MAX_COMMAND_PARAM_SIZE];
|
|
||||||
int argno;
|
int argno;
|
||||||
int argidx = 0;
|
int argidx = 0;
|
||||||
int casei;
|
int casei;
|
||||||
|
@ -541,6 +544,7 @@ ParsedCommandStruct ExtractCommandString(const char *s, bool)
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* read until next command from a. */
|
/* read until next command from a. */
|
||||||
|
std::string param;
|
||||||
const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
|
const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
|
||||||
|
|
||||||
if (ar == nullptr) break;
|
if (ar == nullptr) break;
|
||||||
|
@ -555,7 +559,7 @@ ParsedCommandStruct ExtractCommandString(const char *s, bool)
|
||||||
|
|
||||||
p.consuming_commands[argidx++] = ar;
|
p.consuming_commands[argidx++] = ar;
|
||||||
} else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them
|
} 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char param[MAX_COMMAND_PARAM_SIZE];
|
std::string param;
|
||||||
int argno;
|
int argno;
|
||||||
int casei;
|
int casei;
|
||||||
const CmdStruct *cs = ParseCommandString(&str, param, &argno, &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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue