Files
@ r28025:9116d6e411b0
Branch filter:
Location: cpp/openttd-patchpack/source/src/script/api/script_text.cpp - annotation
r28025:9116d6e411b0
7.9 KiB
text/x-c
Codechange: replace x.size() == 0 with x.empty()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r20473:7d7140ae0710 r26937:a6f9bdfea7b6 r18777:cf24fc430b51 r27049:913f3ce60451 r26890:e661e1f3708a r18777:cf24fc430b51 r18777:cf24fc430b51 r20473:7d7140ae0710 r20473:7d7140ae0710 r21383:942c32fb8b0e r21383:942c32fb8b0e r27367:d55d6f0719f9 r21410:ae5961f02724 r21410:ae5961f02724 r21410:ae5961f02724 r21410:ae5961f02724 r18793:153ee1a0721f r18793:153ee1a0721f r18777:cf24fc430b51 r18793:153ee1a0721f r18793:153ee1a0721f r21642:d4ee019baf14 r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r21642:d4ee019baf14 r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r21642:d4ee019baf14 r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r26935:8e24100a08c1 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r26935:8e24100a08c1 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r23607:36c15679007d r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r21642:d4ee019baf14 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r25705:db1afb7a7392 r23607:36c15679007d r18777:cf24fc430b51 r18777:cf24fc430b51 r26936:79d1aa0fc3c8 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r27737:728d55b97775 r18777:cf24fc430b51 r18777:cf24fc430b51 r21639:04805e592ebb r21639:04805e592ebb r18777:cf24fc430b51 r27551:ea0213f40bc7 r27551:ea0213f40bc7 r27551:ea0213f40bc7 r27551:ea0213f40bc7 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r27737:728d55b97775 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r27687:9834f91f0c39 r18777:cf24fc430b51 r26957:c018305aca7e r20025:983c2ed8d329 r26957:c018305aca7e r27534:3b2933f53491 r27534:3b2933f53491 r27534:3b2933f53491 r26956:da97fd88fa9b r27534:3b2933f53491 r18777:cf24fc430b51 r18777:cf24fc430b51 r27534:3b2933f53491 r18777:cf24fc430b51 r26957:c018305aca7e r26957:c018305aca7e r26957:c018305aca7e r26957:c018305aca7e r26957:c018305aca7e r27534:3b2933f53491 r27534:3b2933f53491 r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r26956:da97fd88fa9b r26937:a6f9bdfea7b6 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27585:ba57a9a2dd40 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27534:3b2933f53491 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27582:b9e4ea73b774 r27049:913f3ce60451 r26937:a6f9bdfea7b6 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27534:3b2933f53491 r27534:3b2933f53491 r27049:913f3ce60451 r27585:ba57a9a2dd40 r27049:913f3ce60451 r27534:3b2933f53491 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27049:913f3ce60451 r27534:3b2933f53491 r27049:913f3ce60451 r26937:a6f9bdfea7b6 r18777:cf24fc430b51 r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r18777:cf24fc430b51 r18777:cf24fc430b51 r26957:c018305aca7e r18777:cf24fc430b51 r20473:7d7140ae0710 r26891:5a795b8188a7 r20473:7d7140ae0710 r27691:699637d670b6 r27413:b706f5407370 r20473:7d7140ae0710 | /*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file script_text.cpp Implementation of ScriptText. */
#include "../../stdafx.h"
#include "../../string_func.h"
#include "../../strings_func.h"
#include "../../game/game_text.hpp"
#include "script_text.hpp"
#include "script_log.hpp"
#include "../script_fatalerror.hpp"
#include "../../table/control_codes.h"
#include "table/strings.h"
#include "../../safeguards.h"
RawText::RawText(const std::string &text) : text(text)
{
}
ScriptText::ScriptText(HSQUIRRELVM vm) :
ZeroedMemoryAllocator()
{
int nparam = sq_gettop(vm) - 1;
if (nparam < 1) {
throw sq_throwerror(vm, "You need to pass at least a StringID to the constructor");
}
/* First resolve the StringID. */
SQInteger sqstring;
if (SQ_FAILED(sq_getinteger(vm, 2, &sqstring))) {
throw sq_throwerror(vm, "First argument must be a valid StringID");
}
this->string = sqstring;
/* The rest of the parameters must be arguments. */
for (int i = 0; i < nparam - 1; i++) {
/* Push the parameter to the top of the stack. */
sq_push(vm, i + 3);
if (SQ_FAILED(this->_SetParam(i, vm))) {
this->~ScriptText();
throw sq_throwerror(vm, "Invalid parameter");
}
/* Pop the parameter again. */
sq_pop(vm, 1);
}
}
SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
{
if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
switch (sq_gettype(vm, -1)) {
case OT_STRING: {
const SQChar *value;
sq_getstring(vm, -1, &value);
this->param[parameter] = StrMakeValid(value);
break;
}
case OT_INTEGER: {
SQInteger value;
sq_getinteger(vm, -1, &value);
this->param[parameter] = value;
break;
}
case OT_INSTANCE: {
SQUserPointer real_instance = nullptr;
HSQOBJECT instance;
sq_getstackobj(vm, -1, &instance);
/* Validate if it is a GSText instance */
sq_pushroottable(vm);
sq_pushstring(vm, "GSText", -1);
sq_get(vm, -2);
sq_pushobject(vm, instance);
if (sq_instanceof(vm) != SQTrue) return SQ_ERROR;
sq_pop(vm, 3);
/* Get the 'real' instance of this class */
sq_getinstanceup(vm, -1, &real_instance, nullptr);
if (real_instance == nullptr) return SQ_ERROR;
ScriptText *value = static_cast<ScriptText *>(real_instance);
this->param[parameter] = ScriptTextRef(value);
break;
}
default: return SQ_ERROR;
}
if (this->paramc <= parameter) this->paramc = parameter + 1;
return 0;
}
SQInteger ScriptText::SetParam(HSQUIRRELVM vm)
{
if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
SQInteger k;
sq_getinteger(vm, 2, &k);
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
if (k < 1) return SQ_ERROR;
k--;
return this->_SetParam(k, vm);
}
SQInteger ScriptText::AddParam(HSQUIRRELVM vm)
{
SQInteger res;
res = this->_SetParam(this->paramc, vm);
if (res != 0) return res;
/* Push our own instance back on top of the stack */
sq_push(vm, 1);
return 1;
}
SQInteger ScriptText::_set(HSQUIRRELVM vm)
{
int32_t k;
if (sq_gettype(vm, 2) == OT_STRING) {
const SQChar *key_string;
sq_getstring(vm, 2, &key_string);
std::string str = StrMakeValid(key_string);
if (!StrStartsWith(str, "param_") || str.size() > 8) return SQ_ERROR;
k = stoi(str.substr(6));
} else if (sq_gettype(vm, 2) == OT_INTEGER) {
SQInteger key;
sq_getinteger(vm, 2, &key);
k = (int32_t)key;
} else {
return SQ_ERROR;
}
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
if (k < 1) return SQ_ERROR;
k--;
return this->_SetParam(k, vm);
}
std::string ScriptText::GetEncodedText()
{
static StringIDList seen_ids;
int param_count = 0;
seen_ids.clear();
std::string result;
auto output = std::back_inserter(result);
this->_GetEncodedText(output, param_count, seen_ids);
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return result;
}
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int ¶m_count, StringIDList &seen_ids)
{
const std::string &name = GetGameStringName(this->string);
if (std::find(seen_ids.begin(), seen_ids.end(), this->string) != seen_ids.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", name));
seen_ids.push_back(this->string);
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
const StringParams ¶ms = GetGameStringParams(this->string);
int cur_idx = 0;
int prev_string = -1;
int prev_idx = -1;
int prev_count = -1;
for (const StringParam &cur_param : params) {
if (cur_idx >= this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name));
if (prev_string != -1) {
/* The previous substring added more parameters than expected, means we will consume them but can't properly validate them. */
for (int i = 0; i < cur_param.consumes; i++) {
if (prev_idx < prev_count) {
ScriptLog::Warning(fmt::format("{}: Parameter {} uses parameter {} from substring {} and cannot be validated", name, param_count + i, prev_idx++, prev_string));
} else {
/* No more extra parameters, assume SQInteger are expected. */
if (cur_idx >= this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name));
if (!std::holds_alternative<SQInteger>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[cur_idx++]));
}
}
if (prev_idx == prev_count) {
/* Re-enable validation. */
prev_string = -1;
}
} else {
switch (cur_param.type) {
case StringParam::RAW_STRING:
if (!std::holds_alternative<std::string>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a raw string", name, param_count));
fmt::format_to(output, ":\"{}\"", std::get<std::string>(this->param[cur_idx++]));
break;
case StringParam::STRING: {
if (!std::holds_alternative<ScriptTextRef>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a substring", name, param_count));
int count = 0;
fmt::format_to(output, ":");
std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(output, count, seen_ids);
if (++count != cur_param.consumes) {
ScriptLog::Error(fmt::format("{}: Parameter {} substring consumes {}, but expected {} to be consumed", name, param_count, count - 1, cur_param.consumes - 1));
/* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
/* Disable validation for the extra params if any. */
if (count > cur_param.consumes) {
prev_string = param_count;
prev_idx = cur_param.consumes - 1;
prev_count = count - 1;
}
}
break;
}
default:
if (cur_idx + cur_param.consumes > this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name));
for (int i = 0; i < cur_param.consumes; i++) {
if (!std::holds_alternative<SQInteger>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[cur_idx++]));
}
}
}
param_count += cur_param.consumes;
}
seen_ids.pop_back();
}
const std::string Text::GetDecodedText()
{
::SetDParamStr(0, this->GetEncodedText());
return ::GetString(STR_JUST_RAW_STRING);
}
|