LCOV - code coverage report
Current view: directory - parser/htmlparser/src - nsExpatDriver.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 577 456 79.0 %
Date: 2012-06-02 Functions: 73 54 74.0 %

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

Generated by: LCOV version 1.7