Changeset - r15580:34393a650f17
[Not reviewed]
master
0 1 0
yexo - 14 years ago 2010-07-31 09:35:42
yexo@openttd.org
(svn r20250) -Feature: [NewGRF] add support for action14 (static grf info)
1 file changed with 194 insertions and 0 deletions:
0 comments (0 inline, 0 general)
src/newgrf.cpp
Show inline comments
 
@@ -5905,6 +5905,199 @@ static void TranslateGRFStrings(ByteRead
 
	}
 
}
 

	
 
/** Callback function for 'INFO'->'NAME' to add a translation to the newgrf name. */
 
static bool ChangeGRFName(byte langid, const char *str)
 
{
 
	AddGRFTextToList(&_cur_grfconfig->name, langid, _cur_grfconfig->ident.grfid, str);
 
	return true;
 
}
 

	
 
/** Callback function for 'INFO'->'DESC' to add a translation to the newgrf description. */
 
static bool ChangeGRFDescription(byte langid, const char *str)
 
{
 
	AddGRFTextToList(&_cur_grfconfig->info, langid, _cur_grfconfig->ident.grfid, str);
 
	return true;
 
}
 

	
 
typedef bool (*DataHandler)(size_t, ByteReader *);  ///< Type of callback function for binary nodes
 
typedef bool (*TextHandler)(byte, const char *str); ///< Type of callback function for text nodes
 
typedef bool (*BranchHandler)(ByteReader *);        ///< Type of callback function for branch nodes
 

	
 
/**
 
 * Data structure to store the allowed id/type combinations for action 14. The
 
 * data can be represented as a tree with 3 types of nodes:
 
 * 1. Branch nodes (identified by 'C' for choice).
 
 * 2. Binary leaf nodes (identified by 'B').
 
 * 3. Text leaf nodes (identified by 'T').
 
 */
 
struct AllowedSubtags {
 
	/** Create empty subtags object used to identify the end of a list. */
 
	AllowedSubtags() :
 
		id(0),
 
		type(0)
 
	{}
 

	
 
	/**
 
	 * Create a binary leaf node.
 
	 * @param id The id for this node.
 
	 * @param handler The callback function to call.
 
	 */
 
	AllowedSubtags(uint32 id, DataHandler handler) :
 
		id(id),
 
		type('B')
 
	{
 
		this->handler.data = handler;
 
	}
 

	
 
	/**
 
	 * Create a text leaf node.
 
	 * @param id The id for this node.
 
	 * @param handler The callback function to call.
 
	 */
 
	AllowedSubtags(uint32 id, TextHandler handler) :
 
		id(id),
 
		type('T')
 
	{
 
		this->handler.text = handler;
 
	}
 

	
 
	/**
 
	 * Create a branch node with a callback handler
 
	 * @param id The id for this node.
 
	 * @param handler The callback function to call.
 
	 */
 
	AllowedSubtags(uint32 id, BranchHandler handler) :
 
		id(id),
 
		type('C')
 
	{
 
		this->handler.call_handler = true;
 
		this->handler.u.branch = handler;
 
	}
 

	
 
	/**
 
	 * Create a branch node with a list of sub-nodes.
 
	 * @param id The id for this node.
 
	 * @param subtags Array with all valid subtags.
 
	 */
 
	AllowedSubtags(uint32 id, AllowedSubtags *subtags) :
 
		id(id),
 
		type('C')
 
	{
 
		this->handler.call_handler = false;
 
		this->handler.u.subtags = subtags;
 
	}
 

	
 
	uint32 id; ///< The identifier for this node
 
	byte type; ///< The type of the node, must be one of 'C', 'B' or 'T'.
 
	union {
 
		DataHandler data; ///< Callback function for a binary node, only valid if type == 'B'.
 
		TextHandler text; ///< Callback function for a text node, only valid if type == 'T'.
 
		struct {
 
			union {
 
				BranchHandler branch;    ///< Callback function for a branch node, only valid if type == 'C' && call_handler.
 
				AllowedSubtags *subtags; ///< Pointer to a list of subtags, only valid if type == 'C' && !call_handler.
 
			} u;
 
