Changeset - r18786:ebe90ae93ff8
[Not reviewed]
master
0 2 0
rubidium - 13 years ago 2011-12-20 22:11:22
rubidium@openttd.org
(svn r23644) -Fix [FS#4899]: prevent game scripts using StringIDs that are not coming from themselves, so the game script doesn't "accidentally" try to display an invalid string or try to display a town name in from an unknown town name generator
2 files changed with 28 insertions and 16 deletions:
0 comments (0 inline, 0 general)
src/strings.cpp
Show inline comments
 
@@ -122,13 +122,13 @@ void CopyOutDParam(uint64 *dst, const ch
 
}
 

	
 
static char *StationGetSpecialString(char *buff, int x, const char *last);
 
static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
 
static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last);
 

	
 
static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool dry_run = false);
 
static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false, bool dry_run = false);
 

	
 
struct LanguagePack : public LanguagePackHeader {
 
	char data[]; // list of strings
 
};
 

	
 
static char **_langpack_offs;
 
@@ -155,40 +155,41 @@ const char *GetStringPtr(StringID string
 
 * Get a parsed string with most special stringcodes replaced by the string parameters.
 
 * @param buffr  Pointer to a string buffer where the formatted string should be written to.
 
 * @param string
 
 * @param args   Arguments for the string.
 
 * @param last   Pointer just past the end of buffr.
 
 * @param case_index  The "case index". This will only be set when FormatString wants to print the string in a different case.
 
 * @param game_script The string is coming directly from a game script.
 
 * @return       Pointer to the final zero byte of the formatted string.
 
 */
 
char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index)
 
char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
 
{
 
	if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
 

	
 
	uint index = GB(string, TAB_SIZE_OFFSET,  TAB_SIZE_BITS);
 
	uint tab   = GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS);
 

	
 
	switch (tab) {
 
		case 4:
 
			if (index >= 0xC0) {
 
			if (index >= 0xC0 && !game_script) {
 
				return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last);
 
			}
 
			break;
 

	
 
		case 14:
 
			if (index >= 0xE4) {
 
			if (index >= 0xE4 && !game_script) {
 
				return GetSpecialNameString(buffr, index - 0xE4, args, last);
 
			}
 
			break;
 

	
 
		case 15:
 
			/* Old table for custom names. This is no longer used */
 
			error("Incorrect conversion of custom name string.");
 

	
 
		case GAME_TEXT_TAB:
 
			return FormatString(buffr, GetGameStringPtr(index), args, last, case_index);
 
			return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
 

	
 
		case 26:
 
			/* Include string within newgrf text (format code 81) */
 
			if (HasBit(index, 10)) {
 
				StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
 
				return GetStringWithArgs(buffr, string, args, last, case_index);
 
@@ -206,12 +207,15 @@ char *GetStringWithArgs(char *buffr, Str
 

	
 
		case 31:
 
			NOT_REACHED();
 
	}
 

	
 
	if (index >= _langtab_num[tab]) {
 
		if (game_script) {
 
			return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
 
		}
 
		error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
 
	}
 

	
 
	return FormatString(buffr, GetStringPtr(string), args, last, case_index);
 
}
 

	
 
@@ -687,13 +691,13 @@ uint ConvertDisplaySpeedToSpeed(uint spe
 
 * @param str   The original string with format codes.
 
 * @param args  Pointer to extra arguments used by various string codes.
 
 * @param case_index
 
 * @param last  Pointer to just past the end of the buff array.
 
 * @param dry_run True when the argt array is not yet initialized.
 
 */
 
static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool dry_run)
 
static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
 
{
 
	uint orig_offset = args->offset;
 

	
 
	/* When there is no array with types there is no need to do a dry run. */
 
	if (args->HasTypeInformation() && !dry_run) {
 
		if (UsingNewGRFTextStack()) {
 
@@ -701,16 +705,16 @@ static char *FormatString(char *buff, co
 
			 * argv array at the time they are encountered. That means that if
 
			 * another string command references a value later in the string it
 
			 * would fail. We solve that by running FormatString twice. The first
 
			 * pass makes sure the argv array is correctly filled and the second
 
			 * pass can reference later values without problems. */
 
			struct TextRefStack *backup = CreateTextRefStackBackup();
 
			FormatString(buff, str_arg, args, last, case_index, true);
 
			FormatString(buff, str_arg, args, last, case_index, game_script, true);
 
			RestoreTextRefStackBackup(backup);
 
		} else {
 
			FormatString(buff, str_arg, args, last, case_index, true);
 
			FormatString(buff, str_arg, args, last, case_index, game_script, true);
 
		}
 
		/* We have to restore the original offset here to to read the correct values. */
 
		args->offset = orig_offset;
 
	}
 
	WChar b;
 
	uint next_substr_case_index = 0;
 
@@ -819,13 +823,13 @@ static char *FormatString(char *buff, co
 
					}
 
				}
 
				/* We error'd out in the while, to error out in themain too */
 
				if (*str == '\0') break;
 

	
 
				str = p;
 
				buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last);
 
				buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
 

	
 
				for (int i = 0; i < 20; i++) {
 
					if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
 
				}
 
				break;
 
			}
 
@@ -941,73 +945,81 @@ static char *FormatString(char *buff, co
 

	
 
			case SCC_REVISION: // {REV}
 
				buff = strecpy(buff, _openttd_revision, last);
 
				break;
 

	
 
			case SCC_STRING_ID: // {STRINL}
 
				if (game_script) break;
 
				buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
 
				break;
 

	
 
			case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
 
				if (game_script) break;
 
				const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
 
				buff = FormatString(buff, str, args, last);
 
				break;
 
			}
 

	
 
			case SCC_STRING: {// {STRING}
 
				StringID str = args->GetInt32(SCC_STRING);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				/* WARNING. It's prohibited for the included string to consume any arguments.
 
				 * For included strings that consume argument, you should use STRING1, STRING2 etc.
 
				 * To debug stuff you can set argv to NULL and it will tell you */
 
				StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
 
				buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index);
 
				buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING1: { // {STRING1}
 
				/* String that consumes ONE argument */
 
				StringID str = args->GetInt32(SCC_STRING1);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 1);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING2: { // {STRING2}
 
				/* String that consumes TWO arguments */
 
				StringID str = args->GetInt32(SCC_STRING2);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 2);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING3: { // {STRING3}
 
				/* String that consumes THREE arguments */
 
				StringID str = args->GetInt32(SCC_STRING3);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 3);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING4: { // {STRING4}
 
				/* String that consumes FOUR arguments */
 
				StringID str = args->GetInt32(SCC_STRING4);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 4);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING5: { // {STRING5}
 
				/* String that consumes FIVE arguments */
 
				StringID str = args->GetInt32(SCC_STRING5);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 5);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_COMMA: // {COMMA}
 
				buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
src/strings_func.h
Show inline comments
 
@@ -135,13 +135,13 @@ public:
 
	}
 
};
 
extern StringParameters _global_string_params;
 

	
 
char *InlineString(char *buf, StringID string);
 
char *GetString(char *buffr, StringID string, const char *last);
 
char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index = 0);
 
char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false);
 
const char *GetStringPtr(StringID string);
 

	
 
void InjectDParam(uint amount);
 

	
 
/**
 
 * Set a string parameter \a v at index \a n in a given array \a s.
0 comments (0 inline, 0 general)