File diff r14666:896110212413 → r14667:a7ee51a0cfe3
src/newgrf_config.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * 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.cpp Finding NewGRFs and configuring them. */
 

	
 
#include "stdafx.h"
 
#include "debug.h"
 
#include "3rdparty/md5/md5.h"
 
#include "newgrf.h"
 
#include "gamelog.h"
 
#include "network/network_func.h"
 
#include "gfx_func.h"
 

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

	
 
GRFConfig::GRFConfig(const char *filename)
 
{
 
	if (filename != NULL) this->filename = strdup(filename);
 
}
 

	
 
GRFConfig::~GRFConfig()
 
{
 
	/* GCF_COPY as in NOT strdupped/alloced the filename, name and info */
 
	if (!HasBit(this->flags, GCF_COPY)) {
 
		free(this->filename);
 
		free(this->name);
 
		free(this->info);
 
		delete this->error;
 
	}
 
}
 

	
 
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
 
@@ -84,82 +99,68 @@ bool FillGRFDetails(GRFConfig *config, b
 
		config->status = GCS_NOT_FOUND;
 
		return false;
 
	}
 

	
 
	/* Find and load the Action 8 information */
 
	LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN);
 

	
 
	/* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */
 
	if (config->ident.grfid == 0 || config->ident.grfid == 0xFFFFFFFF || config->IsOpenTTDBaseGRF()) return false;
 

	
 
	if (is_static) {
 
		/* Perform a 'safety scan' for static GRFs */
 
		LoadNewGRFFile(config, 62, GLS_SAFETYSCAN);
 

	
 
		/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
 
		if (HasBit(config->flags, GCF_UNSAFE)) return false;
 
	}
 

	
 
	config->windows_paletted = (_use_palette == PAL_WINDOWS);
 

	
 
	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);
 
		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;
 
		ClearGRFConfig(&c);
 
		delete c;
 
	}
 
	*config = NULL;
 
}
 

	
 

	
 
/**
 
 * Make a deep copy of a GRFConfig.
 
 * @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);
 
	GRFConfig *config = new GRFConfig();
 
	*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 = 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
 
 * @param init_only the copied GRF will be processed up to GLS_INIT
 
 * @return pointer to the last value added to the destination list */
 
GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only)
 
@@ -182,49 +183,49 @@ GRFConfig **CopyGRFConfigList(GRFConfig 
 
/**
 
 * Removes duplicates from lists of GRFConfigs. These duplicates
 
 * are introduced when the _grfconfig_static GRFs are appended
 
 * to the _grfconfig on a newgame or savegame. As the parameters
 
 * of the static GRFs could be different that the parameters of
 
 * the ones used non-statically. This can result in desyncs in
 
 * multiplayers, so the duplicate static GRFs have to be removed.
 
 *
 
 * This function _assumes_ that all static GRFs are placed after
 
 * the non-static GRFs.
 
 *
 
 * @param list the list to remove the duplicates from
 
 */
 
static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list)
 
{
 
	GRFConfig *prev;
 
	GRFConfig *cur;
 

	
 
	if (list == NULL) return;
 

	
 
	for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) {
 
		if (cur->ident.grfid != list->ident.grfid) continue;
 

	
 
		prev->next = cur->next;
 
		ClearGRFConfig(&cur);
 
		delete cur;
 
		cur = prev; // Just go back one so it continues as normal later on
 
	}
 

	
 
	RemoveDuplicatesFromGRFConfigList(list->next);
 
}
 

	
 
/**
 
 * Appends the static GRFs to a list of GRFs
 
 * @param dst the head of the list to add to
 
 */
 
void AppendStaticGRFConfigs(GRFConfig **dst)
 
{
 
	GRFConfig **tail = dst;
 
	while (*tail != NULL) tail = &(*tail)->next;
 

	
 
	CopyGRFConfigList(tail, _grfconfig_static, false);
 
	RemoveDuplicatesFromGRFConfigList(*dst);
 
}
 

	
 
/** Appends an element to a list of GRFs
 
 * @param dst the head of the list to add to
 
 * @param el the new tail to be */
 
void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el)
 
{
 
@@ -299,84 +300,83 @@ compatible_grf:
 
				if (c->info == NULL && f->info != NULL) c->info = strdup(f->info);
 
				c->error = NULL;
 
			}
 
		}
 
	}
 

	
 
	return res;
 
}
 

	
 
/** Helper for scanning for files with GRF as extension */
 
class GRFFileScanner : FileScanner {
 
public:
 
	/* virtual */ bool AddFile(const char *filename, size_t basepath_length);
 

	
 
	/** Do the scan for GRFs. */
 
	static uint DoScan()
 
	{
 
		GRFFileScanner fs;
 
		return fs.Scan(".grf", DATA_DIR);
 
	}
 
};
 

	
 
bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length)
 
{
 
	GRFConfig *c = CallocT<GRFConfig>(1);
 
	c->filename = strdup(filename + basepath_length);
 
	GRFConfig *c = new GRFConfig(filename + basepath_length);
 

	
 
	bool added = true;
 
	if (FillGRFDetails(c, false)) {
 
		if (_all_grfs == NULL) {
 
			_all_grfs = c;
 
		} else {
 
			/* Insert file into list at a position determined by its
 
			 * name, so the list is sorted as we go along */
 
			GRFConfig **pd, *d;
 
			bool stop = false;
 
			for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) {
 
				if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false;
 
				/* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name,
 
				 *  before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of
 
				 *  just after the first with the same name. Avoids doubles in the list. */
 
				if (strcasecmp(c->name, d->name) <= 0) {
 
					stop = true;
 
				} else if (stop) {
 
					break;
 
				}
 
			}
 
			if (added) {
 
				c->next = d;
 
				*pd = c;
 
			}
 
		}
 
	} else {
 
		added = false;
 
	}
 

	
 
	if (!added) {
 
		/* File couldn't be opened, or is either not a NewGRF or is a
 
		 * 'system' NewGRF or it's already known, so forget about it. */
 
		ClearGRFConfig(&c);
 
		delete c;
 
	}
 

	
 
	return added;
 
}
 

	
 
/**
 
 * Simple sorter for GRFS
 
 * @param p1 the first GRFConfig *
 
 * @param p2 the second GRFConfig *
 
 * @return the same strcmp would return for the name of the NewGRF.
 
 */
 
static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2)
 
{
 
	const GRFConfig *c1 = *p1;
 
	const GRFConfig *c2 = *p2;
 

	
 
	return strcasecmp(c1->name != NULL ? c1->name : c1->filename,
 
		c2->name != NULL ? c2->name : c2->filename);
 
}
 

	
 
/* Scan for all NewGRFs */
 
void ScanNewGRFFiles()
 
{
 
	ClearGRFConfigList(&_all_grfs);