[Scummvm-cvs-logs] SF.net SVN: scummvm:[33447] scummvm/branches/gsoc2008-gui

Tanoku at users.sourceforge.net Tanoku at users.sourceforge.net
Wed Jul 30 15:33:32 CEST 2008


Revision: 33447
          http://scummvm.svn.sourceforge.net/scummvm/?rev=33447&view=rev
Author:   Tanoku
Date:     2008-07-30 13:33:32 +0000 (Wed, 30 Jul 2008)

Log Message:
-----------
Rewrote most of the XML parser class.
Added support for defining the XML layout when parsing, allows for safer parsing.
Updated all the documentation regarding the usage of the XMLParser class.

Modified Paths:
--------------
    scummvm/branches/gsoc2008-gui/common/xmlparser.cpp
    scummvm/branches/gsoc2008-gui/common/xmlparser.h
    scummvm/branches/gsoc2008-gui/gui/ThemeParser.cpp
    scummvm/branches/gsoc2008-gui/gui/ThemeParser.h

Modified: scummvm/branches/gsoc2008-gui/common/xmlparser.cpp
===================================================================
--- scummvm/branches/gsoc2008-gui/common/xmlparser.cpp	2008-07-30 11:36:14 UTC (rev 33446)
+++ scummvm/branches/gsoc2008-gui/common/xmlparser.cpp	2008-07-30 13:33:32 UTC (rev 33447)
@@ -84,7 +84,28 @@
 
 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.
 	for (int i = _activeKey.size() - 1; i >= 0; --i) {
@@ -92,7 +113,13 @@
 			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 @@
 
 	if (_text.ready() == false)
 		return parserError("XML stream not ready for reading.");
+		
+	if (_XMLkeys == 0)
+		buildLayout();
 
 	cleanup();
 
@@ -186,6 +216,7 @@
 					node->name = _token;
 					node->ignore = false;
 					node->depth = _activeKey.size();
+					node->layout = 0;
 					_activeKey.push(node);
 				}
 
@@ -194,7 +225,7 @@
 
 			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;
 					}

Modified: scummvm/branches/gsoc2008-gui/common/xmlparser.h
===================================================================
--- scummvm/branches/gsoc2008-gui/common/xmlparser.h	2008-07-30 11:36:14 UTC (rev 33446)
+++ scummvm/branches/gsoc2008-gui/common/xmlparser.h	2008-07-30 13:33:32 UTC (rev 33447)
@@ -38,7 +38,126 @@
 #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:
 	SeekableReadStream *_stream;
@@ -91,7 +210,7 @@
 	/**
 	 * Parser constructor.
 	 */
-	XMLParser() {}
+	XMLParser() : _XMLkeys(0) {}
 
 	virtual ~XMLParser() {
 		while (!_activeKey.empty())
@@ -109,6 +228,22 @@
 
 		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 @@
 		Common::StringMap values;
 		bool ignore;
 		int depth;
+		XMLKeyLayout *layout;
 	};
 
 	/**
@@ -178,33 +314,38 @@
 	}
 
 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 @@
 	 * 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 @@
 	 * 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 @@
 	 *            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;
 

Modified: scummvm/branches/gsoc2008-gui/gui/ThemeParser.cpp
===================================================================
--- scummvm/branches/gsoc2008-gui/gui/ThemeParser.cpp	2008-07-30 11:36:14 UTC (rev 33446)
+++ scummvm/branches/gsoc2008-gui/gui/ThemeParser.cpp	2008-07-30 13:33:32 UTC (rev 33447)
@@ -40,17 +40,7 @@
 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 @@
 	_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 @@
 	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 @@
 		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();
+bool ThemeParser::parserCallback_color(ParserNode *node) {
+	Common::String name = node->values["name"];
 
-	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"];
-
 	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_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 = node->values["func"]; 
 
-	Common::String functionName = stepNode->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 @@
 		}
 	}*/
 
-	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) {

Modified: scummvm/branches/gsoc2008-gui/gui/ThemeParser.h
===================================================================
--- scummvm/branches/gsoc2008-gui/gui/ThemeParser.h	2008-07-30 11:36:14 UTC (rev 33446)
+++ scummvm/branches/gsoc2008-gui/gui/ThemeParser.h	2008-07-30 13:33:32 UTC (rev 33447)
@@ -312,7 +312,6 @@
 
 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 @@
 
 protected:
 	ThemeRenderer *_theme;
-	bool keyCallback(Common::String keyName);
+	
+	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()
 
-	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();
+			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 @@
 	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 @@
 	Common::HashMap<Common::String, PaletteColor, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _palette;
 };
 
+
+
 }
 
 #endif


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list