Changeset - r14662:8798e984ee81
[Not reviewed]
master
0 3 0
yexo - 14 years ago 2010-02-25 15:54:40
yexo@openttd.org
(svn r19251) -Codechange: add a contructor to GRFError and use it to allocating errors more uniform.
-Fix: some grf error messages didn't free the previous error messages, creating a memory leak
3 files changed with 36 insertions and 45 deletions:
0 comments (0 inline, 0 general)
src/newgrf.cpp
Show inline comments
 
@@ -2747,26 +2747,26 @@ static bool HandleChangeInfoResult(const
 
		case CIR_UNHANDLED:
 
			grfmsg(1, "%s: Ignoring property 0x%02X of feature 0x%02X (not implemented)", caller, property, feature);
 
			return false;
 

	
 
		case CIR_UNKNOWN:
 
			grfmsg(0, "%s: Unknown property 0x%02X of feature 0x%02X, disabling", caller, property, feature);
 
			/* Fall through */
 

	
 
		case CIR_INVALID_ID:
 
			/* No debug message for an invalid ID, as it has already been output */
 
			_skip_sprites = -1;
 
			_cur_grfconfig->status = GCS_DISABLED;
 
			_cur_grfconfig->error  = CallocT<GRFError>(1);
 
			_cur_grfconfig->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 
			delete _cur_grfconfig->error;
 
			_cur_grfconfig->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL);
 
			_cur_grfconfig->error->message  = (cir == CIR_INVALID_ID) ? STR_NEWGRF_ERROR_INVALID_ID : STR_NEWGRF_ERROR_UNKNOWN_PROPERTY;
 
			return true;
 
	}
 
}
 

	
 
/* Action 0x00 */
 
static void FeatureChangeInfo(ByteReader *buf)
 
{
 
	/* <00> <feature> <num-props> <num-info> <id> (<property <new-info>)...
 
	 *
 
	 * B feature
 
	 * B num-props     how many properties to change per vehicle/station
 
@@ -4322,34 +4322,28 @@ static void CfgApply(ByteReader *buf)
 

	
 
/**
 
 * Disable a static NewGRF when it is influencing another (non-static)
 
 * NewGRF as this could cause desyncs.
 
 *
 
 * We could just tell the NewGRF querying that the file doesn't exist,
 
 * but that might give unwanted results. Disabling the NewGRF gives the
 
 * best result as no NewGRF author can complain about that.
 
 * @param c the NewGRF to disable.
 
 */
 
static void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig *c)
 
{
 
	if (c->error != NULL) {
 
		free(c->error->custom_message);
 
		free(c->error->data);
 
		free(c->error);
 
	}
 
	delete c->error;
 
	c->status = GCS_DISABLED;
 
	c->error  = CallocT<GRFError>(1);
 
	c->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC);
 
	c->error->data = strdup(_cur_grfconfig->name);
 
	c->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 
	c->error->message  = STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC;
 

	
 
	ClearTemporaryNewGRFData(GetFileByGRFID(c->grfid));
 
}
 

	
 
/* Action 0x07
 
 * Action 0x09 */
 
static void SkipIf(ByteReader *buf)
 
{
 
	/* <07/09> <param-num> <param-size> <condition-type> <value> <num-sprites>
 
	 *
 
	 * B param-num
 
	 * B param-size
 
@@ -4540,27 +4534,26 @@ static void GRFInfo(ByteReader *buf)
 
	 *
 
	 * B version       newgrf version, currently 06
 
	 * 4*B grf-id      globally unique ID of this .grf file
 
	 * S name          name of this .grf set
 
	 * S info          string describing the set, and e.g. author and copyright */
 

	
 
	uint8 version    = buf->ReadByte();
 
	uint32 grfid     = buf->ReadDWord();
 
	const char *name = buf->ReadString();
 

	
 
	if (_cur_stage < GLS_RESERVE && _cur_grfconfig->status != GCS_UNKNOWN) {
 
		_cur_grfconfig->status = GCS_DISABLED;
 
		_cur_grfconfig->error  = CallocT<GRFError>(1);
 
		_cur_grfconfig->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 
		_cur_grfconfig->error->message  = STR_NEWGRF_ERROR_MULTIPLE_ACTION_8;
 
		delete _cur_grfconfig->error;
 
		_cur_grfconfig->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_MULTIPLE_ACTION_8);
 

	
 
		_skip_sprites = -1;
 
		return;
 
	}
 

	
 
	_cur_grffile->grfid = grfid;
 
	_cur_grffile->grf_version = version;
 
	_cur_grfconfig->status = _cur_stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED;
 

	
 
	/* Do swap the GRFID for displaying purposes since people expect that */
 
	DEBUG(grf, 1, "GRFInfo: Loaded GRFv%d set %08X - %s (palette: %s)", version, BSWAP32(grfid), name, _cur_grfconfig->windows_paletted ? "Windows" : "DOS");
 
}
 
