Update to the low level parser:

* made it detect buffer overflows 
* removed unused code paths
* general simplification

svn-id: r35047
This commit is contained in:
Nicola Mettifogo 2008-11-13 15:15:54 +00:00
parent f7bdf6b40f
commit 618644ba0c
3 changed files with 115 additions and 139 deletions

View File

@ -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] = 0xA;
buf[i+1] = '\0';
}
buf[i] = '\0';
return buf;
}
bool isCommentLine(char *text) {
return text[0] == '#';
}
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;
}
if (line[0] == '\0')
continue;
ignoreLine = false;
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;
}
} while (inBlockComment || ignoreLine);
return line;
}
void Script::clearTokens() {
for (uint16 i = 0; i < MAX_TOKENS; i++)
_tokens[i][0] = '\0';
memset(_tokens, 0, sizeof(_tokens));
_numTokens = 0;
return;
}
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++;
uint16 Script::readLineToken(bool errorOnEOF) {
char buf[200];
char *line = readLine(buf, 200);
if (!line) {
if (errorOnEOF)
error("unexpected end of file while parsing");
else
return 0;
}
_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);
return fillTokens(start);
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]);

View File

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

View File

@ -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;
}
return v194;
if (len == tempSize) {
warning("overflow in LocationParser_ns::parseComment (line %i)", _script->getLine());
}
temp[len-1] = '\0'; // removes the last space pasted in the string
return strdup(temp);
}
DECLARE_ZONE_PARSER(null) {