			bool call_handler; ///< True if there is a callback function for this node, false if there is a list of subnodes.
 
		};
 
	} handler;
 
};
 

	
 
AllowedSubtags _tags_info[] = {
 
	AllowedSubtags('NAME', ChangeGRFName),
 
	AllowedSubtags('DESC', ChangeGRFDescription),
 
	AllowedSubtags()
 
};
 

	
 
AllowedSubtags _tags_root[] = {
 
	AllowedSubtags('INFO', _tags_info),
 
	AllowedSubtags()
 
};
 

	
 

	
 
/**
 
 * Try to skip the current node and all subnodes (if it's a branch node).
 
 * @return True if we could skip the node, false if an error occured.
 
 */
 
static bool SkipUnknownInfo(ByteReader *buf, byte type)
 
{
 
	/* type and id are already read */
 
	switch (type) {
 
		case 'C': {
 
			byte new_type = buf->ReadByte();
 
			while (new_type != 0) {
 
				buf->ReadDWord(); // skip the id
 
				if (!SkipUnknownInfo(buf, new_type)) return false;
 
				new_type = buf->ReadByte();
 
			}
 
			break;
 
		}
 

	
 
		case 'T':
 
			buf->ReadByte(); // lang
 
			buf->ReadString(); // actual text
 
			break;
 

	
 
		case 'B': {
 
			uint16 size = buf->ReadWord();
 
			buf->Skip(size);
 
			break;
 
		}
 

	
 
		default:
 
			return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
static bool HandleNode(byte type, uint32 id, ByteReader *buf, AllowedSubtags subtags[])
 
{
 
	uint i = 0;
 
	AllowedSubtags *tag;
 
	while ((tag = &subtags[i++])->type != 0) {
 
		if (tag->id != BSWAP32(id) || tag->type != type) continue;
 
		switch (type) {
 
			default: NOT_REACHED();
 

	
 
			case 'T': {
 
				byte langid = buf->ReadByte();
 
				return tag->handler.text(langid, buf->ReadString());
 
			}
 

	
 
			case 'B': {
 
				size_t len = buf->ReadWord();
 
				if (buf->Remaining() < len) return false;
 
				return tag->handler.data(len, buf);
 
			}
 

	
 
			case 'C': {
 
				if (tag->handler.call_handler) {
 
					return tag->handler.u.branch(buf);
 
				}
 
				byte new_type = buf->ReadByte();
 
				while (new_type != 0) {
 
					uint32 new_id = buf->ReadDWord();
 
					if (!HandleNode(new_type, new_id, buf, tag->handler.u.subtags)) return false;
 
					new_type = buf->ReadByte();
 
				}
 
				return true;
 
			}
 
		}
 
	}
 
	grfmsg(2, "StaticGRFInfo: unkown type/id combination found, type=%c, id=%x", type, id);
 
	return SkipUnknownInfo(buf, type);
 
}
 

	
 
/* Action 0x14 */
 
static void StaticGRFInfo(ByteReader *buf)
 
{
 
	/* <14> <type> <id> <text/data...> */
 

	
 
	byte type = buf->ReadByte();
 
	uint32 id = buf->ReadDWord();
 
	HandleNode(type, id, buf, _tags_root);
 
}
 

	
 
/* 'Action 0xFF' */
 
static void GRFDataBlock(ByteReader *buf)
 
{
 
@@ -6687,6 +6880,7 @@ static void DecodeSpecialSprite(byte *bu
 
		/* 0x11 */ { SkipAct11,GRFUnsafe, SkipAct11,       SkipAct11,      SkipAct11,         GRFSound, },
 
		/* 0x12 */ { SkipAct12, SkipAct12, SkipAct12,      SkipAct12,      SkipAct12,         LoadFontGlyph, },
 
		/* 0x13 */ { NULL,     NULL,      NULL,            NULL,           NULL,              TranslateGRFStrings, },
 
		/* 0x14 */ { StaticGRFInfo, NULL, NULL,            NULL,           NULL,              NULL, },
 
	};
 

	
 
	GRFLocation location(_cur_grfconfig->ident.grfid, _nfo_line);
0 comments (0 inline, 0 general)