diff options
author | Vicent Marti | 2008-06-13 22:05:21 +0000 |
---|---|---|
committer | Vicent Marti | 2008-06-13 22:05:21 +0000 |
commit | d51a0cab3fe494698f001d81d5d86cea7cd0395b (patch) | |
tree | 45f504bd2ad5e25ea8ca66f20106f0e6d7bb0958 | |
parent | 04b36a12e17252aa3f27392b334b053406847d8f (diff) | |
download | scummvm-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.cpp | 127 | ||||
-rw-r--r-- | gui/ThemeParser.h | 36 |
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; |