aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti2008-06-13 22:05:21 +0000
committerVicent Marti2008-06-13 22:05:21 +0000
commitd51a0cab3fe494698f001d81d5d86cea7cd0395b (patch)
tree45f504bd2ad5e25ea8ca66f20106f0e6d7bb0958
parent04b36a12e17252aa3f27392b334b053406847d8f (diff)
downloadscummvm-rg350-d51a0cab3fe494698f001d81d5d86cea7cd0395b.tar.gz
scummvm-rg350-d51a0cab3fe494698f001d81d5d86cea7cd0395b.tar.bz2
scummvm-rg350-d51a0cab3fe494698f001d81d5d86cea7cd0395b.zip
Parser redesign. Fixed most possible overflows.
svn-id: r32697
-rw-r--r--gui/ThemeParser.cpp127
-rw-r--r--gui/ThemeParser.h36
2 files changed, 88 insertions, 75 deletions
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
index cd77b4a5e1..260e3911a1 100644
--- a/gui/ThemeParser.cpp
+++ b/gui/ThemeParser.cpp
@@ -42,15 +42,11 @@
namespace GUI {
-inline bool isValidNameChar(char c) {
- return isalnum(c) || c == '_';
-}
-
void ThemeParser::debug_testEval() {
static const char *debug_config_text =
"<drawdata id = \"background_default\" cache = true>"
"<draw func = \"roundedsq\" /*/fill = \"gradient\" gradient_start = \"255, 255, 128\" gradient_end = \"128, 128, 128\" size = \"auto\"/>"
- "<draw func = \"roundedsq\" fill = \"none\" color = \"0, 0, 0\" size = \"auto\"/>"
+ "<draw func = \"roundedsq\" fill = \"none\" color = /*\"0, 0, 0\"*/\"0, 1, 2\" size = \"auto\"/>"
"</drawdata>/* lol this is just a simple test*/";
_text = strdup(debug_config_text);
@@ -91,37 +87,38 @@ void ThemeParser::parseActiveKey(bool closed) {
}
}
-void ThemeParser::parseKeyValue(Common::String &key_name) {
- assert(_text[_pos++] == '=');
+bool ThemeParser::parseKeyValue(Common::String &key_name) {
assert(_keyValues.empty() == false);
- if (_keyValues.top().contains(key_name)) {
- parserError("Repeated value inside key.");
- return;
- }
-
- skipSpaces();
+ if (_keyValues.top().contains(key_name))
+ return false;
- Common::String data;
+ Common::String name = key_name;
+ _token.clear();
char string_start;
if (_text[_pos] == '"' || _text[_pos] == '\'') {
string_start = _text[_pos++];
- while (_text[_pos] != string_start)
- data += _text[_pos++];
+ while (_text[_pos] && _text[_pos] != string_start)
+ _token += _text[_pos++];
- _pos++;
- } else {
- while (isValidNameChar(_text[_pos]))
- data += _text[_pos++];
+ if (_text[_pos++] == 0)
+ return false;
+
+ } else if (!parseToken()) {
+ return false;
}
- _keyValues.top()[key_name] = data;
+ _keyValues.top()[name] = _token;
+ return true;
}
bool ThemeParser::parse() {
+ bool active_closure = false;
+ bool self_closure = false;
+
_state = kParserNeedKey;
_pos = 0;
_keyValues.clear();
@@ -131,79 +128,74 @@ bool ThemeParser::parse() {
if (_state == kParserError)
break;
- skipSpaces();
+ if (skipSpaces())
+ continue;
if (skipComments())
continue;
switch (_state) {
case kParserNeedKey:
- if (_text[_pos++] != '<') {
- parserError("Expecting key start.");
- break;
- }
+ if (_text[_pos++] != '<') parserError("Expecting key start.");
+ else _state = kParserNeedKeyName;
+ break;
+ case kParserNeedKeyName:
if (_text[_pos] == '/') {
_pos++;
- _token.clear();
- while (isValidNameChar(_text[_pos]))
- _token += _text[_pos++];
+ active_closure = true;
+ }
+
+ if (!parseToken()) {
+ parserError("Unexpected end of file while parsing token.");
+ break;
+ }
+ if (active_closure) {
if (_activeKey.empty() || _token != _activeKey.top())
parserError("Unexpected closure.");
- else {
- _activeKey.pop();
- _keyValues.pop();
-
- skipSpaces();
-
- if (_text[_pos++] != '>')
- parserError("Malformed tag closure.");
- }
-
- break;
+ } else {
+ _keyValues.push(Common::StringMap());
+ _activeKey.push(_token);
}
- _keyValues.push(Common::StringMap());
- _state = kParserNeedKeyName;
+ _state = kParserNeedPropertyName;
break;
- case kParserNeedKeyName:
- _token.clear();
- while (isValidNameChar(_text[_pos]))
- _token += _text[_pos++];
+ case kParserNeedPropertyName:
+ if (active_closure) {
+ active_closure = false;
+ _activeKey.pop();
+ _keyValues.pop();
- if (!isspace(_text[_pos]) && _text[_pos] != '>') {
- parserError("Invalid character in token name.");
+ if (_text[_pos++] != '>')
+ parserError("Invalid syntax in key closure.");
+
+ _state = kParserNeedKey;
break;
}
- _state = kParserNeedKeyValues;
- _activeKey.push(_token);
- break;
-
- case kParserNeedKeyValues:
- _token.clear();
+ self_closure = (_text[_pos] == '/');
- if ((_text[_pos] == '/' && _text[_pos + 1] == '>') || _text[_pos] == '>') {
- bool closed = _text[_pos] == '/';
- parseActiveKey(closed);
- _pos += closed ? 2 : 1;
+ if ((self_closure && _text[_pos + 1] == '>') || _text[_pos] == '>') {
+ parseActiveKey(self_closure);
+ _pos += self_closure ? 2 : 1;
_state = kParserNeedKey;
break;
}
- while (isValidNameChar(_text[_pos]))
- _token += _text[_pos++];
-
- skipSpaces();
+ if (!parseToken()) parserError("Error when parsing key value.");
+ else _state = kParserNeedPropertyOperator;
+ break;
- if (_text[_pos] != '=') {
- parserError("Unexpected character after key name.");
- break;
- }
+ case kParserNeedPropertyOperator:
+ if (_text[_pos++] != '=') parserError("Unexpected character after key name.");
+ else _state = kParserNeedPropertyValue;
+ break;
- parseKeyValue(_token);
+ case kParserNeedPropertyValue:
+ if (!parseKeyValue(_token)) parserError("Unable to parse key value.");
+ else _state = kParserNeedPropertyName;
break;
default:
@@ -217,6 +209,7 @@ bool ThemeParser::parse() {
if (_state != kParserNeedKey || !_activeKey.empty()) {
parserError("Unexpected end of file.");
+ return false;
}
return true;
diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h
index 762baefd7f..df99893d58 100644
--- a/gui/ThemeParser.h
+++ b/gui/ThemeParser.h
@@ -52,25 +52,33 @@ public:
enum ParserState {
kParserNeedKey,
kParserNeedKeyName,
- kParserNeedKeyValues,
+
+ kParserNeedPropertyName,
+ kParserNeedPropertyOperator,
+ kParserNeedPropertyValue,
+
kParserError
};
bool parse();
- void parseKeyValue(Common::String &key_name);
- void parseActiveKey(bool closed);
-
- void parserError(const char *error_string);
-
void debug_testEval();
protected:
void parserCallback_DRAW();
void parserCallback_DRAWDATA();
- inline void skipSpaces() {
- while (isspace(_text[_pos]))
+ bool parseKeyValue(Common::String &key_name);
+ void parseActiveKey(bool closed);
+ void parserError(const char *error_string);
+
+ inline bool skipSpaces() {
+ if (!isspace(_text[_pos]))
+ return false;
+
+ while (_text[_pos] && isspace(_text[_pos]))
_pos++;
+
+ return true;
}
inline bool skipComments() {
@@ -85,6 +93,18 @@ protected:
return false;
}
+ inline bool isValidNameChar(char c) {
+ return isalnum(c) || c == '_';
+ }
+
+ inline bool parseToken() {
+ _token.clear();
+ while (isValidNameChar(_text[_pos]))
+ _token += _text[_pos++];
+
+ return (_text[_pos] != 0);
+ }
+
int _pos;
char *_text;