@@ -4680,27 +4673,25 @@ static void GRFLoadError(ByteReader *buf
 
	}
 

	
 
	if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
 
		grfmsg(7, "GRFLoadError: Invalid message id.");
 
		return;
 
	}
 

	
 
	if (buf->Remaining() <= 1) {
 
		grfmsg(7, "GRFLoadError: No message data supplied.");
 
		return;
 
	}
 

	
 
	GRFError *error = CallocT<GRFError>(1);
 

	
 
	error->severity = sevstr[severity];
 
	GRFError *error = new GRFError(sevstr[severity]);
 

	
 
	if (message_id == 0xFF) {
 
		/* This is a custom error message. */
 
		if (buf->HasData()) {
 
			const char *message = buf->ReadString();
 

	
 
			error->custom_message = TranslateTTDPatchCodes(_cur_grffile->grfid, message);
 
		} else {
 
			grfmsg(7, "GRFLoadError: No custom message supplied.");
 
			error->custom_message = strdup("");
 
		}
 
	} else {
 
@@ -5550,35 +5541,30 @@ static void TranslateGRFStrings(ByteRead
 
	 * S   text...   Zero-terminated strings */
 

	
 
	uint32 grfid = buf->ReadDWord();
 
	const GRFConfig *c = GetGRFConfig(grfid);
 
	if (c == NULL || (c->status != GCS_INITIALISED && c->status != GCS_ACTIVATED)) {
 
		grfmsg(7, "TranslateGRFStrings: GRFID 0x%08x unknown, skipping action 13", BSWAP32(grfid));
 
		return;
 
	}
 

	
 
	if (c->status == GCS_INITIALISED) {
 
		/* If the file is not active but will be activated later, give an error
 
		 * and disable this file. */
 
		GRFError *error = CallocT<GRFError>(1);
 
		delete _cur_grfconfig->error;
 
		_cur_grfconfig->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_LOAD_AFTER);
 

	
 
		char tmp[256];
 
		GetString(tmp, STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE, lastof(tmp));
 
		error->data = strdup(tmp);
 

	
 
		error->message  = STR_NEWGRF_ERROR_LOAD_AFTER;
 
		error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 

	
 
		if (_cur_grfconfig->error != NULL) free(_cur_grfconfig->error);
 
		_cur_grfconfig->error = error;
 
		_cur_grfconfig->error->data = strdup(tmp);
 

	
 
		_cur_grfconfig->status = GCS_DISABLED;
 
		ClearTemporaryNewGRFData(_cur_grffile);
 
		_skip_sprites = -1;
 
		return;
 
	}
 

	
 
	byte num_strings = buf->ReadByte();
 
	uint16 first_id  = buf->ReadWord();
 

	
 
	if (!((first_id >= 0xD000 && first_id + num_strings <= 0xD3FF) || (first_id >= 0xDC00 && first_id + num_strings <= 0xDCFF))) {
 
		grfmsg(7, "TranslateGRFStrings: Attempting to set out-of-range string IDs in action 13 (first: 0x%4X, number: 0x%2X)", first_id, num_strings);
 
@@ -5853,27 +5839,25 @@ static void ResetNewGRF()
 
		free(f->railtype_list);
 
		free(f);
 
	}
 

	
 
	_grf_files.Clear();
 
	_cur_grffile   = NULL;
 
}
 

	
 
static void ResetNewGRFErrors()
 
{
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (!HasBit(c->flags, GCF_COPY) && c->error != NULL) {
 
			free(c->error->custom_message);
 
			free(c->error->data);
 
			free(c->error);
 
			delete c->error;
 
			c->error = NULL;
 
		}
 
	}
 
}
 

	
 
/**
 
 * Reset all NewGRF loaded data
 
 * TODO
 
 */
 
static void ResetNewGRFData()
 
{
 
	CleanUpStrings();
 
@@ -6352,27 +6336,26 @@ static void DecodeSpecialSprite(byte *bu
 
			grfmsg(7, "DecodeSpecialSprite: Skipping unknown action 0x%02X", action);
 
		} else if (handlers[action][stage] == NULL) {
 
			grfmsg(7, "DecodeSpecialSprite: Skipping action 0x%02X in stage %d", action, stage);
 
		} else {
 
			grfmsg(7, "DecodeSpecialSprite: Handling action 0x%02X in stage %d", action, stage);
 
			handlers[action][stage](bufp);
 
		}
 
	} catch (...) {
 
		grfmsg(1, "DecodeSpecialSprite: Tried to read past end of pseudo-sprite data");
 

	
 
		_skip_sprites = -1;
 
		_cur_grfconfig->status = GCS_DISABLED;
 
		_cur_grfconfig->error  = CallocT<GRFError>(1);
 
		_cur_grfconfig->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 
		_cur_grfconfig->error->message  = STR_NEWGRF_ERROR_READ_BOUNDS;
 
		delete _cur_grfconfig->error;
 
		_cur_grfconfig->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_READ_BOUNDS);
 
	}
 
}
 

	
 

	
 
