Fix for bug 275564 (Mozilla SVG build 2004122009, 2004121909: wrong 'mismatched tag' message). Patch by bz, r=peterv, sr=jst, a=bsmedberg.

This commit is contained in:
peterv%propagandism.org 2005-07-26 13:09:19 +00:00
parent 0ab59e5717
commit 3236c010d5
2 changed files with 116 additions and 108 deletions

View File

@ -721,9 +721,7 @@ CreateSourceText(const PRInt32 aColNumber,
}
nsresult
nsExpatDriver::HandleError(const char *aBuffer,
PRUint32 aLength,
PRBool aIsFinal)
nsExpatDriver::HandleError()
{
PRInt32 code = XML_GetErrorCode(mExpatParser);
NS_WARN_IF_FALSE(code > XML_ERROR_NONE, "unexpected XML error code");
@ -761,9 +759,9 @@ nsExpatDriver::HandleError(const char *aBuffer,
nsAutoString tagName;
if (uriEnd && nameEnd) {
// We have a prefix.
tagName.Append(nameEnd + 1, pos - nameEnd - 1);
tagName.Append(PRUnichar(':'));
// We have a prefix.
tagName.Append(nameEnd + 1, pos - nameEnd - 1);
tagName.Append(PRUnichar(':'));
}
const PRUnichar *nameStart = uriEnd ? uriEnd + 1 : mismatch;
tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
@ -783,40 +781,29 @@ nsExpatDriver::HandleError(const char *aBuffer,
nsTextFormatter::smprintf_free(message);
}
nsAutoString sourceLine;
if (!aIsFinal) {
GetLine(aBuffer, aLength,
XML_GetCurrentByteIndex(mExpatParser) - mBytesParsed,
sourceLine);
}
else {
sourceLine.Append(mLastLine);
}
// Adjust the column number so that it is one based rather than zero based.
PRInt32 colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
PRInt32 lineNumber = XML_GetCurrentLineNumber(mExpatParser);
nsAutoString errorText;
CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
colNumber, errorText);
nsAutoString sourceText;
CreateSourceText(colNumber, mLastLine.get(), sourceText);
nsCOMPtr<nsIConsoleService> cs
(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
if (serr && cs) {
if (NS_SUCCEEDED(serr->Init(description.get(),
mURISpec.get(),
sourceLine.get(),
sourceText.get(),
lineNumber, colNumber,
nsIScriptError::errorFlag, "malformed-xml")))
cs->LogMessage(serr);
}
nsAutoString errorText;
CreateErrorText(description.get(), XML_GetBase(mExpatParser),
XML_GetCurrentLineNumber(mExpatParser), colNumber,
errorText);
nsAutoString sourceText;
CreateSourceText(colNumber, sourceLine.get(), sourceText);
NS_ASSERTION(mSink, "no sink?");
if (mSink) {
mSink->ReportError(errorText.get(), sourceText.get());
@ -831,27 +818,114 @@ nsExpatDriver::ParseBuffer(const char* aBuffer,
PRBool aIsFinal)
{
NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
NS_ASSERTION(aLength % sizeof(PRUnichar) == 0,
"We can have a PRUnichar spanning chunks?");
NS_PRECONDITION(mBytesParsed % sizeof(PRUnichar) == 0,
"Parsed part of a PRUnichar?");
NS_PRECONDITION(mBytePosition % sizeof(PRUnichar) == 0,
"Parsed part of a PRUnichar?");
NS_PRECONDITION(XML_GetCurrentByteIndex(mExpatParser) == -1 ||
XML_GetCurrentByteIndex(mExpatParser) % sizeof(PRUnichar) == 0,
"Consumed part of a PRUnichar?");
if (mExpatParser && mInternalState == NS_OK) {
if (!XML_Parse(mExpatParser, aBuffer, aLength, aIsFinal)) {
if (mInternalState == NS_ERROR_HTMLPARSER_BLOCK ||
mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING) {
mBytePosition = (XML_GetCurrentByteIndex(mExpatParser) - mBytesParsed);
mBytesParsed += mBytePosition;
XML_Bool parsedAll = XML_Parse(mExpatParser, aBuffer, aLength, aIsFinal);
PRInt32 parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser);
NS_ASSERTION(parserBytesConsumed == -1 ||
parserBytesConsumed % sizeof(PRUnichar) == 0,
"Consumed part of a PRUnichar?");
// Now figure out the startOffset for appending to mLastLine -- this
// calculation is the same no matter whether we saw an error, got blocked,
// parsed it all but didn't consume it all, or whatever else happened.
const PRUnichar* const buffer =
NS_REINTERPRET_CAST(const PRUnichar*, aBuffer);
PRUint32 startOffset;
// we assume that if expat failed to consume some bytes last time it won't
// consume them this time without also consuming some bytes from aBuffer.
// Note that if expat consumed everything we passed it, it will have nulled
// out all its internal pointers to data, so parserBytesConsumed will come
// out -1 in that case.
if (buffer) {
if (parserBytesConsumed < 0 ||
(PRUint32)parserBytesConsumed >= mBytesParsed) {
// We consumed something
if (parserBytesConsumed < 0) {
NS_ASSERTION(parserBytesConsumed == -1,
"Unexpected negative value?");
// Consumed everything.
startOffset = aLength;
}
else {
// Consumed something, but not all
NS_ASSERTION(parserBytesConsumed - mBytesParsed <= aLength,
"Too many bytes consumed?");
startOffset = (parserBytesConsumed - mBytesParsed) /
sizeof(PRUnichar);
}
// Now startOffset points one past the last PRUnichar consumed in
// buffer
while (startOffset-- != 0) {
if (buffer[startOffset] == '\n' || buffer[startOffset] == '\r') {
mLastLine.Truncate();
break;
}
}
// Now startOffset is pointing to the last newline we consumed (or to
// -1 if there weren't any consumed in this chunk). Make startOffset
// point to the first char of the first line whose end we haven't
// consumed yet.
++startOffset;
}
else {
HandleError(aBuffer, aLength, aIsFinal);
// Didn't parse anything new. So append all of aBuffer.
startOffset = 0;
}
}
if (!parsedAll) {
if (mInternalState == NS_ERROR_HTMLPARSER_BLOCK ||
mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING) {
NS_ASSERTION((PRUint32)parserBytesConsumed >= mBytesParsed,
"How'd this happen?");
mBytePosition = parserBytesConsumed - mBytesParsed;
mBytesParsed = parserBytesConsumed;
if (buffer) {
PRUint32 endOffset = mBytePosition / sizeof(PRUnichar);
NS_ASSERTION(startOffset <= endOffset,
"Something is confused about what we've consumed");
// Only append the data we actually parsed. The rest will come
// through this method again.
mLastLine.Append(Substring(buffer + startOffset,
buffer + endOffset));
}
}
else {
// An error occured, look for the next newline after the last one we
// consumed.
PRUint32 length = aLength / sizeof(PRUnichar);
if (buffer) {
PRUint32 endOffset = startOffset;
while (endOffset < length && buffer[endOffset] != '\n' &&
buffer[endOffset] != '\r') {
++endOffset;
}
mLastLine.Append(Substring(buffer + startOffset,
buffer + endOffset));
}
HandleError();
mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
}
return mInternalState;
}
if (aBuffer && aLength != 0) {
// Cache the last line in the buffer
GetLine(aBuffer, aLength, aLength - sizeof(PRUnichar), mLastLine);
if (!aIsFinal && buffer) {
mLastLine.Append(Substring(buffer + startOffset,
buffer + aLength / sizeof(PRUnichar)));
}
mBytesParsed += aLength;
mBytePosition = 0;
}
@ -859,76 +933,6 @@ nsExpatDriver::ParseBuffer(const char* aBuffer,
return NS_OK;
}
void
nsExpatDriver::GetLine(const char* aSourceBuffer,
PRUint32 aLength,
PRUint32 aOffset,
nsString& aLine)
{
// Figure out the line inside aSourceBuffer that contains character specified
// by aOffset. Copy it into aLine.
NS_ASSERTION(aOffset < aLength, "?");
// Assert that the byteIndex and the length of the buffer are even.
NS_ASSERTION(aOffset % 2 == 0 && aLength % 2 == 0, "?");
// Will try to find the start of the line.
PRUnichar* start = (PRUnichar*)&aSourceBuffer[aOffset];
// Will try to find the end of the line.
PRUnichar* end = (PRUnichar*)&aSourceBuffer[aOffset];
// Track the position of the 'start' pointer into the buffer.
PRUint32 startIndex = aOffset / sizeof(PRUnichar);
// Track the position of the 'end' pointer into the buffer.
PRUint32 endIndex = aOffset / sizeof(PRUnichar);
PRUint32 numCharsInBuffer = aLength / sizeof(PRUnichar);
// Use start to find the first new line before the error position and end to
// find the first new line after the error position.
PRBool reachedStart = startIndex <= 0 || *start == '\n' || *start == '\r';
PRBool reachedEnd = endIndex >= numCharsInBuffer || *end == '\n' ||
*end == '\r';
while (!reachedStart || !reachedEnd) {
if (!reachedStart) {
--start;
--startIndex;
reachedStart = startIndex <= 0 || *start == '\n' || *start == '\r';
}
if (!reachedEnd) {
++end;
++endIndex;
reachedEnd = endIndex >= numCharsInBuffer || *end == '\n' ||
*end == '\r';
}
}
aLine.Truncate(0);
if (startIndex == endIndex) {
// Special case if the error is on a line where the only character is a
// newline. Do nothing.
}
else {
NS_ASSERTION(endIndex - startIndex >= sizeof(PRUnichar), "?");
// At this point, there are two cases. Either the error is on the first
// line or on subsequent lines. If the error is on the first line,
// startIndex will decrement all the way to zero. If not, startIndex
// will decrement to the position of the newline character on the
// previous line. So, in the first case, the start position of the
// error line = startIndex (== 0). In the second case, the start
// position of the error line = startIndex + 1. In both cases, the end
// position of the error line will be (endIndex - 1).
PRUint32 startPosn = startIndex <= 0 ? startIndex : startIndex + 1;
// At this point the substring starting at startPosn and ending at
// (endIndex - 1) is the line on which the error occurred. Copy that
// substring into the error structure.
const PRUnichar* unicodeBuffer = (const PRUnichar*)aSourceBuffer;
aLine.Append(&unicodeBuffer[startPosn], endIndex - startPosn);
}
}
NS_IMETHODIMP
nsExpatDriver::CreateNewInstance(nsIDTD** aInstancePtrResult)
{
@ -958,8 +962,8 @@ nsExpatDriver::ConsumeToken(nsScanner& aScanner,
if (NS_FAILED(mInternalState)) {
if (mInternalState == NS_ERROR_HTMLPARSER_BLOCK) {
// mBytePosition / 2 => character position, one char is two bytes.
aScanner.SetPosition(start.advance(mBytePosition / 2), PR_TRUE);
aScanner.SetPosition(start.advance(mBytePosition / sizeof(PRUnichar)),
PR_TRUE);
aScanner.Mark();
}

View File

@ -91,7 +91,7 @@ private:
nsAString& aAbsURL);
nsresult ParseBuffer(const char* aBuffer, PRUint32 aLength, PRBool aIsFinal);
nsresult HandleError(const char *aBuffer, PRUint32 aLength, PRBool aIsFinal);
nsresult HandleError();
void GetLine(const char* aSourceBuffer, PRUint32 aLength, PRUint32 aOffset,
nsString& aLine);
@ -106,8 +106,12 @@ private:
PRPackedBool mInCData;
PRPackedBool mInInternalSubset;
PRPackedBool mInExternalDTD;
// Number of bytes parsed in the current buffer.
PRInt32 mBytePosition;
nsresult mInternalState;
// Total number of bytes parsed.
PRUint32 mBytesParsed;
nsCOMPtr<nsIExpatSink> mSink;
const nsCatalogData* mCatalogData; // weak