diff options
| author | Nicola Mettifogo | 2008-11-13 15:15:54 +0000 | 
|---|---|---|
| committer | Nicola Mettifogo | 2008-11-13 15:15:54 +0000 | 
| commit | 618644ba0c3e410ba7df320fe33ba4f469476295 (patch) | |
| tree | ef6cae961bc365273ea052168b5a498344d7cde6 | |
| parent | f7bdf6b40f883ceeac2034763bc0bebc174a13df (diff) | |
| download | scummvm-rg350-618644ba0c3e410ba7df320fe33ba4f469476295.tar.gz scummvm-rg350-618644ba0c3e410ba7df320fe33ba4f469476295.tar.bz2 scummvm-rg350-618644ba0c3e410ba7df320fe33ba4f469476295.zip | |
Update to the low level parser:
* made it detect buffer overflows 
* removed unused code paths
* general simplification
svn-id: r35047
| -rw-r--r-- | engines/parallaction/parser.cpp | 189 | ||||
| -rw-r--r-- | engines/parallaction/parser.h | 4 | ||||
| -rw-r--r-- | engines/parallaction/parser_ns.cpp | 55 | 
3 files changed, 112 insertions, 136 deletions
| diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index c15d1111d3..3dc586dd8c 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -40,46 +40,85 @@ Script::~Script() {  		delete _input;  } -char *Script::readLine(char *buf, size_t bufSize) { - +char *Script::readLineIntern(char *buf, size_t bufSize) {  	uint16 i;  	for (i = 0; i < bufSize; i++) { -  		char c = _input->readSByte(); -  		if (_input->eos())  			break; - -		if (c == 0xA || c == 0xD) +		if (c == '\n' || c == '\r')  			break; +		if (c == '\t') +			c = ' '; -		if (i < bufSize) -			buf[i] = c; +		buf[i] = c;  	} -  	_line++; - -	if (i == 0 && _input->eos()) +	if (i == bufSize) { +		warning("overflow in readLineIntern (line %i)", _line); +	} +	if (i == 0 && _input->eos()) {  		return 0; +	} +	buf[i] = '\0'; +	return buf; +} -	buf[i] = 0xA; -	buf[i+1] = '\0'; +bool isCommentLine(char *text) { +	return text[0] == '#'; +} -	return buf; +bool isStartOfCommentBlock(char *text) { +	return (text[0] == '['); +} +bool isEndOfCommentBlock(char *text) { +	return (text[0] == ']');  } +char *Script::readLine(char *buf, size_t bufSize) { +	bool inBlockComment = false; +	bool ignoreLine = true; +	char *line = 0; +	do { +		line = readLineIntern(buf, bufSize); +		if (line == 0) { +			return 0; +		} -void Script::clearTokens() { +		if (line[0] == '\0') +			continue; -	for (uint16 i = 0; i < MAX_TOKENS; i++) -		_tokens[i][0] = '\0'; +		ignoreLine = false; -	_numTokens = 0; +		line = Common::ltrim(line); +		if (isCommentLine(line)) { +			// ignore this line +			ignoreLine = true; +		} else +		if (isStartOfCommentBlock(line)) { +			// mark this and the following lines as comment +			inBlockComment = true; +		} else +		if (isEndOfCommentBlock(line)) { +			// comment is finished, so stop ignoring +			inBlockComment = false; +			// the current line must be skipped, though, +			// as it contains the end-of-comment marker +			ignoreLine = true; +		} -	return; +	} while (inBlockComment || ignoreLine); +	return line; +} + + + +void Script::clearTokens() { +	memset(_tokens, 0, sizeof(_tokens)); +	_numTokens = 0;  }  void Script::skip(const char* endToken) { @@ -111,21 +150,14 @@ char *Script::parseNextToken(char *s, char *tok, uint16 count, const char *brk,  			if (*s == '\0') {  				*tok = '\0';  				return s; -			} - +			} else  			if (strchr(brk, *s)) {  				*tok = '\0';  				return ++s; -			} - +			} else  			if (*s == '"') { -				if (ignoreQuotes) { -					*tok++ = *s++; -					count--; -				} else { -					state = QUOTED; -					s++; -				} +				state = QUOTED; +				s++;  			} else {  				*tok++ = *s++;  				count--; @@ -136,14 +168,14 @@ char *Script::parseNextToken(char *s, char *tok, uint16 count, const char *brk,  			if (*s == '\0') {  				*tok = '\0';  				return s; -			} -			if (*s == '"' || *s == '\n' || *s == '\t') { +			} else +			if (*s == '"') {  				*tok = '\0';  				return ++s; +			} else { +				*tok++ = *s++; +				count--;  			} - -			*tok++ = *s++; -			count--;  			break;  		} @@ -158,71 +190,23 @@ char *Script::parseNextToken(char *s, char *tok, uint16 count, const char *brk,  } -uint16 Script::fillTokens(char* line) { - -	uint16 i = 0; -	while (strlen(line) > 0 && i < MAX_TOKENS) { -		line = parseNextToken(line, _tokens[i], MAX_TOKEN_LEN, " \t\n"); -		line = Common::ltrim(line); -		i++; -	} - -	_numTokens = i; - -	return i; -} - -bool isCommentLine(char *text) { -	return text[0] == '#'; -} - -bool isStartOfCommentBlock(char *text) { -	return (text[0] == '['); -} - -bool isEndOfCommentBlock(char *text) { -	return (text[0] == ']'); -} -  uint16 Script::readLineToken(bool errorOnEOF) { - -	clearTokens(); - -	bool inBlockComment = false; -  	char buf[200]; -	char *line = NULL; -	char *start; -	do { -		line = readLine(buf, 200); - -		if (line == NULL) { -			if (errorOnEOF) -				error("unexpected end of file while parsing"); -			else -				return 0; -		} -		start = Common::ltrim(line); - -		if (isCommentLine(start)) { -			// ignore this line -			start[0] = '\0'; -		} else -		if (isStartOfCommentBlock(start)) { -			// mark this and the following lines as comment -			inBlockComment = true; -		} else -		if (isEndOfCommentBlock(start)) { -			// comment is finished, so stop ignoring -			inBlockComment = false; -			// the current line must be skipped, though, -			// as it contains the end-of-comment marker -			start[0] = '\0'; -		} - -	} while (inBlockComment || strlen(start) == 0); +	char *line = readLine(buf, 200); +	if (!line) { +		if (errorOnEOF) +			error("unexpected end of file while parsing"); +		else +			return 0; +	} -	return fillTokens(start); +	clearTokens(); +	while (strlen(line) > 0 && _numTokens < MAX_TOKENS) { +		line = parseNextToken(line, _tokens[_numTokens], MAX_TOKEN_LEN, " "); +		line = Common::ltrim(line); +		_numTokens++; +	} +	return _numTokens;  } @@ -328,13 +312,11 @@ class CommentStatementDef : public StatementDef {  	Common::String parseComment(Script &script) {  		Common::String result;  		char buf[401]; -  		do { -			script.readLine(buf, 400); -			buf[strlen(buf)-1] = '\0'; -			if (!scumm_stricmp(buf, "endtext")) +			char *line = script.readLine(buf, 400); +			if (!scumm_stricmp(line, "endtext"))  				break; -			result += Common::String(buf) + "\n"; +			result += Common::String(line) + "\n";  		} while (true);  		result += "endtext\n";  		return result; @@ -408,8 +390,7 @@ void PreProcessor::preprocessScript(Script &script, StatementList &list) {  	_numZones = 0;  	Common::String text;  	do { -		script.readLineToken(false); -		if (_numTokens == 0) +		if (script.readLineToken(false) == 0)  			break;  		StatementDef *def = findDef(_tokens[0]); diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index f184dcbc58..cbeecbb438 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -44,8 +44,8 @@ class Script {  	uint	_line;				// for debug messages  	void clearTokens(); -	uint16 fillTokens(char* line); -	char   *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes = false); +	char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes = false); +	char *readLineIntern(char *buf, size_t bufSize);  public:  	Script(Common::ReadStream *, bool _disposeSource = false); diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index 7864df917d..d6405a4dfd 100644 --- a/engines/parallaction/parser_ns.cpp +++ b/engines/parallaction/parser_ns.cpp @@ -943,21 +943,12 @@ void LocationParser_ns::resolveDialogueForwards(Dialogue *dialogue, uint numQues  }  char *LocationParser_ns::parseDialogueString() { - -	char vC8[200]; -	char *vD0 = NULL; -	do { - -		vD0 = _script->readLine(vC8, 200); -		if (vD0 == 0) return NULL; - -		vD0 = Common::ltrim(vD0); - -	} while (strlen(vD0) == 0); - -	vD0[strlen(vD0)-1] = '\0';	// deletes the trailing '0xA' -								// this is critical for Gfx::displayWrappedString to work properly -	return strdup(vD0); +	char buf[200]; +	char *line = _script->readLine(buf, 200); +	if (line == 0) { +		return 0; +	} +	return strdup(line);  } @@ -1275,26 +1266,30 @@ void ProgramParser_ns::init() {  //	comments are displayed into rectangles on the screen  //  char *LocationParser_ns::parseComment() { - -	char			_tmp_comment[1000] = "\0"; -	char *v194; - +	const int tempSize = 1000; +	char temp[tempSize] = "\0"; +	int len = 0; +	char buf[400];  	do { -		char v190[400]; -		v194 = _script->readLine(v190, 400); - -		v194[strlen(v194)-1] = '\0'; -		if (!scumm_stricmp(v194, "endtext")) +		char *line = _script->readLine(buf, 400); +		if (!scumm_stricmp(line, "endtext"))  			break; -		strcat(_tmp_comment, v194); -		strcat(_tmp_comment, " "); -	} while (true); +		strncat(temp, line, tempSize - len - 1); +		strcat(temp, " "); +		len = len + strlen(line) + 1; +	} while (len < tempSize); -	v194 = strdup(_tmp_comment); -	_tmp_comment[0] = '\0'; +	if (len == 0) { +		return 0; +	} + +	if (len == tempSize) { +		warning("overflow in LocationParser_ns::parseComment (line %i)", _script->getLine()); +	} -	return v194; +	temp[len-1] = '\0';	// removes the last space pasted in the string +	return strdup(temp);  }  DECLARE_ZONE_PARSER(null) { | 
