LCOV - code coverage report
Current view: top level - parser/htmlparser - nsExpatDriver.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 209 596 35.1 %
Date: 2017-07-14 16:53:18 Functions: 25 60 41.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsExpatDriver.h"
       7             : #include "nsCOMPtr.h"
       8             : #include "nsParserCIID.h"
       9             : #include "CParserContext.h"
      10             : #include "nsIExpatSink.h"
      11             : #include "nsIExtendedExpatSink.h"
      12             : #include "nsIContentSink.h"
      13             : #include "nsParserMsgUtils.h"
      14             : #include "nsIURL.h"
      15             : #include "nsIUnicharInputStream.h"
      16             : #include "nsIProtocolHandler.h"
      17             : #include "nsNetUtil.h"
      18             : #include "nsTextFormatter.h"
      19             : #include "nsDirectoryServiceDefs.h"
      20             : #include "nsCRT.h"
      21             : #include "nsIConsoleService.h"
      22             : #include "nsIScriptError.h"
      23             : #include "nsIContentPolicy.h"
      24             : #include "nsContentPolicyUtils.h"
      25             : #include "nsError.h"
      26             : #include "nsXPCOMCIDInternal.h"
      27             : #include "nsUnicharInputStream.h"
      28             : #include "nsContentUtils.h"
      29             : #include "NullPrincipal.h"
      30             : 
      31             : #include "mozilla/Logging.h"
      32             : #include "mozilla/SizePrintfMacros.h"
      33             : 
      34             : using mozilla::fallible;
      35             : using mozilla::LogLevel;
      36             : 
      37             : #define kExpatSeparatorChar 0xFFFF
      38             : 
      39             : static const char16_t kUTF16[] = { 'U', 'T', 'F', '-', '1', '6', '\0' };
      40             : 
      41             : static mozilla::LazyLogModule gExpatDriverLog("expatdriver");
      42             : 
      43             : /***************************** EXPAT CALL BACKS ******************************/
      44             : // The callback handlers that get called from the expat parser.
      45             : 
      46             : static void
      47           4 : Driver_HandleXMLDeclaration(void *aUserData,
      48             :                             const XML_Char *aVersion,
      49             :                             const XML_Char *aEncoding,
      50             :                             int aStandalone)
      51             : {
      52           4 :   NS_ASSERTION(aUserData, "expat driver should exist");
      53           4 :   if (aUserData) {
      54           4 :     nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
      55           4 :     driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
      56             :   }
      57           4 : }
      58             : 
      59             : static void
      60         146 : Driver_HandleStartElement(void *aUserData,
      61             :                           const XML_Char *aName,
      62             :                           const XML_Char **aAtts)
      63             : {
      64         146 :   NS_ASSERTION(aUserData, "expat driver should exist");
      65         146 :   if (aUserData) {
      66             :     static_cast<nsExpatDriver*>(aUserData)->HandleStartElement(aName,
      67         146 :                                                                   aAtts);
      68             :   }
      69         146 : }
      70             : 
      71             : static void
      72         146 : Driver_HandleEndElement(void *aUserData,
      73             :                         const XML_Char *aName)
      74             : {
      75         146 :   NS_ASSERTION(aUserData, "expat driver should exist");
      76         146 :   if (aUserData) {
      77         146 :     static_cast<nsExpatDriver*>(aUserData)->HandleEndElement(aName);
      78             :   }
      79         146 : }
      80             : 
      81             : static void
      82         483 : Driver_HandleCharacterData(void *aUserData,
      83             :                            const XML_Char *aData,
      84             :                            int aLength)
      85             : {
      86         483 :   NS_ASSERTION(aUserData, "expat driver should exist");
      87         483 :   if (aUserData) {
      88         483 :     nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
      89         483 :     driver->HandleCharacterData(aData, uint32_t(aLength));
      90             :   }
      91         483 : }
      92             : 
      93             : static void
      94          23 : Driver_HandleComment(void *aUserData,
      95             :                      const XML_Char *aName)
      96             : {
      97          23 :   NS_ASSERTION(aUserData, "expat driver should exist");
      98          23 :   if(aUserData) {
      99          23 :     static_cast<nsExpatDriver*>(aUserData)->HandleComment(aName);
     100             :   }
     101          23 : }
     102             : 
     103             : static void
     104           0 : Driver_HandleProcessingInstruction(void *aUserData,
     105             :                                    const XML_Char *aTarget,
     106             :                                    const XML_Char *aData)
     107             : {
     108           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     109           0 :   if (aUserData) {
     110           0 :     nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
     111           0 :     driver->HandleProcessingInstruction(aTarget, aData);
     112             :   }
     113           0 : }
     114             : 
     115             : static void
     116          46 : Driver_HandleDefault(void *aUserData,
     117             :                      const XML_Char *aData,
     118             :                      int aLength)
     119             : {
     120          46 :   NS_ASSERTION(aUserData, "expat driver should exist");
     121          46 :   if (aUserData) {
     122          46 :     nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
     123          46 :     driver->HandleDefault(aData, uint32_t(aLength));
     124             :   }
     125          46 : }
     126             : 
     127             : static void
     128           0 : Driver_HandleStartCdataSection(void *aUserData)
     129             : {
     130           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     131           0 :   if (aUserData) {
     132           0 :     static_cast<nsExpatDriver*>(aUserData)->HandleStartCdataSection();
     133             :   }
     134           0 : }
     135             : 
     136             : static void
     137           0 : Driver_HandleEndCdataSection(void *aUserData)
     138             : {
     139           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     140           0 :   if (aUserData) {
     141           0 :     static_cast<nsExpatDriver*>(aUserData)->HandleEndCdataSection();
     142             :   }
     143           0 : }
     144             : 
     145             : static void
     146           0 : Driver_HandleStartDoctypeDecl(void *aUserData,
     147             :                               const XML_Char *aDoctypeName,
     148             :                               const XML_Char *aSysid,
     149             :                               const XML_Char *aPubid,
     150             :                               int aHasInternalSubset)
     151             : {
     152           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     153           0 :   if (aUserData) {
     154             :     static_cast<nsExpatDriver*>(aUserData)->
     155           0 :       HandleStartDoctypeDecl(aDoctypeName, aSysid, aPubid, !!aHasInternalSubset);
     156             :   }
     157           0 : }
     158             : 
     159             : static void
     160           0 : Driver_HandleEndDoctypeDecl(void *aUserData)
     161             : {
     162           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     163           0 :   if (aUserData) {
     164           0 :     static_cast<nsExpatDriver*>(aUserData)->HandleEndDoctypeDecl();
     165             :   }
     166           0 : }
     167             : 
     168             : static int
     169           0 : Driver_HandleExternalEntityRef(void *aExternalEntityRefHandler,
     170             :                                const XML_Char *aOpenEntityNames,
     171             :                                const XML_Char *aBase,
     172             :                                const XML_Char *aSystemId,
     173             :                                const XML_Char *aPublicId)
     174             : {
     175           0 :   NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist");
     176           0 :   if (!aExternalEntityRefHandler) {
     177           0 :     return 1;
     178             :   }
     179             : 
     180             :   nsExpatDriver* driver = static_cast<nsExpatDriver*>
     181           0 :                                      (aExternalEntityRefHandler);
     182             : 
     183             :   return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId,
     184           0 :                                          aPublicId);
     185             : }
     186             : 
     187             : static void
     188           0 : Driver_HandleStartNamespaceDecl(void *aUserData,
     189             :                                 const XML_Char *aPrefix,
     190             :                                 const XML_Char *aUri)
     191             : {
     192           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     193           0 :   if (aUserData) {
     194             :     static_cast<nsExpatDriver*>(aUserData)->
     195           0 :       HandleStartNamespaceDecl(aPrefix, aUri);
     196             :   }
     197           0 : }
     198             : 
     199             : static void
     200           0 : Driver_HandleEndNamespaceDecl(void *aUserData,
     201             :                               const XML_Char *aPrefix)
     202             : {
     203           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     204           0 :   if (aUserData) {
     205             :     static_cast<nsExpatDriver*>(aUserData)->
     206           0 :       HandleEndNamespaceDecl(aPrefix);
     207             :   }
     208           0 : }
     209             : 
     210             : static void
     211           0 : Driver_HandleNotationDecl(void *aUserData,
     212             :                           const XML_Char *aNotationName,
     213             :                           const XML_Char *aBase,
     214             :                           const XML_Char *aSysid,
     215             :                           const XML_Char *aPubid)
     216             : {
     217           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     218           0 :   if (aUserData) {
     219             :     static_cast<nsExpatDriver*>(aUserData)->
     220           0 :       HandleNotationDecl(aNotationName, aBase, aSysid, aPubid);
     221             :   }
     222           0 : }
     223             : 
     224             : static void
     225           0 : Driver_HandleUnparsedEntityDecl(void *aUserData,
     226             :                                 const XML_Char *aEntityName,
     227             :                                 const XML_Char *aBase,
     228             :                                 const XML_Char *aSysid,
     229             :                                 const XML_Char *aPubid,
     230             :                                 const XML_Char *aNotationName)
     231             : {
     232           0 :   NS_ASSERTION(aUserData, "expat driver should exist");
     233           0 :   if (aUserData) {
     234             :     static_cast<nsExpatDriver*>(aUserData)->
     235             :       HandleUnparsedEntityDecl(aEntityName, aBase, aSysid, aPubid,
     236           0 :                                aNotationName);
     237             :   }
     238           0 : }
     239             : 
     240             : 
     241             : /***************************** END CALL BACKS ********************************/
     242             : 
     243             : /***************************** CATALOG UTILS *********************************/
     244             : 
     245             : // Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
     246             : // MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
     247             : // Since Mozilla is not validating, no need to fetch a *huge* file at each
     248             : // click.
     249             : // XXX The cleanest solution here would be to fix Bug 98413: Implement XML
     250             : // Catalogs.
     251             : struct nsCatalogData {
     252             :   const char* mPublicID;
     253             :   const char* mLocalDTD;
     254             :   const char* mAgentSheet;
     255             : };
     256             : 
     257             : // The order of this table is guestimated to be in the optimum order
     258             : static const nsCatalogData kCatalogTable[] = {
     259             :   { "-//W3C//DTD XHTML 1.0 Transitional//EN",    "htmlmathml-f.ent", nullptr },
     260             :   { "-//W3C//DTD XHTML 1.1//EN",                 "htmlmathml-f.ent", nullptr },
     261             :   { "-//W3C//DTD XHTML 1.0 Strict//EN",          "htmlmathml-f.ent", nullptr },
     262             :   { "-//W3C//DTD XHTML 1.0 Frameset//EN",        "htmlmathml-f.ent", nullptr },
     263             :   { "-//W3C//DTD XHTML Basic 1.0//EN",           "htmlmathml-f.ent", nullptr },
     264             :   { "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "htmlmathml-f.ent", nullptr },
     265             :   { "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN", "htmlmathml-f.ent", nullptr },
     266             :   { "-//W3C//DTD MathML 2.0//EN",                "htmlmathml-f.ent", nullptr },
     267             :   { "-//WAPFORUM//DTD XHTML Mobile 1.0//EN",     "htmlmathml-f.ent", nullptr },
     268             :   { nullptr, nullptr, nullptr }
     269             : };
     270             : 
     271             : static const nsCatalogData*
     272           0 : LookupCatalogData(const char16_t* aPublicID)
     273             : {
     274           0 :   nsDependentString publicID(aPublicID);
     275             : 
     276             :   // linear search for now since the number of entries is going to
     277             :   // be negligible, and the fix for bug 98413 would get rid of this
     278             :   // code anyway
     279           0 :   const nsCatalogData* data = kCatalogTable;
     280           0 :   while (data->mPublicID) {
     281           0 :     if (publicID.EqualsASCII(data->mPublicID)) {
     282           0 :       return data;
     283             :     }
     284           0 :     ++data;
     285             :   }
     286             : 
     287           0 :   return nullptr;
     288             : }
     289             : 
     290             : // This function provides a resource URI to a local DTD 
     291             : // in resource://gre/res/dtd/ which may or may not exist.
     292             : // If aCatalogData is provided, it is used to remap the
     293             : // DTD instead of taking the filename from the URI.
     294             : static void
     295           0 : GetLocalDTDURI(const nsCatalogData* aCatalogData, nsIURI* aDTD,
     296             :               nsIURI** aResult)
     297             : {
     298           0 :   NS_ASSERTION(aDTD, "Null parameter.");
     299             : 
     300           0 :   nsAutoCString fileName;
     301           0 :   if (aCatalogData) {
     302             :     // remap the DTD to a known local DTD
     303           0 :     fileName.Assign(aCatalogData->mLocalDTD);
     304             :   }
     305             : 
     306           0 :   if (fileName.IsEmpty()) {
     307             :     // Try to see if the user has installed the DTD file -- we extract the
     308             :     // filename.ext of the DTD here. Hence, for any DTD for which we have
     309             :     // no predefined mapping, users just have to copy the DTD file to our
     310             :     // special DTD directory and it will be picked.
     311           0 :     nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD);
     312           0 :     if (!dtdURL) {
     313           0 :       return;
     314             :     }
     315             : 
     316           0 :     dtdURL->GetFileName(fileName);
     317           0 :     if (fileName.IsEmpty()) {
     318           0 :       return;
     319             :     }
     320             :   }
     321             : 
     322           0 :   nsAutoCString respath("resource://gre/res/dtd/");
     323           0 :   respath += fileName;
     324           0 :   NS_NewURI(aResult, respath);
     325             : }
     326             : 
     327             : /***************************** END CATALOG UTILS *****************************/
     328             : 
     329          66 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsExpatDriver)
     330          44 :   NS_INTERFACE_MAP_ENTRY(nsITokenizer)
     331          22 :   NS_INTERFACE_MAP_ENTRY(nsIDTD)
     332           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
     333           0 : NS_INTERFACE_MAP_END
     334             : 
     335          66 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsExpatDriver)
     336          64 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsExpatDriver)
     337             : 
     338           0 : NS_IMPL_CYCLE_COLLECTION(nsExpatDriver, mSink, mExtendedSink)
     339             : 
     340          22 : nsExpatDriver::nsExpatDriver()
     341             :   : mExpatParser(nullptr),
     342             :     mInCData(false),
     343             :     mInInternalSubset(false),
     344             :     mInExternalDTD(false),
     345             :     mMadeFinalCallToExpat(false),
     346             :     mIsFinalChunk(false),
     347             :     mInternalState(NS_OK),
     348             :     mExpatBuffered(0),
     349             :     mCatalogData(nullptr),
     350          22 :     mInnerWindowID(0)
     351             : {
     352          22 : }
     353             : 
     354           0 : nsExpatDriver::~nsExpatDriver()
     355             : {
     356           0 :   if (mExpatParser) {
     357           0 :     XML_ParserFree(mExpatParser);
     358             :   }
     359           0 : }
     360             : 
     361             : nsresult
     362         146 : nsExpatDriver::HandleStartElement(const char16_t *aValue,
     363             :                                   const char16_t **aAtts)
     364             : {
     365         146 :   NS_ASSERTION(mSink, "content sink not found!");
     366             : 
     367             :   // Calculate the total number of elements in aAtts.
     368             :   // XML_GetSpecifiedAttributeCount will only give us the number of specified
     369             :   // attrs (twice that number, actually), so we have to check for default attrs
     370             :   // ourselves.
     371             :   uint32_t attrArrayLength;
     372         146 :   for (attrArrayLength = XML_GetSpecifiedAttributeCount(mExpatParser);
     373         146 :        aAtts[attrArrayLength];
     374           0 :        attrArrayLength += 2) {
     375             :     // Just looping till we find out what the length is
     376             :   }
     377             : 
     378         146 :   if (mSink) {
     379         146 :     nsresult rv = mSink->
     380         146 :       HandleStartElement(aValue, aAtts, attrArrayLength,
     381         292 :                          XML_GetCurrentLineNumber(mExpatParser));
     382         146 :     MaybeStopParser(rv);
     383             :   }
     384             : 
     385         146 :   return NS_OK;
     386             : }
     387             : 
     388             : nsresult
     389         146 : nsExpatDriver::HandleEndElement(const char16_t *aValue)
     390             : {
     391         146 :   NS_ASSERTION(mSink, "content sink not found!");
     392         146 :   NS_ASSERTION(mInternalState != NS_ERROR_HTMLPARSER_BLOCK,
     393             :                "Shouldn't block from HandleStartElement.");
     394             : 
     395         146 :   if (mSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
     396         146 :     nsresult rv = mSink->HandleEndElement(aValue);
     397         146 :     MaybeStopParser(rv);
     398             :   }
     399             : 
     400         146 :   return NS_OK;
     401             : }
     402             : 
     403             : nsresult
     404         483 : nsExpatDriver::HandleCharacterData(const char16_t *aValue,
     405             :                                    const uint32_t aLength)
     406             : {
     407         483 :   NS_ASSERTION(mSink, "content sink not found!");
     408             : 
     409         483 :   if (mInCData) {
     410           0 :     if (!mCDataText.Append(aValue, aLength, fallible)) {
     411           0 :       MaybeStopParser(NS_ERROR_OUT_OF_MEMORY);
     412             :     }
     413             :   }
     414         483 :   else if (mSink) {
     415         483 :     nsresult rv = mSink->HandleCharacterData(aValue, aLength);
     416         483 :     MaybeStopParser(rv);
     417             :   }
     418             : 
     419         483 :   return NS_OK;
     420             : }
     421             : 
     422             : nsresult
     423          23 : nsExpatDriver::HandleComment(const char16_t *aValue)
     424             : {
     425          23 :   NS_ASSERTION(mSink, "content sink not found!");
     426             : 
     427          23 :   if (mInExternalDTD) {
     428             :     // Ignore comments from external DTDs
     429           0 :     return NS_OK;
     430             :   }
     431             : 
     432          23 :   if (mInInternalSubset) {
     433           0 :     mInternalSubset.AppendLiteral("<!--");
     434           0 :     mInternalSubset.Append(aValue);
     435           0 :     mInternalSubset.AppendLiteral("-->");
     436             :   }
     437          23 :   else if (mSink) {
     438          23 :     nsresult rv = mSink->HandleComment(aValue);
     439          23 :     MaybeStopParser(rv);
     440             :   }
     441             : 
     442          23 :   return NS_OK;
     443             : }
     444             : 
     445             : nsresult
     446           0 : nsExpatDriver::HandleProcessingInstruction(const char16_t *aTarget,
     447             :                                            const char16_t *aData)
     448             : {
     449           0 :   NS_ASSERTION(mSink, "content sink not found!");
     450             : 
     451           0 :   if (mInExternalDTD) {
     452             :     // Ignore PIs in external DTDs for now.  Eventually we want to
     453             :     // pass them to the sink in a way that doesn't put them in the DOM
     454           0 :     return NS_OK;
     455             :   }
     456             : 
     457           0 :   if (mInInternalSubset) {
     458           0 :     mInternalSubset.AppendLiteral("<?");
     459           0 :     mInternalSubset.Append(aTarget);
     460           0 :     mInternalSubset.Append(' ');
     461           0 :     mInternalSubset.Append(aData);
     462           0 :     mInternalSubset.AppendLiteral("?>");
     463             :   }
     464           0 :   else if (mSink) {
     465           0 :     nsresult rv = mSink->HandleProcessingInstruction(aTarget, aData);
     466           0 :     MaybeStopParser(rv);
     467             :   }
     468             : 
     469           0 :   return NS_OK;
     470             : }
     471             : 
     472             : nsresult
     473           4 : nsExpatDriver::HandleXMLDeclaration(const char16_t *aVersion,
     474             :                                     const char16_t *aEncoding,
     475             :                                     int32_t aStandalone)
     476             : {
     477           4 :   if (mSink) {
     478           4 :     nsresult rv = mSink->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
     479           4 :     MaybeStopParser(rv);
     480             :   }
     481             : 
     482           4 :   return NS_OK;
     483             : }
     484             : 
     485             : nsresult
     486          46 : nsExpatDriver::HandleDefault(const char16_t *aValue,
     487             :                              const uint32_t aLength)
     488             : {
     489          46 :   NS_ASSERTION(mSink, "content sink not found!");
     490             : 
     491          46 :   if (mInExternalDTD) {
     492             :     // Ignore newlines in external DTDs
     493           0 :     return NS_OK;
     494             :   }
     495             : 
     496          46 :   if (mInInternalSubset) {
     497           0 :     mInternalSubset.Append(aValue, aLength);
     498             :   }
     499          46 :   else if (mSink) {
     500             :     uint32_t i;
     501          46 :     nsresult rv = mInternalState;
     502          96 :     for (i = 0; i < aLength && NS_SUCCEEDED(rv); ++i) {
     503          50 :       if (aValue[i] == '\n' || aValue[i] == '\r') {
     504          50 :         rv = mSink->HandleCharacterData(&aValue[i], 1);
     505             :       }
     506             :     }
     507          46 :     MaybeStopParser(rv);
     508             :   }
     509             : 
     510          46 :   return NS_OK;
     511             : }
     512             : 
     513             : nsresult
     514           0 : nsExpatDriver::HandleStartCdataSection()
     515             : {
     516           0 :   mInCData = true;
     517             : 
     518           0 :   return NS_OK;
     519             : }
     520             : 
     521             : nsresult
     522           0 : nsExpatDriver::HandleEndCdataSection()
     523             : {
     524           0 :   NS_ASSERTION(mSink, "content sink not found!");
     525             : 
     526           0 :   mInCData = false;
     527           0 :   if (mSink) {
     528           0 :     nsresult rv = mSink->HandleCDataSection(mCDataText.get(),
     529           0 :                                             mCDataText.Length());
     530           0 :     MaybeStopParser(rv);
     531             :   }
     532           0 :   mCDataText.Truncate();
     533             : 
     534           0 :   return NS_OK;
     535             : }
     536             : 
     537             : nsresult
     538           0 : nsExpatDriver::HandleStartNamespaceDecl(const char16_t* aPrefix,
     539             :                                         const char16_t* aUri)
     540             : {
     541           0 :   if (mExtendedSink) {
     542           0 :     nsresult rv = mExtendedSink->HandleStartNamespaceDecl(aPrefix, aUri);
     543           0 :     MaybeStopParser(rv);
     544             :   }
     545           0 :   return NS_OK;
     546             : }
     547             : 
     548             : nsresult
     549           0 : nsExpatDriver::HandleEndNamespaceDecl(const char16_t* aPrefix)
     550             : {
     551           0 :   if (mExtendedSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
     552           0 :     nsresult rv = mExtendedSink->HandleEndNamespaceDecl(aPrefix);
     553           0 :     MaybeStopParser(rv);
     554             :   }
     555           0 :   return NS_OK;
     556             : }
     557             : 
     558             : nsresult
     559           0 : nsExpatDriver::HandleNotationDecl(const char16_t* aNotationName,
     560             :                                   const char16_t* aBase,
     561             :                                   const char16_t* aSysid,
     562             :                                   const char16_t* aPubid)
     563             : {
     564           0 :   if (mExtendedSink) {
     565           0 :     nsresult rv = mExtendedSink->HandleNotationDecl(aNotationName, aSysid,
     566           0 :                                                     aPubid);
     567           0 :     MaybeStopParser(rv);
     568             :   }
     569           0 :   return NS_OK;
     570             : }
     571             : 
     572             : nsresult
     573           0 : nsExpatDriver::HandleUnparsedEntityDecl(const char16_t* aEntityName,
     574             :                                         const char16_t* aBase,
     575             :                                         const char16_t* aSysid,
     576             :                                         const char16_t* aPubid,
     577             :                                         const char16_t* aNotationName)
     578             : {
     579           0 :   if (mExtendedSink) {
     580           0 :     nsresult rv = mExtendedSink->HandleUnparsedEntityDecl(aEntityName,
     581             :                                                           aSysid,
     582             :                                                           aPubid,
     583           0 :                                                           aNotationName);
     584           0 :     MaybeStopParser(rv);
     585             :   }
     586           0 :   return NS_OK;
     587             : }
     588             : 
     589             : nsresult
     590           0 : nsExpatDriver::HandleStartDoctypeDecl(const char16_t* aDoctypeName,
     591             :                                       const char16_t* aSysid,
     592             :                                       const char16_t* aPubid,
     593             :                                       bool aHasInternalSubset)
     594             : {
     595           0 :   mDoctypeName = aDoctypeName;
     596           0 :   mSystemID = aSysid;
     597           0 :   mPublicID = aPubid;
     598             : 
     599           0 :   if (mExtendedSink) {
     600           0 :     nsresult rv = mExtendedSink->HandleStartDTD(aDoctypeName, aSysid, aPubid);
     601           0 :     MaybeStopParser(rv);
     602             :   }
     603             : 
     604           0 :   if (aHasInternalSubset) {
     605             :     // Consuming a huge internal subset translates to numerous
     606             :     // allocations. In an effort to avoid too many allocations
     607             :     // setting mInternalSubset's capacity to be 1K ( just a guesstimate! ).
     608           0 :     mInInternalSubset = true;
     609           0 :     mInternalSubset.SetCapacity(1024);
     610             :   } else {
     611             :     // Distinguish missing internal subset from an empty one
     612           0 :     mInternalSubset.SetIsVoid(true);
     613             :   }
     614             : 
     615           0 :   return NS_OK;
     616             : }
     617             : 
     618             : nsresult
     619           0 : nsExpatDriver::HandleEndDoctypeDecl()
     620             : {
     621           0 :   NS_ASSERTION(mSink, "content sink not found!");
     622             : 
     623           0 :   mInInternalSubset = false;
     624             : 
     625           0 :   if (mSink) {
     626             :     // let the sink know any additional knowledge that we have about the
     627             :     // document (currently, from bug 124570, we only expect to pass additional
     628             :     // agent sheets needed to layout the XML vocabulary of the document)
     629           0 :     nsCOMPtr<nsIURI> data;
     630             : #if 0
     631             :     if (mCatalogData && mCatalogData->mAgentSheet) {
     632             :       NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet);
     633             :     }
     634             : #endif
     635             : 
     636             :     // The unused support for "catalog style sheets" was removed. It doesn't
     637             :     // look like we'll ever fix bug 98413 either.
     638           0 :     MOZ_ASSERT(!mCatalogData || !mCatalogData->mAgentSheet,
     639             :                "Need to add back support for catalog style sheets");
     640             : 
     641             :     // Note: mInternalSubset already doesn't include the [] around it.
     642           0 :     nsresult rv = mSink->HandleDoctypeDecl(mInternalSubset, mDoctypeName,
     643           0 :                                            mSystemID, mPublicID, data);
     644           0 :     MaybeStopParser(rv);
     645             :   }
     646             :   
     647           0 :   mInternalSubset.SetCapacity(0);
     648             : 
     649           0 :   return NS_OK;
     650             : }
     651             : 
     652             : static nsresult
     653           0 : ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
     654             :                             void* aClosure,
     655             :                             const char16_t* aFromSegment,
     656             :                             uint32_t aToOffset,
     657             :                             uint32_t aCount,
     658             :                             uint32_t *aWriteCount)
     659             : {
     660             :   // Pass the buffer to expat for parsing.
     661           0 :   if (XML_Parse((XML_Parser)aClosure, (const char *)aFromSegment,
     662             :                 aCount * sizeof(char16_t), 0) == XML_STATUS_OK) {
     663           0 :     *aWriteCount = aCount;
     664             : 
     665           0 :     return NS_OK;
     666             :   }
     667             : 
     668           0 :   *aWriteCount = 0;
     669             : 
     670           0 :   return NS_ERROR_FAILURE;
     671             : }
     672             : 
     673             : int
     674           0 : nsExpatDriver::HandleExternalEntityRef(const char16_t *openEntityNames,
     675             :                                        const char16_t *base,
     676             :                                        const char16_t *systemId,
     677             :                                        const char16_t *publicId)
     678             : {
     679           0 :   if (mInInternalSubset && !mInExternalDTD && openEntityNames) {
     680           0 :     mInternalSubset.Append(char16_t('%'));
     681           0 :     mInternalSubset.Append(nsDependentString(openEntityNames));
     682           0 :     mInternalSubset.Append(char16_t(';'));
     683             :   }
     684             : 
     685             :   // Load the external entity into a buffer.
     686           0 :   nsCOMPtr<nsIInputStream> in;
     687           0 :   nsAutoString absURL;
     688           0 :   nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base,
     689           0 :                                                getter_AddRefs(in), absURL);
     690           0 :   if (NS_FAILED(rv)) {
     691             : #ifdef DEBUG
     692           0 :     nsCString message("Failed to open external DTD: publicId \"");
     693           0 :     AppendUTF16toUTF8(publicId, message);
     694           0 :     message += "\" systemId \"";
     695           0 :     AppendUTF16toUTF8(systemId, message);
     696           0 :     message += "\" base \"";
     697           0 :     AppendUTF16toUTF8(base, message);
     698           0 :     message += "\" URL \"";
     699           0 :     AppendUTF16toUTF8(absURL, message);
     700           0 :     message += "\"";
     701           0 :     NS_WARNING(message.get());
     702             : #endif
     703           0 :     return 1;
     704             :   }
     705             : 
     706           0 :   nsCOMPtr<nsIUnicharInputStream> uniIn;
     707           0 :   rv = NS_NewUnicharInputStream(in, getter_AddRefs(uniIn));
     708           0 :   NS_ENSURE_SUCCESS(rv, 1);
     709             : 
     710           0 :   int result = 1;
     711           0 :   if (uniIn) {
     712           0 :     XML_Parser entParser = XML_ExternalEntityParserCreate(mExpatParser, 0,
     713           0 :                                                           kUTF16);
     714           0 :     if (entParser) {
     715           0 :       XML_SetBase(entParser, absURL.get());
     716             : 
     717           0 :       mInExternalDTD = true;
     718             : 
     719             :       uint32_t totalRead;
     720           0 :       do {
     721           0 :         rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser,
     722           0 :                                  uint32_t(-1), &totalRead);
     723           0 :       } while (NS_SUCCEEDED(rv) && totalRead > 0);
     724             : 
     725           0 :       result = XML_Parse(entParser, nullptr, 0, 1);
     726             : 
     727           0 :       mInExternalDTD = false;
     728             : 
     729           0 :       XML_ParserFree(entParser);
     730             :     }
     731             :   }
     732             : 
     733           0 :   return result;
     734             : }
     735             : 
     736             : nsresult
     737           0 : nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr,
     738             :                                               const char16_t* aURLStr,
     739             :                                               const char16_t* aBaseURL,
     740             :                                               nsIInputStream** aStream,
     741             :                                               nsAString& aAbsURL)
     742             : {
     743           0 :   nsCOMPtr<nsIURI> baseURI;
     744           0 :   nsresult rv = NS_NewURI(getter_AddRefs(baseURI),
     745           0 :                           NS_ConvertUTF16toUTF8(aBaseURL));
     746           0 :   NS_ENSURE_SUCCESS(rv, rv);
     747             : 
     748           0 :   nsCOMPtr<nsIURI> uri;
     749           0 :   rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nullptr,
     750           0 :                  baseURI);
     751           0 :   NS_ENSURE_SUCCESS(rv, rv);
     752             : 
     753             :   // make sure the URI is allowed to be loaded in sync
     754           0 :   bool isUIResource = false;
     755           0 :   rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
     756           0 :                            &isUIResource);
     757           0 :   NS_ENSURE_SUCCESS(rv, rv);
     758             : 
     759           0 :   nsCOMPtr<nsIURI> localURI;
     760           0 :   if (!isUIResource) {
     761             :     // Check to see if we can map the DTD to a known local DTD, or if a DTD
     762             :     // file of the same name exists in the special DTD directory
     763           0 :     if (aFPIStr) {
     764             :       // see if the Formal Public Identifier (FPI) maps to a catalog entry
     765           0 :       mCatalogData = LookupCatalogData(aFPIStr);
     766           0 :       GetLocalDTDURI(mCatalogData, uri, getter_AddRefs(localURI));
     767             :     }
     768           0 :     if (!localURI) {
     769           0 :       return NS_ERROR_NOT_IMPLEMENTED;
     770             :     }
     771             :   }
     772             : 
     773           0 :   nsCOMPtr<nsIChannel> channel;
     774           0 :   if (localURI) {
     775           0 :     localURI.swap(uri);
     776           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
     777             :                        uri,
     778             :                        nsContentUtils::GetSystemPrincipal(),
     779             :                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     780           0 :                        nsIContentPolicy::TYPE_DTD);
     781             :   }
     782             :   else {
     783           0 :     NS_ASSERTION(mSink == nsCOMPtr<nsIExpatSink>(do_QueryInterface(mOriginalSink)),
     784             :                  "In nsExpatDriver::OpenInputStreamFromExternalDTD: "
     785             :                  "mOriginalSink not the same object as mSink?");
     786           0 :     nsCOMPtr<nsIPrincipal> loadingPrincipal;
     787           0 :     if (mOriginalSink) {
     788           0 :       nsCOMPtr<nsIDocument> doc;
     789           0 :       doc = do_QueryInterface(mOriginalSink->GetTarget());
     790           0 :       if (doc) {
     791           0 :         loadingPrincipal = doc->NodePrincipal();
     792             :       }
     793             :     }
     794           0 :     if (!loadingPrincipal) {
     795           0 :       loadingPrincipal = NullPrincipal::Create();
     796             :     }
     797           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
     798             :                        uri,
     799             :                        loadingPrincipal,
     800             :                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
     801             :                        nsILoadInfo::SEC_ALLOW_CHROME,
     802           0 :                        nsIContentPolicy::TYPE_DTD);
     803             :   }
     804           0 :   NS_ENSURE_SUCCESS(rv, rv);
     805             : 
     806           0 :   nsAutoCString absURL;
     807           0 :   rv = uri->GetSpec(absURL);
     808           0 :   NS_ENSURE_SUCCESS(rv, rv);
     809           0 :   CopyUTF8toUTF16(absURL, aAbsURL);
     810             : 
     811           0 :   channel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
     812           0 :   return channel->Open2(aStream);
     813             : }
     814             : 
     815             : static nsresult
     816           0 : CreateErrorText(const char16_t* aDescription,
     817             :                 const char16_t* aSourceURL,
     818             :                 const uint32_t aLineNumber,
     819             :                 const uint32_t aColNumber,
     820             :                 nsString& aErrorString)
     821             : {
     822           0 :   aErrorString.Truncate();
     823             : 
     824           0 :   nsAutoString msg;
     825             :   nsresult rv =
     826             :     nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
     827           0 :                                                "XMLParsingError", msg);
     828           0 :   NS_ENSURE_SUCCESS(rv, rv);
     829             : 
     830             :   // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$u, Column %4$u:
     831           0 :   char16_t *message = nsTextFormatter::smprintf(msg.get(), aDescription,
     832             :                                                  aSourceURL, aLineNumber,
     833           0 :                                                  aColNumber);
     834           0 :   if (!message) {
     835           0 :     return NS_ERROR_OUT_OF_MEMORY;
     836             :   }
     837             : 
     838           0 :   aErrorString.Assign(message);
     839           0 :   nsTextFormatter::smprintf_free(message);
     840             : 
     841           0 :   return NS_OK;
     842             : }
     843             : 
     844             : static nsresult
     845           0 : AppendErrorPointer(const int32_t aColNumber,
     846             :                    const char16_t *aSourceLine,
     847             :                    nsString& aSourceString)
     848             : {
     849           0 :   aSourceString.Append(char16_t('\n'));
     850             : 
     851             :   // Last character will be '^'.
     852           0 :   int32_t last = aColNumber - 1;
     853             :   int32_t i;
     854           0 :   uint32_t minuses = 0;
     855           0 :   for (i = 0; i < last; ++i) {
     856           0 :     if (aSourceLine[i] == '\t') {
     857             :       // Since this uses |white-space: pre;| a tab stop equals 8 spaces.
     858           0 :       uint32_t add = 8 - (minuses % 8);
     859           0 :       aSourceString.AppendASCII("--------", add);
     860           0 :       minuses += add;
     861             :     }
     862             :     else {
     863           0 :       aSourceString.Append(char16_t('-'));
     864           0 :       ++minuses;
     865             :     }
     866             :   }
     867           0 :   aSourceString.Append(char16_t('^'));
     868             : 
     869           0 :   return NS_OK;
     870             : }
     871             : 
     872             : nsresult
     873           0 : nsExpatDriver::HandleError()
     874             : {
     875           0 :   int32_t code = XML_GetErrorCode(mExpatParser);
     876           0 :   NS_ASSERTION(code > XML_ERROR_NONE, "unexpected XML error code");
     877             : 
     878             :   // Map Expat error code to an error string
     879             :   // XXX Deal with error returns.
     880           0 :   nsAutoString description;
     881           0 :   nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code,
     882           0 :                                            description);
     883             : 
     884           0 :   if (code == XML_ERROR_TAG_MISMATCH) {
     885             :     /**
     886             :      *  Expat can send the following:
     887             :      *    localName
     888             :      *    namespaceURI<separator>localName
     889             :      *    namespaceURI<separator>localName<separator>prefix
     890             :      *
     891             :      *  and we use 0xFFFF for the <separator>.
     892             :      *
     893             :      */
     894           0 :     const char16_t *mismatch = MOZ_XML_GetMismatchedTag(mExpatParser);
     895           0 :     const char16_t *uriEnd = nullptr;
     896           0 :     const char16_t *nameEnd = nullptr;
     897             :     const char16_t *pos;
     898           0 :     for (pos = mismatch; *pos; ++pos) {
     899           0 :       if (*pos == kExpatSeparatorChar) {
     900           0 :         if (uriEnd) {
     901           0 :           nameEnd = pos;
     902             :         }
     903             :         else {
     904           0 :           uriEnd = pos;
     905             :         }
     906             :       }
     907             :     }
     908             : 
     909           0 :     nsAutoString tagName;
     910           0 :     if (uriEnd && nameEnd) {
     911             :       // We have a prefix.
     912           0 :       tagName.Append(nameEnd + 1, pos - nameEnd - 1);
     913           0 :       tagName.Append(char16_t(':'));
     914             :     }
     915           0 :     const char16_t *nameStart = uriEnd ? uriEnd + 1 : mismatch;
     916           0 :     tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
     917             :     
     918           0 :     nsAutoString msg;
     919             :     nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
     920           0 :                                                "Expected", msg);
     921             : 
     922             :     // . Expected: </%S>.
     923           0 :     char16_t *message = nsTextFormatter::smprintf(msg.get(), tagName.get());
     924           0 :     if (!message) {
     925           0 :       return NS_ERROR_OUT_OF_MEMORY;
     926             :     }
     927             : 
     928           0 :     description.Append(message);
     929             : 
     930           0 :     nsTextFormatter::smprintf_free(message);
     931             :   }
     932             : 
     933             :   // Adjust the column number so that it is one based rather than zero based.
     934           0 :   uint32_t colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
     935           0 :   uint32_t lineNumber = XML_GetCurrentLineNumber(mExpatParser);
     936             : 
     937           0 :   nsAutoString errorText;
     938           0 :   CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
     939           0 :                   colNumber, errorText);
     940             : 
     941           0 :   NS_ASSERTION(mSink, "no sink?");
     942             : 
     943           0 :   nsAutoString sourceText(mLastLine);
     944           0 :   AppendErrorPointer(colNumber, mLastLine.get(), sourceText);
     945             : 
     946             :   // Try to create and initialize the script error.
     947           0 :   nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
     948           0 :   nsresult rv = NS_ERROR_FAILURE;
     949           0 :   if (serr) {
     950           0 :     rv = serr->InitWithWindowID(errorText,
     951             :                                 mURISpec,
     952             :                                 mLastLine,
     953             :                                 lineNumber, colNumber,
     954             :                                 nsIScriptError::errorFlag, "malformed-xml",
     955           0 :                                 mInnerWindowID);
     956             :   }
     957             : 
     958             :   // If it didn't initialize, we can't do any logging.
     959           0 :   bool shouldReportError = NS_SUCCEEDED(rv);
     960             : 
     961           0 :   if (mSink && shouldReportError) {
     962           0 :     rv = mSink->ReportError(errorText.get(), 
     963             :                             sourceText.get(), 
     964             :                             serr, 
     965           0 :                             &shouldReportError);
     966           0 :     if (NS_FAILED(rv)) {
     967           0 :       shouldReportError = true;
     968             :     }
     969             :   }
     970             : 
     971           0 :   if (mOriginalSink) {
     972           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOriginalSink->GetTarget());
     973           0 :     if (doc && doc->SuppressParserErrorConsoleMessages()) {
     974           0 :       shouldReportError = false;
     975             :     }
     976             :   }
     977             : 
     978           0 :   if (shouldReportError) {
     979             :     nsCOMPtr<nsIConsoleService> cs
     980           0 :       (do_GetService(NS_CONSOLESERVICE_CONTRACTID));  
     981           0 :     if (cs) {
     982           0 :       cs->LogMessage(serr);
     983             :     }
     984             :   }
     985             : 
     986           0 :   return NS_ERROR_HTMLPARSER_STOPPARSING;
     987             : }
     988             : 
     989             : void
     990          44 : nsExpatDriver::ParseBuffer(const char16_t *aBuffer,
     991             :                            uint32_t aLength,
     992             :                            bool aIsFinal,
     993             :                            uint32_t *aConsumed)
     994             : {
     995          44 :   NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
     996          44 :   NS_ASSERTION(mInternalState != NS_OK || aIsFinal || aBuffer,
     997             :                "Useless call, we won't call Expat");
     998          44 :   NS_PRECONDITION(!BlockedOrInterrupted() || !aBuffer,
     999             :                   "Non-null buffer when resuming");
    1000          44 :   NS_PRECONDITION(XML_GetCurrentByteIndex(mExpatParser) % sizeof(char16_t) == 0,
    1001             :                   "Consumed part of a char16_t?");
    1002             : 
    1003          44 :   if (mExpatParser && (mInternalState == NS_OK || BlockedOrInterrupted())) {
    1004          44 :     int32_t parserBytesBefore = XML_GetCurrentByteIndex(mExpatParser);
    1005          44 :     NS_ASSERTION(parserBytesBefore >= 0, "Unexpected value");
    1006             : 
    1007             :     XML_Status status;
    1008          44 :     if (BlockedOrInterrupted()) {
    1009           0 :       mInternalState = NS_OK; // Resume in case we're blocked.
    1010           0 :       status = XML_ResumeParser(mExpatParser);
    1011             :     }
    1012             :     else {
    1013          44 :       status = XML_Parse(mExpatParser,
    1014             :                          reinterpret_cast<const char*>(aBuffer),
    1015          44 :                          aLength * sizeof(char16_t), aIsFinal);
    1016             :     }
    1017             : 
    1018          44 :     int32_t parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser);
    1019             : 
    1020          44 :     NS_ASSERTION(parserBytesConsumed >= 0, "Unexpected value");
    1021          44 :     NS_ASSERTION(parserBytesConsumed >= parserBytesBefore,
    1022             :                  "How'd this happen?");
    1023          44 :     NS_ASSERTION(parserBytesConsumed % sizeof(char16_t) == 0,
    1024             :                  "Consumed part of a char16_t?");
    1025             : 
    1026             :     // Consumed something.
    1027          44 :     *aConsumed = (parserBytesConsumed - parserBytesBefore) / sizeof(char16_t);
    1028          44 :     NS_ASSERTION(*aConsumed <= aLength + mExpatBuffered,
    1029             :                  "Too many bytes consumed?");
    1030             : 
    1031          44 :     NS_ASSERTION(status != XML_STATUS_SUSPENDED || BlockedOrInterrupted(), 
    1032             :                  "Inconsistent expat suspension state.");
    1033             : 
    1034          44 :     if (status == XML_STATUS_ERROR) {
    1035           0 :       mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
    1036             :     }
    1037             :   }
    1038             :   else {
    1039           0 :     *aConsumed = 0;
    1040             :   }
    1041          44 : }
    1042             : 
    1043             : NS_IMETHODIMP
    1044          44 : nsExpatDriver::ConsumeToken(nsScanner& aScanner, bool& aFlushTokens)
    1045             : {
    1046             :   // We keep the scanner pointing to the position where Expat will start
    1047             :   // parsing.
    1048          44 :   nsScannerIterator currentExpatPosition;
    1049          44 :   aScanner.CurrentPosition(currentExpatPosition);
    1050             : 
    1051             :   // This is the start of the first buffer that we need to pass to Expat.
    1052          44 :   nsScannerIterator start = currentExpatPosition;
    1053          44 :   start.advance(mExpatBuffered);
    1054             : 
    1055             :   // This is the end of the last buffer (at this point, more data could come in
    1056             :   // later).
    1057          44 :   nsScannerIterator end;
    1058          44 :   aScanner.EndReading(end);
    1059             : 
    1060          44 :   MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
    1061             :          ("Remaining in expat's buffer: %i, remaining in scanner: %" PRIuSIZE ".",
    1062             :           mExpatBuffered, Distance(start, end)));
    1063             : 
    1064             :   // We want to call Expat if we have more buffers, or if we know there won't
    1065             :   // be more buffers (and so we want to flush the remaining data), or if we're
    1066             :   // currently blocked and there's data in Expat's buffer.
    1067         220 :   while (start != end || (mIsFinalChunk && !mMadeFinalCallToExpat) ||
    1068          44 :          (BlockedOrInterrupted() && mExpatBuffered > 0)) {
    1069          44 :     bool noMoreBuffers = start == end && mIsFinalChunk;
    1070          44 :     bool blocked = BlockedOrInterrupted();
    1071             : 
    1072             :     const char16_t *buffer;
    1073             :     uint32_t length;
    1074          44 :     if (blocked || noMoreBuffers) {
    1075             :       // If we're blocked we just resume Expat so we don't need a buffer, if
    1076             :       // there aren't any more buffers we pass a null buffer to Expat.
    1077          22 :       buffer = nullptr;
    1078          22 :       length = 0;
    1079             : 
    1080          44 :       if (blocked) {
    1081           0 :         MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
    1082             :                ("Resuming Expat, will parse data remaining in Expat's "
    1083             :                 "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
    1084             :                 NS_ConvertUTF16toUTF8(currentExpatPosition.get(),
    1085             :                                       mExpatBuffered).get()));
    1086             :       }
    1087             :       else {
    1088          22 :         NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end),
    1089             :                      "Didn't pass all the data to Expat?");
    1090          22 :         MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
    1091             :                ("Last call to Expat, will parse data remaining in Expat's "
    1092             :                 "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
    1093             :                 NS_ConvertUTF16toUTF8(currentExpatPosition.get(),
    1094             :                                       mExpatBuffered).get()));
    1095             :       }
    1096             :     }
    1097             :     else {
    1098          22 :       buffer = start.get();
    1099          22 :       length = uint32_t(start.size_forward());
    1100             : 
    1101          22 :       MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
    1102             :              ("Calling Expat, will parse data remaining in Expat's buffer and "
    1103             :               "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew "
    1104             :               "data:\n-----\n%s\n-----\n",
    1105             :               NS_ConvertUTF16toUTF8(currentExpatPosition.get(),
    1106             :                                     mExpatBuffered).get(),
    1107             :               NS_ConvertUTF16toUTF8(start.get(), length).get()));
    1108             :     }
    1109             : 
    1110             :     uint32_t consumed;
    1111          44 :     ParseBuffer(buffer, length, noMoreBuffers, &consumed);
    1112          44 :     if (consumed > 0) {
    1113          22 :       nsScannerIterator oldExpatPosition = currentExpatPosition;
    1114          22 :       currentExpatPosition.advance(consumed);
    1115             : 
    1116             :       // We consumed some data, we want to store the last line of data that
    1117             :       // was consumed in case we run into an error (to show the line in which
    1118             :       // the error occurred).
    1119             : 
    1120             :       // The length of the last line that Expat has parsed.
    1121          22 :       XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser);
    1122             : 
    1123          22 :       if (lastLineLength <= consumed) {
    1124             :         // The length of the last line was less than what expat consumed, so
    1125             :         // there was at least one line break in the consumed data. Store the
    1126             :         // last line until the point where we stopped parsing.
    1127          22 :         nsScannerIterator startLastLine = currentExpatPosition;
    1128          22 :         startLastLine.advance(-((ptrdiff_t)lastLineLength));
    1129          22 :         if (!CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine)) {
    1130           0 :           return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
    1131             :         }
    1132             :       }
    1133             :       else {
    1134             :         // There was no line break in the consumed data, append the consumed
    1135             :         // data.
    1136           0 :         if (!AppendUnicodeTo(oldExpatPosition,
    1137             :                              currentExpatPosition,
    1138             :                              mLastLine)) {
    1139           0 :           return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
    1140             :         }
    1141             :       }
    1142             :     }
    1143             : 
    1144          44 :     mExpatBuffered += length - consumed;
    1145             : 
    1146          44 :     if (BlockedOrInterrupted()) {
    1147           0 :       MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
    1148             :              ("Blocked or interrupted parser (probably for loading linked "
    1149             :               "stylesheets or scripts)."));
    1150             : 
    1151           0 :       aScanner.SetPosition(currentExpatPosition, true);
    1152           0 :       aScanner.Mark();
    1153             : 
    1154           0 :       return mInternalState;
    1155             :     }
    1156             : 
    1157          44 :     if (noMoreBuffers && mExpatBuffered == 0) {
    1158          22 :       mMadeFinalCallToExpat = true;
    1159             :     }
    1160             : 
    1161          44 :     if (NS_FAILED(mInternalState)) {
    1162           0 :       if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) {
    1163           0 :         NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING,
    1164             :                      "Unexpected error");
    1165             : 
    1166             :         // Look for the next newline after the last one we consumed
    1167           0 :         nsScannerIterator lastLine = currentExpatPosition;
    1168           0 :         while (lastLine != end) {
    1169           0 :           length = uint32_t(lastLine.size_forward());
    1170           0 :           uint32_t endOffset = 0;
    1171           0 :           const char16_t *buffer = lastLine.get();
    1172           0 :           while (endOffset < length && buffer[endOffset] != '\n' &&
    1173           0 :                  buffer[endOffset] != '\r') {
    1174           0 :             ++endOffset;
    1175             :           }
    1176           0 :           mLastLine.Append(Substring(buffer, buffer + endOffset));
    1177           0 :           if (endOffset < length) {
    1178             :             // We found a newline.
    1179           0 :             break;
    1180             :           }
    1181             : 
    1182           0 :           lastLine.advance(length);
    1183             :         }
    1184             : 
    1185           0 :         HandleError();
    1186             :       }
    1187             : 
    1188           0 :       return mInternalState;
    1189             :     }
    1190             : 
    1191             :     // Either we have more buffers, or we were blocked (and we'll flush in the
    1192             :     // next iteration), or we should have emptied Expat's buffer.
    1193          44 :     NS_ASSERTION(!noMoreBuffers || blocked ||
    1194             :                  (mExpatBuffered == 0 && currentExpatPosition == end),
    1195             :                  "Unreachable data left in Expat's buffer");
    1196             : 
    1197          44 :     start.advance(length);
    1198             : 
    1199             :     // It's possible for start to have passed end if we received more data
    1200             :     // (e.g. if we spun the event loop in an inline script). Reload end now
    1201             :     // to compensate.
    1202          44 :     aScanner.EndReading(end);
    1203             :   }
    1204             : 
    1205          44 :   aScanner.SetPosition(currentExpatPosition, true);
    1206          44 :   aScanner.Mark();
    1207             : 
    1208          44 :   MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
    1209             :          ("Remaining in expat's buffer: %i, remaining in scanner: %" PRIuSIZE ".",
    1210             :           mExpatBuffered, Distance(currentExpatPosition, end)));
    1211             : 
    1212          44 :   return NS_SUCCEEDED(mInternalState) ? NS_ERROR_HTMLPARSER_EOF : NS_OK;
    1213             : }
    1214             : 
    1215             : NS_IMETHODIMP
    1216          22 : nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
    1217             :                               nsITokenizer* aTokenizer,
    1218             :                               nsIContentSink* aSink)
    1219             : {
    1220          22 :   mSink = do_QueryInterface(aSink);
    1221          22 :   if (!mSink) {
    1222           0 :     NS_ERROR("nsExpatDriver didn't get an nsIExpatSink");
    1223             :     // Make sure future calls to us bail out as needed
    1224           0 :     mInternalState = NS_ERROR_UNEXPECTED;
    1225           0 :     return mInternalState;
    1226             :   }
    1227             : 
    1228          22 :   mOriginalSink = aSink;
    1229             : 
    1230             :   static const XML_Memory_Handling_Suite memsuite = {
    1231             :     malloc,
    1232             :     realloc,
    1233             :     free
    1234             :   };
    1235             : 
    1236             :   static const char16_t kExpatSeparator[] = { kExpatSeparatorChar, '\0' };
    1237             : 
    1238          22 :   mExpatParser = XML_ParserCreate_MM(kUTF16, &memsuite, kExpatSeparator);
    1239          22 :   NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
    1240             : 
    1241          22 :   XML_SetReturnNSTriplet(mExpatParser, XML_TRUE);
    1242             : 
    1243             : #ifdef XML_DTD
    1244          22 :   XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
    1245             : #endif
    1246             : 
    1247          22 :   mURISpec = aParserContext.mScanner->GetFilename();
    1248             : 
    1249          22 :   XML_SetBase(mExpatParser, mURISpec.get());
    1250             : 
    1251          44 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOriginalSink->GetTarget());
    1252          22 :   if (doc) {
    1253          44 :     nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
    1254          44 :     nsCOMPtr<nsPIDOMWindowInner> inner;
    1255          22 :     if (win) {
    1256           0 :       inner = win->GetCurrentInnerWindow();
    1257             :     } else {
    1258             :       bool aHasHadScriptHandlingObject;
    1259             :       nsIScriptGlobalObject *global =
    1260          22 :         doc->GetScriptHandlingObject(aHasHadScriptHandlingObject);
    1261          22 :       if (global) {
    1262           0 :         inner = do_QueryInterface(global);
    1263             :       }
    1264             :     }
    1265          22 :     if (inner) {
    1266           0 :       mInnerWindowID = inner->WindowID();
    1267             :     }
    1268             :   }
    1269             : 
    1270             :   // Set up the callbacks
    1271          22 :   XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration); 
    1272          22 :   XML_SetElementHandler(mExpatParser, Driver_HandleStartElement,
    1273          22 :                         Driver_HandleEndElement);
    1274          22 :   XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
    1275          22 :   XML_SetProcessingInstructionHandler(mExpatParser,
    1276          22 :                                       Driver_HandleProcessingInstruction);
    1277          22 :   XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
    1278          22 :   XML_SetExternalEntityRefHandler(mExpatParser,
    1279             :                                   (XML_ExternalEntityRefHandler)
    1280          22 :                                           Driver_HandleExternalEntityRef);
    1281          22 :   XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
    1282          22 :   XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
    1283          22 :   XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
    1284          22 :                              Driver_HandleEndCdataSection);
    1285             : 
    1286          22 :   XML_SetParamEntityParsing(mExpatParser,
    1287          22 :                             XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
    1288          22 :   XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
    1289          22 :                             Driver_HandleEndDoctypeDecl);
    1290             : 
    1291             :   // If the sink is an nsIExtendedExpatSink,
    1292             :   // register some addtional handlers.
    1293          22 :   mExtendedSink = do_QueryInterface(mSink);
    1294          22 :   if (mExtendedSink) {
    1295           0 :     XML_SetNamespaceDeclHandler(mExpatParser,
    1296             :                                 Driver_HandleStartNamespaceDecl,
    1297           0 :                                 Driver_HandleEndNamespaceDecl);
    1298           0 :     XML_SetUnparsedEntityDeclHandler(mExpatParser,
    1299           0 :                                      Driver_HandleUnparsedEntityDecl);
    1300           0 :     XML_SetNotationDeclHandler(mExpatParser,
    1301           0 :                                Driver_HandleNotationDecl);
    1302             :   }
    1303             : 
    1304             :   // Set up the user data.
    1305          22 :   XML_SetUserData(mExpatParser, this);
    1306             : 
    1307          22 :   return mInternalState;
    1308             : }
    1309             : 
    1310             : NS_IMETHODIMP
    1311          44 : nsExpatDriver::BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink)
    1312             : {
    1313          44 :   return mInternalState;
    1314             : }
    1315             : 
    1316             : NS_IMETHODIMP
    1317          22 : nsExpatDriver::DidBuildModel(nsresult anErrorCode)
    1318             : {
    1319          22 :   mOriginalSink = nullptr;
    1320          22 :   mSink = nullptr;
    1321          22 :   mExtendedSink = nullptr;
    1322          22 :   return NS_OK;
    1323             : }
    1324             : 
    1325             : NS_IMETHODIMP
    1326          44 : nsExpatDriver::WillTokenize(bool aIsFinalChunk)
    1327             : {
    1328          44 :   mIsFinalChunk = aIsFinalChunk;
    1329          44 :   return NS_OK;
    1330             : }
    1331             : 
    1332             : NS_IMETHODIMP_(void)
    1333           0 : nsExpatDriver::Terminate()
    1334             : {
    1335             :   // XXX - not sure what happens to the unparsed data.
    1336           0 :   if (mExpatParser) {
    1337           0 :     XML_StopParser(mExpatParser, XML_FALSE);
    1338             :   }
    1339           0 :   mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
    1340           0 : }
    1341             : 
    1342             : NS_IMETHODIMP_(int32_t)
    1343         154 : nsExpatDriver::GetType()
    1344             : {
    1345         154 :   return NS_IPARSER_FLAG_XML;
    1346             : }
    1347             : 
    1348             : NS_IMETHODIMP_(nsDTDMode)
    1349          22 : nsExpatDriver::GetMode() const
    1350             : {
    1351          22 :   return eDTDMode_full_standards;
    1352             : }
    1353             : 
    1354             : /*************************** Unused methods **********************************/
    1355             : 
    1356             : NS_IMETHODIMP_(bool)
    1357           0 : nsExpatDriver::IsContainer(int32_t aTag) const
    1358             : {
    1359           0 :   return true;
    1360             : }
    1361             : 
    1362             : NS_IMETHODIMP_(bool)
    1363           0 : nsExpatDriver::CanContain(int32_t aParent,int32_t aChild) const
    1364             : {
    1365           0 :   return true;
    1366             : }
    1367             : 
    1368             : void
    1369         848 : nsExpatDriver::MaybeStopParser(nsresult aState)
    1370             : {
    1371         848 :   if (NS_FAILED(aState)) {
    1372             :     // If we had a failure we want to override NS_ERROR_HTMLPARSER_INTERRUPTED
    1373             :     // and we want to override NS_ERROR_HTMLPARSER_BLOCK but not with
    1374             :     // NS_ERROR_HTMLPARSER_INTERRUPTED.
    1375           0 :     if (NS_SUCCEEDED(mInternalState) ||
    1376           0 :         mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
    1377           0 :         (mInternalState == NS_ERROR_HTMLPARSER_BLOCK &&
    1378           0 :          aState != NS_ERROR_HTMLPARSER_INTERRUPTED)) {
    1379           0 :       mInternalState = (aState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
    1380           0 :                         aState == NS_ERROR_HTMLPARSER_BLOCK) ?
    1381             :                        aState :
    1382             :                        NS_ERROR_HTMLPARSER_STOPPARSING;
    1383             :     }
    1384             : 
    1385             :     // If we get an error then we need to stop Expat (by calling XML_StopParser
    1386             :     // with false as the last argument). If the parser should be blocked or
    1387             :     // interrupted we need to pause Expat (by calling XML_StopParser with
    1388             :     // true as the last argument).
    1389           0 :     XML_StopParser(mExpatParser, BlockedOrInterrupted());
    1390             :   }
    1391         848 :   else if (NS_SUCCEEDED(mInternalState)) {
    1392             :     // Only clobber mInternalState with the success code if we didn't block or
    1393             :     // interrupt before.
    1394         848 :     mInternalState = aState;
    1395             :   }
    1396         848 : }

Generated by: LCOV version 1.13