mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Use StringBuilder to create encoded strings.
parent
128e0fcde2
commit
dd073eb38d
|
@ -29,6 +29,7 @@
|
|||
#include "../window_func.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../core/endian_func.hpp"
|
||||
#include "../core/string_builder.hpp"
|
||||
#include "../vehicle_base.h"
|
||||
#include "../company_func.h"
|
||||
#include "../timer/timer_game_economy.h"
|
||||
|
@ -928,7 +929,7 @@ void FixSCCEncoded(std::string &str, bool fix_code)
|
|||
* `:"<STRING>"` becomes `<RS><SCC_ENCODED_STRING><STRING>`
|
||||
*/
|
||||
std::string result;
|
||||
auto output = std::back_inserter(result);
|
||||
StringBuilder builder(result);
|
||||
|
||||
bool is_encoded = false; // Set if we determine by the presence of SCC_ENCODED that the string is an encoded string.
|
||||
bool in_string = false; // Set if we in a string, between double-quotes.
|
||||
|
@ -940,11 +941,11 @@ void FixSCCEncoded(std::string &str, bool fix_code)
|
|||
|
||||
char32_t c;
|
||||
Utf8Decode(&c, &*it);
|
||||
it += len;
|
||||
if (c == SCC_ENCODED || (fix_code && (c == 0xE028 || c == 0xE02A))) {
|
||||
Utf8Encode(output, SCC_ENCODED);
|
||||
builder.PutUtf8(SCC_ENCODED);
|
||||
need_type = false;
|
||||
is_encoded = true;
|
||||
it += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -955,27 +956,24 @@ void FixSCCEncoded(std::string &str, bool fix_code)
|
|||
in_string = !in_string;
|
||||
if (in_string && need_type) {
|
||||
/* Started a new string parameter. */
|
||||
Utf8Encode(output, SCC_ENCODED_STRING);
|
||||
builder.PutUtf8(SCC_ENCODED_STRING);
|
||||
need_type = false;
|
||||
}
|
||||
it += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_string && c == ':') {
|
||||
*output = SCC_RECORD_SEPARATOR;
|
||||
builder.PutUtf8(SCC_RECORD_SEPARATOR);
|
||||
need_type = true;
|
||||
it += len;
|
||||
continue;
|
||||
}
|
||||
if (need_type) {
|
||||
/* Started a new numeric parameter. */
|
||||
Utf8Encode(output, SCC_ENCODED_NUMERIC);
|
||||
builder.PutUtf8(SCC_ENCODED_NUMERIC);
|
||||
need_type = false;
|
||||
}
|
||||
|
||||
Utf8Encode(output, c);
|
||||
it += len;
|
||||
builder.PutUtf8(c);
|
||||
}
|
||||
|
||||
str = std::move(result);
|
||||
|
|
|
@ -163,9 +163,9 @@ EncodedString ScriptText::GetEncodedText()
|
|||
ParamList params;
|
||||
int param_count = 0;
|
||||
std::string result;
|
||||
auto output = std::back_inserter(result);
|
||||
StringBuilder builder(result);
|
||||
this->_FillParamList(params, seen_texts);
|
||||
this->_GetEncodedText(output, param_count, params, true);
|
||||
this->_GetEncodedText(builder, param_count, params, true);
|
||||
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
|
||||
return ::EncodedString{std::move(result)};
|
||||
}
|
||||
|
@ -193,46 +193,46 @@ void ScriptText::_FillParamList(ParamList ¶ms, ScriptTextList &seen_texts)
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptText::ParamCheck::Encode(std::back_insert_iterator<std::string> &output, std::string_view cmd)
|
||||
void ScriptText::ParamCheck::Encode(StringBuilder &builder, std::string_view cmd)
|
||||
{
|
||||
if (this->cmd.empty()) this->cmd = cmd;
|
||||
if (this->used) return;
|
||||
|
||||
struct visitor {
|
||||
std::back_insert_iterator<std::string> &output;
|
||||
StringBuilder &builder;
|
||||
|
||||
void operator()(std::string value)
|
||||
{
|
||||
Utf8Encode(this->output, SCC_ENCODED_STRING);
|
||||
this->builder.PutUtf8(SCC_ENCODED_STRING);
|
||||
StrMakeValidInPlace(value, {StringValidationSetting::ReplaceWithQuestionMark, StringValidationSetting::AllowNewline, StringValidationSetting::ReplaceTabCrNlWithSpace});
|
||||
fmt::format_to(this->output, "{}", value);
|
||||
this->builder.Put(value);
|
||||
}
|
||||
|
||||
void operator()(const SQInteger &value)
|
||||
{
|
||||
Utf8Encode(this->output, SCC_ENCODED_NUMERIC);
|
||||
fmt::format_to(this->output, "{:X}", value);
|
||||
this->builder.PutUtf8(SCC_ENCODED_NUMERIC);
|
||||
this->builder.PutIntegerBase(value, 16);
|
||||
}
|
||||
|
||||
void operator()(const ScriptTextRef &value)
|
||||
{
|
||||
Utf8Encode(this->output, SCC_ENCODED);
|
||||
fmt::format_to(this->output, "{:X}", value->string);
|
||||
this->builder.PutUtf8(SCC_ENCODED);
|
||||
this->builder.PutIntegerBase(value->string.base(), 16);
|
||||
}
|
||||
};
|
||||
|
||||
*output = SCC_RECORD_SEPARATOR;
|
||||
std::visit(visitor{output}, *this->param);
|
||||
builder.PutUtf8(SCC_RECORD_SEPARATOR);
|
||||
std::visit(visitor{builder}, *this->param);
|
||||
this->used = true;
|
||||
}
|
||||
|
||||
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int ¶m_count, ParamSpan args, bool first)
|
||||
void ScriptText::_GetEncodedText(StringBuilder &builder, int ¶m_count, ParamSpan args, bool first)
|
||||
{
|
||||
const std::string &name = GetGameStringName(this->string);
|
||||
|
||||
if (first) {
|
||||
Utf8Encode(output, SCC_ENCODED);
|
||||
fmt::format_to(output, "{:X}", this->string);
|
||||
builder.PutUtf8(SCC_ENCODED);
|
||||
builder.PutIntegerBase(this->string.base(), 16);
|
||||
}
|
||||
|
||||
const StringParams ¶ms = GetGameStringParams(this->string);
|
||||
|
@ -256,7 +256,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
|
|||
case StringParam::RAW_STRING:
|
||||
{
|
||||
ParamCheck &p = *get_next_arg();
|
||||
p.Encode(output, cur_param.cmd);
|
||||
p.Encode(builder, cur_param.cmd);
|
||||
if (p.cmd != cur_param.cmd) throw 1;
|
||||
if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
|
||||
break;
|
||||
|
@ -265,7 +265,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
|
|||
case StringParam::STRING:
|
||||
{
|
||||
ParamCheck &p = *get_next_arg();
|
||||
p.Encode(output, cur_param.cmd);
|
||||
p.Encode(builder, cur_param.cmd);
|
||||
if (p.cmd != cur_param.cmd) throw 1;
|
||||
if (!std::holds_alternative<ScriptTextRef>(*p.param)) {
|
||||
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
|
||||
|
@ -274,12 +274,12 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
|
|||
}
|
||||
int count = 0;
|
||||
ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param);
|
||||
ref->_GetEncodedText(output, count, args.subspan(idx), false);
|
||||
ref->_GetEncodedText(builder, count, args.subspan(idx), false);
|
||||
if (++count != cur_param.consumes) {
|
||||
ScriptLog::Warning(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1));
|
||||
/* Fill missing params if needed. */
|
||||
for (int i = count; i < cur_param.consumes; i++) {
|
||||
Utf8Encode(output, SCC_RECORD_SEPARATOR);
|
||||
builder.PutUtf8(SCC_RECORD_SEPARATOR);
|
||||
}
|
||||
}
|
||||
skip_args(cur_param.consumes - 1);
|
||||
|
@ -289,7 +289,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
|
|||
default:
|
||||
for (int i = 0; i < cur_param.consumes; i++) {
|
||||
ParamCheck &p = *get_next_arg();
|
||||
p.Encode(output, i == 0 ? cur_param.cmd : "");
|
||||
p.Encode(builder, i == 0 ? cur_param.cmd : "");
|
||||
if (i == 0 && p.cmd != cur_param.cmd) throw 1;
|
||||
if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "script_object.hpp"
|
||||
#include "../../strings_func.h"
|
||||
#include "../../core/string_builder.hpp"
|
||||
|
||||
#include <variant>
|
||||
|
||||
|
@ -141,7 +142,7 @@ private:
|
|||
|
||||
ParamCheck(StringIndexInTab owner, int idx, Param *param) : owner(owner), idx(idx), param(param) {}
|
||||
|
||||
void Encode(std::back_insert_iterator<std::string> &output, std::string_view cmd);
|
||||
void Encode(StringBuilder &output, std::string_view cmd);
|
||||
};
|
||||
|
||||
using ParamList = std::vector<ParamCheck>;
|
||||
|
@ -168,7 +169,7 @@ private:
|
|||
* @param args The parameters to be consumed.
|
||||
* @param first Whether it's the first call in the recursion.
|
||||
*/
|
||||
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int ¶m_count, ParamSpan args, bool first);
|
||||
void _GetEncodedText(StringBuilder &output, int ¶m_count, ParamSpan args, bool first);
|
||||
|
||||
/**
|
||||
* Set a parameter, where the value is the first item on the stack.
|
||||
|
|
|
@ -103,41 +103,38 @@ EncodedString GetEncodedString(StringID str)
|
|||
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);
|
||||
StringBuilder builder(result);
|
||||
builder.PutUtf8(SCC_ENCODED_INTERNAL);
|
||||
builder.PutIntegerBase(str, 16);
|
||||
|
||||
struct visitor {
|
||||
std::back_insert_iterator<std::string> &output;
|
||||
StringBuilder &builder;
|
||||
|
||||
void operator()(const std::monostate &) {}
|
||||
|
||||
void operator()(const uint64_t &arg)
|
||||
{
|
||||
Utf8Encode(output, SCC_ENCODED_NUMERIC);
|
||||
fmt::format_to(this->output, "{:X}", arg);
|
||||
this->builder.PutUtf8(SCC_ENCODED_NUMERIC);
|
||||
this->builder.PutIntegerBase(arg, 16);
|
||||
}
|
||||
|
||||
void operator()(const std::string &value)
|
||||
{
|
||||
#ifdef WITH_ASSERT
|
||||
/* Don't allow an encoded string to contain another encoded string. */
|
||||
if (!value.empty()) {
|
||||
char32_t c;
|
||||
const char *p = value.data();
|
||||
if (Utf8Decode(&c, p)) {
|
||||
assert(c != SCC_ENCODED && c != SCC_ENCODED_INTERNAL && c != SCC_RECORD_SEPARATOR);
|
||||
}
|
||||
{
|
||||
auto [len, c] = DecodeUtf8(value);
|
||||
assert(len == 0 || (c != SCC_ENCODED && c != SCC_ENCODED_INTERNAL && c != SCC_RECORD_SEPARATOR));
|
||||
}
|
||||
#endif /* WITH_ASSERT */
|
||||
Utf8Encode(output, SCC_ENCODED_STRING);
|
||||
fmt::format_to(this->output, "{}", value);
|
||||
this->builder.PutUtf8(SCC_ENCODED_STRING);
|
||||
this->builder += value;
|
||||
}
|
||||
};
|
||||
|
||||
visitor v{output};
|
||||
visitor v{builder};
|
||||
for (const auto ¶m : params) {
|
||||
*output = SCC_RECORD_SEPARATOR;
|
||||
builder.PutUtf8(SCC_RECORD_SEPARATOR);
|
||||
std::visit(v, param.data);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue