aboutsummaryrefslogtreecommitdiff
path: root/common/xmlparser.h
diff options
context:
space:
mode:
authorVicent Marti2008-09-05 14:48:47 +0000
committerVicent Marti2008-09-05 14:48:47 +0000
commite0592c7d25acd42cd93b9dab5048209bab858ba8 (patch)
tree485a24967de1b0a8e50204c95191fb0b07388acd /common/xmlparser.h
parent020be5bc2183ef8cdf27595a476b8b1cc4cff194 (diff)
downloadscummvm-rg350-e0592c7d25acd42cd93b9dab5048209bab858ba8.tar.gz
scummvm-rg350-e0592c7d25acd42cd93b9dab5048209bab858ba8.tar.bz2
scummvm-rg350-e0592c7d25acd42cd93b9dab5048209bab858ba8.zip
Fixed severe bottleneck in the XML Parser code.
Applied Max's patch for character drawing. Added new FP squareroot function. svn-id: r34354
Diffstat (limited to 'common/xmlparser.h')
-rw-r--r--common/xmlparser.h238
1 files changed, 45 insertions, 193 deletions
diff --git a/common/xmlparser.h b/common/xmlparser.h
index 4d1c8fc85d..7edabf62f3 100644
--- a/common/xmlparser.h
+++ b/common/xmlparser.h
@@ -40,145 +40,12 @@
namespace Common {
-/***********************************************
- **** XMLParser.cpp/h -- Generic XML Parser ****
- ***********************************************
+/*
+ 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.
-
- Keys which may contain any kind of Property names may be defined with the
- XML_PROP_ANY() macro instead of the XML_PROP() macro. This macro takes no
- arguments.
-
- 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>
-
- Once a layout has been defined, everytime a XML node (that is, a key and
- all its properties) has been parsed, a specific callback funcion is called,
- which should take care of managing the parsed data for the node.
-
- Callback functions must be explicitly declared with the following syntax:
-
- bool parserCallback_KEYNAME(ParserNode *node);
-
- A callback function is needed for each key that can be parsed, since they
- are called automatically; the function will receive a pointer to the XML
- Node that has been parsed. This XML Node has the following properties:
-
- - It's assured to be expected in the layout of the XML file (i.e.
- has the proper position and depth in the XML tree).
-
- - It's assured to contain all the required Properties that have
- been declared in the XML layout.
-
- - It's assured to contain NO unexpected properties (i.e. properties
- which haven't been declared in the XML layout).
-
- Further validation of the Node's data may be performed inside the callback
- function. Once the node has been validated and its data has been parsed/
- managed, the callback function is expected to return true.
-
- If the data in the XML Node is corrupted or there was a problem when
- parsing it, the callback function is expected to return false or,
- preferably, to throw a parserError() using the following syntax:
-
- return parserError("There was a problem in key '%s'.", arg1, ...);
-
- Also, 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.
-
- Lastly, when defining your own Custom XML Parser, further customization
- may be accomplished _optionally_ by overloading several virtual functions
- of the XMLParser class.
-
- Check the API documentation of the following functions for more info:
-
- virtual bool closedKeyCallback(ParserNode *node);
- virtual bool skipComments();
- virtual bool isValidNameChar(char c);
- virtual void cleanup();
-
- Check the sample implementation of the GUI::ThemeParser custom parser
- for a working sample of a Custom XML Parser.
-
+ External documentation available at:
+ http://www.smartlikearoboc.com/scummvm_doc/xmlparser_doc.html
*/
#define XML_KEY(keyName) {\
@@ -226,43 +93,6 @@ namespace Common {
#define PARSER_END() layout.clear(); }
-class XMLStream {
-protected:
- SeekableReadStream *_stream;
- int _pos;
-
-public:
- XMLStream() : _stream(0), _pos(0) {}
-
- ~XMLStream() {
- delete _stream;
- }
-
- SeekableReadStream *stream() {
- return _stream;
- }
-
- char operator [](int idx) {
- assert(_stream && idx >= 0);
-
- if (_pos + 1 != idx)
- _stream->seek(idx, SEEK_SET);
-
- _pos = idx;
-
- return _stream->readByte();
- }
-
- void loadStream(SeekableReadStream *s) {
- delete _stream;
- _stream = s;
- }
-
- bool ready() {
- return _stream != 0;
- }
-};
-
/**
* The base XMLParser class implements generic functionality for parsing
* XML-like files.
@@ -278,13 +108,14 @@ public:
/**
* Parser constructor.
*/
- XMLParser() : _XMLkeys(0) {}
+ XMLParser() : _XMLkeys(0), _stream(0) {}
virtual ~XMLParser() {
while (!_activeKey.empty())
delete _activeKey.pop();
delete _XMLkeys;
+ delete _stream;
for (Common::List<XMLKeyLayout*>::iterator i = _layoutList.begin();
i != _layoutList.end(); ++i)
@@ -352,7 +183,7 @@ public:
}
_fileName = filename;
- _text.loadStream(f);
+ _stream = f;
return true;
}
@@ -365,7 +196,7 @@ public:
}
_fileName = node.getName();
- _text.loadStream(f);
+ _stream = f;
return true;
}
@@ -381,13 +212,13 @@ public:
* no longer needed by the parser.
*/
bool loadBuffer(const byte *buffer, uint32 size, bool disposable = false) {
- _text.loadStream(new MemoryReadStream(buffer, size, disposable));
+ _stream = new MemoryReadStream(buffer, size, disposable);
_fileName = "Memory Stream";
return true;
}
bool loadStream(MemoryReadStream *stream) {
- _text.loadStream(stream);
+ _stream = stream;
_fileName = "Compressed File Stream";
return true;
}
@@ -492,11 +323,11 @@ protected:
* Skips spaces/whitelines etc. Returns true if any spaces were skipped.
*/
bool skipSpaces() {
- if (!isspace(_text[_pos]))
+ if (!isspace(_char))
return false;
- while (_text[_pos] && isspace(_text[_pos]))
- _pos++;
+ while (_char && isspace(_char))
+ _char = _stream->readByte();
return true;
}
@@ -508,14 +339,31 @@ protected:
* or to change the commenting syntax.
*/
virtual bool skipComments() {
- if (_text[_pos] == '/' && _text[_pos + 1] == '*') {
- _pos += 2;
- while (_text[_pos++]) {
- if (_text[_pos - 2] == '*' && _text[_pos - 1] == '/')
+ char endComment1 = 0, endComment2 = 0;
+
+ if (_char == '/') {
+ _char = _stream->readByte();
+
+ if (_char != '*') {
+ _stream->seek(-1, SEEK_CUR);
+ _char = '/';
+ return false;
+ }
+
+ _char = _stream->readByte();
+
+ while (_char) {
+ endComment1 = endComment2;
+ endComment2 = _char;
+ _char = _stream->readByte();
+
+ if (endComment1 == '*' && endComment2 == '/')
break;
- if (_text[_pos] == 0)
+
+ if (_char == 0)
parserError("Comment has no closure.");
}
+ _char = _stream->readByte();
return true;
}
@@ -527,7 +375,7 @@ protected:
* Overload this if you want to support keys with strange characters
* in their name.
*/
- virtual bool isValidNameChar(char c) {
+ virtual inline bool isValidNameChar(char c) {
return isalnum(c) || c == '_';
}
@@ -537,10 +385,13 @@ protected:
*/
bool parseToken() {
_token.clear();
- while (isValidNameChar(_text[_pos]))
- _token += _text[_pos++];
- return isspace(_text[_pos]) != 0 || _text[_pos] == '>' || _text[_pos] == '=' || _text[_pos] == '/';
+ while (isValidNameChar(_char)) {
+ _token += _char;
+ _char = _stream->readByte();
+ }
+
+ return isspace(_char) != 0 || _char == '>' || _char == '=' || _char == '/';
}
/**
@@ -599,7 +450,8 @@ protected:
private:
int _pos; /** Current position on the XML buffer. */
- XMLStream _text; /** Buffer with the text being parsed */
+ char _char;
+ SeekableReadStream *_stream;
Common::String _fileName;
ParserState _state; /** Internal state of the parser */