Back to index

lightning-sunbird  0.9+nobinonly
nsExpatDriver.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsExpatDriver.h"
00039 #include "nsIParser.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsParserCIID.h"
00042 #include "CParserContext.h"
00043 #include "nsIExpatSink.h"
00044 #include "nsIExtendedExpatSink.h"
00045 #include "nsIContentSink.h"
00046 #include "nsParserMsgUtils.h"
00047 #include "nsIURL.h"
00048 #include "nsIUnicharInputStream.h"
00049 #include "nsNetUtil.h"
00050 #include "prprf.h"
00051 #include "prmem.h"
00052 #include "nsTextFormatter.h"
00053 #include "nsDirectoryServiceDefs.h"
00054 #include "nsCRT.h"
00055 #include "nsIConsoleService.h"
00056 #include "nsIScriptError.h"
00057 
00058 #define kExpatSeparatorChar 0xFFFF
00059 
00060 static const PRUnichar kUTF16[] = { 'U', 'T', 'F', '-', '1', '6', '\0' };
00061 
00062 /***************************** EXPAT CALL BACKS ******************************/
00063 // The callback handlers that get called from the expat parser.
00064 
00065 PR_STATIC_CALLBACK(void)
00066 Driver_HandleXMLDeclaration(void *aUserData,
00067                             const XML_Char *aVersion,
00068                             const XML_Char *aEncoding,
00069                             int aStandalone)
00070 {
00071   NS_ASSERTION(aUserData, "expat driver should exist");
00072   if (aUserData) {
00073     nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
00074     driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
00075   }
00076 }
00077 
00078 PR_STATIC_CALLBACK(void)
00079 Driver_HandleStartElement(void *aUserData,
00080                           const XML_Char *aName,
00081                           const XML_Char **aAtts)
00082 {
00083   NS_ASSERTION(aUserData, "expat driver should exist");
00084   if (aUserData) {
00085     NS_STATIC_CAST(nsExpatDriver*, aUserData)->HandleStartElement(aName,
00086                                                                   aAtts);
00087   }
00088 }
00089 
00090 PR_STATIC_CALLBACK(void)
00091 Driver_HandleEndElement(void *aUserData,
00092                         const XML_Char *aName)
00093 {
00094   NS_ASSERTION(aUserData, "expat driver should exist");
00095   if (aUserData) {
00096     NS_STATIC_CAST(nsExpatDriver*, aUserData)->HandleEndElement(aName);
00097   }
00098 }
00099 
00100 PR_STATIC_CALLBACK(void)
00101 Driver_HandleCharacterData(void *aUserData,
00102                            const XML_Char *aData,
00103                            int aLength)
00104 {
00105   NS_ASSERTION(aUserData, "expat driver should exist");
00106   if (aUserData) {
00107     nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
00108     driver->HandleCharacterData(aData, PRUint32(aLength));
00109   }
00110 }
00111 
00112 PR_STATIC_CALLBACK(void)
00113 Driver_HandleComment(void *aUserData,
00114                      const XML_Char *aName)
00115 {
00116   NS_ASSERTION(aUserData, "expat driver should exist");
00117   if(aUserData) {
00118     NS_STATIC_CAST(nsExpatDriver*, aUserData)->HandleComment(aName);
00119   }
00120 }
00121 
00122 PR_STATIC_CALLBACK(void)
00123 Driver_HandleProcessingInstruction(void *aUserData,
00124                                    const XML_Char *aTarget,
00125                                    const XML_Char *aData)
00126 {
00127   NS_ASSERTION(aUserData, "expat driver should exist");
00128   if (aUserData) {
00129     nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
00130     driver->HandleProcessingInstruction(aTarget, aData);
00131   }
00132 }
00133 
00134 PR_STATIC_CALLBACK(void)
00135 Driver_HandleDefault(void *aUserData,
00136                      const XML_Char *aData,
00137                      int aLength)
00138 {
00139   NS_ASSERTION(aUserData, "expat driver should exist");
00140   if (aUserData) {
00141     nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*, aUserData);
00142     driver->HandleDefault(aData, PRUint32(aLength));
00143   }
00144 }
00145 
00146 PR_STATIC_CALLBACK(void)
00147 Driver_HandleStartCdataSection(void *aUserData)
00148 {
00149   NS_ASSERTION(aUserData, "expat driver should exist");
00150   if (aUserData) {
00151     NS_STATIC_CAST(nsExpatDriver*, aUserData)->HandleStartCdataSection();
00152   }
00153 }
00154 
00155 PR_STATIC_CALLBACK(void)
00156 Driver_HandleEndCdataSection(void *aUserData)
00157 {
00158   NS_ASSERTION(aUserData, "expat driver should exist");
00159   if (aUserData) {
00160     NS_STATIC_CAST(nsExpatDriver*, aUserData)->HandleEndCdataSection();
00161   }
00162 }
00163 
00164 PR_STATIC_CALLBACK(void)
00165 Driver_HandleStartDoctypeDecl(void *aUserData,
00166                               const XML_Char *aDoctypeName,
00167                               const XML_Char *aSysid,
00168                               const XML_Char *aPubid,
00169                               int aHasInternalSubset)
00170 {
00171   NS_ASSERTION(aUserData, "expat driver should exist");
00172   if (aUserData) {
00173     NS_STATIC_CAST(nsExpatDriver*, aUserData)->
00174       HandleStartDoctypeDecl(aDoctypeName, aSysid, aPubid, aHasInternalSubset);
00175   }
00176 }
00177 
00178 PR_STATIC_CALLBACK(void)
00179 Driver_HandleEndDoctypeDecl(void *aUserData)
00180 {
00181   NS_ASSERTION(aUserData, "expat driver should exist");
00182   if (aUserData) {
00183     NS_STATIC_CAST(nsExpatDriver*, aUserData)->HandleEndDoctypeDecl();
00184   }
00185 }
00186 
00187 PR_STATIC_CALLBACK(int)
00188 Driver_HandleExternalEntityRef(void *aExternalEntityRefHandler,
00189                                const XML_Char *aOpenEntityNames,
00190                                const XML_Char *aBase,
00191                                const XML_Char *aSystemId,
00192                                const XML_Char *aPublicId)
00193 {
00194   NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist");
00195   if (!aExternalEntityRefHandler) {
00196     return 1;
00197   }
00198 
00199   nsExpatDriver* driver = NS_STATIC_CAST(nsExpatDriver*,
00200                                          aExternalEntityRefHandler);
00201 
00202   return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId,
00203                                          aPublicId);
00204 }
00205 
00206 PR_STATIC_CALLBACK(void)
00207 Driver_HandleStartNamespaceDecl(void *aUserData,
00208                                 const XML_Char *aPrefix,
00209                                 const XML_Char *aUri)
00210 {
00211   NS_ASSERTION(aUserData, "expat driver should exist");
00212   if (aUserData) {
00213     NS_STATIC_CAST(nsExpatDriver*, aUserData)->
00214       HandleStartNamespaceDecl(aPrefix, aUri);
00215   }
00216 }
00217 
00218 PR_STATIC_CALLBACK(void)
00219 Driver_HandleEndNamespaceDecl(void *aUserData,
00220                               const XML_Char *aPrefix)
00221 {
00222   NS_ASSERTION(aUserData, "expat driver should exist");
00223   if (aUserData) {
00224     NS_STATIC_CAST(nsExpatDriver*, aUserData)->
00225       HandleEndNamespaceDecl(aPrefix);
00226   }
00227 }
00228 
00229 PR_STATIC_CALLBACK(void)
00230 Driver_HandleNotationDecl(void *aUserData,
00231                           const XML_Char *aNotationName,
00232                           const XML_Char *aBase,
00233                           const XML_Char *aSysid,
00234                           const XML_Char *aPubid)
00235 {
00236   NS_ASSERTION(aUserData, "expat driver should exist");
00237   if (aUserData) {
00238     NS_STATIC_CAST(nsExpatDriver*, aUserData)->
00239       HandleNotationDecl(aNotationName, aBase, aSysid, aPubid);
00240   }
00241 }
00242 
00243 PR_STATIC_CALLBACK(void)
00244 Driver_HandleUnparsedEntityDecl(void *aUserData,
00245                                 const XML_Char *aEntityName,
00246                                 const XML_Char *aBase,
00247                                 const XML_Char *aSysid,
00248                                 const XML_Char *aPubid,
00249                                 const XML_Char *aNotationName)
00250 {
00251   NS_ASSERTION(aUserData, "expat driver should exist");
00252   if (aUserData) {
00253     NS_STATIC_CAST(nsExpatDriver*, aUserData)->
00254       HandleUnparsedEntityDecl(aEntityName, aBase, aSysid, aPubid,
00255                                aNotationName);
00256   }
00257 }
00258 
00259 
00260 /***************************** END CALL BACKS ********************************/
00261 
00262 /***************************** CATALOG UTILS *********************************/
00263 
00264 // Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
00265 // MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
00266 // Since Mozilla is not validating, no need to fetch a *huge* file at each
00267 // click.
00268 // XXX The cleanest solution here would be to fix Bug 98413: Implement XML
00269 // Catalogs.
00270 struct nsCatalogData {
00271   const char* mPublicID;
00272   const char* mLocalDTD;
00273   const char* mAgentSheet;
00274 };
00275 
00276 // The order of this table is guestimated to be in the optimum order
00277 static const nsCatalogData kCatalogTable[] = {
00278   { "-//W3C//DTD XHTML 1.0 Transitional//EN",    "xhtml11.dtd", nsnull },
00279   { "-//W3C//DTD XHTML 1.1//EN",                 "xhtml11.dtd", nsnull },
00280   { "-//W3C//DTD XHTML 1.0 Strict//EN",          "xhtml11.dtd", nsnull },
00281   { "-//W3C//DTD XHTML 1.0 Frameset//EN",        "xhtml11.dtd", nsnull },
00282   { "-//W3C//DTD XHTML Basic 1.0//EN",           "xhtml11.dtd", nsnull },
00283   { "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "mathml.dtd",  "resource://gre/res/mathml.css" },
00284   { "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN", "mathml.dtd", "resource://gre/res/mathml.css" },
00285   { "-//W3C//DTD MathML 2.0//EN",                "mathml.dtd",  "resource://gre/res/mathml.css" },
00286   { "-//WAPFORUM//DTD XHTML Mobile 1.0//EN",     "xhtml11.dtd", nsnull },
00287   { nsnull, nsnull, nsnull }
00288 };
00289 
00290 static const nsCatalogData*
00291 LookupCatalogData(const PRUnichar* aPublicID)
00292 {
00293   nsDependentString publicID(aPublicID);
00294 
00295   // linear search for now since the number of entries is going to
00296   // be negligible, and the fix for bug 98413 would get rid of this
00297   // code anyway
00298   const nsCatalogData* data = kCatalogTable;
00299   while (data->mPublicID) {
00300     if (publicID.EqualsASCII(data->mPublicID)) {
00301       return data;
00302     }
00303     ++data;
00304   }
00305 
00306   return nsnull;
00307 }
00308 
00309 // aCatalogData can be null. If not null, it provides a hook to additional
00310 // built-in knowledge on the resource that we are trying to load. Returns true
00311 // if the local DTD specified in the catalog data exists or if the filename
00312 // contained within the url exists in the special DTD directory. If either of
00313 // this exists, aResult is set to the file: url that points to the DTD file
00314 // found in the local DTD directory.
00315 static PRBool
00316 IsLoadableDTD(const nsCatalogData* aCatalogData, nsIURI* aDTD,
00317               nsIURI** aResult)
00318 {
00319   NS_ASSERTION(aDTD, "Null parameter.");
00320 
00321   nsCAutoString fileName;
00322   if (aCatalogData) {
00323     // remap the DTD to a known local DTD
00324     fileName.Assign(aCatalogData->mLocalDTD);
00325   }
00326 
00327   if (fileName.IsEmpty()) {
00328     // Try to see if the user has installed the DTD file -- we extract the
00329     // filename.ext of the DTD here. Hence, for any DTD for which we have
00330     // no predefined mapping, users just have to copy the DTD file to our
00331     // special DTD directory and it will be picked.
00332     nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD);
00333     if (!dtdURL) {
00334       return PR_FALSE;
00335     }
00336 
00337     dtdURL->GetFileName(fileName);
00338     if (fileName.IsEmpty()) {
00339       return PR_FALSE;
00340     }
00341   }
00342 
00343   nsCOMPtr<nsIFile> dtdPath;
00344   NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dtdPath));
00345   if (!dtdPath) {
00346     return PR_FALSE;
00347   }
00348 
00349   nsCOMPtr<nsILocalFile> lfile = do_QueryInterface(dtdPath);
00350 
00351   // append res/dtd/<fileName>
00352   // can't do AppendRelativeNativePath("res/dtd/" + fileName)
00353   // as that won't work on all platforms.
00354   lfile->AppendNative(NS_LITERAL_CSTRING("res"));
00355   lfile->AppendNative(NS_LITERAL_CSTRING("dtd"));
00356   lfile->AppendNative(fileName);
00357 
00358   PRBool exists;
00359   dtdPath->Exists(&exists);
00360   if (!exists) {
00361     return PR_FALSE;
00362   }
00363 
00364   // The DTD was found in the local DTD directory.
00365   // Set aDTD to a file: url pointing to the local DTD
00366   NS_NewFileURI(aResult, dtdPath);
00367 
00368   return *aResult != nsnull;
00369 }
00370 
00371 /***************************** END CATALOG UTILS *****************************/
00372 
00373 NS_IMPL_ISUPPORTS2(nsExpatDriver,
00374                    nsITokenizer,
00375                    nsIDTD)
00376 
00377 nsresult
00378 NS_NewExpatDriver(nsIDTD** aResult)
00379 {
00380   *aResult = new nsExpatDriver();
00381   if (!*aResult) {
00382     return NS_ERROR_OUT_OF_MEMORY;
00383   }
00384 
00385   NS_ADDREF(*aResult);
00386 
00387   return NS_OK;
00388 }
00389 
00390 nsExpatDriver::nsExpatDriver()
00391   : mExpatParser(nsnull),
00392     mInCData(PR_FALSE),
00393     mInInternalSubset(PR_FALSE),
00394     mInExternalDTD(PR_FALSE),
00395     mBytePosition(0),
00396     mInternalState(NS_OK),
00397     mBytesParsed(0),
00398     mCatalogData(nsnull)
00399 {
00400 }
00401 
00402 nsExpatDriver::~nsExpatDriver()
00403 {
00404   if (mExpatParser) {
00405     XML_ParserFree(mExpatParser);
00406   }
00407 }
00408 
00409 nsresult
00410 nsExpatDriver::HandleStartElement(const PRUnichar *aValue,
00411                                   const PRUnichar **aAtts)
00412 {
00413   NS_ASSERTION(mSink, "content sink not found!");
00414 
00415   // Calculate the total number of elements in aAtts.
00416   // XML_GetSpecifiedAttributeCount will only give us the number of specified
00417   // attrs (twice that number, actually), so we have to check for default attrs
00418   // ourselves.
00419   PRUint32 attrArrayLength;
00420   for (attrArrayLength = XML_GetSpecifiedAttributeCount(mExpatParser);
00421        aAtts[attrArrayLength];
00422        attrArrayLength += 2) {
00423     // Just looping till we find out what the length is
00424   }
00425 
00426   if (mSink) {
00427     mSink->HandleStartElement(aValue, aAtts,
00428                               attrArrayLength,
00429                               XML_GetIdAttributeIndex(mExpatParser),
00430                               XML_GetCurrentLineNumber(mExpatParser));
00431   }
00432 
00433   return NS_OK;
00434 }
00435 
00436 nsresult
00437 nsExpatDriver::HandleEndElement(const PRUnichar *aValue)
00438 {
00439   NS_ASSERTION(mSink, "content sink not found!");
00440 
00441   if (mSink &&
00442       mSink->HandleEndElement(aValue) == NS_ERROR_HTMLPARSER_BLOCK) {
00443     mInternalState = NS_ERROR_HTMLPARSER_BLOCK;
00444     MOZ_XML_StopParser(mExpatParser, XML_TRUE);
00445   }
00446 
00447   return NS_OK;
00448 }
00449 
00450 nsresult
00451 nsExpatDriver::HandleCharacterData(const PRUnichar *aValue,
00452                                    const PRUint32 aLength)
00453 {
00454   NS_ASSERTION(mSink, "content sink not found!");
00455 
00456   if (mInCData) {
00457     mCDataText.Append(aValue, aLength);
00458   }
00459   else if (mSink) {
00460     mInternalState = mSink->HandleCharacterData(aValue, aLength);
00461   }
00462 
00463   return NS_OK;
00464 }
00465 
00466 nsresult
00467 nsExpatDriver::HandleComment(const PRUnichar *aValue)
00468 {
00469   NS_ASSERTION(mSink, "content sink not found!");
00470 
00471   if (mInExternalDTD) {
00472     // Ignore comments from external DTDs
00473     return NS_OK;
00474   }
00475 
00476   if (mInInternalSubset) {
00477     mInternalSubset.AppendLiteral("<!--");
00478     mInternalSubset.Append(aValue);
00479     mInternalSubset.AppendLiteral("-->");
00480   }
00481   else if (mSink) {
00482     mInternalState = mSink->HandleComment(aValue);
00483   }
00484 
00485   return NS_OK;
00486 }
00487 
00488 nsresult
00489 nsExpatDriver::HandleProcessingInstruction(const PRUnichar *aTarget,
00490                                            const PRUnichar *aData)
00491 {
00492   NS_ASSERTION(mSink, "content sink not found!");
00493 
00494   if (mInExternalDTD) {
00495     // Ignore PIs in external DTDs for now.  Eventually we want to
00496     // pass them to the sink in a way that doesn't put them in the DOM
00497     return NS_OK;
00498   }
00499 
00500   if (mInInternalSubset) {
00501     mInternalSubset.AppendLiteral("<?");
00502     mInternalSubset.Append(aTarget);
00503     mInternalSubset.Append(' ');
00504     mInternalSubset.Append(aData);
00505     mInternalSubset.AppendLiteral("?>");
00506   }
00507   else if (mSink &&
00508            mSink->HandleProcessingInstruction(aTarget, aData) ==
00509            NS_ERROR_HTMLPARSER_BLOCK) {
00510     mInternalState = NS_ERROR_HTMLPARSER_BLOCK;
00511     MOZ_XML_StopParser(mExpatParser, XML_TRUE);
00512   }
00513 
00514   return NS_OK;
00515 }
00516 
00517 nsresult
00518 nsExpatDriver::HandleXMLDeclaration(const PRUnichar *aVersion,
00519                                     const PRUnichar *aEncoding,
00520                                     PRInt32 aStandalone)
00521 {
00522   return mSink->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
00523 }
00524 
00525 nsresult
00526 nsExpatDriver::HandleDefault(const PRUnichar *aValue,
00527                              const PRUint32 aLength)
00528 {
00529   NS_ASSERTION(mSink, "content sink not found!");
00530 
00531   if (mInExternalDTD) {
00532     // Ignore newlines in external DTDs
00533     return NS_OK;
00534   }
00535 
00536   if (mInInternalSubset) {
00537     mInternalSubset.Append(aValue, aLength);
00538   }
00539   else if (mSink) {
00540     static const PRUnichar newline[] = { '\n', '\0' };
00541     PRUint32 i;
00542     for (i = 0; i < aLength && NS_SUCCEEDED(mInternalState); ++i) {
00543       if (aValue[i] == '\n' || aValue[i] == '\r') {
00544         mInternalState = mSink->HandleCharacterData(newline, 1);
00545       }
00546     }
00547   }
00548 
00549   return NS_OK;
00550 }
00551 
00552 nsresult
00553 nsExpatDriver::HandleStartCdataSection()
00554 {
00555   mInCData = PR_TRUE;
00556 
00557   return NS_OK;
00558 }
00559 
00560 nsresult
00561 nsExpatDriver::HandleEndCdataSection()
00562 {
00563   NS_ASSERTION(mSink, "content sink not found!");
00564 
00565   mInCData = PR_FALSE;
00566   if (mSink) {
00567     mInternalState = mSink->HandleCDataSection(mCDataText.get(),
00568                                                mCDataText.Length());
00569   }
00570   mCDataText.Truncate();
00571 
00572   return NS_OK;
00573 }
00574 
00575 nsresult
00576 nsExpatDriver::HandleStartNamespaceDecl(const PRUnichar* aPrefix,
00577                                         const PRUnichar* aUri)
00578 {
00579   if (mExtendedSink) {
00580     mInternalState = mExtendedSink->HandleStartNamespaceDecl(aPrefix,
00581                                                             aUri);
00582   }
00583   return NS_OK;
00584 }
00585 
00586 nsresult
00587 nsExpatDriver::HandleEndNamespaceDecl(const PRUnichar* aPrefix)
00588 {
00589   if (mExtendedSink) {
00590     mInternalState = mExtendedSink->HandleEndNamespaceDecl(aPrefix);
00591   }
00592   return NS_OK;
00593 }
00594 
00595 nsresult
00596 nsExpatDriver::HandleNotationDecl(const PRUnichar* aNotationName,
00597                                   const PRUnichar* aBase,
00598                                   const PRUnichar* aSysid,
00599                                   const PRUnichar* aPubid)
00600 {
00601   if (mExtendedSink) {
00602     mInternalState = mExtendedSink->HandleNotationDecl(aNotationName,
00603                                                        aSysid,
00604                                                        aPubid);
00605   }
00606   return NS_OK;
00607 }
00608 
00609 nsresult
00610 nsExpatDriver::HandleUnparsedEntityDecl(const PRUnichar* aEntityName,
00611                                         const PRUnichar* aBase,
00612                                         const PRUnichar* aSysid,
00613                                         const PRUnichar* aPubid,
00614                                         const PRUnichar* aNotationName)
00615 {
00616   if (mExtendedSink) {
00617     mInternalState = mExtendedSink->HandleUnparsedEntityDecl(aEntityName,
00618                                                              aSysid,
00619                                                              aPubid,
00620                                                              aNotationName);
00621   }
00622   return NS_OK;
00623 }
00624 
00625 nsresult
00626 nsExpatDriver::HandleStartDoctypeDecl(const PRUnichar* aDoctypeName,
00627                                       const PRUnichar* aSysid,
00628                                       const PRUnichar* aPubid,
00629                                       PRBool aHasInternalSubset)
00630 {
00631   mDoctypeName = aDoctypeName;
00632   mSystemID = aSysid;
00633   mPublicID = aPubid;
00634 
00635   if (mExtendedSink) {
00636     mInternalState = mExtendedSink->HandleStartDTD(aDoctypeName,
00637                                                    aSysid, aPubid);
00638   }
00639 
00640   if (aHasInternalSubset) {
00641     // Consuming a huge internal subset translates to numerous
00642     // allocations. In an effort to avoid too many allocations
00643     // setting mInternalSubset's capacity to be 1K ( just a guesstimate! ).
00644     mInInternalSubset = PR_TRUE;
00645     mInternalSubset.SetCapacity(1024);
00646   }
00647 
00648   return NS_OK;
00649 }
00650 
00651 nsresult
00652 nsExpatDriver::HandleEndDoctypeDecl()
00653 {
00654   NS_ASSERTION(mSink, "content sink not found!");
00655 
00656   mInInternalSubset = PR_FALSE;
00657 
00658   if (mSink) {
00659     // let the sink know any additional knowledge that we have about the
00660     // document (currently, from bug 124570, we only expect to pass additional
00661     // agent sheets needed to layout the XML vocabulary of the document)
00662     nsCOMPtr<nsIURI> data;
00663     if (mCatalogData && mCatalogData->mAgentSheet) {
00664       NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet);
00665     }
00666 
00667     // Note: mInternalSubset already doesn't include the [] around it.
00668     mInternalState = mSink->HandleDoctypeDecl(mInternalSubset, mDoctypeName,
00669                                               mSystemID, mPublicID, data);
00670     
00671   }
00672   
00673   mInternalSubset.SetCapacity(0);
00674 
00675   return NS_OK;
00676 }
00677 
00678 static NS_METHOD
00679 ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
00680                             void* aClosure,
00681                             const PRUnichar* aFromSegment,
00682                             PRUint32 aToOffset,
00683                             PRUint32 aCount,
00684                             PRUint32 *aWriteCount)
00685 {
00686   // Pass the buffer to expat for parsing. XML_Parse returns 0 for
00687   // fatal errors.
00688   if (XML_Parse((XML_Parser)aClosure, (const char *)aFromSegment,
00689                 aCount * sizeof(PRUnichar), 0)) {
00690     *aWriteCount = aCount;
00691 
00692     return NS_OK;
00693   }
00694 
00695   *aWriteCount = 0;
00696 
00697   return NS_ERROR_FAILURE;
00698 }
00699 
00700 int
00701 nsExpatDriver::HandleExternalEntityRef(const PRUnichar *openEntityNames,
00702                                        const PRUnichar *base,
00703                                        const PRUnichar *systemId,
00704                                        const PRUnichar *publicId)
00705 {
00706   if (mInInternalSubset && !mInExternalDTD && openEntityNames) {
00707     mInternalSubset.Append(PRUnichar('%'));
00708     mInternalSubset.Append(nsDependentString(openEntityNames));
00709     mInternalSubset.Append(PRUnichar(';'));
00710   }
00711 
00712   // Load the external entity into a buffer.
00713   nsCOMPtr<nsIInputStream> in;
00714   nsAutoString absURL;
00715   nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base,
00716                                                getter_AddRefs(in), absURL);
00717   NS_ENSURE_SUCCESS(rv, 1);
00718 
00719   nsCOMPtr<nsIUnicharInputStream> uniIn;
00720   rv = NS_NewUTF8ConverterStream(getter_AddRefs(uniIn), in, 1024);
00721   NS_ENSURE_SUCCESS(rv, 1);
00722 
00723   int result = 1;
00724   if (uniIn) {
00725     XML_Parser entParser = XML_ExternalEntityParserCreate(mExpatParser, 0,
00726                                                           kUTF16);
00727     if (entParser) {
00728       XML_SetBase(entParser, absURL.get());
00729 
00730       mInExternalDTD = PR_TRUE;
00731 
00732       PRUint32 totalRead;
00733       do {
00734         rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser,
00735                                  PRUint32(-1), &totalRead);
00736       } while (NS_SUCCEEDED(rv) && totalRead > 0);
00737 
00738       result = XML_Parse(entParser, nsnull, 0, 1);
00739 
00740       mInExternalDTD = PR_FALSE;
00741 
00742       XML_ParserFree(entParser);
00743     }
00744   }
00745 
00746   return result;
00747 }
00748 
00749 nsresult
00750 nsExpatDriver::OpenInputStreamFromExternalDTD(const PRUnichar* aFPIStr,
00751                                               const PRUnichar* aURLStr,
00752                                               const PRUnichar* aBaseURL,
00753                                               nsIInputStream** aStream,
00754                                               nsAString& aAbsURL)
00755 {
00756   nsCOMPtr<nsIURI> baseURI;
00757   nsresult rv = NS_NewURI(getter_AddRefs(baseURI),
00758                           NS_ConvertUTF16toUTF8(aBaseURL));
00759   NS_ENSURE_SUCCESS(rv, rv);
00760 
00761   nsCOMPtr<nsIURI> uri;
00762   rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nsnull,
00763                  baseURI);
00764   NS_ENSURE_SUCCESS(rv, rv);
00765 
00766   // check if it is alright to load this uri
00767   PRBool isChrome = PR_FALSE;
00768   uri->SchemeIs("chrome", &isChrome);
00769   if (!isChrome) {
00770     // since the url is not a chrome url, check to see if we can map the DTD
00771     // to a known local DTD, or if a DTD file of the same name exists in the
00772     // special DTD directory
00773     if (aFPIStr) {
00774       // see if the Formal Public Identifier (FPI) maps to a catalog entry
00775       mCatalogData = LookupCatalogData(aFPIStr);
00776     }
00777 
00778     nsCOMPtr<nsIURI> localURI;
00779     if (!IsLoadableDTD(mCatalogData, uri, getter_AddRefs(localURI))) {
00780       return NS_ERROR_NOT_IMPLEMENTED;
00781     }
00782 
00783     localURI.swap(uri);
00784   }
00785 
00786   rv = NS_OpenURI(aStream, uri);
00787 
00788   nsCAutoString absURL;
00789   uri->GetSpec(absURL);
00790 
00791   CopyUTF8toUTF16(absURL, aAbsURL);
00792 
00793   return rv;
00794 }
00795 
00796 static nsresult
00797 CreateErrorText(const PRUnichar* aDescription,
00798                 const PRUnichar* aSourceURL,
00799                 const PRInt32 aLineNumber,
00800                 const PRInt32 aColNumber,
00801                 nsString& aErrorString)
00802 {
00803   aErrorString.Truncate();
00804 
00805   nsAutoString msg;
00806   nsresult rv =
00807     nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
00808                                                "XMLParsingError", msg);
00809   NS_ENSURE_SUCCESS(rv, rv);
00810 
00811   // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$d, Column %4$d:
00812   PRUnichar *message = nsTextFormatter::smprintf(msg.get(), aDescription,
00813                                                  aSourceURL, aLineNumber,
00814                                                  aColNumber);
00815   if (!message) {
00816     return NS_ERROR_OUT_OF_MEMORY;
00817   }
00818 
00819   aErrorString.Assign(message);
00820   nsTextFormatter::smprintf_free(message);
00821 
00822   return NS_OK;
00823 }
00824 
00825 static nsresult
00826 CreateSourceText(const PRInt32 aColNumber,
00827                  const PRUnichar *aSourceLine,
00828                  nsString& aSourceString)
00829 {
00830   aSourceString.Append(aSourceLine);
00831   aSourceString.Append(PRUnichar('\n'));
00832 
00833   // Last character will be '^'.
00834   PRInt32 last = aColNumber - 1;
00835   PRInt32 i;
00836   PRUint32 minuses = 0;
00837   for (i = 0; i < last; ++i) {
00838     if (aSourceLine[i] == '\t') {
00839       // Since this uses |white-space: pre;| a tab stop equals 8 spaces.
00840       PRUint32 add = 8 - (minuses % 8);
00841       aSourceString.AppendASCII("--------", add);
00842       minuses += add;
00843     }
00844     else {
00845       aSourceString.Append(PRUnichar('-'));
00846       ++minuses;
00847     }
00848   }
00849   aSourceString.Append(PRUnichar('^'));
00850 
00851   return NS_OK;
00852 }
00853 
00854 nsresult
00855 nsExpatDriver::HandleError()
00856 {
00857   PRInt32 code = XML_GetErrorCode(mExpatParser);
00858   NS_WARN_IF_FALSE(code > XML_ERROR_NONE, "unexpected XML error code");
00859 
00860   // Map Expat error code to an error string
00861   // XXX Deal with error returns.
00862   nsAutoString description;
00863   nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code,
00864                                            description);
00865 
00866   if (code == XML_ERROR_TAG_MISMATCH) {
00876     const PRUnichar *mismatch = MOZ_XML_GetMismatchedTag(mExpatParser);
00877     const PRUnichar *uriEnd = nsnull;
00878     const PRUnichar *nameEnd = nsnull;
00879     const PRUnichar *pos;
00880     for (pos = mismatch; *pos; ++pos) {
00881       if (*pos == kExpatSeparatorChar) {
00882         if (uriEnd) {
00883           nameEnd = pos;
00884         }
00885         else {
00886           uriEnd = pos;
00887         }
00888       }
00889     }
00890 
00891     nsAutoString tagName;
00892     if (uriEnd && nameEnd) {
00893       // We have a prefix.
00894       tagName.Append(nameEnd + 1, pos - nameEnd - 1);
00895       tagName.Append(PRUnichar(':'));
00896     }
00897     const PRUnichar *nameStart = uriEnd ? uriEnd + 1 : mismatch;
00898     tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
00899     
00900     nsAutoString msg;
00901     nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
00902                                                "Expected", msg);
00903 
00904     // . Expected: </%S>.
00905     PRUnichar *message = nsTextFormatter::smprintf(msg.get(), tagName.get());
00906     if (!message) {
00907       return NS_ERROR_OUT_OF_MEMORY;
00908     }
00909 
00910     description.Append(message);
00911 
00912     nsTextFormatter::smprintf_free(message);
00913   }
00914 
00915   // Adjust the column number so that it is one based rather than zero based.
00916   PRInt32 colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
00917   PRInt32 lineNumber = XML_GetCurrentLineNumber(mExpatParser);
00918 
00919   nsAutoString errorText;
00920   CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
00921                   colNumber, errorText);
00922 
00923   nsAutoString sourceText;
00924   CreateSourceText(colNumber, mLastLine.get(), sourceText);
00925 
00926   nsCOMPtr<nsIConsoleService> cs
00927     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
00928   nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
00929   if (serr && cs) {
00930     if (NS_SUCCEEDED(serr->Init(description.get(),
00931                                 mURISpec.get(),
00932                                 sourceText.get(),
00933                                 lineNumber, colNumber,
00934                                 nsIScriptError::errorFlag, "malformed-xml")))
00935       cs->LogMessage(serr);
00936   }
00937 
00938   NS_ASSERTION(mSink, "no sink?");
00939   if (mSink) {
00940     mSink->ReportError(errorText.get(), sourceText.get());
00941   }
00942 
00943   return NS_ERROR_HTMLPARSER_STOPPARSING;
00944 }
00945 
00946 nsresult
00947 nsExpatDriver::ParseBuffer(const char* aBuffer,
00948                            PRUint32 aLength,
00949                            PRBool aIsFinal)
00950 {
00951   NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
00952   NS_ASSERTION(aLength % sizeof(PRUnichar) == 0,
00953                "We can have a PRUnichar spanning chunks?");
00954   NS_PRECONDITION(mBytesParsed % sizeof(PRUnichar) == 0,
00955                   "Parsed part of a PRUnichar?");
00956   NS_PRECONDITION(mBytePosition % sizeof(PRUnichar) == 0,
00957                   "Parsed part of a PRUnichar?");
00958   NS_PRECONDITION(XML_GetCurrentByteIndex(mExpatParser) == -1 ||
00959                   XML_GetCurrentByteIndex(mExpatParser) % sizeof(PRUnichar) == 0,
00960                   "Consumed part of a PRUnichar?");
00961 
00962   if (mExpatParser && mInternalState == NS_OK) {
00963     XML_Bool parsedAll = XML_Parse(mExpatParser, aBuffer, aLength, aIsFinal);
00964 
00965     PRInt32 parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser);
00966 
00967     NS_ASSERTION(parserBytesConsumed == -1 ||
00968                  parserBytesConsumed % sizeof(PRUnichar) == 0,
00969                  "Consumed part of a PRUnichar?");
00970 
00971     // Now figure out the startOffset for appending to mLastLine -- this
00972     // calculation is the same no matter whether we saw an error, got blocked,
00973     // parsed it all but didn't consume it all, or whatever else happened.
00974     const PRUnichar* const buffer =
00975       NS_REINTERPRET_CAST(const PRUnichar*, aBuffer);
00976     PRUint32 startOffset;
00977     // we assume that if expat failed to consume some bytes last time it won't
00978     // consume them this time without also consuming some bytes from aBuffer.
00979     // Note that if expat consumed everything we passed it, it will have nulled
00980     // out all its internal pointers to data, so parserBytesConsumed will come
00981     // out -1 in that case.
00982     if (buffer) {
00983       if (parserBytesConsumed < 0 ||
00984           (PRUint32)parserBytesConsumed >= mBytesParsed) {
00985         // We consumed something
00986         if (parserBytesConsumed < 0) {
00987           NS_ASSERTION(parserBytesConsumed == -1,
00988                        "Unexpected negative value?");
00989           // Consumed everything.
00990           startOffset = aLength / sizeof(PRUnichar);
00991         }
00992         else {
00993           // Consumed something, but not all
00994           NS_ASSERTION(parserBytesConsumed - mBytesParsed <= aLength,
00995                        "Too many bytes consumed?");
00996           startOffset = (parserBytesConsumed - mBytesParsed) /
00997                         sizeof(PRUnichar);
00998         }
00999         // Now startOffset points one past the last PRUnichar consumed in
01000         // buffer
01001         while (startOffset-- != 0) {
01002           if (buffer[startOffset] == '\n' || buffer[startOffset] == '\r') {
01003             mLastLine.Truncate();
01004             break;
01005           }
01006         }
01007         // Now startOffset is pointing to the last newline we consumed (or to
01008         // -1 if there weren't any consumed in this chunk).  Make startOffset
01009         // point to the first char of the first line whose end we haven't
01010         // consumed yet.
01011         ++startOffset;
01012       }
01013       else {
01014         // Didn't parse anything new.  So append all of aBuffer.
01015         startOffset = 0;
01016       }
01017     }
01018 
01019     if (!parsedAll) {
01020       if (mInternalState == NS_ERROR_HTMLPARSER_BLOCK ||
01021           mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING) {
01022         NS_ASSERTION((PRUint32)parserBytesConsumed >= mBytesParsed,
01023                      "How'd this happen?");
01024         mBytePosition = parserBytesConsumed - mBytesParsed;
01025         mBytesParsed = parserBytesConsumed;
01026         if (buffer) {
01027           PRUint32 endOffset = mBytePosition / sizeof(PRUnichar);
01028           NS_ASSERTION(startOffset <= endOffset,
01029                        "Something is confused about what we've consumed");
01030           // Only append the data we actually parsed.  The rest will come
01031           // through this method again.
01032           mLastLine.Append(Substring(buffer + startOffset,
01033                                      buffer + endOffset));
01034         }
01035       }
01036       else {
01037         // An error occured, look for the next newline after the last one we
01038         // consumed.
01039         PRUint32 length = aLength / sizeof(PRUnichar);
01040         if (buffer) {
01041           PRUint32 endOffset = startOffset;
01042           while (endOffset < length && buffer[endOffset] != '\n' &&
01043                  buffer[endOffset] != '\r') {
01044             ++endOffset;
01045           }
01046           mLastLine.Append(Substring(buffer + startOffset,
01047                                      buffer + endOffset));
01048         }
01049         HandleError();
01050         mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
01051       }
01052 
01053       return mInternalState;
01054     }
01055 
01056     if (!aIsFinal && buffer) {
01057       mLastLine.Append(Substring(buffer + startOffset,
01058                                  buffer + aLength / sizeof(PRUnichar)));
01059     }
01060     mBytesParsed += aLength;
01061     mBytePosition = 0;
01062   }
01063 
01064   return NS_OK;
01065 }
01066 
01067 NS_IMETHODIMP
01068 nsExpatDriver::CreateNewInstance(nsIDTD** aInstancePtrResult)
01069 {
01070   return NS_NewExpatDriver(aInstancePtrResult);
01071 }
01072 
01073 NS_IMETHODIMP
01074 nsExpatDriver::ConsumeToken(nsScanner& aScanner,
01075                             PRBool& aFlushTokens)
01076 {
01077   // Ask the scanner to send us all the data it has
01078   // scanned and pass that data to expat.
01079 
01080   mInternalState = NS_OK; // Resume in case we're blocked.
01081   MOZ_XML_ResumeParser(mExpatParser);
01082 
01083   nsScannerIterator start, end;
01084   aScanner.CurrentPosition(start);
01085   aScanner.EndReading(end);
01086 
01087   while (start != end) {
01088     PRUint32 fragLength = PRUint32(start.size_forward());
01089 
01090     mInternalState = ParseBuffer((const char*)start.get(),
01091                                  fragLength * sizeof(PRUnichar),
01092                                  aFlushTokens);
01093 
01094     if (NS_FAILED(mInternalState)) {
01095       if (mInternalState == NS_ERROR_HTMLPARSER_BLOCK) {
01096         aScanner.SetPosition(start.advance(mBytePosition / sizeof(PRUnichar)),
01097                              PR_TRUE);
01098         aScanner.Mark();
01099       }
01100 
01101       return mInternalState;
01102     }
01103 
01104     start.advance(fragLength);
01105   }
01106 
01107   aScanner.SetPosition(end, PR_TRUE);
01108 
01109   if (NS_SUCCEEDED(mInternalState)) {
01110     return aScanner.FillBuffer();
01111   }
01112 
01113   return NS_OK;
01114 }
01115 
01116 NS_IMETHODIMP_(eAutoDetectResult)
01117 nsExpatDriver::CanParse(CParserContext& aParserContext)
01118 {
01119   NS_ASSERTION(!aParserContext.mMimeType.IsEmpty(),
01120                "How'd we get here with an unknown type?");
01121   
01122   if (eViewSource != aParserContext.mParserCommand &&
01123       aParserContext.mDocType == eXML) {
01124     // The parser context already looked at the MIME type for us
01125   
01126     return ePrimaryDetect;
01127   }
01128 
01129   return eUnknownDetect;
01130 }
01131 
01132 NS_IMETHODIMP
01133 nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
01134                               nsITokenizer* aTokenizer,
01135                               nsIContentSink* aSink)
01136 {
01137   mSink = do_QueryInterface(aSink);
01138   if (!mSink) {
01139     NS_ERROR("nsExpatDriver didn't get an nsIExpatSink");
01140     // Make sure future calls to us bail out as needed
01141     mInternalState = NS_ERROR_UNEXPECTED;
01142     return mInternalState;
01143   }
01144 
01145   static const XML_Memory_Handling_Suite memsuite =
01146     {
01147       (void *(*)(size_t))PR_Malloc,
01148       (void *(*)(void *, size_t))PR_Realloc,
01149       PR_Free
01150     };
01151 
01152   static const PRUnichar kExpatSeparator[] = { kExpatSeparatorChar, '\0' };
01153 
01154   mExpatParser = XML_ParserCreate_MM(kUTF16, &memsuite, kExpatSeparator);
01155   NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
01156 
01157   XML_SetReturnNSTriplet(mExpatParser, XML_TRUE);
01158 
01159 #ifdef XML_DTD
01160   XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
01161 #endif
01162 
01163   mURISpec = aParserContext.mScanner->GetFilename();
01164 
01165   XML_SetBase(mExpatParser, mURISpec.get());
01166 
01167   // Set up the callbacks
01168   XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration); 
01169   XML_SetElementHandler(mExpatParser, Driver_HandleStartElement,
01170                         Driver_HandleEndElement);
01171   XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
01172   XML_SetProcessingInstructionHandler(mExpatParser,
01173                                       Driver_HandleProcessingInstruction);
01174   XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
01175   XML_SetExternalEntityRefHandler(mExpatParser,
01176                                   (XML_ExternalEntityRefHandler)
01177                                           Driver_HandleExternalEntityRef);
01178   XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
01179   XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
01180   XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
01181                              Driver_HandleEndCdataSection);
01182 
01183   XML_SetParamEntityParsing(mExpatParser,
01184                             XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
01185   XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
01186                             Driver_HandleEndDoctypeDecl);
01187 
01188   // If the sink is an nsIExtendedExpatSink,
01189   // register some addtional handlers.
01190   mExtendedSink = do_QueryInterface(mSink);
01191   if (mExtendedSink) {
01192     XML_SetNamespaceDeclHandler(mExpatParser,
01193                                 Driver_HandleStartNamespaceDecl,
01194                                 Driver_HandleEndNamespaceDecl);
01195     XML_SetUnparsedEntityDeclHandler(mExpatParser,
01196                                      Driver_HandleUnparsedEntityDecl);
01197     XML_SetNotationDeclHandler(mExpatParser,
01198                                Driver_HandleNotationDecl);
01199   }
01200 
01201   // Set up the user data.
01202   XML_SetUserData(mExpatParser, this);
01203 
01204   return aSink->WillBuildModel();
01205 }
01206 
01207 NS_IMETHODIMP
01208 nsExpatDriver::BuildModel(nsIParser* aParser,
01209                           nsITokenizer* aTokenizer,
01210                           nsITokenObserver* anObserver,
01211                           nsIContentSink* aSink)
01212 {
01213   return mInternalState;
01214 }
01215 
01216 NS_IMETHODIMP
01217 nsExpatDriver::DidBuildModel(nsresult anErrorCode,
01218                              PRBool aNotifySink,
01219                              nsIParser* aParser,
01220                              nsIContentSink* aSink)
01221 {
01222   // Check for mSink is intentional. This would make sure
01223   // that DidBuildModel() is called only once on the sink.
01224   nsresult result = NS_OK;
01225   if (mSink) {
01226     result = aSink->DidBuildModel();
01227     mSink = nsnull;
01228   }
01229 
01230   mExtendedSink = nsnull;
01231 
01232   return result;
01233 }
01234 
01235 NS_IMETHODIMP
01236 nsExpatDriver::WillTokenize(PRBool aIsFinalChunk,
01237                             nsTokenAllocator* aTokenAllocator)
01238 {
01239   return NS_OK;
01240 }
01241 
01242 NS_IMETHODIMP
01243 nsExpatDriver::WillResumeParse(nsIContentSink* aSink)
01244 {
01245   return aSink ? aSink->WillResume() : NS_OK;
01246 }
01247 
01248 NS_IMETHODIMP
01249 nsExpatDriver::WillInterruptParse(nsIContentSink* aSink)
01250 {
01251   return aSink ? aSink->WillInterrupt() : NS_OK;
01252 }
01253 
01254 NS_IMETHODIMP
01255 nsExpatDriver::DidTokenize(PRBool aIsFinalChunk)
01256 {
01257   return ParseBuffer(nsnull, 0, aIsFinalChunk);
01258 }
01259 
01260 NS_IMETHODIMP_(const nsIID&)
01261 nsExpatDriver::GetMostDerivedIID(void) const
01262 {
01263   return NS_GET_IID(nsIDTD);
01264 }
01265 
01266 NS_IMETHODIMP_(void)
01267 nsExpatDriver::Terminate()
01268 {
01269   // XXX - not sure what happens to the unparsed data.
01270   if (mExpatParser) {
01271     MOZ_XML_StopParser(mExpatParser, XML_FALSE);
01272   }
01273   mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
01274 }
01275 
01276 NS_IMETHODIMP_(PRInt32)
01277 nsExpatDriver::GetType()
01278 {
01279   return NS_IPARSER_FLAG_XML;
01280 }
01281 
01282 /*************************** Unused methods **********************************/
01283 
01284 NS_IMETHODIMP
01285 nsExpatDriver::CollectSkippedContent(PRInt32 aTag, nsAString& aContent,
01286                                      PRInt32 &aLineNo)
01287 {
01288   return NS_OK;
01289 }
01290 
01291 NS_IMETHODIMP_(CToken*)
01292 nsExpatDriver::PushTokenFront(CToken* aToken)
01293 {
01294   return 0;
01295 }
01296 
01297 NS_IMETHODIMP_(CToken*)
01298 nsExpatDriver::PushToken(CToken* aToken)
01299 {
01300   return 0;
01301 }
01302 
01303 NS_IMETHODIMP_(CToken*)
01304 nsExpatDriver::PopToken(void)
01305 {
01306   return 0;
01307 }
01308 
01309 NS_IMETHODIMP_(CToken*)
01310 nsExpatDriver::PeekToken(void)
01311 {
01312   return 0;
01313 }
01314 
01315 NS_IMETHODIMP_(CToken*)
01316 nsExpatDriver::GetTokenAt(PRInt32 anIndex)
01317 {
01318   return 0;
01319 }
01320 
01321 NS_IMETHODIMP_(PRInt32)
01322 nsExpatDriver::GetCount(void)
01323 {
01324   return 0;
01325 }
01326 
01327 NS_IMETHODIMP_(nsTokenAllocator*)
01328 nsExpatDriver::GetTokenAllocator(void)
01329 {
01330   return 0;
01331 }
01332 
01333 NS_IMETHODIMP_(void)
01334 nsExpatDriver::PrependTokens(nsDeque& aDeque)
01335 {
01336 }
01337 
01338 NS_IMETHODIMP
01339 nsExpatDriver::CopyState(nsITokenizer* aTokenizer)
01340 {
01341   return NS_OK;
01342 }
01343 
01344 NS_IMETHODIMP
01345 nsExpatDriver::HandleToken(CToken* aToken,nsIParser* aParser)
01346 {
01347   return NS_OK;
01348 }
01349 
01350 NS_IMETHODIMP_(PRBool)
01351 nsExpatDriver::IsContainer(PRInt32 aTag) const
01352 {
01353   return PR_TRUE;
01354 }
01355 
01356 NS_IMETHODIMP_(PRBool)
01357 nsExpatDriver::CanContain(PRInt32 aParent,PRInt32 aChild) const
01358 {
01359   return PR_TRUE;
01360 }