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; | 
