Parser redesign. Fixed most possible overflows.
svn-id: r32697
This commit is contained in:
parent
04b36a12e1
commit
d51a0cab3f
2 changed files with 92 additions and 79 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue