Parser redesign. Fixed most possible overflows.

svn-id: r32697
This commit is contained in:
Vicent Marti 2008-06-13 22:05:21 +00:00
parent 04b36a12e1
commit d51a0cab3f
2 changed files with 92 additions and 79 deletions

View file

@ -42,15 +42,11 @@
namespace GUI { namespace GUI {
inline bool isValidNameChar(char c) {
return isalnum(c) || c == '_';
}
void ThemeParser::debug_testEval() { void ThemeParser::debug_testEval() {
static const char *debug_config_text = static const char *debug_config_text =
"<drawdata id = \"background_default\" cache = true>" "<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 = \"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*/"; "</drawdata>/* lol this is just a simple test*/";
_text = strdup(debug_config_text); _text = strdup(debug_config_text);
@ -91,37 +87,38 @@ void ThemeParser::parseActiveKey(bool closed) {
} }
} }
void ThemeParser::parseKeyValue(Common::String &key_name) { bool ThemeParser::parseKeyValue(Common::String &key_name) {
assert(_text[_pos++] == '=');
assert(_keyValues.empty() == false); assert(_keyValues.empty() == false);
if (_keyValues.top().contains(key_name)) { if (_keyValues.top().contains(key_name))
parserError("Repeated value inside key."); return false;
return;
}
skipSpaces(); Common::String name = key_name;
_token.clear();
Common::String data;
char string_start; char string_start;
if (_text[_pos] == '"' || _text[_pos] == '\'') { if (_text[_pos] == '"' || _text[_pos] == '\'') {
string_start = _text[_pos++]; string_start = _text[_pos++];
while (_text[_pos] != string_start) while (_text[_pos] && _text[_pos] != string_start)
data += _text[_pos++]; _token += _text[_pos++];
_pos++; if (_text[_pos++] == 0)
} else { return false;
while (isValidNameChar(_text[_pos]))
data += _text[_pos++]; } else if (!parseToken()) {
return false;
} }
_keyValues.top()[key_name] = data; _keyValues.top()[name] = _token;
return true;
} }
bool ThemeParser::parse() { bool ThemeParser::parse() {
bool active_closure = false;
bool self_closure = false;
_state = kParserNeedKey; _state = kParserNeedKey;
_pos = 0; _pos = 0;
_keyValues.clear(); _keyValues.clear();
@ -131,79 +128,74 @@ bool ThemeParser::parse() {
if (_state == kParserError) if (_state == kParserError)
break; break;
skipSpaces(); if (skipSpaces())
continue;
if (skipComments()) if (skipComments())
continue; continue;
switch (_state) { switch (_state) {
case kParserNeedKey: case kParserNeedKey:
if (_text[_pos++] != '<') { if (_text[_pos++] != '<') parserError("Expecting key start.");
parserError("Expecting key start."); else _state = kParserNeedKeyName;
break;
}
if (_text[_pos] == '/') {
_pos++;
_token.clear();
while (isValidNameChar(_text[_pos]))
_token += _text[_pos++];
if (_activeKey.empty() || _token != _activeKey.top())
parserError("Unexpected closure.");
else {
_activeKey.pop();
_keyValues.pop();
skipSpaces();
if (_text[_pos++] != '>')
parserError("Malformed tag closure.");
}
break;
}
_keyValues.push(Common::StringMap());
_state = kParserNeedKeyName;
break; break;
case kParserNeedKeyName: case kParserNeedKeyName:
_token.clear(); if (_text[_pos] == '/') {
while (isValidNameChar(_text[_pos])) _pos++;
_token += _text[_pos++]; active_closure = true;
}
if (!isspace(_text[_pos]) && _text[_pos] != '>') {
parserError("Invalid character in token name."); if (!parseToken()) {
parserError("Unexpected end of file while parsing token.");
break; break;
} }
_state = kParserNeedKeyValues; if (active_closure) {
_activeKey.push(_token); if (_activeKey.empty() || _token != _activeKey.top())
parserError("Unexpected closure.");
} else {
_keyValues.push(Common::StringMap());
_activeKey.push(_token);
}
_state = kParserNeedPropertyName;
break; break;
case kParserNeedKeyValues: case kParserNeedPropertyName:
_token.clear(); if (active_closure) {
active_closure = false;
_activeKey.pop();
_keyValues.pop();
if ((_text[_pos] == '/' && _text[_pos + 1] == '>') || _text[_pos] == '>') { if (_text[_pos++] != '>')
bool closed = _text[_pos] == '/'; parserError("Invalid syntax in key closure.");
parseActiveKey(closed);
_pos += closed ? 2 : 1;
_state = kParserNeedKey; _state = kParserNeedKey;
break; break;
} }
while (isValidNameChar(_text[_pos])) self_closure = (_text[_pos] == '/');
_token += _text[_pos++];
skipSpaces(); if ((self_closure && _text[_pos + 1] == '>') || _text[_pos] == '>') {
parseActiveKey(self_closure);
if (_text[_pos] != '=') { _pos += self_closure ? 2 : 1;
parserError("Unexpected character after key name."); _state = kParserNeedKey;
break; break;
} }
parseKeyValue(_token); 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; break;
default: default:
@ -217,6 +209,7 @@ bool ThemeParser::parse() {
if (_state != kParserNeedKey || !_activeKey.empty()) { if (_state != kParserNeedKey || !_activeKey.empty()) {
parserError("Unexpected end of file."); parserError("Unexpected end of file.");
return false;
} }
return true; return true;

View file

@ -52,25 +52,33 @@ public:
enum ParserState { enum ParserState {
kParserNeedKey, kParserNeedKey,
kParserNeedKeyName, kParserNeedKeyName,
kParserNeedKeyValues,
kParserNeedPropertyName,
kParserNeedPropertyOperator,
kParserNeedPropertyValue,
kParserError kParserError
}; };
bool parse(); bool parse();
void parseKeyValue(Common::String &key_name);
void parseActiveKey(bool closed);
void parserError(const char *error_string);
void debug_testEval(); void debug_testEval();
protected: protected:
void parserCallback_DRAW(); void parserCallback_DRAW();
void parserCallback_DRAWDATA(); void parserCallback_DRAWDATA();
inline void skipSpaces() { bool parseKeyValue(Common::String &key_name);
while (isspace(_text[_pos])) 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++; _pos++;
return true;
} }
inline bool skipComments() { inline bool skipComments() {
@ -85,6 +93,18 @@ protected:
return false; 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; int _pos;
char *_text; char *_text;