mirror of https://github.com/OpenTTD/OpenTTD
(svn r25560) [1.3] -Backport from trunk:
- Fix: [Squirrel] Infinite recursion loop in freeing data via a looping set of references [FS#5568] (r25558) - Fix: One could build bridges over owned land of another company [FS#5524] (r25557) - Fix: [Script] Texts from scripts were not validated before they were shown, causing an assertion to trigger [FS#5632] (r25555) - Fix: Provide a warning when no vehicles are available, and tell what to do in that case [FS#5530] (r25553)release/1.3
parent
526fb6fa21
commit
b0486a940d
|
@ -37,9 +37,13 @@ public:
|
|||
~sqvector()
|
||||
{
|
||||
if(_allocated) {
|
||||
/* Break freeing loops, if this vector (indirectly) links to itself. */
|
||||
size_t allocated_size = _allocated * sizeof(T);
|
||||
_allocated = 0;
|
||||
|
||||
for(SQUnsignedInteger i = 0; i < _size; i++)
|
||||
_vals[i].~T();
|
||||
SQ_FREE(_vals, (_allocated * sizeof(T)));
|
||||
SQ_FREE(_vals, allocated_size);
|
||||
}
|
||||
}
|
||||
void reserve(SQUnsignedInteger newsize) { _realloc(newsize); }
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "company_base.h"
|
||||
#include "vehicle_func.h"
|
||||
#include "articulated_vehicles.h"
|
||||
#include "error.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/engines.h"
|
||||
|
@ -1098,3 +1099,25 @@ bool IsEngineRefittable(EngineID engine)
|
|||
CargoID default_cargo = e->GetDefaultCargoType();
|
||||
return default_cargo != CT_INVALID && ei->refit_mask != 1U << default_cargo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for engines that have an appropriate availability.
|
||||
*/
|
||||
void CheckEngines()
|
||||
{
|
||||
const Engine *e;
|
||||
Date min_date = INT32_MAX;
|
||||
|
||||
FOR_ALL_ENGINES(e) {
|
||||
if (!e->IsEnabled()) continue;
|
||||
|
||||
/* We have an available engine... yay! */
|
||||
if (e->flags & ENGINE_AVAILABLE && e->company_avail != 0) return;
|
||||
|
||||
/* Okay, try to find the earliest date. */
|
||||
min_date = min(min_date, e->info.base_intro);
|
||||
}
|
||||
|
||||
SetDParam(0, min_date);
|
||||
ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE, STR_ERROR_NO_VEHICLES_AVAILABLE_EXPLANATION, WL_WARNING);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
void SetupEngines();
|
||||
void StartupEngines();
|
||||
void CheckEngines();
|
||||
|
||||
/* Original engine data counts and offsets */
|
||||
extern const uint8 _engine_counts[4];
|
||||
|
|
|
@ -4190,6 +4190,9 @@ STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Can't ch
|
|||
|
||||
STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... vehicle is destroyed
|
||||
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE :{WHITE}No vehicles are available yet
|
||||
STR_ERROR_NO_VEHICLES_AVAILABLE_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF that provides early vehicles
|
||||
|
||||
# Specific vehicle errors
|
||||
STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger...
|
||||
STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train...
|
||||
|
|
|
@ -916,6 +916,7 @@ static void MakeNewGameDone()
|
|||
|
||||
if (_settings_client.gui.pause_on_newgame) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE);
|
||||
|
||||
CheckEngines();
|
||||
MarkWholeScreenDirty();
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
|||
sq_getstring(vm, -1, &value);
|
||||
|
||||
this->params[parameter] = strdup(SQ2OTTD(value));
|
||||
ValidateString(this->params[parameter]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -147,6 +148,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
|
|||
const SQChar *key;
|
||||
sq_getstring(vm, 2, &key);
|
||||
const char *key_string = SQ2OTTD(key);
|
||||
ValidateString(key_string);
|
||||
|
||||
if (strncmp(key_string, "param_", 6) != 0 || strlen(key_string) > 8) return SQ_ERROR;
|
||||
k = atoi(key_string + 6);
|
||||
|
|
|
@ -126,12 +126,15 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
|||
const SQChar *sqkey;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &sqkey))) return SQ_ERROR;
|
||||
const char *key = SQ2OTTD(sqkey);
|
||||
ValidateString(key);
|
||||
|
||||
if (strcmp(key, "name") == 0) {
|
||||
const SQChar *sqvalue;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &sqvalue))) return SQ_ERROR;
|
||||
char *name = strdup(SQ2OTTD(sqvalue));
|
||||
char *s;
|
||||
ValidateString(name);
|
||||
|
||||
/* Don't allow '=' and ',' in configure setting names, as we need those
|
||||
* 2 chars to nicely store the settings as a string. */
|
||||
while ((s = strchr(name, '=')) != NULL) *s = '_';
|
||||
|
@ -142,6 +145,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
|||
const SQChar *sqdescription;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &sqdescription))) return SQ_ERROR;
|
||||
config.description = strdup(SQ2OTTD(sqdescription));
|
||||
ValidateString(config.description);
|
||||
items |= 0x002;
|
||||
} else if (strcmp(key, "min_value") == 0) {
|
||||
SQInteger res;
|
||||
|
@ -227,6 +231,7 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
|
|||
const SQChar *sq_setting_name;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &sq_setting_name))) return SQ_ERROR;
|
||||
const char *setting_name = SQ2OTTD(sq_setting_name);
|
||||
ValidateString(setting_name);
|
||||
|
||||
ScriptConfigItem *config = NULL;
|
||||
for (ScriptConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) {
|
||||
|
@ -255,6 +260,7 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
|
|||
const char *key_string = SQ2OTTD(sq_key);
|
||||
int key = atoi(key_string + 1);
|
||||
const char *label = SQ2OTTD(sq_label);
|
||||
ValidateString(label);
|
||||
|
||||
/* !Contains() prevents strdup from leaking. */
|
||||
if (!config->labels->Contains(key)) config->labels->Insert(key, strdup(label));
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "../debug.h"
|
||||
#include "squirrel_std.hpp"
|
||||
#include "../fileio_func.h"
|
||||
#include "../string_func.h"
|
||||
#include <sqstdaux.h>
|
||||
#include <../squirrel/sqpcheader.h>
|
||||
#include <../squirrel/sqvm.h>
|
||||
|
@ -252,6 +253,7 @@ bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_nam
|
|||
if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
|
||||
if (ret._type != OT_STRING) return false;
|
||||
*res = strdup(ObjectToString(&ret));
|
||||
ValidateString(*res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,18 @@ void str_validate(char *str, const char *last, StringValidationSettings settings
|
|||
*dst = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the string for valid characters and if it finds invalid ones,
|
||||
* replaces them with a question mark '?'.
|
||||
* @param str the string to validate
|
||||
*/
|
||||
void ValidateString(const char *str)
|
||||
{
|
||||
/* We know it is '\0' terminated. */
|
||||
str_validate(const_cast<char *>(str), str + strlen(str) + 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the given string is valid, i.e. contains only
|
||||
* valid (printable) characters and is properly terminated.
|
||||
|
|
|
@ -40,6 +40,8 @@ int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FO
|
|||
char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2);
|
||||
|
||||
void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
|
||||
void ValidateString(const char *str);
|
||||
|
||||
void str_fix_scc_encoded(char *str, const char *last);
|
||||
void str_strip_colours(char *str);
|
||||
bool strtolower(char *str);
|
||||
|
|
|
@ -130,7 +130,7 @@ extern const ObjectSpec _original_objects[] = {
|
|||
M(STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER, 0x11, 0, 0, 10, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT),
|
||||
M(STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE, 0x11, 0, 0, 8, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT),
|
||||
M(STR_TOWN_BUILDING_NAME_STATUE_1, 0x11, 0, 0, 5, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_ONLY_IN_SCENEDIT), // Yes, we disallow building this everywhere. Happens in "special" case!
|
||||
M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND, 0x11, 10, 10, 0, OBJECT_FLAG_AUTOREMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_CLEAR_INCOME | OBJECT_FLAG_HAS_NO_FOUNDATION | OBJECT_FLAG_ALLOW_UNDER_BRIDGE),
|
||||
M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND, 0x11, 10, 10, 0, OBJECT_FLAG_AUTOREMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_CLEAR_INCOME | OBJECT_FLAG_HAS_NO_FOUNDATION ), // Only non-silly use case is to use it when you cannot build a station, so disallow bridges
|
||||
M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS, 0x22, 0, 0, 7, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME),
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue