Update internal state before callback; that way, if during the callback we inject some more data

into the parser (e.g. it's an <include> tag or something), the parser is in the correct state.
This commit is contained in:
Laurence Withers 2006-09-29 10:51:10 +01:00
parent f1fa8b5625
commit 71fda14981
2 changed files with 30 additions and 30 deletions

View File

@ -141,8 +141,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
if(ch == xmlRestartMarker[ctx->restartCount]) { if(ch == xmlRestartMarker[ctx->restartCount]) {
if(++ctx->restartCount == 11) { if(++ctx->restartCount == 11) {
csxml_reset(ctx);
ctx->state = StateRestartMarker; ctx->state = StateRestartMarker;
csxml_reset(ctx);
return 0; return 0;
} }
} else { } else {
@ -179,8 +179,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
break; break;
case ClassOpenTag: case ClassOpenTag:
if(ctx->buffer.len) TRY(ctx->whiteSpace(ctx, ctx->buffer.data));
ctx->state = StateOpen; ctx->state = StateOpen;
if(ctx->buffer.len) TRY(ctx->whiteSpace(ctx, ctx->buffer.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
break; break;
@ -197,8 +197,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
// fall through // fall through
default: default:
if(!ctx->elementDepth) ERROR("Content cannot appear at stream level."); if(!ctx->elementDepth) ERROR("Content cannot appear at stream level.");
if(ctx->buffer.len) TRY(ctx->whiteSpace(ctx, ctx->buffer.data));
ctx->state = StateData; ctx->state = StateData;
if(ctx->buffer.len) TRY(ctx->whiteSpace(ctx, ctx->buffer.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
APPEND_CH(buffer, ch); APPEND_CH(buffer, ch);
break; break;
@ -208,9 +208,9 @@ int csxml_feedChar(struct csxml* ctx, char ch)
case StateData: case StateData:
switch(c) { switch(c) {
case ClassOpenTag: case ClassOpenTag:
ctx->state = StateOpen;
TRY(ctx->content(ctx, ctx->buffer.data)); TRY(ctx->content(ctx, ctx->buffer.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
ctx->state = StateOpen;
break; break;
case ClassEntity: case ClassEntity:
@ -240,9 +240,9 @@ int csxml_feedChar(struct csxml* ctx, char ch)
case StateCDATA2: case StateCDATA2:
if(ch == '>') { if(ch == '>') {
ctx->state = StateNone;
TRY(ctx->cdata(ctx, ctx->buffer.data)); TRY(ctx->cdata(ctx, ctx->buffer.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
ctx->state = StateNone;
} else if(ch == ']') { } else if(ch == ']') {
APPEND_CH(buffer, ']'); APPEND_CH(buffer, ']');
} else { } else {
@ -317,8 +317,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
case StatePI2: case StatePI2:
if(ch != '>') ERROR("Invalid target for PI"); if(ch != '>') ERROR("Invalid target for PI");
else { else {
TRY(ctx->PI(ctx, ctx->buffer2.data, 0));
ctx->state = StateNone; ctx->state = StateNone;
TRY(ctx->PI(ctx, ctx->buffer2.data, 0));
} }
break; break;
@ -329,9 +329,9 @@ int csxml_feedChar(struct csxml* ctx, char ch)
case StatePI3: case StatePI3:
if(ch == '>') { if(ch == '>') {
ctx->state = StateNone;
TRY(ctx->PI(ctx, ctx->buffer2.data, ctx->buffer.data)); TRY(ctx->PI(ctx, ctx->buffer2.data, ctx->buffer.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
ctx->state = StateNone;
} else if(ch == '?') { } else if(ch == '?') {
APPEND_CH(buffer, '?'); APPEND_CH(buffer, '?');
} else { } else {
@ -378,9 +378,9 @@ int csxml_feedChar(struct csxml* ctx, char ch)
case StateComment3: case StateComment3:
if(ch != '>') ERROR("`--' not valid in comments"); if(ch != '>') ERROR("`--' not valid in comments");
ctx->state = StateNone;
TRY(ctx->comment(ctx, ctx->buffer.data)); TRY(ctx->comment(ctx, ctx->buffer.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
ctx->state = StateNone;
break; break;
case StateElemName: case StateElemName:
@ -399,8 +399,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
switch(ch) { switch(ch) {
case L'>': case L'>':
TRY(list_push(ctx, &ctx->elemStack, &ctx->elemName)); TRY(list_push(ctx, &ctx->elemStack, &ctx->elemName));
TRY(ctx->element(ctx, ctx->elemName.data, 0));
ctx->state = StateNone; ctx->state = StateNone;
TRY(ctx->element(ctx, ctx->elemName.data, 0));
++ctx->elementDepth; ++ctx->elementDepth;
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
break; break;
@ -430,8 +430,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
switch(ch) { switch(ch) {
case '>': case '>':
TRY(list_push(ctx, &ctx->elemStack, &ctx->elemName)); TRY(list_push(ctx, &ctx->elemStack, &ctx->elemName));
TRY(ctx->element(ctx, ctx->elemName.data, ctx->elemAttrNames.len));
ctx->state = StateNone; ctx->state = StateNone;
TRY(ctx->element(ctx, ctx->elemName.data, ctx->elemAttrNames.len));
++ctx->elementDepth; ++ctx->elementDepth;
break; break;
@ -488,10 +488,10 @@ int csxml_feedChar(struct csxml* ctx, char ch)
if(ch == '/') { if(ch == '/') {
ctx->state = StateNeedClose; ctx->state = StateNeedClose;
} else if(ch == '>') { } else if(ch == '>') {
ctx->state = StateNone;
TRY(ctx->element(ctx, ctx->elemName.data, ctx->elemAttrVals.len)); TRY(ctx->element(ctx, ctx->elemName.data, ctx->elemAttrVals.len));
TRY(list_push(ctx, &ctx->elemStack, &ctx->elemName)); TRY(list_push(ctx, &ctx->elemStack, &ctx->elemName));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
ctx->state = StateNone;
++ctx->elementDepth; ++ctx->elementDepth;
} else ERROR("Invalid character after attribute."); } else ERROR("Invalid character after attribute.");
break; break;
@ -500,10 +500,10 @@ int csxml_feedChar(struct csxml* ctx, char ch)
case StateNeedClose: case StateNeedClose:
if(ch != '>') ERROR("Stray `/' in open tag."); if(ch != '>') ERROR("Stray `/' in open tag.");
ctx->state = StateNone;
TRY(ctx->element(ctx, ctx->elemName.data, ctx->elemAttrVals.len)); TRY(ctx->element(ctx, ctx->elemName.data, ctx->elemAttrVals.len));
TRY(ctx->closeTag(ctx, ctx->elemName.data)); TRY(ctx->closeTag(ctx, ctx->elemName.data));
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
ctx->state = StateNone;
break; break;
case StateClose: case StateClose:
@ -527,8 +527,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
if(ch != '>') ERROR("Invalid character in close tag name."); if(ch != '>') ERROR("Invalid character in close tag name.");
TRY(buffer_copy(ctx, &ctx->elemName, list_pop(&ctx->elemStack))); TRY(buffer_copy(ctx, &ctx->elemName, list_pop(&ctx->elemStack)));
if(strcmp(ctx->elemName.data, ctx->buffer.data)) ERROR("Mismatched close tag."); if(strcmp(ctx->elemName.data, ctx->buffer.data)) ERROR("Mismatched close tag.");
TRY(ctx->closeTag(ctx, ctx->elemName.data));
ctx->state = StateNone; ctx->state = StateNone;
TRY(ctx->closeTag(ctx, ctx->elemName.data));
--ctx->elementDepth; --ctx->elementDepth;
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
@ -540,8 +540,8 @@ int csxml_feedChar(struct csxml* ctx, char ch)
if(ch != '>') ERROR("Invalid data in close tag."); if(ch != '>') ERROR("Invalid data in close tag.");
TRY(buffer_copy(ctx, &ctx->elemName, list_pop(&ctx->elemStack))); TRY(buffer_copy(ctx, &ctx->elemName, list_pop(&ctx->elemStack)));
if(strcmp(ctx->elemName.data, ctx->buffer.data)) ERROR("Mismatched close tag."); if(strcmp(ctx->elemName.data, ctx->buffer.data)) ERROR("Mismatched close tag.");
TRY(ctx->closeTag(ctx, ctx->elemName.data));
ctx->state = StateNone; ctx->state = StateNone;
TRY(ctx->closeTag(ctx, ctx->elemName.data));
--ctx->elementDepth; --ctx->elementDepth;
CLEAR_BUFFER(buffer); CLEAR_BUFFER(buffer);
break; break;
@ -598,8 +598,8 @@ const char* csxml_entityRef(struct csxml* ctx, const char* ent)
q = ctx->entityRef(ctx, ent); q = ctx->entityRef(ctx, ent);
if(!q) { if(!q) {
ctx->unknownEntity(ctx, ent);
ctx->state = StateError; ctx->state = StateError;
ctx->unknownEntity(ctx, ent);
return 0; return 0;
} }

View File

@ -163,26 +163,26 @@ doBuffer:
break; break;
case ClassOpenTag: case ClassOpenTag:
if(!buffer.empty()) callback->whiteSpace(buffer);
state = StateOpen; state = StateOpen;
if(!buffer.empty()) callback->whiteSpace(buffer);
buffer.clear(); buffer.clear();
break; break;
case ClassEntity: case ClassEntity:
if(expandEntities) { if(expandEntities) {
if(!elementDepth) ERROR(L"Entities cannot appear at stream level."); if(!elementDepth) ERROR(L"Entities cannot appear at stream level.");
state = StateEntity;
if(!buffer.empty()) callback->whiteSpace(buffer); if(!buffer.empty()) callback->whiteSpace(buffer);
buffer.clear(); buffer.clear();
parsingAttr = false; parsingAttr = false;
state = StateEntity;
break; break;
} }
// fall through // fall through
default: default:
if(!elementDepth) ERROR(L"Content cannot appear at stream level."); if(!elementDepth) ERROR(L"Content cannot appear at stream level.");
if(!buffer.empty()) callback->whiteSpace(buffer);
state = StateData; state = StateData;
if(!buffer.empty()) callback->whiteSpace(buffer);
buffer = ch; buffer = ch;
break; break;
} }
@ -191,16 +191,16 @@ doBuffer:
case StateData: case StateData:
switch(c) { switch(c) {
case ClassOpenTag: case ClassOpenTag:
state = StateOpen;
callback->content(buffer); callback->content(buffer);
buffer.clear(); buffer.clear();
state = StateOpen;
break; break;
case ClassEntity: case ClassEntity:
state = StateEntity;
callback->content(buffer); callback->content(buffer);
buffer.clear(); buffer.clear();
parsingAttr = false; parsingAttr = false;
state = StateEntity;
break; break;
default: default:
@ -225,9 +225,9 @@ doBuffer:
case StateCDATA2: case StateCDATA2:
if(ch == L'>') { if(ch == L'>') {
state = StateNone;
callback->cdata(buffer); callback->cdata(buffer);
buffer.clear(); buffer.clear();
state = StateNone;
} else if(ch == L']') { } else if(ch == L']') {
buffer += ch; buffer += ch;
} else { } else {
@ -298,9 +298,9 @@ doBuffer:
case StatePI2: case StatePI2:
if(ch != L'>') ERROR(L"Invalid target for PI"); if(ch != L'>') ERROR(L"Invalid target for PI");
else { else {
state = StateNone;
callback->PI(buffer2, L""); callback->PI(buffer2, L"");
buffer.clear(); buffer.clear();
state = StateNone;
} }
break; break;
@ -311,9 +311,9 @@ doBuffer:
case StatePI3: case StatePI3:
if(ch == L'>') { if(ch == L'>') {
state = StateNone;
callback->PI(buffer2, buffer); callback->PI(buffer2, buffer);
buffer.clear(); buffer.clear();
state = StateNone;
} else if(ch == '?') { } else if(ch == '?') {
buffer += L'?'; buffer += L'?';
} else { } else {
@ -360,9 +360,9 @@ doBuffer:
case StateComment3: case StateComment3:
if(ch != L'>') ERROR(L"`--' not valid in comments"); if(ch != L'>') ERROR(L"`--' not valid in comments");
state = StateNone;
callback->comment(buffer); callback->comment(buffer);
buffer.clear(); buffer.clear();
state = StateNone;
break; break;
case StateElemName: case StateElemName:
@ -382,8 +382,8 @@ doBuffer:
switch(ch) { switch(ch) {
case L'>': case L'>':
elemStack.push_back(buffer); elemStack.push_back(buffer);
callback->element(buffer, elemAttrs);
state = StateNone; state = StateNone;
callback->element(buffer, elemAttrs);
++elementDepth; ++elementDepth;
buffer.clear(); buffer.clear();
break; break;
@ -412,9 +412,9 @@ doBuffer:
switch(ch) { switch(ch) {
case L'>': case L'>':
elemStack.push_back(elemName); elemStack.push_back(elemName);
state = StateNone;
callback->element(elemName, elemAttrs); callback->element(elemName, elemAttrs);
buffer.clear(); buffer.clear();
state = StateNone;
++elementDepth; ++elementDepth;
break; break;
@ -474,10 +474,10 @@ doBuffer:
if(ch == L'/') { if(ch == L'/') {
state = StateNeedClose; state = StateNeedClose;
} else if(ch == L'>') { } else if(ch == L'>') {
state = StateNone;
callback->element(elemName, elemAttrs); callback->element(elemName, elemAttrs);
elemStack.push_back(elemName); elemStack.push_back(elemName);
buffer.clear(); buffer.clear();
state = StateNone;
++elementDepth; ++elementDepth;
} else ERROR(L"Invalid character after attribute."); } else ERROR(L"Invalid character after attribute.");
break; break;
@ -486,10 +486,10 @@ doBuffer:
case StateNeedClose: case StateNeedClose:
if(ch != L'>') ERROR(L"Stray `/' in open tag."); if(ch != L'>') ERROR(L"Stray `/' in open tag.");
state = StateNone;
callback->element(elemName, elemAttrs); callback->element(elemName, elemAttrs);
callback->closeTag(elemName); callback->closeTag(elemName);
buffer.clear(); buffer.clear();
state = StateNone;
break; break;
case StateClose: case StateClose:
@ -513,9 +513,9 @@ doBuffer:
if(ch != L'>') ERROR(L"Invalid character in close tag name."); if(ch != L'>') ERROR(L"Invalid character in close tag name.");
if(elemStack.back() != buffer) ERROR(L"Mismatched close tag."); if(elemStack.back() != buffer) ERROR(L"Mismatched close tag.");
elemStack.pop_back(); elemStack.pop_back();
state = StateNone;
callback->closeTag(buffer); callback->closeTag(buffer);
buffer.clear(); buffer.clear();
state = StateNone;
--elementDepth; --elementDepth;
} }
break; break;
@ -525,9 +525,9 @@ doBuffer:
if(ch != L'>') ERROR(L"Invalid data in close tag."); if(ch != L'>') ERROR(L"Invalid data in close tag.");
if(elemStack.back() != elemName) ERROR(L"Mismatched close tag."); if(elemStack.back() != elemName) ERROR(L"Mismatched close tag.");
elemStack.pop_back(); elemStack.pop_back();
state = StateNone;
callback->closeTag(elemName); callback->closeTag(elemName);
buffer.clear(); buffer.clear();
state = StateNone;
--elementDepth; --elementDepth;
break; break;