From 42036e7fd332a25cb902a220aa020e82cb0794ef Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 18 Jun 2008 00:15:21 +0000 Subject: Expanded parser. Added regex support for Common::String Changed drawstep state saving. svn-id: r32729 --- common/str.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ common/str.h | 17 ++++++++++ 2 files changed, 116 insertions(+) (limited to 'common') diff --git a/common/str.cpp b/common/str.cpp index ad48ef6087..e849cb042d 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -283,6 +283,105 @@ void String::toUppercase() { _str[i] = toupper(_str[i]); } +bool String::regexMatch(const char *regex, bool skipSpaces) { + int pos = 0; + + if (regex[0] == '^') + return regexMatchPos(1, regex, 1, skipSpaces); + + do { + if (regexMatchPos(pos, regex, 0, skipSpaces)) + return true; + } while (_str[pos++]); + + return false; +} + +bool String::regexMatchCharacter(RegexMatchType type, char regexChar, char strChar) { + switch (type) { + case kRegexMatchAny: + return true; + + case kRegexMatchDigit: + return isdigit(strChar) != 0; + + case kRegexMatchSpace: + return isspace(strChar) != 0; + + case kRegexMatchAlphanum: + return isalnum(strChar) != 0; + + case kRegexMatchAlpha: + return isalpha(strChar) != 0; + + case kRegexMatchWord: + return isalnum(strChar) != 0 || strChar == '_'; + + case kRegexMatchCharacter: + return regexChar == strChar; + + default: + return false; + } +} + +bool String::regexMatchStar(RegexMatchType type, char regexChar, const char *regex, int regexPos, int strPos, bool skipSpaces) { + + do { + if (regexMatchPos(strPos, regex, regexPos, skipSpaces)) + return true; + } while (_str[strPos] && regexMatchCharacter(type, regexChar, _str[strPos++])); + + return false; +} + +bool String::regexMatchPos(int strPos, const char *regex, int regexPos, bool skipSpaces) { + RegexMatchType matchT = kRegexMatchCharacter; + + if (skipSpaces) { + while (isspace(_str[strPos])) + strPos++; + + while (isspace(regex[regexPos])) + regexPos++; + } + + if (regex[regexPos] == '\0') + return true; + + if (regex[regexPos] == '.') + matchT = kRegexMatchAny; + else if (regex[regexPos] == '[') { + String group; + while (regex[regexPos - 1] != ']') + group += regex[regexPos++]; + + regexPos--; + + if (group == "[digit]" || group == "[d]") + matchT = kRegexMatchDigit; + else if (group == "[space]" || group == "[s]") + matchT = kRegexMatchSpace; + else if (group == "[alnum]") + matchT = kRegexMatchAlphanum; + else if (group == "[alpha]") + matchT = kRegexMatchAlpha; + else if (group == "[word]") + matchT = kRegexMatchWord; + } + + if (regex[regexPos + 1] == '*') + return regexMatchStar(matchT, regex[regexPos], regex, regexPos + 2, strPos, skipSpaces); + + if (regex[regexPos] == '$' && regex[regexPos + 1] == 0) + return _str[strPos] == 0; + + if (_str[strPos] && regexMatchCharacter(matchT, regex[regexPos], _str[strPos])) + return regexMatchPos(strPos + 1, regex, regexPos + 1, skipSpaces); + + return false; +} + /** * Ensure that enough storage is available to store at least new_len * characters plus a null byte. In addition, if we currently share diff --git a/common/str.h b/common/str.h index a92ec34fff..2ea151ba96 100644 --- a/common/str.h +++ b/common/str.h @@ -165,6 +165,9 @@ public: uint hash() const; + // Tanoku: Regular expression support for the String class + bool regexMatch(const char *regex, bool skipSpaces = false); + public: typedef char * iterator; typedef const char * const_iterator; @@ -189,6 +192,20 @@ protected: void ensureCapacity(uint32 new_len, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); + + enum RegexMatchType { + kRegexMatchAny, + kRegexMatchDigit, + kRegexMatchSpace, + kRegexMatchAlphanum, + kRegexMatchAlpha, + kRegexMatchWord, + kRegexMatchCharacter + }; + + bool regexMatchStar(RegexMatchType type, char regexChar, const char *regex, int regexPos, int strPos, bool skipSpaces); + bool regexMatchCharacter(RegexMatchType type, char regexChar, char strChar); + bool regexMatchPos(int strPos, const char *regex, int regexPos, bool skipSpaces); }; // Append two strings to form a new (temp) string -- cgit v1.2.3 From a4b4534a66bb6f24a66a27e28f7df0d390e1eea8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 18 Jun 2008 23:49:47 +0000 Subject: Split ThemeParser into XMLParser and ThemeParser as child class to have a common XML Parser. svn-id: r32734 --- common/module.mk | 1 + common/xmlparser.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++ common/xmlparser.h | 208 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+) create mode 100644 common/xmlparser.cpp create mode 100644 common/xmlparser.h (limited to 'common') diff --git a/common/module.mk b/common/module.mk index c3f2a38c3f..ed15bf75ea 100644 --- a/common/module.mk +++ b/common/module.mk @@ -16,6 +16,7 @@ MODULE_OBJS := \ system.o \ unarj.o \ unzip.o \ + xmlparser.o \ zlib.o # Include common rules diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp new file mode 100644 index 0000000000..7728d90d48 --- /dev/null +++ b/common/xmlparser.cpp @@ -0,0 +1,216 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" +#include "common/system.h" +#include "common/events.h" +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "common/xmlparser.h" + +namespace Common { + +using namespace Graphics; + +void XMLParser::debug_testEval() { + static const char *debugConfigText = + "\n" + "\n" + "//\n" + "/* lol this is just a simple test*/\n"; + + _text = strdup(debugConfigText); + + Common::String test = "12, 125, 125"; + + printf("\n\nRegex result: %s.\n\n", test.regexMatch("^[d]*,[d]*,[d]*$", true) ? "Success." : "Fail"); + + parse(); +} + + +void XMLParser::parserError(const char *error_string) { + _state = kParserError; + printf("PARSER ERROR: %s\n", error_string); +} + +void XMLParser::parseActiveKey(bool closed) { + if (keyCallback(_activeKey.top()->name) == false) { + parserError("Unhandled value inside key."); + return; + } + + if (closed) { + delete _activeKey.pop(); + } +} + +bool XMLParser::parseKeyValue(Common::String keyName) { + assert(_activeKey.empty() == false); + + if (_activeKey.top()->values.contains(keyName)) + return false; + + _token.clear(); + char stringStart; + + if (_text[_pos] == '"' || _text[_pos] == '\'') { + stringStart = _text[_pos++]; + + while (_text[_pos] && _text[_pos] != stringStart) + _token += _text[_pos++]; + + if (_text[_pos++] == 0) + return false; + + } else if (!parseToken()) { + return false; + } + + _activeKey.top()->values[keyName] = _token; + return true; +} + +bool XMLParser::parse() { + + bool activeClosure = false; + bool selfClosure = false; + + _state = kParserNeedKey; + _pos = 0; + _activeKey.clear(); + + while (_text[_pos]) { + if (_state == kParserError) + break; + + if (skipSpaces()) + continue; + + if (skipComments()) + continue; + + switch (_state) { + case kParserNeedKey: + if (_text[_pos++] != '<') { + parserError("Expecting key start."); + break; + } + + if (_text[_pos] == 0) { + parserError("Unexpected end of file."); + break; + } + + if (_text[_pos] == '/' && _text[_pos + 1] != '*') { + _pos++; + activeClosure = true; + } + + _state = kParserNeedKeyName; + break; + + case kParserNeedKeyName: + if (!parseToken()) { + parserError("Invalid key name."); + break; + } + + if (activeClosure) { + if (_activeKey.empty() || _token != _activeKey.top()->name) + parserError("Unexpected closure."); + } else { + ParserNode *node = new ParserNode; + node->name = _token; + _activeKey.push(node); + } + + _state = kParserNeedPropertyName; + break; + + case kParserNeedPropertyName: + if (activeClosure) { + activeClosure = false; + delete _activeKey.pop(); + + if (_text[_pos++] != '>') + parserError("Invalid syntax in key closure."); + else + _state = kParserNeedKey; + + break; + } + + selfClosure = (_text[_pos] == '/'); + + if ((selfClosure && _text[_pos + 1] == '>') || _text[_pos] == '>') { + parseActiveKey(selfClosure); + _pos += selfClosure ? 2 : 1; + _state = kParserNeedKey; + break; + } + + if (!parseToken()) + parserError("Error when parsing key value."); + else + _state = kParserNeedPropertyOperator; + + break; + + case kParserNeedPropertyOperator: + if (_text[_pos++] != '=') + parserError("Unexpected character after key name."); + else + _state = kParserNeedPropertyValue; + + break; + + case kParserNeedPropertyValue: + if (!parseKeyValue(_token)) + parserError("Unable to parse key value."); + else + _state = kParserNeedPropertyName; + + break; + + default: + break; + } + } + + if (_state == kParserError) { + return false; + } + + if (_state != kParserNeedKey || !_activeKey.empty()) { + parserError("Unexpected end of file."); + return false; + } + + return true; +} + +} + diff --git a/common/xmlparser.h b/common/xmlparser.h new file mode 100644 index 0000000000..3edc2b31e1 --- /dev/null +++ b/common/xmlparser.h @@ -0,0 +1,208 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef XML_PARSER_H +#define XML_PARSER_H + +#include "common/scummsys.h" +#include "graphics/surface.h" +#include "common/system.h" +#include "common/xmlparser.h" + +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "common/stack.h" + +namespace Common { + +/** + * The base XMLParser class implements generic functionality for parsing + * XML-like files. + * + * In order to use it, it must be inherited with a child class that implements + * the XMLParser::keyCallback() function. + * + * @see XMLParser::keyCallback() + */ +class XMLParser { + /** Maximum depth for nested keys that the parser supports */ + static const int kParserMaxDepth = 4; + +public: + /** + * Parser constructor. + */ + XMLParser() {} + + virtual ~XMLParser() {} + + /** Active state for the parser */ + enum ParserState { + kParserNeedKey, + kParserNeedKeyName, + + kParserNeedPropertyName, + kParserNeedPropertyOperator, + kParserNeedPropertyValue, + + kParserError + }; + + /** Struct representing a parsed node */ + struct ParserNode { + Common::String name; + Common::StringMap values; + }; + + virtual bool parse(); + void debug_testEval(); + + /** + * Returns the active node being parsed (the one on top of + * the node stack). + */ + ParserNode *activeNode() { + if (!_activeKey.empty()) + return _activeKey.top(); + + return 0; + } + +protected: + /** + * The keycallback function must be overloaded by inheriting classes + * to implement parser-specific functions. + * + * 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. + * + * 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. + * + * Return true if the key was properly handled. False otherwise. + * See the sample implementation in GUI::ThemeParser. + */ + virtual bool keyCallback(Common::String keyName) { + return false; + } + + /** + * Parses the value of a given key. There's no reason to overload this. + */ + virtual 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 void parseActiveKey(bool closed); + + /** + * Prints an error message when parsing fails and stops the parser. + * TODO: More descriptive error messages. + */ + virtual void parserError(const char *errorString); + + /** + * Skips spaces/whitelines etc. Returns true if any spaces were skipped. + * Overload this if you want to make your parser depend on newlines or + * whatever. + */ + virtual bool skipSpaces() { + if (!isspace(_text[_pos])) + return false; + + while (_text[_pos] && isspace(_text[_pos])) + _pos++; + + return true; + } + + /** + * Skips comment blocks and comment lines. + * Returns true if any comments were skipped. + * Overload this if you want to disable comments on your XML syntax + * 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] == '/') + break; + if (_text[_pos] == 0) + parserError("Comment has no closure."); + } + return true; + } + + if (_text[_pos] == '/' && _text[_pos + 1] == '/') { + _pos += 2; + while (_text[_pos] && _text[_pos] != '\n') + _pos++; + return true; + } + + return false; + } + + /** + * Check if a given character can be part of a KEY or VALUE name. + * Overload this if you want to support keys with strange characters + * in their name. + */ + virtual bool isValidNameChar(char c) { + return isalnum(c) || c == '_'; + } + + /** + * Parses a the first textual token found. + * There's no reason to overload this. + */ + virtual bool parseToken() { + _token.clear(); + while (isValidNameChar(_text[_pos])) + _token += _text[_pos++]; + + return isspace(_text[_pos]) != 0 || _text[_pos] == '>'; + } + + int _pos; /** Current position on the XML buffer. */ + char *_text; /** Buffer with the text being parsed */ + + ParserState _state; /** Internal state of the parser */ + + Common::String _error; /** Current error message */ + Common::String _token; /** Current text token */ + + Common::FixedStack _activeKey; /** Node stack of the parsed keys */ +}; + +} + +#endif -- cgit v1.2.3 From 8caa7d3f8b1146fafc6dff6de4f801eb2e8b61ae Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 24 Jun 2008 19:48:01 +0000 Subject: Common: - Added function to get the active host type as a string. XMLParser: - Added support for ignoring keys while parsing (check documentation). Backwards compatible. - parserError() has been revamped. Shows all kinds of detailed information regarding the error ala Python InterfaceManager/ThemeParser: - DrawData keys and their DrawStep subkeys are now successfully parsed and loaded into structs. That's a win. - Bug fixes. svn-id: r32768 --- common/util.cpp | 29 ++++++++++++++++++ common/util.h | 7 +++++ common/xmlparser.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++---------- common/xmlparser.h | 17 +++++++---- 4 files changed, 117 insertions(+), 21 deletions(-) (limited to 'common') diff --git a/common/util.cpp b/common/util.cpp index 6f0fdcb233..51bd8bcad6 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -481,6 +481,34 @@ uint32 getEnabledSpecialDebugLevels() { return gDebugLevelsEnabled; } +const char *getHostPlatformString() { + +#if defined(__SYMBIAN32__) + return "symbian"; +#elif defined(_WIN32_WCE) || defined(_MSC_VER) || defined(__MINGW32__) || defined(UNIX) + return "pc"; +#elif defined(__PALMOS_TRAPS__) || defined (__PALMOS_ARMLET__) + return "palmos"; +#elif defined(__DC__) + return "dc"; +#elif defined(__GP32__) + return "gp32"; +#elif defined(__PLAYSTATION2__) + return "ps2"; +#elif defined(__PSP__) + return "psp"; +#elif defined(__amigaos4__) + return "amigaos"; +#elif defined (__DS__) //NeilM + return "nds"; +#elif defined(__WII__) + return "wii"; +#else + return ""; +#endif + +} + } // End of namespace Common @@ -694,3 +722,4 @@ Common::String tag2string(uint32 tag) { str[4] = '\0'; return Common::String(str); } + diff --git a/common/util.h b/common/util.h index c23513596c..c4cbf35212 100644 --- a/common/util.h +++ b/common/util.h @@ -323,6 +323,13 @@ const DebugLevelContainer &listSpecialDebugLevels(); uint32 getEnabledSpecialDebugLevels(); +/** + * Return a string containing the name of the currently running host. + * E.g. returns "wii" if ScummVM is being run in a Wii, and so on. + */ +const char *getHostPlatformString(); + + } // End of namespace Common diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 7728d90d48..de10269cdb 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -36,35 +36,86 @@ using namespace Graphics; void XMLParser::debug_testEval() { static const char *debugConfigText = - "\n" - "\n" + "\n" + "\n" "//\n" "/* lol this is just a simple test*/\n"; _text = strdup(debugConfigText); + _fileName = strdup("test_parse.xml"); Common::String test = "12, 125, 125"; - printf("\n\nRegex result: %s.\n\n", test.regexMatch("^[d]*,[d]*,[d]*$", true) ? "Success." : "Fail"); - parse(); } -void XMLParser::parserError(const char *error_string) { +void XMLParser::parserError(const char *error_string, ...) { _state = kParserError; - printf("PARSER ERROR: %s\n", error_string); + + int pos = _pos; + int line_count = 1; + int line_start = -1; + int line_width = 1; + + do { + if (_text[pos] == '\n' || _text[pos] == '\r') { + line_count++; + + if (line_start == -1) + line_start = pos; + } + } while (pos-- > 0); + + line_start = MAX(line_start, _pos - 80); + + do { + if (_text[line_start + line_width] == '\n' || _text[line_start + line_width] == '\r') + break; + } while (_text[line_start + line_width++]); + + line_width = MIN(line_width, 80); + + char linestr[81]; + strncpy(linestr, &_text[line_start] + 1, line_width ); + linestr[line_width - 1] = 0; + + printf(" File <%s>, line %d:\n", _fileName, line_count); + + printf("%s\n", linestr); + for (int i = 1; i < _pos - line_start; ++i) + printf(" "); + + printf("^\n"); + printf("Parser error: "); + + va_list args; + va_start(args, error_string); + vprintf(error_string, args); + va_end(args); + + printf("\n"); } -void XMLParser::parseActiveKey(bool closed) { - if (keyCallback(_activeKey.top()->name) == false) { - parserError("Unhandled value inside key."); - return; +bool XMLParser::parseActiveKey(bool closed) { + bool ignore = false; + + // 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) { + if (_activeKey[i]->ignore) + ignore = true; + } + + if (ignore == false && keyCallback(_activeKey.top()->name) == false) { + return false; } if (closed) { delete _activeKey.pop(); } + + return true; } bool XMLParser::parseKeyValue(Common::String keyName) { @@ -115,7 +166,7 @@ bool XMLParser::parse() { switch (_state) { case kParserNeedKey: if (_text[_pos++] != '<') { - parserError("Expecting key start."); + parserError("Parser expecting key start."); break; } @@ -144,6 +195,7 @@ bool XMLParser::parse() { } else { ParserNode *node = new ParserNode; node->name = _token; + node->ignore = false; _activeKey.push(node); } @@ -166,9 +218,10 @@ bool XMLParser::parse() { selfClosure = (_text[_pos] == '/'); if ((selfClosure && _text[_pos + 1] == '>') || _text[_pos] == '>') { - parseActiveKey(selfClosure); - _pos += selfClosure ? 2 : 1; - _state = kParserNeedKey; + if (parseActiveKey(selfClosure)) { + _pos += selfClosure ? 2 : 1; + _state = kParserNeedKey; + } break; } @@ -181,7 +234,7 @@ bool XMLParser::parse() { case kParserNeedPropertyOperator: if (_text[_pos++] != '=') - parserError("Unexpected character after key name."); + parserError("Syntax error after key name."); else _state = kParserNeedPropertyValue; @@ -189,7 +242,7 @@ bool XMLParser::parse() { case kParserNeedPropertyValue: if (!parseKeyValue(_token)) - parserError("Unable to parse key value."); + parserError("Invalid key value."); else _state = kParserNeedPropertyName; diff --git a/common/xmlparser.h b/common/xmlparser.h index 3edc2b31e1..c7f7218857 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -74,6 +74,7 @@ public: struct ParserNode { Common::String name; Common::StringMap values; + bool ignore; }; virtual bool parse(); @@ -103,7 +104,13 @@ protected: * Remember to leave the node stack _UNCHANGED_ in your own function. Removal * of closed keys is done automatically. * - * Return true if the key was properly handled. False otherwise. + * When parsing a key, 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. * See the sample implementation in GUI::ThemeParser. */ virtual bool keyCallback(Common::String keyName) { @@ -120,13 +127,12 @@ protected: * node stack and calls the keyCallback. * There's no reason to overload this. */ - virtual void parseActiveKey(bool closed); + virtual bool parseActiveKey(bool closed); /** * Prints an error message when parsing fails and stops the parser. - * TODO: More descriptive error messages. */ - virtual void parserError(const char *errorString); + virtual void parserError(const char *errorString, ...); /** * Skips spaces/whitelines etc. Returns true if any spaces were skipped. @@ -163,7 +169,7 @@ protected: if (_text[_pos] == '/' && _text[_pos + 1] == '/') { _pos += 2; - while (_text[_pos] && _text[_pos] != '\n') + while (_text[_pos] && _text[_pos] != '\n' && _text[_pos] != '\r') _pos++; return true; } @@ -194,6 +200,7 @@ protected: int _pos; /** Current position on the XML buffer. */ char *_text; /** Buffer with the text being parsed */ + char *_fileName; ParserState _state; /** Internal state of the parser */ -- cgit v1.2.3 From f0e63a49e38d635d70869f6eb1cda42c684fee8b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 25 Jun 2008 11:34:58 +0000 Subject: - Reverted getHostPlatformString() from util.cpp (Yeah, Max was right) - XMLParser now supports streams! - Added remaining key values for DrawStep parsing. - XMLParser parserError() bugfixes. svn-id: r32782 --- common/xmlparser.cpp | 51 +++++++++++++++++++++++---------------------------- common/xmlparser.h | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 30 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index de10269cdb..4c2c4b58f1 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -36,12 +36,13 @@ using namespace Graphics; void XMLParser::debug_testEval() { static const char *debugConfigText = - "\n" - "\n" - "//\n" - "/* lol this is just a simple test*/\n"; + "\n" + "\n" + "\n" + "/* lol this is just a simple test*/\n" + "I loled"; - _text = strdup(debugConfigText); + _text.fillFromMem(strdup(debugConfigText)); _fileName = strdup("test_parse.xml"); Common::String test = "12, 125, 125"; @@ -50,48 +51,42 @@ void XMLParser::debug_testEval() { } -void XMLParser::parserError(const char *error_string, ...) { +void XMLParser::parserError(const char *errorString, ...) { _state = kParserError; int pos = _pos; - int line_count = 1; - int line_start = -1; - int line_width = 1; + int lineCount = 1; + int lineStart = -1; do { if (_text[pos] == '\n' || _text[pos] == '\r') { - line_count++; + lineCount++; - if (line_start == -1) - line_start = pos; + if (lineStart == -1) + lineStart = MAX(pos + 1, _pos - 60); } } while (pos-- > 0); - line_start = MAX(line_start, _pos - 80); + char lineStr[70]; + _text.stream()->seek(lineStart, SEEK_SET); + _text.stream()->readLine(lineStr, 70); - do { - if (_text[line_start + line_width] == '\n' || _text[line_start + line_width] == '\r') - break; - } while (_text[line_start + line_width++]); - - line_width = MIN(line_width, 80); - - char linestr[81]; - strncpy(linestr, &_text[line_start] + 1, line_width ); - linestr[line_width - 1] = 0; + printf(" File <%s>, line %d:\n", _fileName, lineCount); - printf(" File <%s>, line %d:\n", _fileName, line_count); + printf("%s%s%s\n", + lineStr[0] == '<' ? "" : "...", + lineStr[strlen(lineStr) - 1] == '>' ? "" : "...", + lineStr); - printf("%s\n", linestr); - for (int i = 1; i < _pos - line_start; ++i) + for (int i = 0; i < _pos - lineStart + 3; ++i) printf(" "); printf("^\n"); printf("Parser error: "); va_list args; - va_start(args, error_string); - vprintf(error_string, args); + va_start(args, errorString); + vprintf(errorString, args); va_end(args); printf("\n"); diff --git a/common/xmlparser.h b/common/xmlparser.h index c7f7218857..d7d929cb9a 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -30,6 +30,7 @@ #include "graphics/surface.h" #include "common/system.h" #include "common/xmlparser.h" +#include "common/stream.h" #include "common/hashmap.h" #include "common/hash-str.h" @@ -37,6 +38,43 @@ namespace Common { +class XMLStream { +protected: + SeekableReadStream *_stream; + int _pos; + +public: + XMLStream() : _stream(0), _pos(0) {} + + ~XMLStream() { + delete _stream; + } + + SeekableReadStream *stream() { + return _stream; + } + + const char operator [](int idx) { + assert(_stream && idx >= 0); + + if (_pos + 1 != idx) + _stream->seek(idx, SEEK_SET); + + _pos = idx; + + return _stream->readSByte(); + } + + void fillFromMem(const char *buffer, bool dispose = false) { + delete _stream; + _stream = new MemoryReadStream((const byte*)buffer, strlen(buffer), dispose); + } + + void fillFromFile(const char *filename) { + + } +}; + /** * The base XMLParser class implements generic functionality for parsing * XML-like files. @@ -132,7 +170,7 @@ protected: /** * Prints an error message when parsing fails and stops the parser. */ - virtual void parserError(const char *errorString, ...); + virtual void parserError(const char *errorString, ...) GCC_PRINTF(1, 2); /** * Skips spaces/whitelines etc. Returns true if any spaces were skipped. @@ -199,7 +237,7 @@ protected: } int _pos; /** Current position on the XML buffer. */ - char *_text; /** Buffer with the text being parsed */ + XMLStream _text; /** Buffer with the text being parsed */ char *_fileName; ParserState _state; /** Internal state of the parser */ -- cgit v1.2.3 From 2fcbb970056c9b596699f22d949fe17f9df791d3 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 25 Jun 2008 14:19:56 +0000 Subject: XMLParser: - Cleanup. - Support for file/buffer loading. ThemeParser: - Triangle orientation. svn-id: r32784 --- common/xmlparser.cpp | 17 +++++++---------- common/xmlparser.h | 33 +++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 18 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 4c2c4b58f1..bb8754d480 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -42,16 +42,14 @@ void XMLParser::debug_testEval() { "/* lol this is just a simple test*/\n" "I loled"; - _text.fillFromMem(strdup(debugConfigText)); + loadBuffer(debugConfigText); _fileName = strdup("test_parse.xml"); - Common::String test = "12, 125, 125"; - parse(); } -void XMLParser::parserError(const char *errorString, ...) { +bool XMLParser::parserError(const char *errorString, ...) { _state = kParserError; int pos = _pos; @@ -90,6 +88,8 @@ void XMLParser::parserError(const char *errorString, ...) { va_end(args); printf("\n"); + + return false; } bool XMLParser::parseActiveKey(bool closed) { @@ -248,14 +248,11 @@ bool XMLParser::parse() { } } - if (_state == kParserError) { + if (_state == kParserError) return false; - } - if (_state != kParserNeedKey || !_activeKey.empty()) { - parserError("Unexpected end of file."); - return false; - } + if (_state != kParserNeedKey || !_activeKey.empty()) + return parserError("Unexpected end of file."); return true; } diff --git a/common/xmlparser.h b/common/xmlparser.h index d7d929cb9a..5b03f54b9d 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -31,6 +31,7 @@ #include "common/system.h" #include "common/xmlparser.h" #include "common/stream.h" +#include "common/file.h" #include "common/hashmap.h" #include "common/hash-str.h" @@ -65,13 +66,9 @@ public: return _stream->readSByte(); } - void fillFromMem(const char *buffer, bool dispose = false) { + void loadStream(SeekableReadStream *stream) { delete _stream; - _stream = new MemoryReadStream((const byte*)buffer, strlen(buffer), dispose); - } - - void fillFromFile(const char *filename) { - + _stream = stream; } }; @@ -94,7 +91,10 @@ public: */ XMLParser() {} - virtual ~XMLParser() {} + virtual ~XMLParser() { + while (!_activeKey.empty()) + delete _activeKey.pop(); + } /** Active state for the parser */ enum ParserState { @@ -115,6 +115,21 @@ public: bool ignore; }; + virtual bool loadFile(const char *filename) { + Common::File *f = new Common::File; + + if (!f->open(filename, Common::File::kFileReadMode)) + return false; + + _text.loadStream(f); + return true; + } + + virtual bool loadBuffer(const char *buffer, bool disposable = false) { + _text.loadStream(new MemoryReadStream((const byte*)buffer, strlen(buffer), disposable)); + return true; + } + virtual bool parse(); void debug_testEval(); @@ -169,8 +184,10 @@ protected: /** * 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 void parserError(const char *errorString, ...) GCC_PRINTF(1, 2); + virtual bool parserError(const char *errorString, ...) GCC_PRINTF(1, 2); /** * Skips spaces/whitelines etc. Returns true if any spaces were skipped. -- cgit v1.2.3 From 917b750839282f768178d8436d54deda3078a1f6 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 25 Jun 2008 17:56:00 +0000 Subject: XMLParser: - Bug fixes. ThemeParser: - Support for palette colors. - Expanded theme syntax. svn-id: r32787 --- common/xmlparser.cpp | 40 +++++++++++++++++++++++++--------------- common/xmlparser.h | 12 ++++++++++-- 2 files changed, 35 insertions(+), 17 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index bb8754d480..b2178afbd0 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -36,14 +36,18 @@ using namespace Graphics; void XMLParser::debug_testEval() { static const char *debugConfigText = - "\n" - "\n" - "\n" - "/* lol this is just a simple test*/\n" - "I loled"; + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "/* lol this is just a simple test*/\n" + ""; loadBuffer(debugConfigText); - _fileName = strdup("test_parse.xml"); + _fileName = "test_parse.xml"; parse(); } @@ -54,13 +58,13 @@ bool XMLParser::parserError(const char *errorString, ...) { int pos = _pos; int lineCount = 1; - int lineStart = -1; + int lineStart = 0; do { if (_text[pos] == '\n' || _text[pos] == '\r') { lineCount++; - if (lineStart == -1) + if (lineStart == 0) lineStart = MAX(pos + 1, _pos - 60); } } while (pos-- > 0); @@ -69,14 +73,17 @@ bool XMLParser::parserError(const char *errorString, ...) { _text.stream()->seek(lineStart, SEEK_SET); _text.stream()->readLine(lineStr, 70); - printf(" File <%s>, line %d:\n", _fileName, lineCount); + printf(" File <%s>, line %d:\n", _fileName.c_str(), lineCount); - printf("%s%s%s\n", - lineStr[0] == '<' ? "" : "...", - lineStr[strlen(lineStr) - 1] == '>' ? "" : "...", - lineStr); + bool startFull = lineStr[0] == '<'; + bool endFull = lineStr[strlen(lineStr) - 1] == '>'; - for (int i = 0; i < _pos - lineStart + 3; ++i) + printf("%s%s%s\n", startFull ? "" : "...", endFull ? "" : "...", lineStr); + + if (!startFull) + lineStart -= 3; + + for (int i = 0; i < _pos - lineStart; ++i) printf(" "); printf("^\n"); @@ -185,12 +192,15 @@ bool XMLParser::parse() { } if (activeClosure) { - if (_activeKey.empty() || _token != _activeKey.top()->name) + if (_activeKey.empty() || _token != _activeKey.top()->name) { parserError("Unexpected closure."); + break; + } } else { ParserNode *node = new ParserNode; node->name = _token; node->ignore = false; + node->depth = _activeKey.size(); _activeKey.push(node); } diff --git a/common/xmlparser.h b/common/xmlparser.h index 5b03f54b9d..548b9cf3e2 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -113,6 +113,7 @@ public: Common::String name; Common::StringMap values; bool ignore; + int depth; }; virtual bool loadFile(const char *filename) { @@ -137,13 +138,20 @@ public: * Returns the active node being parsed (the one on top of * the node stack). */ - ParserNode *activeNode() { + ParserNode *getActiveNode() { if (!_activeKey.empty()) return _activeKey.top(); return 0; } + /** + * Returns the parent of a given node in the stack. + */ + ParserNode *getParentNode(ParserNode *child) { + return child->depth > 0 ? _activeKey[child->depth - 1] : 0; + } + protected: /** * The keycallback function must be overloaded by inheriting classes @@ -255,7 +263,7 @@ protected: int _pos; /** Current position on the XML buffer. */ XMLStream _text; /** Buffer with the text being parsed */ - char *_fileName; + Common::String _fileName; ParserState _state; /** Internal state of the parser */ -- cgit v1.2.3 From 7fd6b3916fce8a61b2235ad720bd7fa7b40a7914 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 25 Jun 2008 18:11:17 +0000 Subject: GCC Fixes svn-id: r32788 --- common/xmlparser.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 548b9cf3e2..bfbc03b97b 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -66,9 +66,9 @@ public: return _stream->readSByte(); } - void loadStream(SeekableReadStream *stream) { + void loadStream(SeekableReadStream *s) { delete _stream; - _stream = stream; + _stream = s; } }; @@ -195,7 +195,7 @@ protected: * 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(1, 2); + virtual bool parserError(const char *errorString, ...) GCC_PRINTF(2, 3); /** * Skips spaces/whitelines etc. Returns true if any spaces were skipped. -- cgit v1.2.3 From 73d5715a799f393e8b2611f2deff1b7f90f6130a Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 25 Jun 2008 22:30:28 +0000 Subject: - XMLParser: Improved file stream support - InterfaceManager: Config file loading/parsing added. - ThemeParser: Fixed GCC warnings/various bugs. svn-id: r32792 --- common/xmlparser.cpp | 3 +++ common/xmlparser.h | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index b2178afbd0..6cb3a8a441 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -148,6 +148,9 @@ bool XMLParser::parseKeyValue(Common::String keyName) { bool XMLParser::parse() { + if (_text.ready() == false) + return parserError("XML stream not ready for reading."); + bool activeClosure = false; bool selfClosure = false; diff --git a/common/xmlparser.h b/common/xmlparser.h index bfbc03b97b..3eb87efd31 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -70,6 +70,10 @@ public: delete _stream; _stream = s; } + + bool ready() { + return _stream != 0; + } }; /** @@ -116,7 +120,7 @@ public: int depth; }; - virtual bool loadFile(const char *filename) { + virtual bool loadFile(Common::String filename) { Common::File *f = new Common::File; if (!f->open(filename, Common::File::kFileReadMode)) -- cgit v1.2.3 From 3ae28530ef1807d3b99c462ab3f53acbe3153b12 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 26 Jun 2008 09:18:41 +0000 Subject: Actually reverted stupid changes in Common::String and Util.cpp regarding Regex and the platform function. svn-id: r32797 --- common/str.cpp | 99 --------------------------------------------------------- common/str.h | 17 ---------- common/util.cpp | 29 ----------------- common/util.h | 7 ---- 4 files changed, 152 deletions(-) (limited to 'common') diff --git a/common/str.cpp b/common/str.cpp index e849cb042d..ad48ef6087 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -283,105 +283,6 @@ void String::toUppercase() { _str[i] = toupper(_str[i]); } -bool String::regexMatch(const char *regex, bool skipSpaces) { - int pos = 0; - - if (regex[0] == '^') - return regexMatchPos(1, regex, 1, skipSpaces); - - do { - if (regexMatchPos(pos, regex, 0, skipSpaces)) - return true; - } while (_str[pos++]); - - return false; -} - -bool String::regexMatchCharacter(RegexMatchType type, char regexChar, char strChar) { - switch (type) { - case kRegexMatchAny: - return true; - - case kRegexMatchDigit: - return isdigit(strChar) != 0; - - case kRegexMatchSpace: - return isspace(strChar) != 0; - - case kRegexMatchAlphanum: - return isalnum(strChar) != 0; - - case kRegexMatchAlpha: - return isalpha(strChar) != 0; - - case kRegexMatchWord: - return isalnum(strChar) != 0 || strChar == '_'; - - case kRegexMatchCharacter: - return regexChar == strChar; - - default: - return false; - } -} - -bool String::regexMatchStar(RegexMatchType type, char regexChar, const char *regex, int regexPos, int strPos, bool skipSpaces) { - - do { - if (regexMatchPos(strPos, regex, regexPos, skipSpaces)) - return true; - } while (_str[strPos] && regexMatchCharacter(type, regexChar, _str[strPos++])); - - return false; -} - -bool String::regexMatchPos(int strPos, const char *regex, int regexPos, bool skipSpaces) { - RegexMatchType matchT = kRegexMatchCharacter; - - if (skipSpaces) { - while (isspace(_str[strPos])) - strPos++; - - while (isspace(regex[regexPos])) - regexPos++; - } - - if (regex[regexPos] == '\0') - return true; - - if (regex[regexPos] == '.') - matchT = kRegexMatchAny; - else if (regex[regexPos] == '[') { - String group; - while (regex[regexPos - 1] != ']') - group += regex[regexPos++]; - - regexPos--; - - if (group == "[digit]" || group == "[d]") - matchT = kRegexMatchDigit; - else if (group == "[space]" || group == "[s]") - matchT = kRegexMatchSpace; - else if (group == "[alnum]") - matchT = kRegexMatchAlphanum; - else if (group == "[alpha]") - matchT = kRegexMatchAlpha; - else if (group == "[word]") - matchT = kRegexMatchWord; - } - - if (regex[regexPos + 1] == '*') - return regexMatchStar(matchT, regex[regexPos], regex, regexPos + 2, strPos, skipSpaces); - - if (regex[regexPos] == '$' && regex[regexPos + 1] == 0) - return _str[strPos] == 0; - - if (_str[strPos] && regexMatchCharacter(matchT, regex[regexPos], _str[strPos])) - return regexMatchPos(strPos + 1, regex, regexPos + 1, skipSpaces); - - return false; -} - /** * Ensure that enough storage is available to store at least new_len * characters plus a null byte. In addition, if we currently share diff --git a/common/str.h b/common/str.h index 2ea151ba96..a92ec34fff 100644 --- a/common/str.h +++ b/common/str.h @@ -165,9 +165,6 @@ public: uint hash() const; - // Tanoku: Regular expression support for the String class - bool regexMatch(const char *regex, bool skipSpaces = false); - public: typedef char * iterator; typedef const char * const_iterator; @@ -192,20 +189,6 @@ protected: void ensureCapacity(uint32 new_len, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); - - enum RegexMatchType { - kRegexMatchAny, - kRegexMatchDigit, - kRegexMatchSpace, - kRegexMatchAlphanum, - kRegexMatchAlpha, - kRegexMatchWord, - kRegexMatchCharacter - }; - - bool regexMatchStar(RegexMatchType type, char regexChar, const char *regex, int regexPos, int strPos, bool skipSpaces); - bool regexMatchCharacter(RegexMatchType type, char regexChar, char strChar); - bool regexMatchPos(int strPos, const char *regex, int regexPos, bool skipSpaces); }; // Append two strings to form a new (temp) string diff --git a/common/util.cpp b/common/util.cpp index 51bd8bcad6..6f0fdcb233 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -481,34 +481,6 @@ uint32 getEnabledSpecialDebugLevels() { return gDebugLevelsEnabled; } -const char *getHostPlatformString() { - -#if defined(__SYMBIAN32__) - return "symbian"; -#elif defined(_WIN32_WCE) || defined(_MSC_VER) || defined(__MINGW32__) || defined(UNIX) - return "pc"; -#elif defined(__PALMOS_TRAPS__) || defined (__PALMOS_ARMLET__) - return "palmos"; -#elif defined(__DC__) - return "dc"; -#elif defined(__GP32__) - return "gp32"; -#elif defined(__PLAYSTATION2__) - return "ps2"; -#elif defined(__PSP__) - return "psp"; -#elif defined(__amigaos4__) - return "amigaos"; -#elif defined (__DS__) //NeilM - return "nds"; -#elif defined(__WII__) - return "wii"; -#else - return ""; -#endif - -} - } // End of namespace Common @@ -722,4 +694,3 @@ Common::String tag2string(uint32 tag) { str[4] = '\0'; return Common::String(str); } - diff --git a/common/util.h b/common/util.h index c4cbf35212..c23513596c 100644 --- a/common/util.h +++ b/common/util.h @@ -323,13 +323,6 @@ const DebugLevelContainer &listSpecialDebugLevels(); uint32 getEnabledSpecialDebugLevels(); -/** - * Return a string containing the name of the currently running host. - * E.g. returns "wii" if ScummVM is being run in a Wii, and so on. - */ -const char *getHostPlatformString(); - - } // End of namespace Common -- cgit v1.2.3 From 0cd183b94b7d24f9df8453ee126bceddc1dfd857 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 26 Jun 2008 13:50:16 +0000 Subject: InterfaceManager now loads themes. svn-id: r32800 --- common/xmlparser.cpp | 19 ------------------- common/xmlparser.h | 24 +++++++++++++++++++++++- 2 files changed, 23 insertions(+), 20 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 6cb3a8a441..22b8b22e48 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -34,25 +34,6 @@ namespace Common { using namespace Graphics; -void XMLParser::debug_testEval() { - static const char *debugConfigText = - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "/* lol this is just a simple test*/\n" - ""; - - loadBuffer(debugConfigText); - _fileName = "test_parse.xml"; - - parse(); -} - - bool XMLParser::parserError(const char *errorString, ...) { _state = kParserError; diff --git a/common/xmlparser.h b/common/xmlparser.h index 3eb87efd31..4c8e1b986f 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -120,23 +120,45 @@ public: int depth; }; + /** + * Loads a file into the parser. + * Used for the loading of Theme Description files + * straight from the filesystem. + * + * @param filename Name of the file to load. + */ virtual bool loadFile(Common::String filename) { Common::File *f = new Common::File; if (!f->open(filename, Common::File::kFileReadMode)) return false; + _fileName = filename; _text.loadStream(f); return true; } + /** + * Loads a memory buffer into the parser. + * Used for loading the default theme fallback directly + * from memory if no themes can be found. + * + * @param buffer Pointer to the buffer. + * @param disposable Sets if the XMLParser owns the buffer, + * i.e. if it can be freed safely after it's + * no longer needed by the parser. + */ virtual bool loadBuffer(const char *buffer, bool disposable = false) { _text.loadStream(new MemoryReadStream((const byte*)buffer, strlen(buffer), disposable)); + _fileName = "Memory Stream"; return true; } + /** + * The actual parsing function. + * Parses the loaded data stream, returns true if successful. + */ virtual bool parse(); - void debug_testEval(); /** * Returns the active node being parsed (the one on top of -- cgit v1.2.3 From 5534ce68a17aeeb0e1dff74297d85ff7af1b9f9e Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 26 Jun 2008 19:54:55 +0000 Subject: - MILESTONE: A widget is drawn on screen loaded straight from its XML description. Yippie. - XMLParser: Bugfixes. - ThemeParser: Support for default color values. svn-id: r32808 --- common/xmlparser.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 22b8b22e48..8ff93a4c59 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -61,10 +61,12 @@ bool XMLParser::parserError(const char *errorString, ...) { printf("%s%s%s\n", startFull ? "" : "...", endFull ? "" : "...", lineStr); + int cursor = MIN(_pos - lineStart, 70); + if (!startFull) - lineStart -= 3; + cursor += 3; - for (int i = 0; i < _pos - lineStart; ++i) + while (cursor--) printf(" "); printf("^\n"); -- cgit v1.2.3 From 3f0f7fa08bea272fa61b0fde5d7783aa44b1ff25 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 28 Jun 2008 00:02:54 +0000 Subject: Improved support for parsing integers in the XML parser. Bug fixes. svn-id: r32818 --- common/xmlparser.h | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 4c8e1b986f..c3cdbc3e02 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -55,7 +55,7 @@ public: return _stream; } - const char operator [](int idx) { + char operator [](int idx) { assert(_stream && idx >= 0); if (_pos + 1 != idx) @@ -287,6 +287,51 @@ protected: return isspace(_text[_pos]) != 0 || _text[_pos] == '>'; } + /** + * Parses the values inside an integer key. + * The count parameter specifies the number of values inside + * the key, which are expected to be separated with commas. + * + * Sample usage: + * parseIntegerKey("255, 255, 255", 3, &red, &green, &blue); + * [will parse each field into its own integer] + * + * parseIntegerKey("1234", 1, &number); + * [will parse the single number into the variable] + * + * @param key String containing the integers to be parsed. + * @param count Number of comma-separated ints in the string. + * @param ... Integer variables to store the parsed ints, passed + * by reference. + * @returns True if the parsing succeeded. + */ + virtual bool parseIntegerKey(const char *key, int count, ...) { + char *parseEnd = 0; + int *num_ptr; + + va_list args; + va_start(args, count); + + while (count--) { + while (isspace(*key)) + key++; + + num_ptr = va_arg(args, int*); + *num_ptr = strtol(key, &parseEnd, 10); + + while (isspace(*parseEnd)) + parseEnd++; + + if (count && *parseEnd++ != ',') + return false; + + key = parseEnd; + } + + va_end(args); + return (*parseEnd == 0); + } + int _pos; /** Current position on the XML buffer. */ XMLStream _text; /** Buffer with the text being parsed */ Common::String _fileName; -- cgit v1.2.3 From 2f5319e7507d1ac5733a7d0a5b9021465c7eda19 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 28 Jun 2008 13:44:10 +0000 Subject: Bugfix: Empty integer key parsing. svn-id: r32822 --- common/xmlparser.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index c3cdbc3e02..4850dc5113 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -306,7 +306,7 @@ protected: * @returns True if the parsing succeeded. */ virtual bool parseIntegerKey(const char *key, int count, ...) { - char *parseEnd = 0; + char *parseEnd; int *num_ptr; va_list args; @@ -319,17 +319,17 @@ protected: num_ptr = va_arg(args, int*); *num_ptr = strtol(key, &parseEnd, 10); - while (isspace(*parseEnd)) - parseEnd++; + key = parseEnd; - if (count && *parseEnd++ != ',') - return false; + while (isspace(*key)) + key++; - key = parseEnd; + if (count && *key++ != ',') + return false; } va_end(args); - return (*parseEnd == 0); + return (*key == 0); } int _pos; /** Current position on the XML buffer. */ -- cgit v1.2.3 From 48fd843e759ab3a8a23ba2be902a8a815a41e8f8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 3 Jul 2008 10:26:55 +0000 Subject: Rendering pipeline. WIP. svn-id: r32882 --- common/xmlparser.cpp | 2 ++ common/xmlparser.h | 8 ++++++++ 2 files changed, 10 insertions(+) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 8ff93a4c59..3452db9e00 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -134,6 +134,8 @@ bool XMLParser::parse() { if (_text.ready() == false) return parserError("XML stream not ready for reading."); + cleanup(); + bool activeClosure = false; bool selfClosure = false; diff --git a/common/xmlparser.h b/common/xmlparser.h index 4850dc5113..d31c69ebee 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -332,6 +332,14 @@ protected: return (*key == 0); } + /** + * Internal state cleanup. Overload this if your parser needs + * to clean itself up before doing a second parse. + * E.g. the Theme Parser cleans the color palette after parsing + * a theme. + */ + virtual void cleanup() {} + int _pos; /** Current position on the XML buffer. */ XMLStream _text; /** Buffer with the text being parsed */ Common::String _fileName; -- cgit v1.2.3 From 52aba6b6daa020808f2b124ac83cf7d8fffa0ed4 Mon Sep 17 00:00:00 2001 From: Stephen Kennedy Date: Thu, 3 Jul 2008 16:09:54 +0000 Subject: changed loadBuffer to use byte* rather than char* svn-id: r32894 --- common/xmlparser.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index d31c69ebee..94512c3ab7 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -144,12 +144,13 @@ public: * from memory if no themes can be found. * * @param buffer Pointer to the buffer. + * @param size Size of the buffer * @param disposable Sets if the XMLParser owns the buffer, * i.e. if it can be freed safely after it's * no longer needed by the parser. */ - virtual bool loadBuffer(const char *buffer, bool disposable = false) { - _text.loadStream(new MemoryReadStream((const byte*)buffer, strlen(buffer), disposable)); + virtual bool loadBuffer(const byte *buffer, uint32 size, bool disposable = false) { + _text.loadStream(new MemoryReadStream(buffer, size, disposable)); _fileName = "Memory Stream"; return true; } -- cgit v1.2.3 From 919d81f03be0d3f03cb1fdca0735a9b3ae563af2 Mon Sep 17 00:00:00 2001 From: Stephen Kennedy Date: Thu, 3 Jul 2008 19:32:57 +0000 Subject: Changed XMLParser to internally use a Stack rather than a FixedStack svn-id: r32897 --- common/xmlparser.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 94512c3ab7..fa1f10061a 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -86,8 +86,6 @@ public: * @see XMLParser::keyCallback() */ class XMLParser { - /** Maximum depth for nested keys that the parser supports */ - static const int kParserMaxDepth = 4; public: /** @@ -333,14 +331,6 @@ protected: return (*key == 0); } - /** - * Internal state cleanup. Overload this if your parser needs - * to clean itself up before doing a second parse. - * E.g. the Theme Parser cleans the color palette after parsing - * a theme. - */ - virtual void cleanup() {} - int _pos; /** Current position on the XML buffer. */ XMLStream _text; /** Buffer with the text being parsed */ Common::String _fileName; @@ -350,7 +340,7 @@ protected: Common::String _error; /** Current error message */ Common::String _token; /** Current text token */ - Common::FixedStack _activeKey; /** Node stack of the parsed keys */ + Common::Stack _activeKey; /** Node stack of the parsed keys */ }; } -- cgit v1.2.3 From 8240e5b96d072fda2f84abdf84c27cf90ee891a5 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 3 Jul 2008 19:42:04 +0000 Subject: Rendering pipeline. WIP. (I see working buttons) svn-id: r32898 --- common/xmlparser.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index fa1f10061a..167d04249c 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -63,7 +63,7 @@ public: _pos = idx; - return _stream->readSByte(); + return _stream->readByte(); } void loadStream(SeekableReadStream *s) { @@ -331,6 +331,13 @@ protected: return (*key == 0); } + /** + * Overload if your parser needs to support parsing the same file + * several times, so you can clean up the internal state of the + * parser before each parse. + */ + virtual void cleanup() {} + int _pos; /** Current position on the XML buffer. */ XMLStream _text; /** Buffer with the text being parsed */ Common::String _fileName; -- cgit v1.2.3 From 3b73b199a6006a84df06453335354e4e6728f6af Mon Sep 17 00:00:00 2001 From: Stephen Kennedy Date: Fri, 4 Jul 2008 11:56:31 +0000 Subject: - XMLParser - small improvement to allow "key=value" syntax as well as "key = value" syntax svn-id: r32906 --- common/xmlparser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 167d04249c..3738b69b7b 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -283,7 +283,7 @@ protected: while (isValidNameChar(_text[_pos])) _token += _text[_pos++]; - return isspace(_text[_pos]) != 0 || _text[_pos] == '>'; + return isspace(_text[_pos]) != 0 || _text[_pos] == '>' || _text[_pos] == '='; } /** -- cgit v1.2.3 From 96f2d9ca18eea27eaffda76fbce2168cddebbfb1 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 4 Jul 2008 20:05:30 +0000 Subject: Memory leaks. Bug fixes. svn-id: r32908 --- common/xmlparser.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 3452db9e00..d5c8535932 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -143,10 +143,7 @@ bool XMLParser::parse() { _pos = 0; _activeKey.clear(); - while (_text[_pos]) { - if (_state == kParserError) - break; - + while (_text[_pos] && _state != kParserError) { if (skipSpaces()) continue; -- cgit v1.2.3 From 40bf717d3ba7974d95414bf8c8cf1abe34de288d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 4 Jul 2008 23:51:23 +0000 Subject: closedKeyCallback on XMLParser (as asked by Kenny) svn-id: r32909 --- common/xmlparser.cpp | 5 +++++ common/xmlparser.h | 14 ++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index d5c8535932..d0c89a9d3e 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -194,6 +194,11 @@ bool XMLParser::parse() { case kParserNeedPropertyName: if (activeClosure) { + if (!closedKeyCallback(_activeKey.top()->name)) { + parserError("Missing data when closing key '%s'.", _activeKey.top()->name.c_str()); + break; + } + activeClosure = false; delete _activeKey.pop(); diff --git a/common/xmlparser.h b/common/xmlparser.h index 3738b69b7b..4c77696482 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -203,6 +203,20 @@ protected: return false; } + /** + * The closed key callback function must be overloaded by inheriting classes to + * implement parser-specific functions. + * + * The closedKeyCallback is issued once a key has been finished parsing, to let + * the parser verify that all the required subkeys, etc, were included. + * + * Returns true if the key was properly closed, false otherwise. + * By default, all keys are properly closed. + */ + virtual bool closedKeyCallback(Common::String keyName) { + return true; + } + /** * Parses the value of a given key. There's no reason to overload this. */ -- cgit v1.2.3 From c5d673801177a6905114f724c229f802ca2756f3 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 22 Jul 2008 20:07:53 +0000 Subject: Dirty rectangle handling, round four. :/ svn-id: r33216 --- common/rect.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'common') diff --git a/common/rect.h b/common/rect.h index f71124434a..01a0a0d431 100644 --- a/common/rect.h +++ b/common/rect.h @@ -124,6 +124,16 @@ struct Rect { return contains(p.x, p.y); } + /*! @brief check if the given rect is _fully_ contained inside this rectangle + + @param r The rectangle to check + + @retur true if the given rect is inside, false otherwise + */ + bool contains(const Rect &r) const { + return (left < r.left) && (right > r.right) && (top < r.top) && (bottom > r.bottom); + } + /*! @brief check if given rectangle intersects with this rectangle @param r the rectangle to check -- cgit v1.2.3 From e7959952bbd2256fc83f0ca2f1c0b498e313617e Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 30 Jul 2008 13:33:32 +0000 Subject: 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. svn-id: r33447 --- common/xmlparser.cpp | 35 +++++++++- common/xmlparser.h | 186 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 196 insertions(+), 25 deletions(-) (limited to 'common') 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::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: + + + + + + + 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 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 ChildMap; + + /** nested struct representing the layout of the XML file */ + struct XMLKeyLayout { + void *custom; + struct XMLKeyProperty { + Common::String name; + bool required; + }; + + Common::List 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; -- cgit v1.2.3 From f930bbac59c6216169d6cc8b4926792ae4b0e976 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 30 Jul 2008 14:08:07 +0000 Subject: Finished documentation. svn-id: r33449 --- common/xmlparser.h | 89 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 17 deletions(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 221d382a70..8b2d2ee956 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -55,12 +55,14 @@ namespace Common { 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. + 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(). + 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: @@ -101,9 +103,9 @@ namespace Common { 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. + 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: @@ -123,10 +125,55 @@ namespace Common { - TODO: documentation on callbacks + 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. - 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. + 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. + */ #define XML_KEY(keyName) {\ @@ -215,6 +262,8 @@ public: virtual ~XMLParser() { while (!_activeKey.empty()) delete _activeKey.pop(); + + delete _XMLkeys; } /** Active state for the parser */ @@ -243,6 +292,12 @@ public: Common::List properties; ChildMap children; + + ~XMLKeyLayout() { + properties.clear(); + children.clear(); +// delete custom; + } } *_XMLkeys; /** Struct representing a parsed node */ @@ -261,7 +316,7 @@ public: * * @param filename Name of the file to load. */ - virtual bool loadFile(Common::String filename) { + bool loadFile(Common::String filename) { Common::File *f = new Common::File; if (!f->open(filename, Common::File::kFileReadMode)) @@ -283,7 +338,7 @@ public: * i.e. if it can be freed safely after it's * no longer needed by the parser. */ - virtual bool loadBuffer(const byte *buffer, uint32 size, bool disposable = false) { + bool loadBuffer(const byte *buffer, uint32 size, bool disposable = false) { _text.loadStream(new MemoryReadStream(buffer, size, disposable)); _fileName = "Memory Stream"; return true; @@ -293,7 +348,7 @@ public: * The actual parsing function. * Parses the loaded data stream, returns true if successful. */ - virtual bool parse(); + bool parse(); /** * Returns the active node being parsed (the one on top of @@ -378,10 +433,8 @@ protected: /** * Skips spaces/whitelines etc. Returns true if any spaces were skipped. - * Overload this if you want to make your parser depend on newlines or - * whatever. */ - virtual bool skipSpaces() { + bool skipSpaces() { if (!isspace(_text[_pos])) return false; @@ -492,6 +545,8 @@ protected: */ virtual void cleanup() {} + +private: int _pos; /** Current position on the XML buffer. */ XMLStream _text; /** Buffer with the text being parsed */ Common::String _fileName; -- cgit v1.2.3 From e8278c4c6891b8b3b2ef95f2f55e4730d76234ba Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 31 Jul 2008 17:23:38 +0000 Subject: GUI Layout parsing. Work in progress. svn-id: r33475 --- common/xmlparser.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 030b5b9491..89dd5d7e32 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -41,25 +41,34 @@ bool XMLParser::parserError(const char *errorString, ...) { int lineCount = 1; int lineStart = 0; - do { - if (_text[pos] == '\n' || _text[pos] == '\r') { - lineCount++; - - if (lineStart == 0) - lineStart = MAX(pos + 1, _pos - 60); - } - } while (pos-- > 0); + if (_fileName == "Memory Stream") { + lineStart = MAX(0, _pos - 35); + lineCount = 0; + } else { + do { + if (_text[pos] == '\n' || _text[pos] == '\r') { + lineCount++; + + if (lineStart == 0) + lineStart = MAX(pos + 1, _pos - 60); + } + } while (pos-- > 0); + } char lineStr[70]; _text.stream()->seek(lineStart, SEEK_SET); _text.stream()->readLine(lineStr, 70); + + for (int i = 0; i < 70; ++i) + if (lineStr[i] == '\n') + lineStr[i] = ' '; - printf(" File <%s>, line %d:\n", _fileName.c_str(), lineCount); + printf("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount); bool startFull = lineStr[0] == '<'; bool endFull = lineStr[strlen(lineStr) - 1] == '>'; - printf("%s%s%s\n", startFull ? "" : "...", endFull ? "" : "...", lineStr); + printf("%s%s%s\n", startFull ? "" : "...", lineStr, endFull ? "" : "..."); int cursor = MIN(_pos - lineStart, 70); @@ -77,7 +86,7 @@ bool XMLParser::parserError(const char *errorString, ...) { vprintf(errorString, args); va_end(args); - printf("\n"); + printf("\n\n"); return false; } @@ -123,9 +132,8 @@ bool XMLParser::parseActiveKey(bool closed) { return false; } - if (closed) { + if (closed) delete _activeKey.pop(); - } return true; } -- cgit v1.2.3 From 9bd3b07647bfbd5016f06a4f055a4310b3269587 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 1 Aug 2008 10:18:47 +0000 Subject: Support for XML layout with unspecified keys. XML Layout parsing. WIP. svn-id: r33488 --- common/xmlparser.cpp | 2 +- common/xmlparser.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 89dd5d7e32..25c79e65c0 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -112,7 +112,7 @@ bool XMLParser::parseActiveKey(bool closed) { return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str()); } - if (localMap.empty() == false) + if (key->layout.anyProps == false && 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. diff --git a/common/xmlparser.h b/common/xmlparser.h index 11028dbaa8..9308524388 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -108,6 +108,10 @@ namespace Common { 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) @@ -178,6 +182,7 @@ namespace Common { #define XML_KEY(keyName) {\ lay = new XMLKeyLayout; \ + lay->anyProps = false; \ lay->custom = new kLocalParserName::CustomParserCallback; \ ((kLocalParserName::CustomParserCallback*)(lay->custom))->callback = (&kLocalParserName::parserCallback_##keyName); \ layout.top()->children[#keyName] = lay; \ @@ -189,6 +194,9 @@ namespace Common { prop.name = #propName; \ prop.required = req; \ layout.top()->properties.push_back(prop); }\ + +#define XML_PROP_ANY() {\ + layout.top()->anyProps = true; } #define CUSTOM_XML_PARSER(parserName) \ protected: \ @@ -291,6 +299,7 @@ public: }; Common::List properties; + bool anyProps; ChildMap children; ~XMLKeyLayout() { -- cgit v1.2.3 From 262cc33dc7c883e8071e6913f71d02eab443d63c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 1 Aug 2008 10:29:27 +0000 Subject: Fixed compiler problem with anyProp var. svn-id: r33489 --- common/xmlparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 25c79e65c0..5ea10f2278 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -112,7 +112,7 @@ bool XMLParser::parseActiveKey(bool closed) { return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str()); } - if (key->layout.anyProps == false && localMap.empty() == false) + if (key->layout->anyProps == false && 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. -- cgit v1.2.3 From 7cb23c76a267955790fa58380d65fe55b4a5dcd1 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 2 Aug 2008 15:15:32 +0000 Subject: Improved looks on the Modern theme in the new GUI. Added support for including externally the default theme in the code. Added Modern theme as a separate XML file in the themes/ dir. Added "makedeftheme.py" script to convert XML themes into include files. svn-id: r33528 --- common/xmlparser.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 9308524388..031ee2be14 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -471,13 +471,6 @@ protected: return true; } - if (_text[_pos] == '/' && _text[_pos + 1] == '/') { - _pos += 2; - while (_text[_pos] && _text[_pos] != '\n' && _text[_pos] != '\r') - _pos++; - return true; - } - return false; } -- cgit v1.2.3 From 85c36885f5bbf2d47276c7702f1b8ccbf22ecc34 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 4 Aug 2008 16:59:55 +0000 Subject: Theme layout parsing. Work in progress. svn-id: r33613 --- common/xmlparser.cpp | 27 ++++++++++++++------------- common/xmlparser.h | 12 ++++++++++++ 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 5ea10f2278..526e6e6fb1 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -98,22 +98,23 @@ bool XMLParser::parseActiveKey(bool closed) { 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]; + if (layout->children.contains(key->name)) { + key->layout = layout->children[key->name]; - Common::StringMap localMap = key->values; + Common::StringMap localMap = key->values; - for (Common::List::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()); - } + for (Common::List::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 (key->layout->anyProps == false && localMap.empty() == false) - return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str()); + if (key->layout->anyProps == false && localMap.empty() == false) + return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str()); + } else if (layout->anyKeys == false) { + return parserError("Unexpected key in the active scope: '%s'.", key->name.c_str()); + } // check if any of the parents must be ignored. // if a parent is ignored, all children are too. diff --git a/common/xmlparser.h b/common/xmlparser.h index 031ee2be14..0510ec0ab6 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -183,10 +183,16 @@ namespace Common { #define XML_KEY(keyName) {\ lay = new XMLKeyLayout; \ lay->anyProps = false; \ + lay->anyKeys = false; \ lay->custom = new kLocalParserName::CustomParserCallback; \ ((kLocalParserName::CustomParserCallback*)(lay->custom))->callback = (&kLocalParserName::parserCallback_##keyName); \ layout.top()->children[#keyName] = lay; \ layout.push(lay); + +#define XML_KEY_RECURSIVE(keyName) {\ + layout.top()->children[#keyName] = layout.top();\ + layout.push(layout.top());\ + } #define KEY_END() layout.pop(); } @@ -197,6 +203,9 @@ namespace Common { #define XML_PROP_ANY() {\ layout.top()->anyProps = true; } + +#define XML_KEY_ANY() {\ + layout.top()->anyKeys = true; } #define CUSTOM_XML_PARSER(parserName) \ protected: \ @@ -209,6 +218,8 @@ namespace Common { XMLKeyLayout *lay = 0; \ XMLKeyLayout::XMLKeyProperty prop; \ _XMLkeys = new XMLKeyLayout; \ + _XMLkeys->anyProps = false; \ + _XMLkeys->anyKeys = false; \ layout.push(_XMLkeys); #define PARSER_END() layout.clear(); } @@ -300,6 +311,7 @@ public: Common::List properties; bool anyProps; + bool anyKeys; ChildMap children; ~XMLKeyLayout() { -- cgit v1.2.3 From 70ef50343499ee6736389a0cad006ea6eeeca5bd Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 5 Aug 2008 09:54:36 +0000 Subject: Massive refactoring on the layout parsing API. Added support for layout spacings. Fixed bug in theme conversion python script. svn-id: r33630 --- common/xmlparser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index 0510ec0ab6..2f73b5905d 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -504,7 +504,7 @@ protected: while (isValidNameChar(_text[_pos])) _token += _text[_pos++]; - return isspace(_text[_pos]) != 0 || _text[_pos] == '>' || _text[_pos] == '='; + return isspace(_text[_pos]) != 0 || _text[_pos] == '>' || _text[_pos] == '=' || _text[_pos] == '/'; } /** -- cgit v1.2.3 From dab1fa0942cffa82c1944170774b659b8bcfb6b2 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 8 Aug 2008 18:30:16 +0000 Subject: Resolution-dependence in XML files. G1X scaler GUI now loads. Added layout for the launcher menu. MILESTONE: All core GUI dialogs/widgets working on G2x/G3x MILESTONE: Completely removed old Evaluator/Parser. Improved layout expanding again. Improved XML parser. Several bugfixes. svn-id: r33704 --- common/xmlparser.cpp | 5 +++-- common/xmlparser.h | 24 ++++++++++-------------- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 526e6e6fb1..b845f7f66f 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -110,9 +110,10 @@ bool XMLParser::parseActiveKey(bool closed) { return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str()); } - if (key->layout->anyProps == false && localMap.empty() == false) + if (localMap.empty() == false) return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str()); - } else if (layout->anyKeys == false) { + + } else { return parserError("Unexpected key in the active scope: '%s'.", key->name.c_str()); } diff --git a/common/xmlparser.h b/common/xmlparser.h index 2f73b5905d..e26ea1eb53 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -182,12 +182,12 @@ namespace Common { #define XML_KEY(keyName) {\ lay = new XMLKeyLayout; \ - lay->anyProps = false; \ - lay->anyKeys = false; \ lay->custom = new kLocalParserName::CustomParserCallback; \ ((kLocalParserName::CustomParserCallback*)(lay->custom))->callback = (&kLocalParserName::parserCallback_##keyName); \ layout.top()->children[#keyName] = lay; \ - layout.push(lay); + layout.push(lay); \ + for (Common::List::const_iterator p = globalProps.begin(); p != globalProps.end(); ++p){\ + layout.top()->properties.push_back(*p);} #define XML_KEY_RECURSIVE(keyName) {\ layout.top()->children[#keyName] = layout.top();\ @@ -199,13 +199,13 @@ namespace Common { #define XML_PROP(propName, req) {\ prop.name = #propName; \ prop.required = req; \ - layout.top()->properties.push_back(prop); }\ + layout.top()->properties.push_back(prop); } + +#define XML_GLOBAL_PROP(propName, req) {\ + prop.name = #propName; \ + prop.required = req;\ + globalProps.push_back(prop); } -#define XML_PROP_ANY() {\ - layout.top()->anyProps = true; } - -#define XML_KEY_ANY() {\ - layout.top()->anyKeys = true; } #define CUSTOM_XML_PARSER(parserName) \ protected: \ @@ -217,9 +217,8 @@ namespace Common { Common::Stack layout; \ XMLKeyLayout *lay = 0; \ XMLKeyLayout::XMLKeyProperty prop; \ + Common::List globalProps; \ _XMLkeys = new XMLKeyLayout; \ - _XMLkeys->anyProps = false; \ - _XMLkeys->anyKeys = false; \ layout.push(_XMLkeys); #define PARSER_END() layout.clear(); } @@ -310,14 +309,11 @@ public: }; Common::List properties; - bool anyProps; - bool anyKeys; ChildMap children; ~XMLKeyLayout() { properties.clear(); children.clear(); -// delete custom; } } *_XMLkeys; -- cgit v1.2.3 From f546aa9dc8d3bc811a4a356271022c29d121711d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 8 Aug 2008 18:48:12 +0000 Subject: BUGFIX: XMLParser issuing key-close callbacks on ignored keys. svn-id: r33706 --- common/xmlparser.cpp | 22 +++++++++++++++++++--- common/xmlparser.h | 9 +++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index b845f7f66f..6c6bc4b7f8 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -135,7 +135,7 @@ bool XMLParser::parseActiveKey(bool closed) { } if (closed) - delete _activeKey.pop(); + return closeKey(); return true; } @@ -166,6 +166,23 @@ bool XMLParser::parseKeyValue(Common::String keyName) { return true; } +bool XMLParser::closeKey() { + bool ignore = false; + bool result = true; + + for (int i = _activeKey.size() - 1; i >= 0; --i) { + if (_activeKey[i]->ignore) + ignore = true; + } + + if (ignore == false) + result = closedKeyCallback(_activeKey.top()); + + delete _activeKey.pop(); + + return result; +} + bool XMLParser::parse() { if (_text.ready() == false) @@ -235,13 +252,12 @@ bool XMLParser::parse() { case kParserNeedPropertyName: if (activeClosure) { - if (!closedKeyCallback(_activeKey.top())) { + if (!closeKey()) { parserError("Missing data when closing key '%s'.", _activeKey.top()->name.c_str()); break; } activeClosure = false; - delete _activeKey.pop(); if (_text[_pos++] != '>') parserError("Invalid syntax in key closure."); diff --git a/common/xmlparser.h b/common/xmlparser.h index e26ea1eb53..d1abd321e7 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -423,12 +423,21 @@ protected: * The closedKeyCallback is issued once a key has been finished parsing, to let * the parser verify that all the required subkeys, etc, were included. * + * Unlike the keyCallbacks(), there's just a closedKeyCallback() for all keys. + * Use "node->name" to distinguish between each key type. + * * Returns true if the key was properly closed, false otherwise. * By default, all keys are properly closed. */ virtual bool closedKeyCallback(ParserNode *node) { return true; } + + /** + * Called when a node is closed. Manages its cleanup and calls the + * closing callback function if needed. + */ + bool closeKey(); /** * Parses the value of a given key. There's no reason to overload this. -- cgit v1.2.3 From ea69217a136210347689e9536d67e1dda883f45a Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 9 Aug 2008 14:15:34 +0000 Subject: Fixed 1.000.000 Valgrind warnings. svn-id: r33711 --- common/xmlparser.cpp | 3 +++ common/xmlparser.h | 42 +++++++++++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 15 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 6c6bc4b7f8..900f2f81ab 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -191,6 +191,9 @@ bool XMLParser::parse() { if (_XMLkeys == 0) buildLayout(); + while (!_activeKey.empty()) + delete _activeKey.pop(); + cleanup(); bool activeClosure = false; diff --git a/common/xmlparser.h b/common/xmlparser.h index d1abd321e7..b7a7093bc5 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -179,13 +179,13 @@ namespace Common { for a working sample of a Custom XML Parser. */ - + #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; \ + lay = new CustomXMLKeyLayout;\ + lay->callback = (&kLocalParserName::parserCallback_##keyName);\ + layout.top()->children[#keyName] = lay;\ layout.push(lay); \ + _layoutList.push_back(lay);\ for (Common::List::const_iterator p = globalProps.begin(); p != globalProps.end(); ++p){\ layout.top()->properties.push_back(*p);} @@ -209,16 +209,18 @@ namespace Common { #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);}\ + bool keyCallback(ParserNode *node) {return node->layout->doCallback(this, node); }\ + struct CustomXMLKeyLayout : public XMLKeyLayout {\ + typedef bool (parserName::*ParserCallback)(ParserNode *node);\ + ParserCallback callback;\ + bool doCallback(XMLParser *parent, ParserNode *node) {return ((kLocalParserName*)parent->*callback)(node);} };\ virtual void buildLayout() { \ Common::Stack layout; \ - XMLKeyLayout *lay = 0; \ + CustomXMLKeyLayout *lay = 0; \ XMLKeyLayout::XMLKeyProperty prop; \ Common::List globalProps; \ - _XMLkeys = new XMLKeyLayout; \ + _XMLkeys = new CustomXMLKeyLayout; \ layout.push(_XMLkeys); #define PARSER_END() layout.clear(); } @@ -280,8 +282,14 @@ public: virtual ~XMLParser() { while (!_activeKey.empty()) delete _activeKey.pop(); - + delete _XMLkeys; + + for (Common::List::iterator i = _layoutList.begin(); + i != _layoutList.end(); ++i) + delete *i; + + _layoutList.clear(); } /** Active state for the parser */ @@ -297,12 +305,12 @@ public: }; struct XMLKeyLayout; + struct ParserNode; typedef Common::HashMap ChildMap; /** nested struct representing the layout of the XML file */ struct XMLKeyLayout { - void *custom; struct XMLKeyProperty { Common::String name; bool required; @@ -311,9 +319,10 @@ public: Common::List properties; ChildMap children; - ~XMLKeyLayout() { + virtual bool doCallback(XMLParser *parent, ParserNode *node) = 0; + + virtual ~XMLKeyLayout() { properties.clear(); - children.clear(); } } *_XMLkeys; @@ -336,8 +345,10 @@ public: bool loadFile(Common::String filename) { Common::File *f = new Common::File; - if (!f->open(filename)) + if (!f->open(filename)) { + delete f; return false; + } _fileName = filename; _text.loadStream(f); @@ -564,6 +575,7 @@ protected: */ virtual void cleanup() {} + Common::List _layoutList; private: int _pos; /** Current position on the XML buffer. */ -- cgit v1.2.3 From 103a4f66813df8f806467ad6f27cd0831ae0abf4 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 9 Aug 2008 18:34:16 +0000 Subject: Added support for image loading/blitting. Added support for loading theme files. (Make sure to grab the sample theme "scummodern.zip" from the gui/themes/ directory to try it out) Misc fixes. svn-id: r33718 --- common/xmlparser.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index b7a7093bc5..e3d39bfb82 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -371,6 +371,12 @@ public: _fileName = "Memory Stream"; return true; } + + bool loadStream(MemoryReadStream *stream) { + _text.loadStream(stream); + _fileName = "Compressed File Stream"; + return true; + } /** * The actual parsing function. -- cgit v1.2.3 From 5201a46054a1390739b21532c45e0e9926b857bc Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 16 Aug 2008 14:06:26 +0000 Subject: Added support for loading uncompressed/unpackaged themes. svn-id: r33941 --- common/xmlparser.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/xmlparser.h b/common/xmlparser.h index e3d39bfb82..4d1c8fc85d 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -32,6 +32,7 @@ #include "common/xmlparser.h" #include "common/stream.h" #include "common/file.h" +#include "common/fs.h" #include "common/hashmap.h" #include "common/hash-str.h" @@ -342,7 +343,7 @@ public: * * @param filename Name of the file to load. */ - bool loadFile(Common::String filename) { + bool loadFile(const Common::String &filename) { Common::File *f = new Common::File; if (!f->open(filename)) { @@ -354,6 +355,19 @@ public: _text.loadStream(f); return true; } + + bool loadFile(const FilesystemNode &node) { + Common::File *f = new Common::File; + + if (!f->open(node)) { + delete f; + return false; + } + + _fileName = node.getName(); + _text.loadStream(f); + return true; + } /** * Loads a memory buffer into the parser. -- cgit v1.2.3 From e0592c7d25acd42cd93b9dab5048209bab858ba8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 5 Sep 2008 14:48:47 +0000 Subject: Fixed severe bottleneck in the XML Parser code. Applied Max's patch for character drawing. Added new FP squareroot function. svn-id: r34354 --- common/xmlparser.cpp | 62 +++++++++----- common/xmlparser.h | 238 ++++++++++----------------------------------------- 2 files changed, 85 insertions(+), 215 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 900f2f81ab..44bf03336e 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -37,7 +37,8 @@ using namespace Graphics; bool XMLParser::parserError(const char *errorString, ...) { _state = kParserError; - int pos = _pos; + int original_pos = _stream->pos(); + int pos = original_pos; int lineCount = 1; int lineStart = 0; @@ -46,18 +47,21 @@ bool XMLParser::parserError(const char *errorString, ...) { lineCount = 0; } else { do { - if (_text[pos] == '\n' || _text[pos] == '\r') { + if (_char == '\n' || _char == '\r') { lineCount++; if (lineStart == 0) lineStart = MAX(pos + 1, _pos - 60); } - } while (pos-- > 0); + + _stream->seek(-1, SEEK_CUR); + + } while (_stream->pos() > 0); } char lineStr[70]; - _text.stream()->seek(lineStart, SEEK_SET); - _text.stream()->readLine(lineStr, 70); + _stream->seek(original_pos - 35, SEEK_SET); + _stream->readLine(lineStr, 70); for (int i = 0; i < 70; ++i) if (lineStr[i] == '\n') @@ -70,7 +74,7 @@ bool XMLParser::parserError(const char *errorString, ...) { printf("%s%s%s\n", startFull ? "" : "...", lineStr, endFull ? "" : "..."); - int cursor = MIN(_pos - lineStart, 70); + int cursor = 35; if (!startFull) cursor += 3; @@ -149,15 +153,20 @@ bool XMLParser::parseKeyValue(Common::String keyName) { _token.clear(); char stringStart; - if (_text[_pos] == '"' || _text[_pos] == '\'') { - stringStart = _text[_pos++]; + if (_char == '"' || _char == '\'') { + stringStart = _char; + _char = _stream->readByte(); - while (_text[_pos] && _text[_pos] != stringStart) - _token += _text[_pos++]; + while (_char && _char != stringStart) { + _token += _char; + _char = _stream->readByte(); + } - if (_text[_pos++] == 0) + if (_char == 0) return false; + _char = _stream->readByte(); + } else if (!parseToken()) { return false; } @@ -185,7 +194,7 @@ bool XMLParser::closeKey() { bool XMLParser::parse() { - if (_text.ready() == false) + if (_stream == 0) return parserError("XML stream not ready for reading."); if (_XMLkeys == 0) @@ -202,8 +211,10 @@ bool XMLParser::parse() { _state = kParserNeedKey; _pos = 0; _activeKey.clear(); + + _char = _stream->readByte(); - while (_text[_pos] && _state != kParserError) { + while (_char && _state != kParserError) { if (skipSpaces()) continue; @@ -212,18 +223,18 @@ bool XMLParser::parse() { switch (_state) { case kParserNeedKey: - if (_text[_pos++] != '<') { + if (_char != '<') { parserError("Parser expecting key start."); break; } - if (_text[_pos] == 0) { + if ((_char = _stream->readByte()) == 0) { parserError("Unexpected end of file."); break; } - if (_text[_pos] == '/' && _text[_pos + 1] != '*') { - _pos++; + if (_char == '/') { // FIXME: What if it's a comment start + _char = _stream->readByte(); activeClosure = true; } @@ -262,19 +273,25 @@ bool XMLParser::parse() { activeClosure = false; - if (_text[_pos++] != '>') + if (_char != '>') parserError("Invalid syntax in key closure."); else _state = kParserNeedKey; + _char = _stream->readByte(); break; } - selfClosure = (_text[_pos] == '/'); + selfClosure = false; + + if (_char == '/') { // FIXME: comment start? + selfClosure = true; + _char = _stream->readByte(); + } - if ((selfClosure && _text[_pos + 1] == '>') || _text[_pos] == '>') { + if (_char == '>') { if (parseActiveKey(selfClosure)) { - _pos += selfClosure ? 2 : 1; + _char = _stream->readByte(); _state = kParserNeedKey; } break; @@ -288,11 +305,12 @@ bool XMLParser::parse() { break; case kParserNeedPropertyOperator: - if (_text[_pos++] != '=') + if (_char != '=') parserError("Syntax error after key name."); else _state = kParserNeedPropertyValue; + _char = _stream->readByte(); break; case kParserNeedPropertyValue: 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: - - - - - - - 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::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 */ -- cgit v1.2.3 From c8f42a39737dbd50cbdc4cad7c6a6c89ca0efe69 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 29 Sep 2008 10:27:16 +0000 Subject: Reduced memory usage by closing theme files after parsing. Could make things a tad slower. svn-id: r34677 --- common/xmlparser.cpp | 5 ++--- common/xmlparser.h | 10 ++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index b93a5205be..6c1aa7d0e4 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -43,7 +43,7 @@ bool XMLParser::parserError(const char *errorString, ...) { int lineStart = 0; if (_fileName == "Memory Stream") { - lineStart = MAX(0, _pos - 35); + lineStart = MAX(0, original_pos - 35); lineCount = 0; } else { do { @@ -51,7 +51,7 @@ bool XMLParser::parserError(const char *errorString, ...) { lineCount++; if (lineStart == 0) - lineStart = MAX(pos + 1, _pos - 60); + lineStart = MAX(pos + 1, original_pos - 60); } _stream->seek(-1, SEEK_CUR); @@ -210,7 +210,6 @@ bool XMLParser::parse() { bool selfClosure = false; _state = kParserNeedKey; - _pos = 0; _activeKey.clear(); _char = _stream->readByte(); diff --git a/common/xmlparser.h b/common/xmlparser.h index 7edabf62f3..967b73535b 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -222,6 +222,13 @@ public: _fileName = "Compressed File Stream"; return true; } + + void close() { + if (_stream) { + delete _stream; + _stream = 0; + } + } /** * The actual parsing function. @@ -361,7 +368,7 @@ protected: break; if (_char == 0) - parserError("Comment has no closure."); + return parserError("Comment has no closure."); } _char = _stream->readByte(); return true; @@ -449,7 +456,6 @@ protected: Common::List _layoutList; private: - int _pos; /** Current position on the XML buffer. */ char _char; SeekableReadStream *_stream; Common::String _fileName; -- cgit v1.2.3 From b15a6a9a152ce9e056c72f62d8299c982884f15b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 29 Sep 2008 21:44:07 +0000 Subject: Removed unnecessary unzOpenFile() calls in getAllNames() svn-id: r34690 --- common/unzip.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/unzip.cpp b/common/unzip.cpp index 27001519a1..bdba2a544a 100644 --- a/common/unzip.cpp +++ b/common/unzip.cpp @@ -1399,17 +1399,12 @@ int ZipArchive::getAllNames(Common::StringList &list) { if (unzGoToFirstFile(_zipFile) != UNZ_OK) return 0; - char fileNameBuffer[UNZ_MAXFILENAMEINZIP+1]; + char fileNameBuffer[UNZ_MAXFILENAMEINZIP + 1]; list.clear(); do { - unzOpenCurrentFile(_zipFile); - unzGetCurrentFileInfo(_zipFile, 0, fileNameBuffer, UNZ_MAXFILENAMEINZIP+1, 0, 0, 0, 0); - + unzGetCurrentFileInfo(_zipFile, 0, fileNameBuffer, UNZ_MAXFILENAMEINZIP + 1, 0, 0, 0, 0); list.push_back(Common::String(fileNameBuffer)); - - unzCloseCurrentFile(_zipFile); - } while (unzGoToNextFile(_zipFile) == UNZ_OK); return list.size(); -- cgit v1.2.3 From e290a3b6f3cf2fd1b686230126a8a27451cabdff Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 30 Sep 2008 11:55:32 +0000 Subject: Ported ZipArchive::getAllNames() fix from trunk. svn-id: r34699 --- common/unzip.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/unzip.cpp b/common/unzip.cpp index bdba2a544a..24744203da 100644 --- a/common/unzip.cpp +++ b/common/unzip.cpp @@ -1395,19 +1395,20 @@ bool ZipArchive::hasFile(const Common::String &name) { int ZipArchive::getAllNames(Common::StringList &list) { if (!_zipFile) return 0; - + if (unzGoToFirstFile(_zipFile) != UNZ_OK) return 0; char fileNameBuffer[UNZ_MAXFILENAMEINZIP + 1]; - list.clear(); - + int fileCount = 0; + do { unzGetCurrentFileInfo(_zipFile, 0, fileNameBuffer, UNZ_MAXFILENAMEINZIP + 1, 0, 0, 0, 0); list.push_back(Common::String(fileNameBuffer)); + fileCount++; } while (unzGoToNextFile(_zipFile) == UNZ_OK); - - return list.size(); + + return fileCount; } /* -- cgit v1.2.3 From e32fc0ccca2570fc560969507351cf99a304ebf4 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 5 Oct 2008 10:19:09 +0000 Subject: Added a fixed memory pool for XML Node allocation, as suggested by Max. svn-id: r34747 --- common/xmlparser.cpp | 6 +++--- common/xmlparser.h | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 6c1aa7d0e4..44274f7c8d 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -188,7 +188,7 @@ bool XMLParser::closeKey() { if (ignore == false) result = closedKeyCallback(_activeKey.top()); - delete _activeKey.pop(); + freeNode(_activeKey.pop()); return result; } @@ -202,7 +202,7 @@ bool XMLParser::parse() { buildLayout(); while (!_activeKey.empty()) - delete _activeKey.pop(); + freeNode(_activeKey.pop()); cleanup(); @@ -253,7 +253,7 @@ bool XMLParser::parse() { break; } } else { - ParserNode *node = new ParserNode; + ParserNode *node = allocNode(); //new ParserNode; node->name = _token; node->ignore = false; node->depth = _activeKey.size(); diff --git a/common/xmlparser.h b/common/xmlparser.h index 4b76278d47..ad9ad799f0 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -47,6 +47,8 @@ namespace Common { External documentation available at: http://www.smartlikearoboc.com/scummvm_doc/xmlparser_doc.html */ + +#define MAX_XML_DEPTH 8 #define XML_KEY(keyName) {\ lay = new CustomXMLKeyLayout;\ @@ -112,7 +114,7 @@ public: virtual ~XMLParser() { while (!_activeKey.empty()) - delete _activeKey.pop(); + freeNode(_activeKey.pop()); delete _XMLkeys; delete _stream; @@ -166,6 +168,18 @@ public: int depth; XMLKeyLayout *layout; }; + + FixedSizeMemoryPool _nodePool; + + ParserNode *allocNode() { + void* mem = _nodePool.malloc(); + return new (mem) ParserNode; + } + + void freeNode(ParserNode *node) { + node->~ParserNode(); + _nodePool.free(node); + } /** * Loads a file into the parser. -- cgit v1.2.3