1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/parser/htmlparser/src/nsExpatDriver.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1377 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsExpatDriver.h" 1.10 +#include "nsCOMPtr.h" 1.11 +#include "nsParserCIID.h" 1.12 +#include "CParserContext.h" 1.13 +#include "nsIExpatSink.h" 1.14 +#include "nsIExtendedExpatSink.h" 1.15 +#include "nsIContentSink.h" 1.16 +#include "nsParserMsgUtils.h" 1.17 +#include "nsIURL.h" 1.18 +#include "nsIUnicharInputStream.h" 1.19 +#include "nsISimpleUnicharStreamFactory.h" 1.20 +#include "nsNetUtil.h" 1.21 +#include "prprf.h" 1.22 +#include "prmem.h" 1.23 +#include "nsTextFormatter.h" 1.24 +#include "nsDirectoryServiceDefs.h" 1.25 +#include "nsCRT.h" 1.26 +#include "nsIConsoleService.h" 1.27 +#include "nsIScriptError.h" 1.28 +#include "nsIContentPolicy.h" 1.29 +#include "nsContentPolicyUtils.h" 1.30 +#include "nsError.h" 1.31 +#include "nsXPCOMCIDInternal.h" 1.32 +#include "nsUnicharInputStream.h" 1.33 + 1.34 +#define kExpatSeparatorChar 0xFFFF 1.35 + 1.36 +static const char16_t kUTF16[] = { 'U', 'T', 'F', '-', '1', '6', '\0' }; 1.37 + 1.38 +#ifdef PR_LOGGING 1.39 +static PRLogModuleInfo * 1.40 +GetExpatDriverLog() 1.41 +{ 1.42 + static PRLogModuleInfo *sLog; 1.43 + if (!sLog) 1.44 + sLog = PR_NewLogModule("expatdriver"); 1.45 + return sLog; 1.46 +} 1.47 +#endif 1.48 + 1.49 +/***************************** EXPAT CALL BACKS ******************************/ 1.50 +// The callback handlers that get called from the expat parser. 1.51 + 1.52 +static void 1.53 +Driver_HandleXMLDeclaration(void *aUserData, 1.54 + const XML_Char *aVersion, 1.55 + const XML_Char *aEncoding, 1.56 + int aStandalone) 1.57 +{ 1.58 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.59 + if (aUserData) { 1.60 + nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData); 1.61 + driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone); 1.62 + } 1.63 +} 1.64 + 1.65 +static void 1.66 +Driver_HandleStartElement(void *aUserData, 1.67 + const XML_Char *aName, 1.68 + const XML_Char **aAtts) 1.69 +{ 1.70 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.71 + if (aUserData) { 1.72 + static_cast<nsExpatDriver*>(aUserData)->HandleStartElement(aName, 1.73 + aAtts); 1.74 + } 1.75 +} 1.76 + 1.77 +static void 1.78 +Driver_HandleEndElement(void *aUserData, 1.79 + const XML_Char *aName) 1.80 +{ 1.81 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.82 + if (aUserData) { 1.83 + static_cast<nsExpatDriver*>(aUserData)->HandleEndElement(aName); 1.84 + } 1.85 +} 1.86 + 1.87 +static void 1.88 +Driver_HandleCharacterData(void *aUserData, 1.89 + const XML_Char *aData, 1.90 + int aLength) 1.91 +{ 1.92 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.93 + if (aUserData) { 1.94 + nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData); 1.95 + driver->HandleCharacterData(aData, uint32_t(aLength)); 1.96 + } 1.97 +} 1.98 + 1.99 +static void 1.100 +Driver_HandleComment(void *aUserData, 1.101 + const XML_Char *aName) 1.102 +{ 1.103 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.104 + if(aUserData) { 1.105 + static_cast<nsExpatDriver*>(aUserData)->HandleComment(aName); 1.106 + } 1.107 +} 1.108 + 1.109 +static void 1.110 +Driver_HandleProcessingInstruction(void *aUserData, 1.111 + const XML_Char *aTarget, 1.112 + const XML_Char *aData) 1.113 +{ 1.114 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.115 + if (aUserData) { 1.116 + nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData); 1.117 + driver->HandleProcessingInstruction(aTarget, aData); 1.118 + } 1.119 +} 1.120 + 1.121 +static void 1.122 +Driver_HandleDefault(void *aUserData, 1.123 + const XML_Char *aData, 1.124 + int aLength) 1.125 +{ 1.126 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.127 + if (aUserData) { 1.128 + nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData); 1.129 + driver->HandleDefault(aData, uint32_t(aLength)); 1.130 + } 1.131 +} 1.132 + 1.133 +static void 1.134 +Driver_HandleStartCdataSection(void *aUserData) 1.135 +{ 1.136 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.137 + if (aUserData) { 1.138 + static_cast<nsExpatDriver*>(aUserData)->HandleStartCdataSection(); 1.139 + } 1.140 +} 1.141 + 1.142 +static void 1.143 +Driver_HandleEndCdataSection(void *aUserData) 1.144 +{ 1.145 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.146 + if (aUserData) { 1.147 + static_cast<nsExpatDriver*>(aUserData)->HandleEndCdataSection(); 1.148 + } 1.149 +} 1.150 + 1.151 +static void 1.152 +Driver_HandleStartDoctypeDecl(void *aUserData, 1.153 + const XML_Char *aDoctypeName, 1.154 + const XML_Char *aSysid, 1.155 + const XML_Char *aPubid, 1.156 + int aHasInternalSubset) 1.157 +{ 1.158 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.159 + if (aUserData) { 1.160 + static_cast<nsExpatDriver*>(aUserData)-> 1.161 + HandleStartDoctypeDecl(aDoctypeName, aSysid, aPubid, !!aHasInternalSubset); 1.162 + } 1.163 +} 1.164 + 1.165 +static void 1.166 +Driver_HandleEndDoctypeDecl(void *aUserData) 1.167 +{ 1.168 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.169 + if (aUserData) { 1.170 + static_cast<nsExpatDriver*>(aUserData)->HandleEndDoctypeDecl(); 1.171 + } 1.172 +} 1.173 + 1.174 +static int 1.175 +Driver_HandleExternalEntityRef(void *aExternalEntityRefHandler, 1.176 + const XML_Char *aOpenEntityNames, 1.177 + const XML_Char *aBase, 1.178 + const XML_Char *aSystemId, 1.179 + const XML_Char *aPublicId) 1.180 +{ 1.181 + NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist"); 1.182 + if (!aExternalEntityRefHandler) { 1.183 + return 1; 1.184 + } 1.185 + 1.186 + nsExpatDriver* driver = static_cast<nsExpatDriver*> 1.187 + (aExternalEntityRefHandler); 1.188 + 1.189 + return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId, 1.190 + aPublicId); 1.191 +} 1.192 + 1.193 +static void 1.194 +Driver_HandleStartNamespaceDecl(void *aUserData, 1.195 + const XML_Char *aPrefix, 1.196 + const XML_Char *aUri) 1.197 +{ 1.198 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.199 + if (aUserData) { 1.200 + static_cast<nsExpatDriver*>(aUserData)-> 1.201 + HandleStartNamespaceDecl(aPrefix, aUri); 1.202 + } 1.203 +} 1.204 + 1.205 +static void 1.206 +Driver_HandleEndNamespaceDecl(void *aUserData, 1.207 + const XML_Char *aPrefix) 1.208 +{ 1.209 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.210 + if (aUserData) { 1.211 + static_cast<nsExpatDriver*>(aUserData)-> 1.212 + HandleEndNamespaceDecl(aPrefix); 1.213 + } 1.214 +} 1.215 + 1.216 +static void 1.217 +Driver_HandleNotationDecl(void *aUserData, 1.218 + const XML_Char *aNotationName, 1.219 + const XML_Char *aBase, 1.220 + const XML_Char *aSysid, 1.221 + const XML_Char *aPubid) 1.222 +{ 1.223 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.224 + if (aUserData) { 1.225 + static_cast<nsExpatDriver*>(aUserData)-> 1.226 + HandleNotationDecl(aNotationName, aBase, aSysid, aPubid); 1.227 + } 1.228 +} 1.229 + 1.230 +static void 1.231 +Driver_HandleUnparsedEntityDecl(void *aUserData, 1.232 + const XML_Char *aEntityName, 1.233 + const XML_Char *aBase, 1.234 + const XML_Char *aSysid, 1.235 + const XML_Char *aPubid, 1.236 + const XML_Char *aNotationName) 1.237 +{ 1.238 + NS_ASSERTION(aUserData, "expat driver should exist"); 1.239 + if (aUserData) { 1.240 + static_cast<nsExpatDriver*>(aUserData)-> 1.241 + HandleUnparsedEntityDecl(aEntityName, aBase, aSysid, aPubid, 1.242 + aNotationName); 1.243 + } 1.244 +} 1.245 + 1.246 + 1.247 +/***************************** END CALL BACKS ********************************/ 1.248 + 1.249 +/***************************** CATALOG UTILS *********************************/ 1.250 + 1.251 +// Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus 1.252 +// MathML 2.0" DTD to the the lightweight customized version that Mozilla uses. 1.253 +// Since Mozilla is not validating, no need to fetch a *huge* file at each 1.254 +// click. 1.255 +// XXX The cleanest solution here would be to fix Bug 98413: Implement XML 1.256 +// Catalogs. 1.257 +struct nsCatalogData { 1.258 + const char* mPublicID; 1.259 + const char* mLocalDTD; 1.260 + const char* mAgentSheet; 1.261 +}; 1.262 + 1.263 +// The order of this table is guestimated to be in the optimum order 1.264 +static const nsCatalogData kCatalogTable[] = { 1.265 + { "-//W3C//DTD XHTML 1.0 Transitional//EN", "htmlmathml-f.ent", nullptr }, 1.266 + { "-//W3C//DTD XHTML 1.1//EN", "htmlmathml-f.ent", nullptr }, 1.267 + { "-//W3C//DTD XHTML 1.0 Strict//EN", "htmlmathml-f.ent", nullptr }, 1.268 + { "-//W3C//DTD XHTML 1.0 Frameset//EN", "htmlmathml-f.ent", nullptr }, 1.269 + { "-//W3C//DTD XHTML Basic 1.0//EN", "htmlmathml-f.ent", nullptr }, 1.270 + { "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "htmlmathml-f.ent", "resource://gre-resources/mathml.css" }, 1.271 + { "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN", "htmlmathml-f.ent", "resource://gre-resources/mathml.css" }, 1.272 + { "-//W3C//DTD MathML 2.0//EN", "htmlmathml-f.ent", "resource://gre-resources/mathml.css" }, 1.273 + { "-//WAPFORUM//DTD XHTML Mobile 1.0//EN", "htmlmathml-f.ent", nullptr }, 1.274 + { nullptr, nullptr, nullptr } 1.275 +}; 1.276 + 1.277 +static const nsCatalogData* 1.278 +LookupCatalogData(const char16_t* aPublicID) 1.279 +{ 1.280 + nsDependentString publicID(aPublicID); 1.281 + 1.282 + // linear search for now since the number of entries is going to 1.283 + // be negligible, and the fix for bug 98413 would get rid of this 1.284 + // code anyway 1.285 + const nsCatalogData* data = kCatalogTable; 1.286 + while (data->mPublicID) { 1.287 + if (publicID.EqualsASCII(data->mPublicID)) { 1.288 + return data; 1.289 + } 1.290 + ++data; 1.291 + } 1.292 + 1.293 + return nullptr; 1.294 +} 1.295 + 1.296 +// This function provides a resource URI to a local DTD 1.297 +// in resource://gre/res/dtd/ which may or may not exist. 1.298 +// If aCatalogData is provided, it is used to remap the 1.299 +// DTD instead of taking the filename from the URI. 1.300 +static void 1.301 +GetLocalDTDURI(const nsCatalogData* aCatalogData, nsIURI* aDTD, 1.302 + nsIURI** aResult) 1.303 +{ 1.304 + NS_ASSERTION(aDTD, "Null parameter."); 1.305 + 1.306 + nsAutoCString fileName; 1.307 + if (aCatalogData) { 1.308 + // remap the DTD to a known local DTD 1.309 + fileName.Assign(aCatalogData->mLocalDTD); 1.310 + } 1.311 + 1.312 + if (fileName.IsEmpty()) { 1.313 + // Try to see if the user has installed the DTD file -- we extract the 1.314 + // filename.ext of the DTD here. Hence, for any DTD for which we have 1.315 + // no predefined mapping, users just have to copy the DTD file to our 1.316 + // special DTD directory and it will be picked. 1.317 + nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD); 1.318 + if (!dtdURL) { 1.319 + return; 1.320 + } 1.321 + 1.322 + dtdURL->GetFileName(fileName); 1.323 + if (fileName.IsEmpty()) { 1.324 + return; 1.325 + } 1.326 + } 1.327 + 1.328 + nsAutoCString respath("resource://gre/res/dtd/"); 1.329 + respath += fileName; 1.330 + NS_NewURI(aResult, respath); 1.331 +} 1.332 + 1.333 +/***************************** END CATALOG UTILS *****************************/ 1.334 + 1.335 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsExpatDriver) 1.336 + NS_INTERFACE_MAP_ENTRY(nsITokenizer) 1.337 + NS_INTERFACE_MAP_ENTRY(nsIDTD) 1.338 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD) 1.339 +NS_INTERFACE_MAP_END 1.340 + 1.341 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsExpatDriver) 1.342 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsExpatDriver) 1.343 + 1.344 +NS_IMPL_CYCLE_COLLECTION(nsExpatDriver, mSink, mExtendedSink) 1.345 + 1.346 +nsExpatDriver::nsExpatDriver() 1.347 + : mExpatParser(nullptr), 1.348 + mInCData(false), 1.349 + mInInternalSubset(false), 1.350 + mInExternalDTD(false), 1.351 + mMadeFinalCallToExpat(false), 1.352 + mIsFinalChunk(false), 1.353 + mInternalState(NS_OK), 1.354 + mExpatBuffered(0), 1.355 + mCatalogData(nullptr), 1.356 + mInnerWindowID(0) 1.357 +{ 1.358 +} 1.359 + 1.360 +nsExpatDriver::~nsExpatDriver() 1.361 +{ 1.362 + if (mExpatParser) { 1.363 + XML_ParserFree(mExpatParser); 1.364 + } 1.365 +} 1.366 + 1.367 +nsresult 1.368 +nsExpatDriver::HandleStartElement(const char16_t *aValue, 1.369 + const char16_t **aAtts) 1.370 +{ 1.371 + NS_ASSERTION(mSink, "content sink not found!"); 1.372 + 1.373 + // Calculate the total number of elements in aAtts. 1.374 + // XML_GetSpecifiedAttributeCount will only give us the number of specified 1.375 + // attrs (twice that number, actually), so we have to check for default attrs 1.376 + // ourselves. 1.377 + uint32_t attrArrayLength; 1.378 + for (attrArrayLength = XML_GetSpecifiedAttributeCount(mExpatParser); 1.379 + aAtts[attrArrayLength]; 1.380 + attrArrayLength += 2) { 1.381 + // Just looping till we find out what the length is 1.382 + } 1.383 + 1.384 + if (mSink) { 1.385 + nsresult rv = mSink-> 1.386 + HandleStartElement(aValue, aAtts, attrArrayLength, 1.387 + XML_GetIdAttributeIndex(mExpatParser), 1.388 + XML_GetCurrentLineNumber(mExpatParser)); 1.389 + MaybeStopParser(rv); 1.390 + } 1.391 + 1.392 + return NS_OK; 1.393 +} 1.394 + 1.395 +nsresult 1.396 +nsExpatDriver::HandleEndElement(const char16_t *aValue) 1.397 +{ 1.398 + NS_ASSERTION(mSink, "content sink not found!"); 1.399 + NS_ASSERTION(mInternalState != NS_ERROR_HTMLPARSER_BLOCK, 1.400 + "Shouldn't block from HandleStartElement."); 1.401 + 1.402 + if (mSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) { 1.403 + nsresult rv = mSink->HandleEndElement(aValue); 1.404 + MaybeStopParser(rv); 1.405 + } 1.406 + 1.407 + return NS_OK; 1.408 +} 1.409 + 1.410 +nsresult 1.411 +nsExpatDriver::HandleCharacterData(const char16_t *aValue, 1.412 + const uint32_t aLength) 1.413 +{ 1.414 + NS_ASSERTION(mSink, "content sink not found!"); 1.415 + 1.416 + if (mInCData) { 1.417 + mCDataText.Append(aValue, aLength); 1.418 + } 1.419 + else if (mSink) { 1.420 + nsresult rv = mSink->HandleCharacterData(aValue, aLength); 1.421 + MaybeStopParser(rv); 1.422 + } 1.423 + 1.424 + return NS_OK; 1.425 +} 1.426 + 1.427 +nsresult 1.428 +nsExpatDriver::HandleComment(const char16_t *aValue) 1.429 +{ 1.430 + NS_ASSERTION(mSink, "content sink not found!"); 1.431 + 1.432 + if (mInExternalDTD) { 1.433 + // Ignore comments from external DTDs 1.434 + return NS_OK; 1.435 + } 1.436 + 1.437 + if (mInInternalSubset) { 1.438 + mInternalSubset.AppendLiteral("<!--"); 1.439 + mInternalSubset.Append(aValue); 1.440 + mInternalSubset.AppendLiteral("-->"); 1.441 + } 1.442 + else if (mSink) { 1.443 + nsresult rv = mSink->HandleComment(aValue); 1.444 + MaybeStopParser(rv); 1.445 + } 1.446 + 1.447 + return NS_OK; 1.448 +} 1.449 + 1.450 +nsresult 1.451 +nsExpatDriver::HandleProcessingInstruction(const char16_t *aTarget, 1.452 + const char16_t *aData) 1.453 +{ 1.454 + NS_ASSERTION(mSink, "content sink not found!"); 1.455 + 1.456 + if (mInExternalDTD) { 1.457 + // Ignore PIs in external DTDs for now. Eventually we want to 1.458 + // pass them to the sink in a way that doesn't put them in the DOM 1.459 + return NS_OK; 1.460 + } 1.461 + 1.462 + if (mInInternalSubset) { 1.463 + mInternalSubset.AppendLiteral("<?"); 1.464 + mInternalSubset.Append(aTarget); 1.465 + mInternalSubset.Append(' '); 1.466 + mInternalSubset.Append(aData); 1.467 + mInternalSubset.AppendLiteral("?>"); 1.468 + } 1.469 + else if (mSink) { 1.470 + nsresult rv = mSink->HandleProcessingInstruction(aTarget, aData); 1.471 + MaybeStopParser(rv); 1.472 + } 1.473 + 1.474 + return NS_OK; 1.475 +} 1.476 + 1.477 +nsresult 1.478 +nsExpatDriver::HandleXMLDeclaration(const char16_t *aVersion, 1.479 + const char16_t *aEncoding, 1.480 + int32_t aStandalone) 1.481 +{ 1.482 + if (mSink) { 1.483 + nsresult rv = mSink->HandleXMLDeclaration(aVersion, aEncoding, aStandalone); 1.484 + MaybeStopParser(rv); 1.485 + } 1.486 + 1.487 + return NS_OK; 1.488 +} 1.489 + 1.490 +nsresult 1.491 +nsExpatDriver::HandleDefault(const char16_t *aValue, 1.492 + const uint32_t aLength) 1.493 +{ 1.494 + NS_ASSERTION(mSink, "content sink not found!"); 1.495 + 1.496 + if (mInExternalDTD) { 1.497 + // Ignore newlines in external DTDs 1.498 + return NS_OK; 1.499 + } 1.500 + 1.501 + if (mInInternalSubset) { 1.502 + mInternalSubset.Append(aValue, aLength); 1.503 + } 1.504 + else if (mSink) { 1.505 + uint32_t i; 1.506 + nsresult rv = mInternalState; 1.507 + for (i = 0; i < aLength && NS_SUCCEEDED(rv); ++i) { 1.508 + if (aValue[i] == '\n' || aValue[i] == '\r') { 1.509 + rv = mSink->HandleCharacterData(&aValue[i], 1); 1.510 + } 1.511 + } 1.512 + MaybeStopParser(rv); 1.513 + } 1.514 + 1.515 + return NS_OK; 1.516 +} 1.517 + 1.518 +nsresult 1.519 +nsExpatDriver::HandleStartCdataSection() 1.520 +{ 1.521 + mInCData = true; 1.522 + 1.523 + return NS_OK; 1.524 +} 1.525 + 1.526 +nsresult 1.527 +nsExpatDriver::HandleEndCdataSection() 1.528 +{ 1.529 + NS_ASSERTION(mSink, "content sink not found!"); 1.530 + 1.531 + mInCData = false; 1.532 + if (mSink) { 1.533 + nsresult rv = mSink->HandleCDataSection(mCDataText.get(), 1.534 + mCDataText.Length()); 1.535 + MaybeStopParser(rv); 1.536 + } 1.537 + mCDataText.Truncate(); 1.538 + 1.539 + return NS_OK; 1.540 +} 1.541 + 1.542 +nsresult 1.543 +nsExpatDriver::HandleStartNamespaceDecl(const char16_t* aPrefix, 1.544 + const char16_t* aUri) 1.545 +{ 1.546 + if (mExtendedSink) { 1.547 + nsresult rv = mExtendedSink->HandleStartNamespaceDecl(aPrefix, aUri); 1.548 + MaybeStopParser(rv); 1.549 + } 1.550 + return NS_OK; 1.551 +} 1.552 + 1.553 +nsresult 1.554 +nsExpatDriver::HandleEndNamespaceDecl(const char16_t* aPrefix) 1.555 +{ 1.556 + if (mExtendedSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) { 1.557 + nsresult rv = mExtendedSink->HandleEndNamespaceDecl(aPrefix); 1.558 + MaybeStopParser(rv); 1.559 + } 1.560 + return NS_OK; 1.561 +} 1.562 + 1.563 +nsresult 1.564 +nsExpatDriver::HandleNotationDecl(const char16_t* aNotationName, 1.565 + const char16_t* aBase, 1.566 + const char16_t* aSysid, 1.567 + const char16_t* aPubid) 1.568 +{ 1.569 + if (mExtendedSink) { 1.570 + nsresult rv = mExtendedSink->HandleNotationDecl(aNotationName, aSysid, 1.571 + aPubid); 1.572 + MaybeStopParser(rv); 1.573 + } 1.574 + return NS_OK; 1.575 +} 1.576 + 1.577 +nsresult 1.578 +nsExpatDriver::HandleUnparsedEntityDecl(const char16_t* aEntityName, 1.579 + const char16_t* aBase, 1.580 + const char16_t* aSysid, 1.581 + const char16_t* aPubid, 1.582 + const char16_t* aNotationName) 1.583 +{ 1.584 + if (mExtendedSink) { 1.585 + nsresult rv = mExtendedSink->HandleUnparsedEntityDecl(aEntityName, 1.586 + aSysid, 1.587 + aPubid, 1.588 + aNotationName); 1.589 + MaybeStopParser(rv); 1.590 + } 1.591 + return NS_OK; 1.592 +} 1.593 + 1.594 +nsresult 1.595 +nsExpatDriver::HandleStartDoctypeDecl(const char16_t* aDoctypeName, 1.596 + const char16_t* aSysid, 1.597 + const char16_t* aPubid, 1.598 + bool aHasInternalSubset) 1.599 +{ 1.600 + mDoctypeName = aDoctypeName; 1.601 + mSystemID = aSysid; 1.602 + mPublicID = aPubid; 1.603 + 1.604 + if (mExtendedSink) { 1.605 + nsresult rv = mExtendedSink->HandleStartDTD(aDoctypeName, aSysid, aPubid); 1.606 + MaybeStopParser(rv); 1.607 + } 1.608 + 1.609 + if (aHasInternalSubset) { 1.610 + // Consuming a huge internal subset translates to numerous 1.611 + // allocations. In an effort to avoid too many allocations 1.612 + // setting mInternalSubset's capacity to be 1K ( just a guesstimate! ). 1.613 + mInInternalSubset = true; 1.614 + mInternalSubset.SetCapacity(1024); 1.615 + } else { 1.616 + // Distinguish missing internal subset from an empty one 1.617 + mInternalSubset.SetIsVoid(true); 1.618 + } 1.619 + 1.620 + return NS_OK; 1.621 +} 1.622 + 1.623 +nsresult 1.624 +nsExpatDriver::HandleEndDoctypeDecl() 1.625 +{ 1.626 + NS_ASSERTION(mSink, "content sink not found!"); 1.627 + 1.628 + mInInternalSubset = false; 1.629 + 1.630 + if (mSink) { 1.631 + // let the sink know any additional knowledge that we have about the 1.632 + // document (currently, from bug 124570, we only expect to pass additional 1.633 + // agent sheets needed to layout the XML vocabulary of the document) 1.634 + nsCOMPtr<nsIURI> data; 1.635 + if (mCatalogData && mCatalogData->mAgentSheet) { 1.636 + NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet); 1.637 + } 1.638 + 1.639 + // Note: mInternalSubset already doesn't include the [] around it. 1.640 + nsresult rv = mSink->HandleDoctypeDecl(mInternalSubset, mDoctypeName, 1.641 + mSystemID, mPublicID, data); 1.642 + MaybeStopParser(rv); 1.643 + } 1.644 + 1.645 + mInternalSubset.SetCapacity(0); 1.646 + 1.647 + return NS_OK; 1.648 +} 1.649 + 1.650 +static NS_METHOD 1.651 +ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn, 1.652 + void* aClosure, 1.653 + const char16_t* aFromSegment, 1.654 + uint32_t aToOffset, 1.655 + uint32_t aCount, 1.656 + uint32_t *aWriteCount) 1.657 +{ 1.658 + // Pass the buffer to expat for parsing. 1.659 + if (XML_Parse((XML_Parser)aClosure, (const char *)aFromSegment, 1.660 + aCount * sizeof(char16_t), 0) == XML_STATUS_OK) { 1.661 + *aWriteCount = aCount; 1.662 + 1.663 + return NS_OK; 1.664 + } 1.665 + 1.666 + *aWriteCount = 0; 1.667 + 1.668 + return NS_ERROR_FAILURE; 1.669 +} 1.670 + 1.671 +int 1.672 +nsExpatDriver::HandleExternalEntityRef(const char16_t *openEntityNames, 1.673 + const char16_t *base, 1.674 + const char16_t *systemId, 1.675 + const char16_t *publicId) 1.676 +{ 1.677 + if (mInInternalSubset && !mInExternalDTD && openEntityNames) { 1.678 + mInternalSubset.Append(char16_t('%')); 1.679 + mInternalSubset.Append(nsDependentString(openEntityNames)); 1.680 + mInternalSubset.Append(char16_t(';')); 1.681 + } 1.682 + 1.683 + // Load the external entity into a buffer. 1.684 + nsCOMPtr<nsIInputStream> in; 1.685 + nsAutoString absURL; 1.686 + nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base, 1.687 + getter_AddRefs(in), absURL); 1.688 + if (NS_FAILED(rv)) { 1.689 +#ifdef DEBUG 1.690 + nsCString message("Failed to open external DTD: publicId \""); 1.691 + AppendUTF16toUTF8(publicId, message); 1.692 + message += "\" systemId \""; 1.693 + AppendUTF16toUTF8(systemId, message); 1.694 + message += "\" base \""; 1.695 + AppendUTF16toUTF8(base, message); 1.696 + message += "\" URL \""; 1.697 + AppendUTF16toUTF8(absURL, message); 1.698 + message += "\""; 1.699 + NS_WARNING(message.get()); 1.700 +#endif 1.701 + return 1; 1.702 + } 1.703 + 1.704 + nsCOMPtr<nsIUnicharInputStream> uniIn; 1.705 + rv = nsSimpleUnicharStreamFactory::GetInstance()-> 1.706 + CreateInstanceFromUTF8Stream(in, getter_AddRefs(uniIn)); 1.707 + NS_ENSURE_SUCCESS(rv, 1); 1.708 + 1.709 + int result = 1; 1.710 + if (uniIn) { 1.711 + XML_Parser entParser = XML_ExternalEntityParserCreate(mExpatParser, 0, 1.712 + kUTF16); 1.713 + if (entParser) { 1.714 + XML_SetBase(entParser, absURL.get()); 1.715 + 1.716 + mInExternalDTD = true; 1.717 + 1.718 + uint32_t totalRead; 1.719 + do { 1.720 + rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser, 1.721 + uint32_t(-1), &totalRead); 1.722 + } while (NS_SUCCEEDED(rv) && totalRead > 0); 1.723 + 1.724 + result = XML_Parse(entParser, nullptr, 0, 1); 1.725 + 1.726 + mInExternalDTD = false; 1.727 + 1.728 + XML_ParserFree(entParser); 1.729 + } 1.730 + } 1.731 + 1.732 + return result; 1.733 +} 1.734 + 1.735 +nsresult 1.736 +nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr, 1.737 + const char16_t* aURLStr, 1.738 + const char16_t* aBaseURL, 1.739 + nsIInputStream** aStream, 1.740 + nsAString& aAbsURL) 1.741 +{ 1.742 + nsCOMPtr<nsIURI> baseURI; 1.743 + nsresult rv = NS_NewURI(getter_AddRefs(baseURI), 1.744 + NS_ConvertUTF16toUTF8(aBaseURL)); 1.745 + NS_ENSURE_SUCCESS(rv, rv); 1.746 + 1.747 + nsCOMPtr<nsIURI> uri; 1.748 + rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nullptr, 1.749 + baseURI); 1.750 + NS_ENSURE_SUCCESS(rv, rv); 1.751 + 1.752 + // check if it is alright to load this uri 1.753 + bool isChrome = false; 1.754 + uri->SchemeIs("chrome", &isChrome); 1.755 + if (!isChrome) { 1.756 + // since the url is not a chrome url, check to see if we can map the DTD 1.757 + // to a known local DTD, or if a DTD file of the same name exists in the 1.758 + // special DTD directory 1.759 + if (aFPIStr) { 1.760 + // see if the Formal Public Identifier (FPI) maps to a catalog entry 1.761 + mCatalogData = LookupCatalogData(aFPIStr); 1.762 + } 1.763 + 1.764 + nsCOMPtr<nsIURI> localURI; 1.765 + GetLocalDTDURI(mCatalogData, uri, getter_AddRefs(localURI)); 1.766 + if (!localURI) { 1.767 + return NS_ERROR_NOT_IMPLEMENTED; 1.768 + } 1.769 + 1.770 + localURI.swap(uri); 1.771 + } 1.772 + 1.773 + nsCOMPtr<nsIDocument> doc; 1.774 + NS_ASSERTION(mSink == nsCOMPtr<nsIExpatSink>(do_QueryInterface(mOriginalSink)), 1.775 + "In nsExpatDriver::OpenInputStreamFromExternalDTD: " 1.776 + "mOriginalSink not the same object as mSink?"); 1.777 + if (mOriginalSink) 1.778 + doc = do_QueryInterface(mOriginalSink->GetTarget()); 1.779 + int16_t shouldLoad = nsIContentPolicy::ACCEPT; 1.780 + rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_DTD, 1.781 + uri, 1.782 + (doc ? doc->NodePrincipal() : nullptr), 1.783 + doc, 1.784 + EmptyCString(), //mime guess 1.785 + nullptr, //extra 1.786 + &shouldLoad); 1.787 + if (NS_FAILED(rv)) return rv; 1.788 + if (NS_CP_REJECTED(shouldLoad)) { 1.789 + // Disallowed by content policy 1.790 + return NS_ERROR_CONTENT_BLOCKED; 1.791 + } 1.792 + 1.793 + nsAutoCString absURL; 1.794 + uri->GetSpec(absURL); 1.795 + 1.796 + CopyUTF8toUTF16(absURL, aAbsURL); 1.797 + 1.798 + nsCOMPtr<nsIChannel> channel; 1.799 + rv = NS_NewChannel(getter_AddRefs(channel), uri); 1.800 + NS_ENSURE_SUCCESS(rv, rv); 1.801 + 1.802 + channel->SetContentType(NS_LITERAL_CSTRING("application/xml")); 1.803 + return channel->Open(aStream); 1.804 +} 1.805 + 1.806 +static nsresult 1.807 +CreateErrorText(const char16_t* aDescription, 1.808 + const char16_t* aSourceURL, 1.809 + const uint32_t aLineNumber, 1.810 + const uint32_t aColNumber, 1.811 + nsString& aErrorString) 1.812 +{ 1.813 + aErrorString.Truncate(); 1.814 + 1.815 + nsAutoString msg; 1.816 + nsresult rv = 1.817 + nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES, 1.818 + "XMLParsingError", msg); 1.819 + NS_ENSURE_SUCCESS(rv, rv); 1.820 + 1.821 + // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$u, Column %4$u: 1.822 + char16_t *message = nsTextFormatter::smprintf(msg.get(), aDescription, 1.823 + aSourceURL, aLineNumber, 1.824 + aColNumber); 1.825 + if (!message) { 1.826 + return NS_ERROR_OUT_OF_MEMORY; 1.827 + } 1.828 + 1.829 + aErrorString.Assign(message); 1.830 + nsTextFormatter::smprintf_free(message); 1.831 + 1.832 + return NS_OK; 1.833 +} 1.834 + 1.835 +static nsresult 1.836 +AppendErrorPointer(const int32_t aColNumber, 1.837 + const char16_t *aSourceLine, 1.838 + nsString& aSourceString) 1.839 +{ 1.840 + aSourceString.Append(char16_t('\n')); 1.841 + 1.842 + // Last character will be '^'. 1.843 + int32_t last = aColNumber - 1; 1.844 + int32_t i; 1.845 + uint32_t minuses = 0; 1.846 + for (i = 0; i < last; ++i) { 1.847 + if (aSourceLine[i] == '\t') { 1.848 + // Since this uses |white-space: pre;| a tab stop equals 8 spaces. 1.849 + uint32_t add = 8 - (minuses % 8); 1.850 + aSourceString.AppendASCII("--------", add); 1.851 + minuses += add; 1.852 + } 1.853 + else { 1.854 + aSourceString.Append(char16_t('-')); 1.855 + ++minuses; 1.856 + } 1.857 + } 1.858 + aSourceString.Append(char16_t('^')); 1.859 + 1.860 + return NS_OK; 1.861 +} 1.862 + 1.863 +nsresult 1.864 +nsExpatDriver::HandleError() 1.865 +{ 1.866 + int32_t code = XML_GetErrorCode(mExpatParser); 1.867 + NS_ASSERTION(code > XML_ERROR_NONE, "unexpected XML error code"); 1.868 + 1.869 + // Map Expat error code to an error string 1.870 + // XXX Deal with error returns. 1.871 + nsAutoString description; 1.872 + nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code, 1.873 + description); 1.874 + 1.875 + if (code == XML_ERROR_TAG_MISMATCH) { 1.876 + /** 1.877 + * Expat can send the following: 1.878 + * localName 1.879 + * namespaceURI<separator>localName 1.880 + * namespaceURI<separator>localName<separator>prefix 1.881 + * 1.882 + * and we use 0xFFFF for the <separator>. 1.883 + * 1.884 + */ 1.885 + const char16_t *mismatch = MOZ_XML_GetMismatchedTag(mExpatParser); 1.886 + const char16_t *uriEnd = nullptr; 1.887 + const char16_t *nameEnd = nullptr; 1.888 + const char16_t *pos; 1.889 + for (pos = mismatch; *pos; ++pos) { 1.890 + if (*pos == kExpatSeparatorChar) { 1.891 + if (uriEnd) { 1.892 + nameEnd = pos; 1.893 + } 1.894 + else { 1.895 + uriEnd = pos; 1.896 + } 1.897 + } 1.898 + } 1.899 + 1.900 + nsAutoString tagName; 1.901 + if (uriEnd && nameEnd) { 1.902 + // We have a prefix. 1.903 + tagName.Append(nameEnd + 1, pos - nameEnd - 1); 1.904 + tagName.Append(char16_t(':')); 1.905 + } 1.906 + const char16_t *nameStart = uriEnd ? uriEnd + 1 : mismatch; 1.907 + tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart); 1.908 + 1.909 + nsAutoString msg; 1.910 + nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES, 1.911 + "Expected", msg); 1.912 + 1.913 + // . Expected: </%S>. 1.914 + char16_t *message = nsTextFormatter::smprintf(msg.get(), tagName.get()); 1.915 + if (!message) { 1.916 + return NS_ERROR_OUT_OF_MEMORY; 1.917 + } 1.918 + 1.919 + description.Append(message); 1.920 + 1.921 + nsTextFormatter::smprintf_free(message); 1.922 + } 1.923 + 1.924 + // Adjust the column number so that it is one based rather than zero based. 1.925 + uint32_t colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1; 1.926 + uint32_t lineNumber = XML_GetCurrentLineNumber(mExpatParser); 1.927 + 1.928 + nsAutoString errorText; 1.929 + CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber, 1.930 + colNumber, errorText); 1.931 + 1.932 + NS_ASSERTION(mSink, "no sink?"); 1.933 + 1.934 + nsAutoString sourceText(mLastLine); 1.935 + AppendErrorPointer(colNumber, mLastLine.get(), sourceText); 1.936 + 1.937 + // Try to create and initialize the script error. 1.938 + nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); 1.939 + nsresult rv = NS_ERROR_FAILURE; 1.940 + if (serr) { 1.941 + rv = serr->InitWithWindowID(description, 1.942 + mURISpec, 1.943 + mLastLine, 1.944 + lineNumber, colNumber, 1.945 + nsIScriptError::errorFlag, "malformed-xml", 1.946 + mInnerWindowID); 1.947 + } 1.948 + 1.949 + // If it didn't initialize, we can't do any logging. 1.950 + bool shouldReportError = NS_SUCCEEDED(rv); 1.951 + 1.952 + if (mSink && shouldReportError) { 1.953 + rv = mSink->ReportError(errorText.get(), 1.954 + sourceText.get(), 1.955 + serr, 1.956 + &shouldReportError); 1.957 + if (NS_FAILED(rv)) { 1.958 + shouldReportError = true; 1.959 + } 1.960 + } 1.961 + 1.962 + if (shouldReportError) { 1.963 + nsCOMPtr<nsIConsoleService> cs 1.964 + (do_GetService(NS_CONSOLESERVICE_CONTRACTID)); 1.965 + if (cs) { 1.966 + cs->LogMessage(serr); 1.967 + } 1.968 + } 1.969 + 1.970 + return NS_ERROR_HTMLPARSER_STOPPARSING; 1.971 +} 1.972 + 1.973 +void 1.974 +nsExpatDriver::ParseBuffer(const char16_t *aBuffer, 1.975 + uint32_t aLength, 1.976 + bool aIsFinal, 1.977 + uint32_t *aConsumed) 1.978 +{ 1.979 + NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?"); 1.980 + NS_ASSERTION(mInternalState != NS_OK || aIsFinal || aBuffer, 1.981 + "Useless call, we won't call Expat"); 1.982 + NS_PRECONDITION(!BlockedOrInterrupted() || !aBuffer, 1.983 + "Non-null buffer when resuming"); 1.984 + NS_PRECONDITION(XML_GetCurrentByteIndex(mExpatParser) % sizeof(char16_t) == 0, 1.985 + "Consumed part of a char16_t?"); 1.986 + 1.987 + if (mExpatParser && (mInternalState == NS_OK || BlockedOrInterrupted())) { 1.988 + int32_t parserBytesBefore = XML_GetCurrentByteIndex(mExpatParser); 1.989 + NS_ASSERTION(parserBytesBefore >= 0, "Unexpected value"); 1.990 + 1.991 + XML_Status status; 1.992 + if (BlockedOrInterrupted()) { 1.993 + mInternalState = NS_OK; // Resume in case we're blocked. 1.994 + status = XML_ResumeParser(mExpatParser); 1.995 + } 1.996 + else { 1.997 + status = XML_Parse(mExpatParser, 1.998 + reinterpret_cast<const char*>(aBuffer), 1.999 + aLength * sizeof(char16_t), aIsFinal); 1.1000 + } 1.1001 + 1.1002 + int32_t parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser); 1.1003 + 1.1004 + NS_ASSERTION(parserBytesConsumed >= 0, "Unexpected value"); 1.1005 + NS_ASSERTION(parserBytesConsumed >= parserBytesBefore, 1.1006 + "How'd this happen?"); 1.1007 + NS_ASSERTION(parserBytesConsumed % sizeof(char16_t) == 0, 1.1008 + "Consumed part of a char16_t?"); 1.1009 + 1.1010 + // Consumed something. 1.1011 + *aConsumed = (parserBytesConsumed - parserBytesBefore) / sizeof(char16_t); 1.1012 + NS_ASSERTION(*aConsumed <= aLength + mExpatBuffered, 1.1013 + "Too many bytes consumed?"); 1.1014 + 1.1015 + NS_ASSERTION(status != XML_STATUS_SUSPENDED || BlockedOrInterrupted(), 1.1016 + "Inconsistent expat suspension state."); 1.1017 + 1.1018 + if (status == XML_STATUS_ERROR) { 1.1019 + mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING; 1.1020 + } 1.1021 + } 1.1022 + else { 1.1023 + *aConsumed = 0; 1.1024 + } 1.1025 +} 1.1026 + 1.1027 +NS_IMETHODIMP 1.1028 +nsExpatDriver::ConsumeToken(nsScanner& aScanner, bool& aFlushTokens) 1.1029 +{ 1.1030 + // We keep the scanner pointing to the position where Expat will start 1.1031 + // parsing. 1.1032 + nsScannerIterator currentExpatPosition; 1.1033 + aScanner.CurrentPosition(currentExpatPosition); 1.1034 + 1.1035 + // This is the start of the first buffer that we need to pass to Expat. 1.1036 + nsScannerIterator start = currentExpatPosition; 1.1037 + start.advance(mExpatBuffered); 1.1038 + 1.1039 + // This is the end of the last buffer (at this point, more data could come in 1.1040 + // later). 1.1041 + nsScannerIterator end; 1.1042 + aScanner.EndReading(end); 1.1043 + 1.1044 + PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG, 1.1045 + ("Remaining in expat's buffer: %i, remaining in scanner: %i.", 1.1046 + mExpatBuffered, Distance(start, end))); 1.1047 + 1.1048 + // We want to call Expat if we have more buffers, or if we know there won't 1.1049 + // be more buffers (and so we want to flush the remaining data), or if we're 1.1050 + // currently blocked and there's data in Expat's buffer. 1.1051 + while (start != end || (mIsFinalChunk && !mMadeFinalCallToExpat) || 1.1052 + (BlockedOrInterrupted() && mExpatBuffered > 0)) { 1.1053 + bool noMoreBuffers = start == end && mIsFinalChunk; 1.1054 + bool blocked = BlockedOrInterrupted(); 1.1055 + 1.1056 + const char16_t *buffer; 1.1057 + uint32_t length; 1.1058 + if (blocked || noMoreBuffers) { 1.1059 + // If we're blocked we just resume Expat so we don't need a buffer, if 1.1060 + // there aren't any more buffers we pass a null buffer to Expat. 1.1061 + buffer = nullptr; 1.1062 + length = 0; 1.1063 + 1.1064 +#if defined(PR_LOGGING) || defined (DEBUG) 1.1065 + if (blocked) { 1.1066 + PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG, 1.1067 + ("Resuming Expat, will parse data remaining in Expat's " 1.1068 + "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n", 1.1069 + NS_ConvertUTF16toUTF8(currentExpatPosition.get(), 1.1070 + mExpatBuffered).get())); 1.1071 + } 1.1072 + else { 1.1073 + NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end), 1.1074 + "Didn't pass all the data to Expat?"); 1.1075 + PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG, 1.1076 + ("Last call to Expat, will parse data remaining in Expat's " 1.1077 + "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n", 1.1078 + NS_ConvertUTF16toUTF8(currentExpatPosition.get(), 1.1079 + mExpatBuffered).get())); 1.1080 + } 1.1081 +#endif 1.1082 + } 1.1083 + else { 1.1084 + buffer = start.get(); 1.1085 + length = uint32_t(start.size_forward()); 1.1086 + 1.1087 + PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG, 1.1088 + ("Calling Expat, will parse data remaining in Expat's buffer and " 1.1089 + "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew " 1.1090 + "data:\n-----\n%s\n-----\n", 1.1091 + NS_ConvertUTF16toUTF8(currentExpatPosition.get(), 1.1092 + mExpatBuffered).get(), 1.1093 + NS_ConvertUTF16toUTF8(start.get(), length).get())); 1.1094 + } 1.1095 + 1.1096 + uint32_t consumed; 1.1097 + ParseBuffer(buffer, length, noMoreBuffers, &consumed); 1.1098 + if (consumed > 0) { 1.1099 + nsScannerIterator oldExpatPosition = currentExpatPosition; 1.1100 + currentExpatPosition.advance(consumed); 1.1101 + 1.1102 + // We consumed some data, we want to store the last line of data that 1.1103 + // was consumed in case we run into an error (to show the line in which 1.1104 + // the error occurred). 1.1105 + 1.1106 + // The length of the last line that Expat has parsed. 1.1107 + XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser); 1.1108 + 1.1109 + if (lastLineLength <= consumed) { 1.1110 + // The length of the last line was less than what expat consumed, so 1.1111 + // there was at least one line break in the consumed data. Store the 1.1112 + // last line until the point where we stopped parsing. 1.1113 + nsScannerIterator startLastLine = currentExpatPosition; 1.1114 + startLastLine.advance(-((ptrdiff_t)lastLineLength)); 1.1115 + CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine); 1.1116 + } 1.1117 + else { 1.1118 + // There was no line break in the consumed data, append the consumed 1.1119 + // data. 1.1120 + AppendUnicodeTo(oldExpatPosition, currentExpatPosition, mLastLine); 1.1121 + } 1.1122 + } 1.1123 + 1.1124 + mExpatBuffered += length - consumed; 1.1125 + 1.1126 + if (BlockedOrInterrupted()) { 1.1127 + PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG, 1.1128 + ("Blocked or interrupted parser (probably for loading linked " 1.1129 + "stylesheets or scripts).")); 1.1130 + 1.1131 + aScanner.SetPosition(currentExpatPosition, true); 1.1132 + aScanner.Mark(); 1.1133 + 1.1134 + return mInternalState; 1.1135 + } 1.1136 + 1.1137 + if (noMoreBuffers && mExpatBuffered == 0) { 1.1138 + mMadeFinalCallToExpat = true; 1.1139 + } 1.1140 + 1.1141 + if (NS_FAILED(mInternalState)) { 1.1142 + if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) { 1.1143 + NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING, 1.1144 + "Unexpected error"); 1.1145 + 1.1146 + // Look for the next newline after the last one we consumed 1.1147 + nsScannerIterator lastLine = currentExpatPosition; 1.1148 + while (lastLine != end) { 1.1149 + length = uint32_t(lastLine.size_forward()); 1.1150 + uint32_t endOffset = 0; 1.1151 + const char16_t *buffer = lastLine.get(); 1.1152 + while (endOffset < length && buffer[endOffset] != '\n' && 1.1153 + buffer[endOffset] != '\r') { 1.1154 + ++endOffset; 1.1155 + } 1.1156 + mLastLine.Append(Substring(buffer, buffer + endOffset)); 1.1157 + if (endOffset < length) { 1.1158 + // We found a newline. 1.1159 + break; 1.1160 + } 1.1161 + 1.1162 + lastLine.advance(length); 1.1163 + } 1.1164 + 1.1165 + HandleError(); 1.1166 + } 1.1167 + 1.1168 + return mInternalState; 1.1169 + } 1.1170 + 1.1171 + // Either we have more buffers, or we were blocked (and we'll flush in the 1.1172 + // next iteration), or we should have emptied Expat's buffer. 1.1173 + NS_ASSERTION(!noMoreBuffers || blocked || 1.1174 + (mExpatBuffered == 0 && currentExpatPosition == end), 1.1175 + "Unreachable data left in Expat's buffer"); 1.1176 + 1.1177 + start.advance(length); 1.1178 + 1.1179 + // It's possible for start to have passed end if we received more data 1.1180 + // (e.g. if we spun the event loop in an inline script). Reload end now 1.1181 + // to compensate. 1.1182 + aScanner.EndReading(end); 1.1183 + } 1.1184 + 1.1185 + aScanner.SetPosition(currentExpatPosition, true); 1.1186 + aScanner.Mark(); 1.1187 + 1.1188 + PR_LOG(GetExpatDriverLog(), PR_LOG_DEBUG, 1.1189 + ("Remaining in expat's buffer: %i, remaining in scanner: %i.", 1.1190 + mExpatBuffered, Distance(currentExpatPosition, end))); 1.1191 + 1.1192 + return NS_SUCCEEDED(mInternalState) ? kEOF : NS_OK; 1.1193 +} 1.1194 + 1.1195 +NS_IMETHODIMP 1.1196 +nsExpatDriver::WillBuildModel(const CParserContext& aParserContext, 1.1197 + nsITokenizer* aTokenizer, 1.1198 + nsIContentSink* aSink) 1.1199 +{ 1.1200 + mSink = do_QueryInterface(aSink); 1.1201 + if (!mSink) { 1.1202 + NS_ERROR("nsExpatDriver didn't get an nsIExpatSink"); 1.1203 + // Make sure future calls to us bail out as needed 1.1204 + mInternalState = NS_ERROR_UNEXPECTED; 1.1205 + return mInternalState; 1.1206 + } 1.1207 + 1.1208 + mOriginalSink = aSink; 1.1209 + 1.1210 + static const XML_Memory_Handling_Suite memsuite = 1.1211 + { 1.1212 + (void *(*)(size_t))PR_Malloc, 1.1213 + (void *(*)(void *, size_t))PR_Realloc, 1.1214 + PR_Free 1.1215 + }; 1.1216 + 1.1217 + static const char16_t kExpatSeparator[] = { kExpatSeparatorChar, '\0' }; 1.1218 + 1.1219 + mExpatParser = XML_ParserCreate_MM(kUTF16, &memsuite, kExpatSeparator); 1.1220 + NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE); 1.1221 + 1.1222 + XML_SetReturnNSTriplet(mExpatParser, XML_TRUE); 1.1223 + 1.1224 +#ifdef XML_DTD 1.1225 + XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS); 1.1226 +#endif 1.1227 + 1.1228 + mURISpec = aParserContext.mScanner->GetFilename(); 1.1229 + 1.1230 + XML_SetBase(mExpatParser, mURISpec.get()); 1.1231 + 1.1232 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOriginalSink->GetTarget()); 1.1233 + if (doc) { 1.1234 + nsCOMPtr<nsPIDOMWindow> win = doc->GetWindow(); 1.1235 + if (!win) { 1.1236 + bool aHasHadScriptHandlingObject; 1.1237 + nsIScriptGlobalObject *global = 1.1238 + doc->GetScriptHandlingObject(aHasHadScriptHandlingObject); 1.1239 + if (global) { 1.1240 + win = do_QueryInterface(global); 1.1241 + } 1.1242 + } 1.1243 + if (win && !win->IsInnerWindow()) { 1.1244 + win = win->GetCurrentInnerWindow(); 1.1245 + } 1.1246 + if (win) { 1.1247 + mInnerWindowID = win->WindowID(); 1.1248 + } 1.1249 + } 1.1250 + 1.1251 + // Set up the callbacks 1.1252 + XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration); 1.1253 + XML_SetElementHandler(mExpatParser, Driver_HandleStartElement, 1.1254 + Driver_HandleEndElement); 1.1255 + XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData); 1.1256 + XML_SetProcessingInstructionHandler(mExpatParser, 1.1257 + Driver_HandleProcessingInstruction); 1.1258 + XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault); 1.1259 + XML_SetExternalEntityRefHandler(mExpatParser, 1.1260 + (XML_ExternalEntityRefHandler) 1.1261 + Driver_HandleExternalEntityRef); 1.1262 + XML_SetExternalEntityRefHandlerArg(mExpatParser, this); 1.1263 + XML_SetCommentHandler(mExpatParser, Driver_HandleComment); 1.1264 + XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection, 1.1265 + Driver_HandleEndCdataSection); 1.1266 + 1.1267 + XML_SetParamEntityParsing(mExpatParser, 1.1268 + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE); 1.1269 + XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl, 1.1270 + Driver_HandleEndDoctypeDecl); 1.1271 + 1.1272 + // If the sink is an nsIExtendedExpatSink, 1.1273 + // register some addtional handlers. 1.1274 + mExtendedSink = do_QueryInterface(mSink); 1.1275 + if (mExtendedSink) { 1.1276 + XML_SetNamespaceDeclHandler(mExpatParser, 1.1277 + Driver_HandleStartNamespaceDecl, 1.1278 + Driver_HandleEndNamespaceDecl); 1.1279 + XML_SetUnparsedEntityDeclHandler(mExpatParser, 1.1280 + Driver_HandleUnparsedEntityDecl); 1.1281 + XML_SetNotationDeclHandler(mExpatParser, 1.1282 + Driver_HandleNotationDecl); 1.1283 + } 1.1284 + 1.1285 + // Set up the user data. 1.1286 + XML_SetUserData(mExpatParser, this); 1.1287 + 1.1288 + // XML must detect invalid character convertion 1.1289 + aParserContext.mScanner->OverrideReplacementCharacter(0xffff); 1.1290 + 1.1291 + return mInternalState; 1.1292 +} 1.1293 + 1.1294 +NS_IMETHODIMP 1.1295 +nsExpatDriver::BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) 1.1296 +{ 1.1297 + return mInternalState; 1.1298 +} 1.1299 + 1.1300 +NS_IMETHODIMP 1.1301 +nsExpatDriver::DidBuildModel(nsresult anErrorCode) 1.1302 +{ 1.1303 + mOriginalSink = nullptr; 1.1304 + mSink = nullptr; 1.1305 + mExtendedSink = nullptr; 1.1306 + return NS_OK; 1.1307 +} 1.1308 + 1.1309 +NS_IMETHODIMP 1.1310 +nsExpatDriver::WillTokenize(bool aIsFinalChunk) 1.1311 +{ 1.1312 + mIsFinalChunk = aIsFinalChunk; 1.1313 + return NS_OK; 1.1314 +} 1.1315 + 1.1316 +NS_IMETHODIMP_(void) 1.1317 +nsExpatDriver::Terminate() 1.1318 +{ 1.1319 + // XXX - not sure what happens to the unparsed data. 1.1320 + if (mExpatParser) { 1.1321 + XML_StopParser(mExpatParser, XML_FALSE); 1.1322 + } 1.1323 + mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING; 1.1324 +} 1.1325 + 1.1326 +NS_IMETHODIMP_(int32_t) 1.1327 +nsExpatDriver::GetType() 1.1328 +{ 1.1329 + return NS_IPARSER_FLAG_XML; 1.1330 +} 1.1331 + 1.1332 +NS_IMETHODIMP_(nsDTDMode) 1.1333 +nsExpatDriver::GetMode() const 1.1334 +{ 1.1335 + return eDTDMode_full_standards; 1.1336 +} 1.1337 + 1.1338 +/*************************** Unused methods **********************************/ 1.1339 + 1.1340 +NS_IMETHODIMP_(bool) 1.1341 +nsExpatDriver::IsContainer(int32_t aTag) const 1.1342 +{ 1.1343 + return true; 1.1344 +} 1.1345 + 1.1346 +NS_IMETHODIMP_(bool) 1.1347 +nsExpatDriver::CanContain(int32_t aParent,int32_t aChild) const 1.1348 +{ 1.1349 + return true; 1.1350 +} 1.1351 + 1.1352 +void 1.1353 +nsExpatDriver::MaybeStopParser(nsresult aState) 1.1354 +{ 1.1355 + if (NS_FAILED(aState)) { 1.1356 + // If we had a failure we want to override NS_ERROR_HTMLPARSER_INTERRUPTED 1.1357 + // and we want to override NS_ERROR_HTMLPARSER_BLOCK but not with 1.1358 + // NS_ERROR_HTMLPARSER_INTERRUPTED. 1.1359 + if (NS_SUCCEEDED(mInternalState) || 1.1360 + mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED || 1.1361 + (mInternalState == NS_ERROR_HTMLPARSER_BLOCK && 1.1362 + aState != NS_ERROR_HTMLPARSER_INTERRUPTED)) { 1.1363 + mInternalState = (aState == NS_ERROR_HTMLPARSER_INTERRUPTED || 1.1364 + aState == NS_ERROR_HTMLPARSER_BLOCK) ? 1.1365 + aState : 1.1366 + NS_ERROR_HTMLPARSER_STOPPARSING; 1.1367 + } 1.1368 + 1.1369 + // If we get an error then we need to stop Expat (by calling XML_StopParser 1.1370 + // with false as the last argument). If the parser should be blocked or 1.1371 + // interrupted we need to pause Expat (by calling XML_StopParser with 1.1372 + // true as the last argument). 1.1373 + XML_StopParser(mExpatParser, BlockedOrInterrupted()); 1.1374 + } 1.1375 + else if (NS_SUCCEEDED(mInternalState)) { 1.1376 + // Only clobber mInternalState with the success code if we didn't block or 1.1377 + // interrupt before. 1.1378 + mInternalState = aState; 1.1379 + } 1.1380 +}