Part of fix for bug 192139 (Integrate latest Expat). Some cleanup in nsExpatDriver.cpp/.h. r=Pike, sr=jst.

This commit is contained in:
peterv%propagandism.org 2004-05-08 14:07:18 +00:00
Родитель 21356a8491
Коммит b9cefb2fdb
2 изменённых файлов: 450 добавлений и 429 удалений

Просмотреть файл

@ -34,6 +34,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsExpatDriver.h"
#include "nsIParser.h"
#include "nsCOMPtr.h"
@ -52,10 +53,11 @@
#include "nsCRT.h"
static const char kWhitespace[] = " \r\n\t"; // Optimized for typical cases
static const PRUnichar kUTF16[] = { 'U', 'T', 'F', '-', '1', '6', '\0' };
/***************************** EXPAT CALL BACKS *******************************/
/***************************** EXPAT CALL BACKS ******************************/
// The callback handlers that get called from the expat parser.
// The callback handlers that get called from the expat parser
PR_STATIC_CALLBACK(void)
Driver_HandleStartElement(void *aUserData,
const XML_Char *aName,
@ -85,8 +87,8 @@ Driver_HandleCharacterData(void *aUserData,
{
NS_ASSERTION(aUserData, "expat driver should exist");
if (aUserData) {
NS_STATIC_CAST(nsExpatDriver*,aUserData)->HandleCharacterData((PRUnichar*)aData,
PRUint32(aLength));
nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
driver->HandleCharacterData((const PRUnichar*)aData, PRUint32(aLength));
}
}
@ -107,8 +109,8 @@ Driver_HandleProcessingInstruction(void *aUserData,
{
NS_ASSERTION(aUserData, "expat driver should exist");
if (aUserData) {
NS_STATIC_CAST(nsExpatDriver*,aUserData)->HandleProcessingInstruction((const PRUnichar*)aTarget,
(const PRUnichar*)aData);
nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
driver->HandleProcessingInstruction((const PRUnichar*)aTarget, (const PRUnichar*)aData);
}
}
@ -119,8 +121,8 @@ Driver_HandleDefault(void *aUserData,
{
NS_ASSERTION(aUserData, "expat driver should exist");
if (aUserData) {
NS_STATIC_CAST(nsExpatDriver*,aUserData)->HandleDefault((const PRUnichar*)aData,
PRUint32(aLength));
nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
driver->HandleDefault((const PRUnichar*)aData, PRUint32(aLength));
}
}
@ -163,29 +165,35 @@ Driver_HandleEndDoctypeDecl(void *aUserData)
PR_STATIC_CALLBACK(int)
Driver_HandleExternalEntityRef(void *aExternalEntityRefHandler,
const XML_Char *openEntityNames,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId)
const XML_Char *aOpenEntityNames,
const XML_Char *aBase,
const XML_Char *aSystemId,
const XML_Char *aPublicId)
{
NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist");
if (aExternalEntityRefHandler) {
return NS_STATIC_CAST(nsExpatDriver*,
aExternalEntityRefHandler)->HandleExternalEntityRef(
(const PRUnichar*)openEntityNames, (const PRUnichar*)base,
(const PRUnichar*)systemId, (const PRUnichar*)publicId);
}
if (!aExternalEntityRefHandler) {
return 1;
}
/***************************** END CALL BACKS *********************************/
nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*,
aExternalEntityRefHandler);
/***************************** CATALOG UTILS **********************************/
return driver->HandleExternalEntityRef((const PRUnichar*)aOpenEntityNames,
(const PRUnichar*)aBase,
(const PRUnichar*)aSystemId,
(const PRUnichar*)aPublicId);
}
/***************************** END CALL BACKS ********************************/
/***************************** CATALOG UTILS *********************************/
// Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
// MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
// Since Mozilla is not validating, no need to fetch a *huge* file at each click.
// XXX The cleanest solution here would be to fix Bug 98413: Implement XML Catalogs
// Since Mozilla is not validating, no need to fetch a *huge* file at each
// click.
// XXX The cleanest solution here would be to fix Bug 98413: Implement XML
// Catalogs.
struct nsCatalogData {
const char* mPublicID;
const char* mLocalDTD;
@ -210,67 +218,61 @@ static const nsCatalogData kCatalogTable[] = {
static const nsCatalogData*
LookupCatalogData(const PRUnichar* aPublicID)
{
nsCAutoString publicID;
publicID.AssignWithConversion(aPublicID);
nsDependentString publicID(aPublicID);
// linear search for now since the number of entries is going to
// be negligible, and the fix for bug 98413 would get rid of this
// code anyway
const nsCatalogData* data = kCatalogTable;
while (data->mPublicID) {
if (publicID.Equals(data->mPublicID)) {
if (publicID.EqualsASCII(data->mPublicID)) {
return data;
}
++data;
}
return nsnull;
}
// aCatalogData can be null. If not null, it provides a hook to additional
// built-in knowledge on the resource that we are trying to load.
// aDTD is an in/out parameter. Returns true if the local DTD specified in the
// catalog data exists or if the filename contained within the url exists in
// the special DTD directory. If either of this exists, aDTD is set to the
// file: url that points to the DTD file found in the local DTD directory AND
// the old URI is relased.
// built-in knowledge on the resource that we are trying to load. Returns true
// if the local DTD specified in the catalog data exists or if the filename
// contained within the url exists in the special DTD directory. If either of
// this exists, aResult is set to the file: url that points to the DTD file
// found in the local DTD directory.
static PRBool
IsLoadableDTD(const nsCatalogData* aCatalogData, nsCOMPtr<nsIURI>* aDTD)
IsLoadableDTD(const nsCatalogData* aCatalogData, nsIURI* aDTD,
nsIURI** aResult)
{
PRBool isLoadable = PR_FALSE;
nsresult res = NS_OK;
if (!aDTD || !*aDTD) {
NS_ASSERTION(0, "Null parameter.");
return PR_FALSE;
}
NS_ASSERTION(aDTD, "Null parameter.");
nsCAutoString fileName;
if (aCatalogData) {
// remap the DTD to a known local DTD
fileName.Assign(aCatalogData->mLocalDTD);
}
if (fileName.IsEmpty()) {
// try to see if the user has installed the DTD file -- we extract the
// Try to see if the user has installed the DTD file -- we extract the
// filename.ext of the DTD here. Hence, for any DTD for which we have
// no predefined mapping, users just have to copy the DTD file to our
// special DTD directory and it will be picked
nsCOMPtr<nsIURL> dtdURL;
dtdURL = do_QueryInterface(*aDTD, &res);
if (NS_FAILED(res)) {
// special DTD directory and it will be picked.
nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD);
if (!dtdURL) {
return PR_FALSE;
}
res = dtdURL->GetFileName(fileName);
if (NS_FAILED(res) || fileName.IsEmpty()) {
dtdURL->GetFileName(fileName);
if (fileName.IsEmpty()) {
return PR_FALSE;
}
}
nsCOMPtr<nsIFile> dtdPath;
NS_GetSpecialDirectory(NS_GRE_DIR,
getter_AddRefs(dtdPath));
if (!dtdPath)
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dtdPath));
if (!dtdPath) {
return PR_FALSE;
}
nsCOMPtr<nsILocalFile> lfile = do_QueryInterface(dtdPath);
@ -283,39 +285,38 @@ IsLoadableDTD(const nsCatalogData* aCatalogData, nsCOMPtr<nsIURI>* aDTD)
PRBool exists;
dtdPath->Exists(&exists);
if (!exists) {
return PR_FALSE;
}
if (exists) {
// The DTD was found in the local DTD directory.
// Set aDTD to a file: url pointing to the local DT
nsCOMPtr<nsIURI> dtdURI;
NS_NewFileURI(getter_AddRefs(dtdURI), dtdPath);
// Set aDTD to a file: url pointing to the local DTD
NS_NewFileURI(aResult, dtdPath);
if (dtdURI) {
*aDTD = dtdURI;
isLoadable = PR_TRUE;
}
return *aResult != nsnull;
}
return isLoadable;
}
/***************************** END CATALOG UTILS ******************************/
/***************************** END CATALOG UTILS *****************************/
NS_IMPL_ISUPPORTS2(nsExpatDriver,
nsITokenizer,
nsIDTD)
nsresult
NS_NewExpatDriver(nsIDTD** aResult) {
nsExpatDriver* driver = nsnull;
NS_NEWXPCOM(driver, nsExpatDriver);
NS_ENSURE_TRUE(driver,NS_ERROR_OUT_OF_MEMORY);
NS_NewExpatDriver(nsIDTD** aResult)
{
*aResult = new nsExpatDriver();
if (!*aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
return driver->QueryInterface(NS_GET_IID(nsIDTD), (void**)aResult);
NS_ADDREF(*aResult);
return NS_OK;
}
nsExpatDriver::nsExpatDriver()
:mExpatParser(0),
: mExpatParser(nsnull),
mInCData(PR_FALSE),
mInDoctype(PR_FALSE),
mInExternalDTD(PR_FALSE),
@ -323,17 +324,14 @@ nsExpatDriver::nsExpatDriver()
mBytePosition(0),
mInternalState(NS_OK),
mBytesParsed(0),
mSink(0),
mCatalogData(nsnull)
{
}
nsExpatDriver::~nsExpatDriver()
{
NS_IF_RELEASE(mSink);
if (mExpatParser) {
XML_ParserFree(mExpatParser);
mExpatParser = nsnull;
}
}
@ -360,6 +358,7 @@ nsExpatDriver::HandleStartElement(const PRUnichar *aValue,
XML_GetIdAttributeIndex(mExpatParser),
XML_GetCurrentLineNumber(mExpatParser));
}
return NS_OK;
}
@ -368,13 +367,11 @@ nsExpatDriver::HandleEndElement(const PRUnichar *aValue)
{
NS_ASSERTION(mSink, "content sink not found!");
if (mSink){
nsresult result = mSink->HandleEndElement(aValue);
if (result == NS_ERROR_HTMLPARSER_BLOCK) {
if (mSink &&
mSink->HandleEndElement(aValue) == NS_ERROR_HTMLPARSER_BLOCK) {
mInternalState = NS_ERROR_HTMLPARSER_BLOCK;
XML_BlockParser(mExpatParser);
}
}
return NS_OK;
}
@ -418,13 +415,12 @@ nsExpatDriver::HandleProcessingInstruction(const PRUnichar *aTarget,
{
NS_ASSERTION(mSink, "content sink not found!");
if (mSink){
nsresult result = mSink->HandleProcessingInstruction(aTarget, aData);
if (result == NS_ERROR_HTMLPARSER_BLOCK) {
if (mSink &&
mSink->HandleProcessingInstruction(aTarget, aData) ==
NS_ERROR_HTMLPARSER_BLOCK) {
mInternalState = NS_ERROR_HTMLPARSER_BLOCK;
XML_BlockParser(mExpatParser);
}
}
return NS_OK;
}
@ -437,8 +433,9 @@ nsExpatDriver::HandleXMLDeclaration(const PRUnichar *aValue,
// <?xml version='a'?>
// 0123456789012345678
PRUint32 i = 17; // ?> can start at position 17 at the earliest
for (; i < aLength; ++i) {
// ?> can start at position 17 at the earliest
PRUint32 i;
for (i = 17; i < aLength; ++i) {
if (aValue[i] == '?')
break;
}
@ -447,8 +444,9 @@ nsExpatDriver::HandleXMLDeclaration(const PRUnichar *aValue,
// +1 because '>' follows '?'
i += 2;
if (i > aLength)
if (i > aLength) {
return NS_OK; // Bad declaration
}
return mSink->HandleXMLDeclaration(aValue, i);
}
@ -468,14 +466,14 @@ nsExpatDriver::HandleDefault(const PRUnichar *aValue,
if (!mHandledXMLDeclaration && !mBytesParsed) {
static const PRUnichar xmlDecl[] = { '<', '?', 'x', 'm', 'l', ' ', '\0' };
// strlen("<?xml version='a'?>") == 19, shortest decl
if ((aLength >= 19) &&
(nsCRT::strncmp(aValue, xmlDecl, 6) == 0)) {
if (aLength >= 19 && nsCRT::strncmp(aValue, xmlDecl, 6) == 0) {
HandleXMLDeclaration(aValue, aLength);
}
}
static const PRUnichar newline[] = { '\n', '\0' };
for (PRUint32 i = 0; i < aLength && NS_SUCCEEDED(mInternalState); i++) {
PRUint32 i;
for (i = 0; i < aLength && NS_SUCCEEDED(mInternalState); ++i) {
if (aValue[i] == '\n' || aValue[i] == '\r') {
mInternalState = mSink->HandleCharacterData(newline, 1);
}
@ -489,6 +487,7 @@ nsresult
nsExpatDriver::HandleStartCdataSection()
{
mInCData = PR_TRUE;
return NS_OK;
}
@ -499,7 +498,8 @@ nsExpatDriver::HandleEndCdataSection()
mInCData = PR_FALSE;
if (mSink) {
mInternalState = mSink->HandleCDataSection(mCDataText.get(),mCDataText.Length());
mInternalState = mSink->HandleCDataSection(mCDataText.get(),
mCDataText.Length());
}
mCDataText.Truncate();
@ -516,17 +516,17 @@ nsExpatDriver::HandleEndCdataSection()
* We assume the string will not contain the ending '>'.
*/
static void
GetDocTypeToken(nsString& aStr,
nsString& aToken,
PRBool aQuotedString)
GetDocTypeToken(nsString& aStr, nsString& aToken, PRBool aQuotedString)
{
aStr.Trim(kWhitespace,PR_TRUE,PR_FALSE); // If we don't do this we must look ahead
// before Cut() and adjust the cut amount.
// If we don't do this we must look ahead before Cut() and adjust the cut
// amount.
aStr.Trim(kWhitespace, PR_TRUE, PR_FALSE);
if (aQuotedString) {
PRInt32 endQuote = aStr.FindChar(aStr[0], 1);
aStr.Mid(aToken, 1, endQuote - 1);
aStr.Cut(0, endQuote + 1);
} else {
}
else {
static const char* kDelimiter = " [\r\n\t"; // Optimized for typical cases
PRInt32 tokenEnd = aStr.FindCharInSet(kDelimiter);
if (tokenEnd < 0) {
@ -547,6 +547,7 @@ nsExpatDriver::HandleStartDoctypeDecl()
// allocations. In an effort to avoid too many allocations
// setting mDoctypeText's capacity to be 1K ( just a guesstimate! ).
mDoctypeText.SetCapacity(1024);
return NS_OK;
}
@ -558,9 +559,9 @@ nsExpatDriver::HandleEndDoctypeDecl()
mInDoctype = PR_FALSE;
if (mSink) {
// let the sink know any additional knowledge that we have about the document
// (currently, from bug 124570, we only expect to pass additional agent sheets
// needed to layout the XML vocabulary of the document)
// let the sink know any additional knowledge that we have about the
// document (currently, from bug 124570, we only expect to pass additional
// agent sheets needed to layout the XML vocabulary of the document)
nsCOMPtr<nsIURI> data;
if (mCatalogData && mCatalogData->mAgentSheet) {
NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet);
@ -571,34 +572,28 @@ nsExpatDriver::HandleEndDoctypeDecl()
nsAutoString token, publicId, systemId;
GetDocTypeToken(mDoctypeText, token, PR_FALSE);
if (token.Equals(NS_LITERAL_STRING("PUBLIC"))) {
if (token.EqualsLiteral("PUBLIC")) {
GetDocTypeToken(mDoctypeText, publicId, PR_TRUE);
GetDocTypeToken(mDoctypeText, systemId, PR_TRUE);
}
else if (token.Equals(NS_LITERAL_STRING("SYSTEM"))) {
else if (token.EqualsLiteral("SYSTEM")) {
GetDocTypeToken(mDoctypeText, systemId, PR_TRUE);
}
// The rest is the internal subset with [] (minus whitespace)
mDoctypeText.Trim(kWhitespace);
// Take out the brackets too, if any
if (mDoctypeText.Length() > 2) {
const nsAString& internalSubset = Substring(mDoctypeText, 1,
mDoctypeText.Length() - 2);
mInternalState = mSink->HandleDoctypeDecl(internalSubset,
name,
systemId,
publicId,
data);
mInternalState = mSink->HandleDoctypeDecl(internalSubset, name, systemId,
publicId, data);
} else {
// There's nothing but brackets, don't include them
mInternalState = mSink->HandleDoctypeDecl(nsString(),// !internalSubset
name,
systemId,
publicId,
data);
mInternalState = mSink->HandleDoctypeDecl(EmptyString(), name, systemId,
publicId, data);
}
}
mDoctypeText.SetCapacity(0);
@ -619,9 +614,12 @@ ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
if (XML_Parse((XML_Parser)aClosure, (char *)aFromSegment,
aCount * sizeof(PRUnichar), 0)) {
*aWriteCount = aCount;
return NS_OK;
}
*aWriteCount = 0;
return NS_ERROR_FAILURE;
}
@ -637,37 +635,21 @@ nsExpatDriver::HandleExternalEntityRef(const PRUnichar *openEntityNames,
mDoctypeText.Append(PRUnichar(';'));
}
int result = 1;
// Load the external entity into a buffer
// Load the external entity into a buffer.
nsCOMPtr<nsIInputStream> in;
nsAutoString absURL;
nsresult rv = OpenInputStreamFromExternalDTD(publicId,
systemId,
base,
getter_AddRefs(in),
absURL);
if (NS_FAILED(rv)) {
return result;
}
nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base,
getter_AddRefs(in), absURL);
NS_ENSURE_SUCCESS(rv, 1);
nsCOMPtr<nsIUnicharInputStream> uniIn;
rv = NS_NewUTF8ConverterStream(getter_AddRefs(uniIn), in, 1024);
NS_ENSURE_SUCCESS(rv, 1);
if (NS_FAILED(rv)) {
return result;
}
int result = 1;
if (uniIn) {
XML_Parser entParser =
XML_ExternalEntityParserCreate(
mExpatParser,
0,
(const XML_Char*) NS_LITERAL_STRING("UTF-16").get());
XML_ExternalEntityParserCreate(mExpatParser, 0, (const XML_Char*)kUTF16);
if (entParser) {
XML_SetBase(entParser, (const XML_Char*)absURL.get());
@ -675,8 +657,8 @@ nsExpatDriver::HandleExternalEntityRef(const PRUnichar *openEntityNames,
PRUint32 totalRead;
do {
rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc,
(void*)entParser, PRUint32(-1), &totalRead);
rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser,
PRUint32(-1), &totalRead);
} while (NS_SUCCEEDED(rv) && totalRead > 0);
result = XML_Parse(entParser, nsnull, 0, 1);
@ -694,17 +676,19 @@ nsresult
nsExpatDriver::OpenInputStreamFromExternalDTD(const PRUnichar* aFPIStr,
const PRUnichar* aURLStr,
const PRUnichar* aBaseURL,
nsIInputStream** in,
nsIInputStream** aStream,
nsAString& aAbsURL)
{
nsresult rv;
nsCOMPtr<nsIURI> baseURI;
rv = NS_NewURI(getter_AddRefs(baseURI), NS_ConvertUTF16toUTF8(aBaseURL));
if (NS_SUCCEEDED(rv) && baseURI) {
nsresult rv = NS_NewURI(getter_AddRefs(baseURI),
NS_ConvertUTF16toUTF8(aBaseURL));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nsnull,
baseURI);
if (NS_SUCCEEDED(rv) && uri) {
NS_ENSURE_SUCCESS(rv, rv);
// check if it is alright to load this uri
PRBool isChrome = PR_FALSE;
uri->SchemeIs("chrome", &isChrome);
@ -716,15 +700,22 @@ nsExpatDriver::OpenInputStreamFromExternalDTD(const PRUnichar* aFPIStr,
// see if the Formal Public Identifier (FPI) maps to a catalog entry
mCatalogData = LookupCatalogData(aFPIStr);
}
if (!IsLoadableDTD(mCatalogData, address_of(uri)))
nsCOMPtr<nsIURI> localURI;
if (!IsLoadableDTD(mCatalogData, uri, getter_AddRefs(localURI))) {
return NS_ERROR_NOT_IMPLEMENTED;
}
rv = NS_OpenURI(in, uri);
localURI.swap(uri);
}
rv = NS_OpenURI(aStream, uri);
nsCAutoString absURL;
uri->GetSpec(absURL);
CopyUTF8toUTF16(absURL, aAbsURL);
}
}
return rv;
}
@ -738,16 +729,19 @@ CreateErrorText(const PRUnichar* aDescription,
aErrorString.Truncate();
nsAutoString msg;
nsresult rv = nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,"XMLParsingError",msg);
if (NS_FAILED(rv)) {
return rv;
}
nsresult rv =
nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
"XMLParsingError", msg);
NS_ENSURE_SUCCESS(rv, rv);
// XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$d, Column %4$d:
PRUnichar *message = nsTextFormatter::smprintf(msg.get(),aDescription,aSourceURL,aLineNumber,aColNumber);
PRUnichar *message = nsTextFormatter::smprintf(msg.get(), aDescription,
aSourceURL, aLineNumber,
aColNumber);
if (!message) {
return NS_ERROR_OUT_OF_MEMORY;
}
aErrorString.Assign(message);
nsTextFormatter::smprintf_free(message);
@ -759,11 +753,11 @@ CreateSourceText(const PRInt32 aColNumber,
const PRUnichar *aSourceLine,
nsString& aSourceString)
{
PRInt32 errorPosition = aColNumber;
aSourceString.Append(aSourceLine);
aSourceString.Append(PRUnichar('\n'));
for (PRInt32 i = 0; i < errorPosition - 1; ++i) {
PRInt32 i;
for (i = aColNumber - 1; i > 0; --i) {
aSourceString.Append(PRUnichar('-'));
}
aSourceString.Append(PRUnichar('^'));
@ -776,30 +770,37 @@ nsExpatDriver::HandleError(const char *aBuffer,
PRUint32 aLength,
PRBool aIsFinal)
{
PRInt32 code = XML_GetErrorCode(mExpatParser);
NS_WARN_IF_FALSE(code >= 1, "unexpected XML error code");
NS_WARN_IF_FALSE(code > XML_ERROR_NONE, "unexpected XML error code");
// Map Expat error code to an error string
// XXX Deal with error returns.
nsAutoString description;
nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code, description);
nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code,
description);
if (code == XML_ERROR_TAG_MISMATCH) {
nsAutoString msg;
nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES, "Expected", msg);
nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
"Expected", msg);
// . Expected: </%S>.
PRUnichar *message = nsTextFormatter::smprintf(msg.get(), (const PRUnichar*)XML_GetMismatchedTag(mExpatParser));
PRUnichar *message =
nsTextFormatter::smprintf(msg.get(),
MOZ_XML_GetMismatchedTag(mExpatParser));
if (!message) {
return NS_ERROR_OUT_OF_MEMORY;
}
description.Append(message);
nsTextFormatter::smprintf_free(message);
}
nsAutoString sourceLine;
if (!aIsFinal) {
GetLine(aBuffer, aLength, (XML_GetCurrentByteIndex(mExpatParser) - mBytesParsed), sourceLine);
GetLine(aBuffer, aLength,
XML_GetCurrentByteIndex(mExpatParser) - mBytesParsed,
sourceLine);
}
else {
sourceLine.Append(mLastLine);
@ -809,8 +810,7 @@ nsExpatDriver::HandleError(const char *aBuffer,
PRInt32 colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
nsAutoString errorText;
CreateErrorText(description.get(),
(PRUnichar*)XML_GetBase(mExpatParser),
CreateErrorText(description.get(), (const PRUnichar*)XML_GetBase(mExpatParser),
XML_GetCurrentLineNumber(mExpatParser),
colNumber, errorText);
@ -830,8 +830,7 @@ nsExpatDriver::ParseBuffer(const char* aBuffer,
PRUint32 aLength,
PRBool aIsFinal)
{
nsresult result = NS_OK;
NS_ASSERTION((aBuffer && aLength) || (aBuffer == nsnull && aLength == 0), "?");
NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
if (mExpatParser && mInternalState == NS_OK) {
if (!XML_Parse(mExpatParser, aBuffer, aLength, aIsFinal)) {
@ -844,17 +843,20 @@ nsExpatDriver::ParseBuffer(const char* aBuffer,
HandleError(aBuffer, aLength, aIsFinal);
mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
}
return mInternalState;
}
else if (aBuffer && aLength) {
if (aBuffer && aLength != 0) {
// Cache the last line in the buffer
GetLine(aBuffer, aLength, aLength - sizeof(PRUnichar), mLastLine);
}
mBytesParsed += aLength;
mBytePosition = 0;
}
return result;
return NS_OK;
}
void
@ -863,61 +865,70 @@ nsExpatDriver::GetLine(const char* aSourceBuffer,
PRUint32 aOffset,
nsString& aLine)
{
/* Figure out the line inside aSourceBuffer that contains character specified by aOffset.
Copy it into aLine. */
NS_ASSERTION(aOffset >= 0 && aOffset < aLength, "?");
/* Assert that the byteIndex and the length of the buffer is even */
// 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, "?");
PRUnichar* start = (PRUnichar* ) &aSourceBuffer[aOffset]; /* Will try to find the start of the line */
PRUnichar* end = (PRUnichar* ) &aSourceBuffer[aOffset]; /* Will try to find the end of the line */
PRUint32 startIndex = aOffset / sizeof(PRUnichar); /* Track the position of the 'start' pointer into the buffer */
PRUint32 endIndex = aOffset / sizeof(PRUnichar); /* Track the position of the 'end' pointer into the buffer */
// 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);
PRBool reachedStart;
PRBool reachedEnd;
/* Use start to find the first new line before the error position and
end to find the first new line after the error position */
reachedStart = (startIndex <= 0 || '\n' == *start || '\r' == *start);
reachedEnd = (endIndex >= numCharsInBuffer || '\n' == *end || '\r' == *end);
// 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 || '\n' == *start || '\r' == *start);
reachedStart = startIndex <= 0 || *start == '\n' || *start == '\r';
}
if (!reachedEnd) {
++end;
++endIndex;
reachedEnd = (endIndex >= numCharsInBuffer || '\n' == *end || '\r' == *end);
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
// 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, 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. */
// 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)
{
@ -947,10 +958,11 @@ nsExpatDriver::ConsumeToken(nsScanner& aScanner,
if (NS_FAILED(mInternalState)) {
if (mInternalState == NS_ERROR_HTMLPARSER_BLOCK) {
// mBytePosition / 2 => character position. Since one char = two bytes.
// mBytePosition / 2 => character position, one char is two bytes.
aScanner.SetPosition(start.advance(mBytePosition / 2), PR_TRUE);
aScanner.Mark();
}
return mInternalState;
}
@ -971,9 +983,10 @@ nsExpatDriver::CanParse(CParserContext& aParserContext,
const nsString& aBuffer,
PRInt32 aVersion)
{
eAutoDetectResult result = eUnknownDetect;
if (aParserContext.mParserCommand == eViewSource) {
return eUnknownDetect;
}
if (eViewSource != aParserContext.mParserCommand) {
if (aParserContext.mMimeType.Equals(kXMLTextContentType) ||
aParserContext.mMimeType.Equals(kXMLApplicationContentType) ||
aParserContext.mMimeType.Equals(kXHTMLApplicationContentType)||
@ -982,18 +995,18 @@ nsExpatDriver::CanParse(CParserContext& aParserContext,
aParserContext.mMimeType.Equals(kSVGTextContentType) ||
#endif
aParserContext.mMimeType.Equals(kXULTextContentType)) {
result=ePrimaryDetect;
}
else {
if (aParserContext.mMimeType.IsEmpty() &&
kNotFound != aBuffer.Find("<?xml ")) {
aParserContext.SetMimeType(NS_LITERAL_CSTRING(kXMLTextContentType));
result=eValidDetect;
}
}
return ePrimaryDetect;
}
return result;
if (aParserContext.mMimeType.IsEmpty() &&
aBuffer.Find("<?xml ") != kNotFound) {
aParserContext.SetMimeType(NS_LITERAL_CSTRING(kXMLTextContentType));
return eValidDetect;
}
return eUnknownDetect;
}
NS_IMETHODIMP
@ -1001,34 +1014,39 @@ nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
nsITokenizer* aTokenizer,
nsIContentSink* aSink)
{
NS_ENSURE_ARG_POINTER(aSink);
aSink->QueryInterface(NS_GET_IID(nsIExpatSink),(void**)&(mSink));
mSink = do_QueryInterface(aSink);
NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE);
mExpatParser = XML_ParserCreate((const XML_Char*) NS_LITERAL_STRING("UTF-16").get());
mExpatParser = XML_ParserCreate((const XML_Char*)kUTF16);
NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
#ifdef XML_DTD
XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
#endif
XML_SetBase(mExpatParser, (const XML_Char*) (aParserContext.mScanner->GetFilename()).get());
XML_SetBase(mExpatParser,
(const XML_Char*)aParserContext.mScanner->GetFilename().get());
// Set up the callbacks
XML_SetElementHandler(mExpatParser, Driver_HandleStartElement, Driver_HandleEndElement);
XML_SetElementHandler(mExpatParser, Driver_HandleStartElement,
Driver_HandleEndElement);
XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
XML_SetProcessingInstructionHandler(mExpatParser, Driver_HandleProcessingInstruction);
XML_SetProcessingInstructionHandler(mExpatParser,
Driver_HandleProcessingInstruction);
XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
XML_SetExternalEntityRefHandler(mExpatParser, Driver_HandleExternalEntityRef);
XML_SetExternalEntityRefHandler(mExpatParser,
Driver_HandleExternalEntityRef);
XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
Driver_HandleEndCdataSection);
XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl, Driver_HandleEndDoctypeDecl);
XML_SetParamEntityParsing(mExpatParser,
XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
Driver_HandleEndDoctypeDecl);
// Set up the user data.
XML_SetUserData(mExpatParser, this);
@ -1056,8 +1074,9 @@ nsExpatDriver::DidBuildModel(nsresult anErrorCode,
nsresult result = NS_OK;
if (mSink) {
result = aSink->DidBuildModel();
NS_RELEASE(mSink); // assigns null
mSink = nsnull;
}
return result;
}
@ -1071,13 +1090,13 @@ nsExpatDriver::WillTokenize(PRBool aIsFinalChunk,
NS_IMETHODIMP
nsExpatDriver::WillResumeParse(nsIContentSink* aSink)
{
return (aSink)? aSink->WillResume():NS_OK;
return aSink ? aSink->WillResume() : NS_OK;
}
NS_IMETHODIMP
nsExpatDriver::WillInterruptParse(nsIContentSink* aSink)
{
return (aSink)? aSink->WillInterrupt():NS_OK;
return aSink ? aSink->WillInterrupt() : NS_OK;
}
NS_IMETHODIMP
@ -1095,7 +1114,8 @@ nsExpatDriver::GetMostDerivedIID(void) const
NS_IMETHODIMP_(void)
nsExpatDriver::Terminate()
{
XML_BlockParser(mExpatParser); // XXX - not sure what happens to the unparsed data.
// XXX - not sure what happens to the unparsed data.
XML_BlockParser(mExpatParser);
mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
}
@ -1105,10 +1125,11 @@ nsExpatDriver::GetType()
return NS_IPARSER_FLAG_XML;
}
/*************************** Unused methods ***************************************/
/*************************** Unused methods **********************************/
NS_IMETHODIMP
nsExpatDriver::CollectSkippedContent(PRInt32 aTag, nsAString& aContent, PRInt32 &aLineNo)
nsExpatDriver::CollectSkippedContent(PRInt32 aTag, nsAString& aContent,
PRInt32 &aLineNo)
{
return NS_OK;
}
@ -1214,5 +1235,3 @@ nsExpatDriver::IntTagToAtom(PRInt32 aIntTag) const
{
return 0;
}
/******************************************************************************/

Просмотреть файл

@ -39,6 +39,7 @@
#define NS_EXPAT_DRIVER__
#include "xmlparse.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIDTD.h"
#include "nsITokenizer.h"
@ -58,15 +59,16 @@ public:
nsExpatDriver();
virtual ~nsExpatDriver();
int HandleExternalEntityRef(const PRUnichar *openEntityNames,
const PRUnichar *base,
const PRUnichar *systemId,
const PRUnichar *publicId);
int HandleExternalEntityRef(const PRUnichar *aOpenEntityNames,
const PRUnichar *aBase,
const PRUnichar *aSystemId,
const PRUnichar *aPublicId);
nsresult HandleStartElement(const PRUnichar *aName, const PRUnichar **aAtts);
nsresult HandleEndElement(const PRUnichar *aName);
nsresult HandleCharacterData(const PRUnichar *aCData, const PRUint32 aLength);
nsresult HandleComment(const PRUnichar *aName);
nsresult HandleProcessingInstruction(const PRUnichar *aTarget, const PRUnichar *aData);
nsresult HandleProcessingInstruction(const PRUnichar *aTarget,
const PRUnichar *aData);
nsresult HandleXMLDeclaration(const PRUnichar *aData, const PRUint32 aLength);
nsresult HandleDefault(const PRUnichar *aData, const PRUint32 aLength);
nsresult HandleStartCdataSection();
@ -74,18 +76,18 @@ public:
nsresult HandleStartDoctypeDecl();
nsresult HandleEndDoctypeDecl();
protected:
private:
// Load up an external stream to get external entity information
nsresult OpenInputStreamFromExternalDTD(const PRUnichar* aFPIStr,
const PRUnichar* aURLStr,
const PRUnichar* aBaseURL,
nsIInputStream** in,
nsIInputStream** aStream,
nsAString& aAbsURL);
nsresult ParseBuffer(const char* aBuffer, PRUint32 aLength, PRBool aIsFinal);
nsresult HandleError(const char *aBuffer, PRUint32 aLength, PRBool aIsFinal);
void GetLine(const char* aSourceBuffer, PRUint32 aLength, PRUint32 aOffset, nsString& aLine);
void GetLine(const char* aSourceBuffer, PRUint32 aLength, PRUint32 aOffset,
nsString& aLine);
XML_Parser mExpatParser;
nsString mLastLine;
@ -98,10 +100,10 @@ protected:
PRInt32 mBytePosition;
nsresult mInternalState;
PRUint32 mBytesParsed;
nsIExpatSink* mSink;
nsCOMPtr<nsIExpatSink> mSink;
const nsCatalogData* mCatalogData; // weak
};
nsresult NS_NewExpatDriver(nsIDTD** aDriver);
#endif