void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage)
 
{
 
	const char *filename = config->filename;
 
	uint16 num;
 

	
 
	/* A .grf file is activated only if it was active when the game was
 
	 * started.  If a game is loaded, only its active .grfs will be
 
	 * reactivated, unless "loadallgraphics on" is used.  A .grf file is
 
@@ -6384,27 +6367,25 @@ void LoadNewGRFFile(GRFConfig *config, u
 
	 * processed once at initialization.  */
 
	if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
 
		_cur_grffile = GetFileByFilename(filename);
 
		if (_cur_grffile == NULL) usererror("File '%s' lost in cache.\n", filename);
 
		if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return;
 
		if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return;
 
		_cur_grffile->is_ottdfile = config->IsOpenTTDBaseGRF();
 
	}
 

	
 
	if (file_index > LAST_GRF_SLOT) {
 
		DEBUG(grf, 0, "'%s' is not loaded as the maximum number of GRFs has been reached", filename);
 
		config->status = GCS_DISABLED;
 
		config->error  = CallocT<GRFError>(1);
 
		config->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 
		config->error->message  = STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED;
 
		config->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
 
		return;
 
	}
 

	
 
	FioOpenFile(file_index, filename);
 
	_file_index = file_index; // XXX
 
	_palette_remap_grf[_file_index] = (config->windows_paletted != (_use_palette == PAL_WINDOWS));
 

	
 
	_cur_grfconfig = config;
 

	
 
	DEBUG(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '%s'", filename);
 

	
 
	/* Skip the first sprite; we don't care about how many sprites this
 
@@ -6432,27 +6413,26 @@ void LoadNewGRFFile(GRFConfig *config, u
 

	
 
				/* Stop all processing if we are to skip the remaining sprites */
 
				if (_skip_sprites == -1) break;
 

	
 
				continue;
 
			} else {
 
				FioSkipBytes(num);
 
			}
 
		} else {
 
			if (_skip_sprites == 0) {
 
				grfmsg(0, "LoadNewGRFFile: Unexpected sprite, disabling");
 
				config->status = GCS_DISABLED;
 
				config->error  = CallocT<GRFError>(1);
 
				config->error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 
				config->error->message  = STR_NEWGRF_ERROR_UNEXPECTED_SPRITE;
 
				delete config->error;
 
				config->error  = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_UNEXPECTED_SPRITE);
 
				break;
 
			}
 

	
 
			FioSkipBytes(7);
 
			SkipSpriteData(type, num - 8);
 
		}
 

	
 
		if (_skip_sprites > 0) _skip_sprites--;
 
	}
 
}
 

	
 
/**
src/newgrf_config.cpp
Show inline comments
 
@@ -17,24 +17,35 @@
 
#include "network/network_func.h"
 
#include "gfx_func.h"
 

	
 
#include "fileio_func.h"
 
#include "fios.h"
 

	
 

	
 
GRFConfig *_all_grfs;
 
GRFConfig *_grfconfig;
 
GRFConfig *_grfconfig_newgame;
 
GRFConfig *_grfconfig_static;
 

	
 
GRFError::GRFError(StringID severity, StringID message) :
 
	message(message),
 
	severity(severity)
 
{
 
}
 

	
 
GRFError::~GRFError()
 
{
 
	free(this->custom_message);
 
	free(this->data);
 
 }
 

	
 
/**
 
 * Update the palettes of the graphics from the config file.
 
 * This is needed because the config file gets read and parsed
 
 * before the palette is chosen (one can configure the base
 
 * graphics set governing the palette in the config after all).
 
 * As a result of this we update the settings from the config
 
 * once we have determined the palette.
 
 */
 
void UpdateNewGRFConfigPalette()
 
