mirror of
https://github.com/OpenTTD/OpenTTD
synced 2026-01-16 17:02:37 +01:00
Codechange: String parameter encoding for regular strings.
This allows a string and its parameters to be encoded and stored as just one string, instead of juggling with capturing and restoring string parameters. The advantage of EncodedStrings over raw strings is they use current language and parameter values at the point of decoding.
This commit is contained in:
committed by
Peter Nelson
parent
4010313180
commit
1f21e9dc74
@@ -95,6 +95,65 @@ const StringParameter &StringParameters::GetNextParameterReference()
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string with no parameters into an encoded string.
|
||||
* @param str The StringID to format.
|
||||
* @returns The encoded string.
|
||||
*/
|
||||
EncodedString GetEncodedString(StringID str)
|
||||
{
|
||||
return GetEncodedStringWithArgs(str, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string with its parameters into an encoded string.
|
||||
* The encoded string can be stored and decoded later without requiring parameters to be stored separately.
|
||||
* @param str The StringID to format.
|
||||
* @param params The parameters of the string.
|
||||
* @returns The encoded string.
|
||||
*/
|
||||
EncodedString GetEncodedStringWithArgs(StringID str, std::span<const StringParameter> params)
|
||||
{
|
||||
std::string result;
|
||||
auto output = std::back_inserter(result);
|
||||
Utf8Encode(output, SCC_ENCODED_INTERNAL);
|
||||
fmt::format_to(output, "{:X}", str);
|
||||
|
||||
struct visitor {
|
||||
std::back_insert_iterator<std::string> &output;
|
||||
|
||||
void operator()(const std::monostate &) {}
|
||||
|
||||
void operator()(const uint64_t &arg)
|
||||
{
|
||||
Utf8Encode(output, SCC_ENCODED_NUMERIC);
|
||||
fmt::format_to(this->output, "{:X}", arg);
|
||||
}
|
||||
|
||||
void operator()(const std::string &value)
|
||||
{
|
||||
Utf8Encode(output, SCC_ENCODED_STRING);
|
||||
fmt::format_to(this->output, "{}", value);
|
||||
}
|
||||
};
|
||||
|
||||
visitor v{output};
|
||||
for (const auto ¶m : params) {
|
||||
*output = SCC_RECORD_SEPARATOR;
|
||||
std::visit(v, param.data);
|
||||
}
|
||||
|
||||
return EncodedString{std::move(result)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the encoded string.
|
||||
* @returns Decoded raw string.
|
||||
*/
|
||||
std::string EncodedString::GetDecodedString() const
|
||||
{
|
||||
return GetString(STR_JUST_RAW_STRING, this->string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a string parameter \a v at index \a n in the global string parameter array.
|
||||
@@ -956,10 +1015,11 @@ uint ConvertDisplaySpeedToKmhishSpeed(uint speed, VehicleType type)
|
||||
/**
|
||||
* Decodes an encoded string during FormatString.
|
||||
* @param str The buffer of the encoded string.
|
||||
* @param game_script Set if decoding a GameScript-encoded string. This affects how string IDs are handled.
|
||||
* @param builder The string builder to write the string to.
|
||||
* @returns Updated position position in input buffer.
|
||||
*/
|
||||
static const char *DecodeEncodedString(const char *str, StringBuilder &builder)
|
||||
static const char *DecodeEncodedString(const char *str, bool game_script, StringBuilder &builder)
|
||||
{
|
||||
ArrayStringParameters<20> sub_args;
|
||||
|
||||
@@ -970,7 +1030,7 @@ static const char *DecodeEncodedString(const char *str, StringBuilder &builder)
|
||||
builder += "(invalid SCC_ENCODED)";
|
||||
return p;
|
||||
}
|
||||
if (id >= TAB_SIZE_GAMESCRIPT) {
|
||||
if (game_script && id >= TAB_SIZE_GAMESCRIPT) {
|
||||
while (*p != '\0') p++;
|
||||
builder += "(invalid StringID)";
|
||||
return p;
|
||||
@@ -984,6 +1044,12 @@ static const char *DecodeEncodedString(const char *str, StringBuilder &builder)
|
||||
/* Find end of the parameter. */
|
||||
for (; *p != '\0' && *p != SCC_RECORD_SEPARATOR; ++p) {}
|
||||
|
||||
if (s == p) {
|
||||
/* This is an empty parameter. */
|
||||
sub_args.SetParam(i++, std::monostate{});
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the parameter type. */
|
||||
char32_t parameter_type;
|
||||
size_t len = Utf8Decode(¶meter_type, s);
|
||||
@@ -1014,13 +1080,13 @@ static const char *DecodeEncodedString(const char *str, StringBuilder &builder)
|
||||
}
|
||||
|
||||
default:
|
||||
/* Skip unknown parameter. */
|
||||
i++;
|
||||
/* Unknown parameter, make it blank. */
|
||||
sub_args.SetParam(i++, std::monostate{});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StringID stringid = MakeStringID(TEXT_TAB_GAMESCRIPT_START, id);
|
||||
StringID stringid = game_script ? MakeStringID(TEXT_TAB_GAMESCRIPT_START, id) : StringID{id.base()};
|
||||
GetStringWithArgs(builder, stringid, sub_args, true);
|
||||
|
||||
return p;
|
||||
@@ -1092,7 +1158,8 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
|
||||
args.SetTypeOfNextParameter(b);
|
||||
switch (b) {
|
||||
case SCC_ENCODED:
|
||||
str = DecodeEncodedString(str, builder);
|
||||
case SCC_ENCODED_INTERNAL:
|
||||
str = DecodeEncodedString(str, b == SCC_ENCODED, builder);
|
||||
break;
|
||||
|
||||
case SCC_NEWGRF_STRINL: {
|
||||
|
||||
Reference in New Issue
Block a user