diff options
| -rw-r--r-- | common/xmlparser.cpp | 35 | ||||
| -rw-r--r-- | common/xmlparser.h | 186 | ||||
| -rw-r--r-- | gui/ThemeParser.cpp | 182 | ||||
| -rw-r--r-- | gui/ThemeParser.h | 109 | 
4 files changed, 326 insertions, 186 deletions
diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index d0c89a9d3e..030b5b9491 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -84,6 +84,27 @@ bool XMLParser::parserError(const char *errorString, ...) {  bool XMLParser::parseActiveKey(bool closed) {  	bool ignore = false; +	assert(_activeKey.empty() == false); + +	ParserNode *key = _activeKey.top(); +	XMLKeyLayout *layout = (_activeKey.size() == 1) ? _XMLkeys : getParentNode(key)->layout; +	 +	if (layout->children.contains(key->name) == false) +		return parserError("Unexpected key in the active scope: '%s'.", key->name.c_str()); +		 +	key->layout = layout->children[key->name]; +	 +	Common::StringMap localMap = key->values; +	 +	for (Common::List<XMLKeyLayout::XMLKeyProperty>::const_iterator i = key->layout->properties.begin(); i != key->layout->properties.end(); ++i) { +		if (localMap.contains(i->name)) +			localMap.erase(i->name); +		else if (i->required) +			return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str()); +	} +	 +	if (localMap.empty() == false) +		return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str());  	// check if any of the parents must be ignored.  	// if a parent is ignored, all children are too. @@ -92,7 +113,13 @@ bool XMLParser::parseActiveKey(bool closed) {  			ignore = true;  	} -	if (ignore == false && keyCallback(_activeKey.top()->name) == false) { +	if (ignore == false && keyCallback(key) == false) { +		// HACK:  People may be stupid and overlook the fact that +		// when keyCallback() fails, a parserError() must be set. +		// We set it manually in that case. +		if (_state != kParserError) +			parserError("Unhandled exception when parsing '%s' key.", key->name.c_str()); +			  		return false;  	} @@ -133,6 +160,9 @@ bool XMLParser::parse() {  	if (_text.ready() == false)  		return parserError("XML stream not ready for reading."); +		 +	if (_XMLkeys == 0) +		buildLayout();  	cleanup(); @@ -186,6 +216,7 @@ bool XMLParser::parse() {  					node->name = _token;  					node->ignore = false;  					node->depth = _activeKey.size(); +					node->layout = 0;  					_activeKey.push(node);  				} @@ -194,7 +225,7 @@ bool XMLParser::parse() {  			case kParserNeedPropertyName:  				if (activeClosure) { -					if (!closedKeyCallback(_activeKey.top()->name)) { +					if (!closedKeyCallback(_activeKey.top())) {  						parserError("Missing data when closing key '%s'.", _activeKey.top()->name.c_str());   						break;  					} diff --git a/common/xmlparser.h b/common/xmlparser.h index 4c77696482..221d382a70 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -38,6 +38,125 @@  #include "common/stack.h"  namespace Common { +	 +/*********************************************** + **** XMLParser.cpp/h -- Generic XML Parser **** + *********************************************** + +	This is a simple implementation of a generic parser which is able to +	interpret a subset of the XML language. +	 +	The XMLParser class is virtual, and must be derived into a child class, +	called a Custom Parser Class, which will manage the parsed data for your +	specific needs. +	 +	Custom Parser Classes have two basic requirements: +	They must inherit directly the XMLParser class, and they must define the +	parsing layout of the XML file. +	 +	Declaring the XML layout is done with the help of the CUSTOM_XML_PARSER() +	macro: this macro must appear once inside the Custom Parser Class declaration, +	and takes a single parameter, the name of the Custom Parser Class. +	 +	The macro must be followed by the actual layout of the XML files to be parsed, +	and closed with the PARSER_END() macro. The layout of XML files is defined by +	the use of 3 helper macros: XML_KEY(), KEY_END() and XML_PROP(). +	 +	Here's a sample of its usage: +	 +	===========	===========	===========	===========	===========	=========== +	 +	CUSTOM_XML_PARSER(ThemeParser) { +		XML_KEY(render_info) +			XML_KEY(palette) +				XML_KEY(color) +					XML_PROP(name, true) +					XML_PROP(rgb, true) +				KEY_END() +			KEY_END() + +			XML_KEY(fonts) +				XML_KEY(font) +					XML_PROP(id, true) +					XML_PROP(type, true) +					XML_PROP(color, true) +				KEY_END() +			KEY_END() + +			XML_KEY(defaults) +				XML_PROP(stroke, false) +				XML_PROP(shadow, false) +				XML_PROP(factor, false) +				XML_PROP(fg_color, false) +				XML_PROP(bg_color, false) +				XML_PROP(gradient_start, false) +				XML_PROP(gradient_end, false) +				XML_PROP(gradient_factor, false) +				XML_PROP(fill, false) +			KEY_END() +		KEY_END() +	} PARSER_END() +			 +	===========	===========	===========	===========	===========	=========== +	 +	The XML_KEY() macro takes a single argument, the name of the expected key. +	Inside the scope of each key, you may define properties for the given key +	with the XML_PROP() macro, which takes as parameters the name of the property +	and whether it's optional or required. You might also define the contained +	children keys, using the XML_KEY() macro again. +	The scope of a XML key is closed with the KEY_END() macro. +	 +	As an example, the following XML layout: +	 +		XML_KEY(palette) +			XML_KEY(color) +				XML_PROP(name, true) +				XML_PROP(rgb, true) +				XML_PROP(optional_param, false) +			KEY_END() +		KEY_END() +		 +	will expect to parse a syntax like this: +	 +		<palette> +			<color name = "red" rgb = "255, 0, 0" /> +			<color name = "blue" rgb = "0, 0, 255" optional_param = "565" /> +		</palette> +		 +	TODO: documentation on callbacks +	 +	Note that the XML parser doesn't take into account the actual order of the keys and +	properties in the XML layout definition, only its layout and relationships. +*/ +	 +#define XML_KEY(keyName) {\ +		lay = new XMLKeyLayout; \ +		lay->custom = new kLocalParserName::CustomParserCallback; \ +		((kLocalParserName::CustomParserCallback*)(lay->custom))->callback = (&kLocalParserName::parserCallback_##keyName); \ +		layout.top()->children[#keyName] = lay; \ +		layout.push(lay); + +#define KEY_END() layout.pop(); } + +#define XML_PROP(propName, req) {\ +		prop.name = #propName; \ +		prop.required = req; \ +		layout.top()->properties.push_back(prop); }\ +	 +#define CUSTOM_XML_PARSER(parserName) \ +	protected: \ +	typedef bool (parserName::*ParserCallback)(ParserNode *node); \ +	typedef parserName kLocalParserName; \ +	struct CustomParserCallback { ParserCallback callback; }; \ +	bool keyCallback(ParserNode *node) {return (this->*(((parserName::CustomParserCallback*)(node->layout->custom))->callback))(node);}\ +	virtual void buildLayout() { \ +		Common::Stack<XMLKeyLayout*> layout; \ +		XMLKeyLayout *lay = 0; \ +		XMLKeyLayout::XMLKeyProperty prop; \ +		_XMLkeys = new XMLKeyLayout; \ +		layout.push(_XMLkeys); +	 +#define PARSER_END() layout.clear(); }  class XMLStream {  protected: @@ -91,7 +210,7 @@ public:  	/**  	 * Parser constructor.  	 */ -	XMLParser() {} +	XMLParser() : _XMLkeys(0) {}  	virtual ~XMLParser() {  		while (!_activeKey.empty()) @@ -109,6 +228,22 @@ public:  		kParserError  	}; +	 +	struct XMLKeyLayout; +	 +	typedef Common::HashMap<Common::String, XMLParser::XMLKeyLayout*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ChildMap; +	 +	/** nested struct representing the layout of the XML file */ +	struct XMLKeyLayout { +		void *custom; +		struct XMLKeyProperty { +			Common::String name; +			bool required; +		}; +		 +		Common::List<XMLKeyProperty> properties; +		ChildMap children; +	} *_XMLkeys;  	/** Struct representing a parsed node */  	struct ParserNode { @@ -116,6 +251,7 @@ public:  		Common::StringMap values;  		bool ignore;  		int depth; +		XMLKeyLayout *layout;  	};  	/** @@ -178,33 +314,38 @@ public:  	}  protected: +	  	/** -	 * The keycallback function must be overloaded by inheriting classes -	 * to implement parser-specific functions. +	 * The buildLayout function builds the layout for the parser to use +	 * based on a series of helper macros. This function is automatically +	 * generated by the CUSTOM_XML_PARSER() macro on custom parsers.  	 * -	 * This function is called everytime a key has successfully been parsed. -	 * The keyName parameter contains the name of the key that has just been -	 * parsed; this same key is still on top of the Node Stack. +	 * See the documentation regarding XML layouts. +	 */ +	virtual void buildLayout() = 0; +	 +	/** +	 * The keycallback function is automatically overloaded on custom parsers +	 * when using the CUSTOM_XML_PARSER() macro.   	 * -	 * Access the node stack to view this key's properties and its parents. -	 * Remember to leave the node stack _UNCHANGED_ in your own function. Removal -	 * of closed keys is done automatically. +	 * Its job is to call the corresponding Callback function for the given node. +	 * A function for each key type must be declared separately. See the custom +	 * parser creation instructions.  	 * -	 * When parsing a key, one may chose to skip it, e.g. because it's not needed +	 * When parsing a key in such function, one may chose to skip it, e.g. because it's not needed  	 * on the current configuration. In order to ignore a key, you must set  	 * the "ignore" field of its KeyNode struct to "true": The key and all its children  	 * will then be automatically ignored by the parser.  	 * -	 * Return true if the key was properly handled (this includes the case when the -	 * key is being ignored). False otherwise. +	 * The callback function must return true if the key was properly handled (this includes the case when the +	 * key is being ignored). False otherwise. The return of keyCallback() is the same as +	 * the callback function's.  	 * See the sample implementation in GUI::ThemeParser.  	 */ -	virtual bool keyCallback(Common::String keyName) { -		return false; -	} +	virtual bool keyCallback(ParserNode *node) = 0;  	/** -	 * The closed key callback function must be overloaded by inheriting classes to +	 * The closed key callback function MAY be overloaded by inheriting classes to  	 * implement parser-specific functions.  	 *  	 * The closedKeyCallback is issued once a key has been finished parsing, to let @@ -213,28 +354,27 @@ protected:  	 * Returns true if the key was properly closed, false otherwise.  	 * By default, all keys are properly closed.  	 */ -	virtual bool closedKeyCallback(Common::String keyName) { +	virtual bool closedKeyCallback(ParserNode *node) {  		return true;  	}  	/**  	 * Parses the value of a given key. There's no reason to overload this.  	 */ -	virtual bool parseKeyValue(Common::String keyName); +	bool parseKeyValue(Common::String keyName);  	/**  	 * Called once a key has been parsed. It handles the closing/cleanup of the  	 * node stack and calls the keyCallback. -	 * There's no reason to overload this.  	 */ -	virtual bool parseActiveKey(bool closed); +	bool parseActiveKey(bool closed);  	/**  	 * Prints an error message when parsing fails and stops the parser.  	 * Parser error always returns "false" so we can pass the return value directly  	 * and break down the parsing.  	 */ -	virtual bool parserError(const char *errorString, ...) GCC_PRINTF(2, 3); +	bool parserError(const char *errorString, ...) GCC_PRINTF(2, 3);  	/**  	 * Skips spaces/whitelines etc. Returns true if any spaces were skipped. @@ -292,7 +432,7 @@ protected:  	 * Parses a the first textual token found.  	 * There's no reason to overload this.  	 */ -	virtual bool parseToken() { +	bool parseToken() {  		_token.clear();  		while (isValidNameChar(_text[_pos]))  			_token += _text[_pos++]; @@ -318,7 +458,7 @@ protected:  	 *            by reference.  	 * @returns True if the parsing succeeded.  	 */ -	virtual bool parseIntegerKey(const char *key, int count, ...) { +	bool parseIntegerKey(const char *key, int count, ...) {  		char *parseEnd;  		int *num_ptr; diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp index 66750b8c1a..9733be4125 100644 --- a/gui/ThemeParser.cpp +++ b/gui/ThemeParser.cpp @@ -40,17 +40,7 @@ namespace GUI {  using namespace Graphics;  using namespace Common; -ThemeParser::ThemeParser(ThemeRenderer *parent) : XMLParser() { -	_callbacks["drawstep"] = &ThemeParser::parserCallback_DRAWSTEP; -	_callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA; -	_callbacks["palette"] = &ThemeParser::parserCallback_palette; -	_callbacks["color"] = &ThemeParser::parserCallback_color; -	_callbacks["render_info"] = &ThemeParser::parserCallback_renderInfo; -	_callbacks["layout_info"] = &ThemeParser::parserCallback_layoutInfo; -	_callbacks["defaults"] = &ThemeParser::parserCallback_defaultSet; -	_callbacks["text"] = &ThemeParser::parserCallback_text; -	_callbacks["fonts"] = &ThemeParser::parserCallback_fonts; -	_callbacks["font"] = &ThemeParser::parserCallback_font; +ThemeParser::ThemeParser(ThemeRenderer *parent) : XMLParser() {	  	_drawFunctions["circle"]  = &Graphics::VectorRenderer::drawCallback_CIRCLE;  	_drawFunctions["square"]  = &Graphics::VectorRenderer::drawCallback_SQUARE; @@ -76,14 +66,6 @@ void ThemeParser::cleanup() {  	_palette.clear();  } -bool ThemeParser::keyCallback(Common::String keyName) { -	// automatically handle with a function from the hash table. -	if (!_callbacks.contains(_activeKey.top()->name)) -		return parserError("%s is not a valid key name.", keyName.c_str()); - -	return (this->*(_callbacks[_activeKey.top()->name]))(); -} -  Graphics::DrawStep *ThemeParser::defaultDrawStep() {  	Graphics::DrawStep *step = new DrawStep; @@ -125,14 +107,10 @@ Graphics::DrawStep *ThemeParser::newDrawStep() {  	return step;  } -bool ThemeParser::parserCallback_defaultSet() { -	ParserNode *defNode = getActiveNode(); -	ParserNode *parentNode = getParentNode(defNode); +bool ThemeParser::parserCallback_defaults(ParserNode *node) { +	ParserNode *parentNode = getParentNode(node);  	Graphics::DrawStep *step = 0; -	if (parentNode == 0) -		return parserError("The <default> key must be contained inside <render_info> keys."); -  	if (parentNode->name == "render_info") {  		step = _defaultStepGlobal;  	} else if (parentNode->name == "drawdata") { @@ -145,143 +123,76 @@ bool ThemeParser::parserCallback_defaultSet() {  		return parserError("<default> key out of scope. Must be inside <drawdata> or <render_info> keys.");  	} -	return parseDrawStep(defNode, step, false); +	return parseDrawStep(node, step, false);  } -bool ThemeParser::parserCallback_font() { -	ParserNode *tNode = getActiveNode(); -	ParserNode *parentNode = getParentNode(tNode); -	 -	if (parentNode == 0 || parentNode->name != "fonts") -		return parserError("Text Steps must be contained inside <fonts> keys."); -		 -	if (!tNode->values.contains("id")) -		return parserError("Font definitions need a valid identifier."); -	 -	if (!tNode->values.contains("type")) -		return parserError("Font definitions need a valid typename."); -	 -	if (tNode->values.contains("horizontal_align") || tNode->values.contains("vertical_align")) -		return parserError("Font definitions cannot contain alignments."); -		 +bool ThemeParser::parserCallback_font(ParserNode *node) {		  	int red, green, blue; -	if (tNode->values.contains("color")) { - -		if (_palette.contains(tNode->values["color"])) -			getPaletteColor(tNode->values["color"], red, green, blue); -		else if (!parseIntegerKey(tNode->values["color"].c_str(), 3, &red, &green, &blue)) -			return parserError("Error when parsing color value for font definition."); - -	} else { -		return parserError("Cannot assign color in font definition."); -	} +	if (_palette.contains(node->values["color"])) +		getPaletteColor(node->values["color"], red, green, blue); +	else if (!parseIntegerKey(node->values["color"].c_str(), 3, &red, &green, &blue)) +		return parserError("Error when parsing color value for font definition."); -	if (!_theme->addFont(tNode->values["id"], red, green, blue)) +	if (!_theme->addFont(node->values["id"], red, green, blue))  		return parserError("Error when loading Font in theme engine.");  	return true;  } -bool ThemeParser::parserCallback_fonts() { -	ParserNode *tNode = getActiveNode(); -	 -	if (getParentNode(tNode) == 0 || getParentNode(tNode)->name != "render_info") -		return parserError("Font definition keys must be contained inside a <render_info> section."); -		 +bool ThemeParser::parserCallback_fonts(ParserNode *node) {		  	return true;	  } -bool ThemeParser::parserCallback_text() { -	ParserNode *tNode = getActiveNode(); -	ParserNode *parentNode = getParentNode(tNode); -	 -	if (parentNode == 0 || parentNode->name != "drawdata") -		return parserError("Text Steps must be contained inside <drawdata> keys."); -		 +bool ThemeParser::parserCallback_text(ParserNode *node) {		  	GUI::Theme::TextAlign alignH;  	GUI::Theme::TextAlignVertical alignV; -	 -	if (tNode->values.contains("horizontal_align") == false || tNode->values.contains("vertical_align") == false) -		return parserError("Text inside widgets requires proper alignment keys."); - -	if (tNode->values.contains("font") == false) -		return parserError("Text definitions must include a valid Font identifier."); -	if (tNode->values["horizontal_align"] == "left") +	if (node->values["horizontal_align"] == "left")  		alignH = GUI::Theme::kTextAlignLeft; -	else if (tNode->values["horizontal_align"] == "right") +	else if (node->values["horizontal_align"] == "right")  		alignH = GUI::Theme::kTextAlignRight; -	else if (tNode->values["horizontal_align"] == "center") +	else if (node->values["horizontal_align"] == "center")  		alignH = GUI::Theme::kTextAlignCenter;  	else return parserError("Invalid value for text alignment."); -	if (tNode->values["vertical_align"] == "top") +	if (node->values["vertical_align"] == "top")  		alignV = GUI::Theme::kTextAlignVTop; -	else if (tNode->values["vertical_align"] == "center") +	else if (node->values["vertical_align"] == "center")  		alignV = GUI::Theme::kTextAlignVCenter; -	else if (tNode->values["vertical_align"] == "bottom") +	else if (node->values["vertical_align"] == "bottom")  		alignV = GUI::Theme::kTextAlignVBottom;  	else return parserError("Invalid value for text alignment."); -	if (!_theme->addTextData(parentNode->values["id"], tNode->values["font"], alignH, alignV)) -		return parserError("Error when adding Text Data for '%s'.", parentNode->values["id"].c_str()); +	if (!_theme->addTextData(getParentNode(node)->values["id"], node->values["font"], alignH, alignV)) +		return parserError("Error when adding Text Data for '%s'.", getParentNode(node)->values["id"].c_str());  	return true;  } -bool ThemeParser::parserCallback_renderInfo() { -	ParserNode *infoNode = getActiveNode(); - -	assert(infoNode->name == "render_info"); - -	if (getParentNode(infoNode) != 0) -		return parserError("<render_info> keys must be root elements."); - +bool ThemeParser::parserCallback_render_info(ParserNode *node) {  	// TODO: Skip key if it's not for this platform. -  	return true;  } -bool ThemeParser::parserCallback_layoutInfo() { -	ParserNode *layoutNode = getActiveNode(); - -	assert(layoutNode->name == "layout_info"); - -	if (getParentNode(layoutNode) != 0) -		return parserError("<layout_info> keys must be root elements."); - +bool ThemeParser::parserCallback_layout_info(ParserNode *node) { +	// TODO: skip key  	return true;  } -bool ThemeParser::parserCallback_palette() { -	ParserNode *paletteNode = getActiveNode(); - -	assert(paletteNode->name == "palette"); - -	if (getParentNode(paletteNode) == 0 || getParentNode(paletteNode)->name != "render_info") -		return parserError("Palette keys must be contained inside a <render_info> section."); - +bool ThemeParser::parserCallback_palette(ParserNode *node) {  	return true;  } -bool ThemeParser::parserCallback_color() { -	ParserNode *colorNode = getActiveNode(); - -	if (getParentNode(colorNode) == 0 || getParentNode(colorNode)->name != "palette") -		return parserError("Colors must be specified inside <palette> tags."); - -	if (!colorNode->values.contains("name") || !colorNode->values.contains("rgb")) -		return parserError("Color keys must contain 'name' and 'rgb' values for the color."); - -	Common::String name = colorNode->values["name"]; +bool ThemeParser::parserCallback_color(ParserNode *node) { +	Common::String name = node->values["name"];  	if (_palette.contains(name))  		return parserError("Color '%s' has already been defined.", name.c_str());  	int red, green, blue; -	if (parseIntegerKey(colorNode->values["rgb"].c_str(), 3, &red, &green, &blue) == false || +	if (parseIntegerKey(node->values["rgb"].c_str(), 3, &red, &green, &blue) == false ||  		red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255)  		return parserError("Error when parsing RGB values for palette color '%s'", name.c_str());\ @@ -293,53 +204,32 @@ bool ThemeParser::parserCallback_color() {  } -bool ThemeParser::parserCallback_DRAWSTEP() { -	ParserNode *stepNode = _activeKey.top(); -	ParserNode *drawdataNode = getParentNode(stepNode); - -	if (!drawdataNode || drawdataNode->name != "drawdata") -		return parserError("DrawStep keys must be located inside a DrawData set."); - -	assert(stepNode->name == "drawstep"); -	assert(drawdataNode->values.contains("id")); - +bool ThemeParser::parserCallback_drawstep(ParserNode *node) {  	Graphics::DrawStep *drawstep = newDrawStep(); -	if (!stepNode->values.contains("func")) -		return parserError("All Draw Steps must contain a 'func' definition."); - -	Common::String functionName = stepNode->values["func"];  +	Common::String functionName = node->values["func"];   	if (_drawFunctions.contains(functionName) == false)  		return parserError("%s is not a valid drawing function name", functionName.c_str());  	drawstep->drawingCall = _drawFunctions[functionName]; -	if (!parseDrawStep(stepNode, drawstep, true)) +	if (!parseDrawStep(node, drawstep, true))  		return false; -	_theme->addDrawStep(drawdataNode->values["id"], *drawstep); +	_theme->addDrawStep(getParentNode(node)->values["id"], *drawstep);  	delete drawstep;  	return true;  } -bool ThemeParser::parserCallback_DRAWDATA() { -	ParserNode *drawdataNode = _activeKey.top(); +bool ThemeParser::parserCallback_drawdata(ParserNode *node) {  	bool cached = false; -	assert(drawdataNode->name == "drawdata"); - -	if (getParentNode(drawdataNode) == 0 || getParentNode(drawdataNode)->name != "render_info") -		return parserError("DrawData keys must be contained inside a <render_info> section."); - -	if (drawdataNode->values.contains("id") == false) -		return parserError("DrawData keys must contain an identifier."); - -	if (drawdataNode->values.contains("cache")) { -		if (drawdataNode->values["cache"] == "true")  +	if (node->values.contains("cache")) { +		if (node->values["cache"] == "true")   			cached = true; -		else if (drawdataNode->values["cache"] == "false") +		else if (node->values["cache"] == "false")  			cached = false;  		else return parserError("'Parsed' value must be either true or false.");  	} @@ -354,7 +244,7 @@ bool ThemeParser::parserCallback_DRAWDATA() {  		}  	}*/ -	if (_theme->addDrawData(drawdataNode->values["id"], cached) == false) +	if (_theme->addDrawData(node->values["id"], cached) == false)  		return parserError("Error when adding Draw Data set: Invalid DrawData name.");  	if (_defaultStepLocal) { diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h index 59ba188fc1..485cc135bc 100644 --- a/gui/ThemeParser.h +++ b/gui/ThemeParser.h @@ -312,7 +312,6 @@ class ThemeRenderer;  class ThemeParser : public XMLParser {  	typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const DrawStep &); -	typedef bool (ThemeParser::*ParserCallback)();  public:  	ThemeParser(GUI::ThemeRenderer *parent); @@ -330,19 +329,98 @@ public:  protected:  	ThemeRenderer *_theme; -	bool keyCallback(Common::String keyName); - -	bool parserCallback_DRAWSTEP(); -	bool parserCallback_DRAWDATA(); -	bool parserCallback_palette(); -	bool parserCallback_color(); -	bool parserCallback_renderInfo(); -	bool parserCallback_layoutInfo(); -	bool parserCallback_defaultSet(); -	bool parserCallback_text(); -	bool parserCallback_fonts(); -	bool parserCallback_font(); - +	 +	CUSTOM_XML_PARSER(ThemeParser) { +		 +		XML_KEY(render_info) +			XML_KEY(palette) +				XML_KEY(color) +					XML_PROP(name, true) +					XML_PROP(rgb, true) +				KEY_END() +			KEY_END() + +			XML_KEY(fonts) +				XML_KEY(font) +					XML_PROP(id, true) +					XML_PROP(type, true) +					XML_PROP(color, true) +				KEY_END() +			KEY_END() + +			XML_KEY(defaults) +				XML_PROP(stroke, false) +				XML_PROP(shadow, false) +				XML_PROP(factor, false) +				XML_PROP(fg_color, false) +				XML_PROP(bg_color, false) +				XML_PROP(gradient_start, false) +				XML_PROP(gradient_end, false) +				XML_PROP(gradient_factor, false) +				XML_PROP(fill, false) +			KEY_END() + +			XML_KEY(drawdata) +				XML_PROP(id, true) +				XML_PROP(cache, false) + +				XML_KEY(defaults) +					XML_PROP(stroke, false) +					XML_PROP(shadow, false) +					XML_PROP(factor, false) +					XML_PROP(fg_color, false) +					XML_PROP(bg_color, false) +					XML_PROP(gradient_start, false) +					XML_PROP(gradient_end, false) +					XML_PROP(gradient_factor, false) +					XML_PROP(fill, false) +				KEY_END() + +				XML_KEY(drawstep) +					XML_PROP(func, true) +					XML_PROP(stroke, false) +					XML_PROP(shadow, false) +					XML_PROP(factor, false) +					XML_PROP(fg_color, false) +					XML_PROP(bg_color, false) +					XML_PROP(gradient_start, false) +					XML_PROP(gradient_end, false) +					XML_PROP(gradient_factor, false) +					XML_PROP(fill, false) +					XML_PROP(bevel, false) +					XML_PROP(radius, false) +					XML_PROP(width, false) +					XML_PROP(height, false) +					XML_PROP(xpos, false) +					XML_PROP(ypos, false) +					XML_PROP(orientation, false) +				KEY_END() + +				XML_KEY(text) +					XML_PROP(font, true) +					XML_PROP(vertical_align, true) +					XML_PROP(horizontal_align, true) +				KEY_END() +			KEY_END() + +		KEY_END() // render_info end + +		XML_KEY(layout_info) +		KEY_END() +		 +	} PARSER_END(); +	 +	bool parserCallback_defaults(ParserNode *node); +	bool parserCallback_font(ParserNode *node); +	bool parserCallback_fonts(ParserNode *node); +	bool parserCallback_text(ParserNode *node); +	bool parserCallback_render_info(ParserNode *node); +	bool parserCallback_layout_info(ParserNode *node); +	bool parserCallback_palette(ParserNode *node); +	bool parserCallback_color(ParserNode *node); +	bool parserCallback_drawstep(ParserNode *node); +	bool parserCallback_drawdata(ParserNode *node); +	  	void cleanup();  	Graphics::DrawStep *newDrawStep(); @@ -353,7 +431,6 @@ protected:  	Graphics::DrawStep *_defaultStepLocal;  	Common::HashMap<Common::String, DrawingFunctionCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _drawFunctions; -	Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _callbacks;  	struct PaletteColor {  		uint8 r, g, b; @@ -362,6 +439,8 @@ protected:  	Common::HashMap<Common::String, PaletteColor, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _palette;  }; + +  }  #endif  | 