{
 
	for (GRFConfig *c = _grfconfig_newgame; c != NULL; c = c->next) c->windows_paletted = (_use_palette == PAL_WINDOWS);
 
@@ -92,30 +103,25 @@ bool FillGRFDetails(GRFConfig *config, b
 

	
 
	return CalcGRFMD5Sum(config);
 
}
 

	
 

	
 
void ClearGRFConfig(GRFConfig **config)
 
{
 
	/* GCF_COPY as in NOT strdupped/alloced the filename, name and info */
 
	if (!HasBit((*config)->flags, GCF_COPY)) {
 
		free((*config)->filename);
 
		free((*config)->name);
 
		free((*config)->info);
 

	
 
		if ((*config)->error != NULL) {
 
			free((*config)->error->custom_message);
 
			free((*config)->error->data);
 
			free((*config)->error);
 
		}
 
		delete (*config)->error;
 
	}
 
	free(*config);
 
	*config = NULL;
 
}
 

	
 

	
 
/* Clear a GRF Config list */
 
void ClearGRFConfigList(GRFConfig **config)
 
{
 
	GRFConfig *c, *next;
 
	for (c = *config; c != NULL; c = next) {
 
		next = c->next;
 
@@ -130,26 +136,27 @@ void ClearGRFConfigList(GRFConfig **conf
 
 * @param c the grfconfig to copy
 
 * @return A pointer to a new grfconfig that's a copy of the original
 
 */
 
GRFConfig *DuplicateGRFConfig(const GRFConfig *c)
 
{
 
	GRFConfig *config = MallocT<GRFConfig>(1);
 
	*config = *c;
 

	
 
	if (c->filename != NULL) config->filename = strdup(c->filename);
 
	if (c->name     != NULL) config->name = strdup(c->name);
 
	if (c->info     != NULL) config->info = strdup(c->info);
 
	if (c->error    != NULL) {
 
		config->error = MallocT<GRFError>(1);
 
		memcpy(config->error, c->error, sizeof(GRFError));
 
		config->error = new GRFError(c->error->severity, c->error->message);
 
		config->error->num_params = c->error->num_params;
 
		memcpy(config->error->param_value, c->error->param_value, sizeof(config->error->param_value));
 
		if (c->error->data           != NULL) config->error->data = strdup(c->error->data);
 
		if (c->error->custom_message != NULL) config->error->custom_message = strdup(c->error->custom_message);
 
	}
 

	
 
	ClrBit(config->flags, GCF_COPY);
 

	
 
	return config;
 
}
 

	
 
/** Copy a GRF Config list
 
 * @param dst pointer to destination list
 
 * @param src pointer to source list values
src/newgrf_config.h
Show inline comments
 
@@ -4,24 +4,25 @@
 
 * 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 newgrf_config.h Functions to find and configure NewGRFs. */
 

	
 
#ifndef NEWGRF_CONFIG_H
 
#define NEWGRF_CONFIG_H
 

	
 
#include "strings_type.h"
 
#include "core/alloc_type.hpp"
 

	
 
/** GRF config bit flags */
 
enum GCF_Flags {
 
	GCF_SYSTEM,     ///< GRF file is an openttd-internal system grf
 
	GCF_UNSAFE,     ///< GRF file is unsafe for static usage
 
	GCF_STATIC,     ///< GRF file is used statically (can be used in any MP game)
 
	GCF_COMPATIBLE, ///< GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches)
 
	GCF_COPY,       ///< The data is copied from a grf in _all_grfs
 
	GCF_INIT_ONLY,  ///< GRF file is processed up to GLS_INIT
 
	GCF_RESERVED,   ///< GRF file passed GLS_RESERVE stage
 

	
 
};
 
@@ -46,25 +47,28 @@ enum GRFListCompatibility {
 
	GLC_ALL_GOOD,   ///< All GRF needed by game are present
 
	GLC_COMPATIBLE, ///< Compatible (eg. the same ID, but different chacksum) GRF found in at least one case
 
	GLC_NOT_FOUND   ///< At least one GRF couldn't be found (higher priority than GLC_COMPATIBLE)
 
};
 

	
 
/** Basic data to distinguish a GRF. Used in the server list window */
 
struct GRFIdentifier {
 
	uint32 grfid;     ///< GRF ID (defined by Action 0x08)
 
	uint8 md5sum[16]; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
 
};
 

	
 
/** Information about why GRF had problems during initialisation */
 
struct GRFError {
 
struct GRFError : ZeroedMemoryAllocator {
 
	GRFError(StringID severity, StringID message = 0);
 
	~GRFError();
 

	
 
	char *custom_message;  ///< Custom message (if present)
 
	char *data;            ///< Additional data for message and custom_message
 
	StringID message;      ///< Default message
 
	StringID severity;     ///< Info / Warning / Error / Fatal
 
	uint8 num_params;      ///< Number of additinal parameters for message and custom_message (0, 1 or 2)
 
	uint32 param_value[2]; ///< Values of GRF parameters to show for message and custom_message
 
};
 

	
 
/** Information about GRF, used in the game and (part of it) in savegames */
 
struct GRFConfig : public GRFIdentifier {
 
	char *filename;     ///< Filename - either with or without full path
 
	char *name;         ///< NOSAVE: GRF name (Action 0x08)
0 comments (0 inline, 0 general)