Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / parser / htmlparser / src / nsExpatDriver.cpp
blobecf8054acd9bcd31752ec3199e614f3e440bbcbd
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
23 * Henri Sivonen <hsivonen@iki.fi>
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.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsExpatDriver.h"
40 #include "nsIParser.h"
41 #include "nsCOMPtr.h"
42 #include "nsParserCIID.h"
43 #include "CParserContext.h"
44 #include "nsIExpatSink.h"
45 #include "nsIExtendedExpatSink.h"
46 #include "nsIContentSink.h"
47 #include "nsParserMsgUtils.h"
48 #include "nsIURL.h"
49 #include "nsIUnicharInputStream.h"
50 #include "nsISimpleUnicharStreamFactory.h"
51 #include "nsNetUtil.h"
52 #include "prprf.h"
53 #include "prmem.h"
54 #include "nsTextFormatter.h"
55 #include "nsDirectoryServiceDefs.h"
56 #include "nsCRT.h"
57 #include "nsIConsoleService.h"
58 #include "nsIScriptError.h"
59 #include "nsIContentPolicy.h"
60 #include "nsContentPolicyUtils.h"
61 #include "nsContentErrors.h"
62 #include "nsXPCOMCIDInternal.h"
63 #include "nsUnicharInputStream.h"
65 #define kExpatSeparatorChar 0xFFFF
67 static const PRUnichar kUTF16[] = { 'U', 'T', 'F', '-', '1', '6', '\0' };
69 #ifdef PR_LOGGING
70 static PRLogModuleInfo *gExpatDriverLog = PR_NewLogModule("expatdriver");
71 #endif
73 /***************************** EXPAT CALL BACKS ******************************/
74 // The callback handlers that get called from the expat parser.
76 static void
77 Driver_HandleXMLDeclaration(void *aUserData,
78 const XML_Char *aVersion,
79 const XML_Char *aEncoding,
80 int aStandalone)
82 NS_ASSERTION(aUserData, "expat driver should exist");
83 if (aUserData) {
84 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
85 driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
89 static void
90 Driver_HandleStartElement(void *aUserData,
91 const XML_Char *aName,
92 const XML_Char **aAtts)
94 NS_ASSERTION(aUserData, "expat driver should exist");
95 if (aUserData) {
96 static_cast<nsExpatDriver*>(aUserData)->HandleStartElement(aName,
97 aAtts);
101 static void
102 Driver_HandleEndElement(void *aUserData,
103 const XML_Char *aName)
105 NS_ASSERTION(aUserData, "expat driver should exist");
106 if (aUserData) {
107 static_cast<nsExpatDriver*>(aUserData)->HandleEndElement(aName);
111 static void
112 Driver_HandleCharacterData(void *aUserData,
113 const XML_Char *aData,
114 int aLength)
116 NS_ASSERTION(aUserData, "expat driver should exist");
117 if (aUserData) {
118 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
119 driver->HandleCharacterData(aData, PRUint32(aLength));
123 static void
124 Driver_HandleComment(void *aUserData,
125 const XML_Char *aName)
127 NS_ASSERTION(aUserData, "expat driver should exist");
128 if(aUserData) {
129 static_cast<nsExpatDriver*>(aUserData)->HandleComment(aName);
133 static void
134 Driver_HandleProcessingInstruction(void *aUserData,
135 const XML_Char *aTarget,
136 const XML_Char *aData)
138 NS_ASSERTION(aUserData, "expat driver should exist");
139 if (aUserData) {
140 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
141 driver->HandleProcessingInstruction(aTarget, aData);
145 static void
146 Driver_HandleDefault(void *aUserData,
147 const XML_Char *aData,
148 int aLength)
150 NS_ASSERTION(aUserData, "expat driver should exist");
151 if (aUserData) {
152 nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
153 driver->HandleDefault(aData, PRUint32(aLength));
157 static void
158 Driver_HandleStartCdataSection(void *aUserData)
160 NS_ASSERTION(aUserData, "expat driver should exist");
161 if (aUserData) {
162 static_cast<nsExpatDriver*>(aUserData)->HandleStartCdataSection();
166 static void
167 Driver_HandleEndCdataSection(void *aUserData)
169 NS_ASSERTION(aUserData, "expat driver should exist");
170 if (aUserData) {
171 static_cast<nsExpatDriver*>(aUserData)->HandleEndCdataSection();
175 static void
176 Driver_HandleStartDoctypeDecl(void *aUserData,
177 const XML_Char *aDoctypeName,
178 const XML_Char *aSysid,
179 const XML_Char *aPubid,
180 int aHasInternalSubset)
182 NS_ASSERTION(aUserData, "expat driver should exist");
183 if (aUserData) {
184 static_cast<nsExpatDriver*>(aUserData)->
185 HandleStartDoctypeDecl(aDoctypeName, aSysid, aPubid, !!aHasInternalSubset);
189 static void
190 Driver_HandleEndDoctypeDecl(void *aUserData)
192 NS_ASSERTION(aUserData, "expat driver should exist");
193 if (aUserData) {
194 static_cast<nsExpatDriver*>(aUserData)->HandleEndDoctypeDecl();
198 static int
199 Driver_HandleExternalEntityRef(void *aExternalEntityRefHandler,
200 const XML_Char *aOpenEntityNames,
201 const XML_Char *aBase,
202 const XML_Char *aSystemId,
203 const XML_Char *aPublicId)
205 NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist");
206 if (!aExternalEntityRefHandler) {
207 return 1;
210 nsExpatDriver* driver = static_cast<nsExpatDriver*>
211 (aExternalEntityRefHandler);
213 return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId,
214 aPublicId);
217 static void
218 Driver_HandleStartNamespaceDecl(void *aUserData,
219 const XML_Char *aPrefix,
220 const XML_Char *aUri)
222 NS_ASSERTION(aUserData, "expat driver should exist");
223 if (aUserData) {
224 static_cast<nsExpatDriver*>(aUserData)->
225 HandleStartNamespaceDecl(aPrefix, aUri);
229 static void
230 Driver_HandleEndNamespaceDecl(void *aUserData,
231 const XML_Char *aPrefix)
233 NS_ASSERTION(aUserData, "expat driver should exist");
234 if (aUserData) {
235 static_cast<nsExpatDriver*>(aUserData)->
236 HandleEndNamespaceDecl(aPrefix);
240 static void
241 Driver_HandleNotationDecl(void *aUserData,
242 const XML_Char *aNotationName,
243 const XML_Char *aBase,
244 const XML_Char *aSysid,
245 const XML_Char *aPubid)
247 NS_ASSERTION(aUserData, "expat driver should exist");
248 if (aUserData) {
249 static_cast<nsExpatDriver*>(aUserData)->
250 HandleNotationDecl(aNotationName, aBase, aSysid, aPubid);
254 static void
255 Driver_HandleUnparsedEntityDecl(void *aUserData,
256 const XML_Char *aEntityName,
257 const XML_Char *aBase,
258 const XML_Char *aSysid,
259 const XML_Char *aPubid,
260 const XML_Char *aNotationName)
262 NS_ASSERTION(aUserData, "expat driver should exist");
263 if (aUserData) {
264 static_cast<nsExpatDriver*>(aUserData)->
265 HandleUnparsedEntityDecl(aEntityName, aBase, aSysid, aPubid,
266 aNotationName);
271 /***************************** END CALL BACKS ********************************/
273 /***************************** CATALOG UTILS *********************************/
275 // Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
276 // MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
277 // Since Mozilla is not validating, no need to fetch a *huge* file at each
278 // click.
279 // XXX The cleanest solution here would be to fix Bug 98413: Implement XML
280 // Catalogs.
281 struct nsCatalogData {
282 const char* mPublicID;
283 const char* mLocalDTD;
284 const char* mAgentSheet;
287 // The order of this table is guestimated to be in the optimum order
288 static const nsCatalogData kCatalogTable[] = {
289 { "-//W3C//DTD XHTML 1.0 Transitional//EN", "xhtml11.dtd", nsnull },
290 { "-//W3C//DTD XHTML 1.1//EN", "xhtml11.dtd", nsnull },
291 { "-//W3C//DTD XHTML 1.0 Strict//EN", "xhtml11.dtd", nsnull },
292 { "-//W3C//DTD XHTML 1.0 Frameset//EN", "xhtml11.dtd", nsnull },
293 { "-//W3C//DTD XHTML Basic 1.0//EN", "xhtml11.dtd", nsnull },
294 { "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "mathml.dtd", "resource://gre/res/mathml.css" },
295 { "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN", "mathml.dtd", "resource://gre/res/mathml.css" },
296 { "-//W3C//DTD MathML 2.0//EN", "mathml.dtd", "resource://gre/res/mathml.css" },
297 { "-//WAPFORUM//DTD XHTML Mobile 1.0//EN", "xhtml11.dtd", nsnull },
298 { nsnull, nsnull, nsnull }
301 static const nsCatalogData*
302 LookupCatalogData(const PRUnichar* aPublicID)
304 nsDependentString publicID(aPublicID);
306 // linear search for now since the number of entries is going to
307 // be negligible, and the fix for bug 98413 would get rid of this
308 // code anyway
309 const nsCatalogData* data = kCatalogTable;
310 while (data->mPublicID) {
311 if (publicID.EqualsASCII(data->mPublicID)) {
312 return data;
314 ++data;
317 return nsnull;
320 // aCatalogData can be null. If not null, it provides a hook to additional
321 // built-in knowledge on the resource that we are trying to load. Returns true
322 // if the local DTD specified in the catalog data exists or if the filename
323 // contained within the url exists in the special DTD directory. If either of
324 // this exists, aResult is set to the file: url that points to the DTD file
325 // found in the local DTD directory.
326 static PRBool
327 IsLoadableDTD(const nsCatalogData* aCatalogData, nsIURI* aDTD,
328 nsIURI** aResult)
330 NS_ASSERTION(aDTD, "Null parameter.");
332 nsCAutoString fileName;
333 if (aCatalogData) {
334 // remap the DTD to a known local DTD
335 fileName.Assign(aCatalogData->mLocalDTD);
338 if (fileName.IsEmpty()) {
339 // Try to see if the user has installed the DTD file -- we extract the
340 // filename.ext of the DTD here. Hence, for any DTD for which we have
341 // no predefined mapping, users just have to copy the DTD file to our
342 // special DTD directory and it will be picked.
343 nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD);
344 if (!dtdURL) {
345 return PR_FALSE;
348 dtdURL->GetFileName(fileName);
349 if (fileName.IsEmpty()) {
350 return PR_FALSE;
354 nsCOMPtr<nsIFile> dtdPath;
355 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dtdPath));
356 if (!dtdPath) {
357 return PR_FALSE;
360 nsCOMPtr<nsILocalFile> lfile = do_QueryInterface(dtdPath);
362 // append res/dtd/<fileName>
363 // can't do AppendRelativeNativePath("res/dtd/" + fileName)
364 // as that won't work on all platforms.
365 lfile->AppendNative(NS_LITERAL_CSTRING("res"));
366 lfile->AppendNative(NS_LITERAL_CSTRING("dtd"));
367 lfile->AppendNative(fileName);
369 PRBool exists;
370 dtdPath->Exists(&exists);
371 if (!exists) {
372 return PR_FALSE;
375 // The DTD was found in the local DTD directory.
376 // Set aDTD to a file: url pointing to the local DTD
377 NS_NewFileURI(aResult, dtdPath);
379 return *aResult != nsnull;
382 /***************************** END CATALOG UTILS *****************************/
384 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsExpatDriver)
385 NS_INTERFACE_MAP_ENTRY(nsITokenizer)
386 NS_INTERFACE_MAP_ENTRY(nsIDTD)
387 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
388 NS_INTERFACE_MAP_END
390 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsExpatDriver)
391 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsExpatDriver)
393 NS_IMPL_CYCLE_COLLECTION_2(nsExpatDriver, mSink, mExtendedSink)
395 nsExpatDriver::nsExpatDriver()
396 : mExpatParser(nsnull),
397 mInCData(PR_FALSE),
398 mInInternalSubset(PR_FALSE),
399 mInExternalDTD(PR_FALSE),
400 mIsFinalChunk(PR_FALSE),
401 mInternalState(NS_OK),
402 mExpatBuffered(0),
403 mCatalogData(nsnull)
407 nsExpatDriver::~nsExpatDriver()
409 if (mExpatParser) {
410 XML_ParserFree(mExpatParser);
414 nsresult
415 nsExpatDriver::HandleStartElement(const PRUnichar *aValue,
416 const PRUnichar **aAtts)
418 NS_ASSERTION(mSink, "content sink not found!");
420 // Calculate the total number of elements in aAtts.
421 // XML_GetSpecifiedAttributeCount will only give us the number of specified
422 // attrs (twice that number, actually), so we have to check for default attrs
423 // ourselves.
424 PRUint32 attrArrayLength;
425 for (attrArrayLength = XML_GetSpecifiedAttributeCount(mExpatParser);
426 aAtts[attrArrayLength];
427 attrArrayLength += 2) {
428 // Just looping till we find out what the length is
431 if (mSink) {
432 nsresult rv = mSink->
433 HandleStartElement(aValue, aAtts, attrArrayLength,
434 XML_GetIdAttributeIndex(mExpatParser),
435 XML_GetCurrentLineNumber(mExpatParser));
436 MaybeStopParser(rv);
439 return NS_OK;
442 nsresult
443 nsExpatDriver::HandleEndElement(const PRUnichar *aValue)
445 NS_ASSERTION(mSink, "content sink not found!");
446 NS_ASSERTION(mInternalState != NS_ERROR_HTMLPARSER_BLOCK,
447 "Shouldn't block from HandleStartElement.");
449 if (mSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
450 nsresult rv = mSink->HandleEndElement(aValue);
451 MaybeStopParser(rv);
454 return NS_OK;
457 nsresult
458 nsExpatDriver::HandleCharacterData(const PRUnichar *aValue,
459 const PRUint32 aLength)
461 NS_ASSERTION(mSink, "content sink not found!");
463 if (mInCData) {
464 mCDataText.Append(aValue, aLength);
466 else if (mSink) {
467 nsresult rv = mSink->HandleCharacterData(aValue, aLength);
468 MaybeStopParser(rv);
471 return NS_OK;
474 nsresult
475 nsExpatDriver::HandleComment(const PRUnichar *aValue)
477 NS_ASSERTION(mSink, "content sink not found!");
479 if (mInExternalDTD) {
480 // Ignore comments from external DTDs
481 return NS_OK;
484 if (mInInternalSubset) {
485 mInternalSubset.AppendLiteral("<!--");
486 mInternalSubset.Append(aValue);
487 mInternalSubset.AppendLiteral("-->");
489 else if (mSink) {
490 nsresult rv = mSink->HandleComment(aValue);
491 MaybeStopParser(rv);
494 return NS_OK;
497 nsresult
498 nsExpatDriver::HandleProcessingInstruction(const PRUnichar *aTarget,
499 const PRUnichar *aData)
501 NS_ASSERTION(mSink, "content sink not found!");
503 if (mInExternalDTD) {
504 // Ignore PIs in external DTDs for now. Eventually we want to
505 // pass them to the sink in a way that doesn't put them in the DOM
506 return NS_OK;
509 if (mInInternalSubset) {
510 mInternalSubset.AppendLiteral("<?");
511 mInternalSubset.Append(aTarget);
512 mInternalSubset.Append(' ');
513 mInternalSubset.Append(aData);
514 mInternalSubset.AppendLiteral("?>");
516 else if (mSink) {
517 nsresult rv = mSink->HandleProcessingInstruction(aTarget, aData);
518 MaybeStopParser(rv);
521 return NS_OK;
524 nsresult
525 nsExpatDriver::HandleXMLDeclaration(const PRUnichar *aVersion,
526 const PRUnichar *aEncoding,
527 PRInt32 aStandalone)
529 if (mSink) {
530 nsresult rv = mSink->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
531 MaybeStopParser(rv);
534 return NS_OK;
537 nsresult
538 nsExpatDriver::HandleDefault(const PRUnichar *aValue,
539 const PRUint32 aLength)
541 NS_ASSERTION(mSink, "content sink not found!");
543 if (mInExternalDTD) {
544 // Ignore newlines in external DTDs
545 return NS_OK;
548 if (mInInternalSubset) {
549 mInternalSubset.Append(aValue, aLength);
551 else if (mSink) {
552 PRUint32 i;
553 nsresult rv = mInternalState;
554 for (i = 0; i < aLength && NS_SUCCEEDED(rv); ++i) {
555 if (aValue[i] == '\n' || aValue[i] == '\r') {
556 rv = mSink->HandleCharacterData(&aValue[i], 1);
559 MaybeStopParser(rv);
562 return NS_OK;
565 nsresult
566 nsExpatDriver::HandleStartCdataSection()
568 mInCData = PR_TRUE;
570 return NS_OK;
573 nsresult
574 nsExpatDriver::HandleEndCdataSection()
576 NS_ASSERTION(mSink, "content sink not found!");
578 mInCData = PR_FALSE;
579 if (mSink) {
580 nsresult rv = mSink->HandleCDataSection(mCDataText.get(),
581 mCDataText.Length());
582 MaybeStopParser(rv);
584 mCDataText.Truncate();
586 return NS_OK;
589 nsresult
590 nsExpatDriver::HandleStartNamespaceDecl(const PRUnichar* aPrefix,
591 const PRUnichar* aUri)
593 if (mExtendedSink) {
594 nsresult rv = mExtendedSink->HandleStartNamespaceDecl(aPrefix, aUri);
595 MaybeStopParser(rv);
597 return NS_OK;
600 nsresult
601 nsExpatDriver::HandleEndNamespaceDecl(const PRUnichar* aPrefix)
603 if (mExtendedSink && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
604 nsresult rv = mExtendedSink->HandleEndNamespaceDecl(aPrefix);
605 MaybeStopParser(rv);
607 return NS_OK;
610 nsresult
611 nsExpatDriver::HandleNotationDecl(const PRUnichar* aNotationName,
612 const PRUnichar* aBase,
613 const PRUnichar* aSysid,
614 const PRUnichar* aPubid)
616 if (mExtendedSink) {
617 nsresult rv = mExtendedSink->HandleNotationDecl(aNotationName, aSysid,
618 aPubid);
619 MaybeStopParser(rv);
621 return NS_OK;
624 nsresult
625 nsExpatDriver::HandleUnparsedEntityDecl(const PRUnichar* aEntityName,
626 const PRUnichar* aBase,
627 const PRUnichar* aSysid,
628 const PRUnichar* aPubid,
629 const PRUnichar* aNotationName)
631 if (mExtendedSink) {
632 nsresult rv = mExtendedSink->HandleUnparsedEntityDecl(aEntityName,
633 aSysid,
634 aPubid,
635 aNotationName);
636 MaybeStopParser(rv);
638 return NS_OK;
641 nsresult
642 nsExpatDriver::HandleStartDoctypeDecl(const PRUnichar* aDoctypeName,
643 const PRUnichar* aSysid,
644 const PRUnichar* aPubid,
645 PRBool aHasInternalSubset)
647 mDoctypeName = aDoctypeName;
648 mSystemID = aSysid;
649 mPublicID = aPubid;
651 if (mExtendedSink) {
652 nsresult rv = mExtendedSink->HandleStartDTD(aDoctypeName, aSysid, aPubid);
653 MaybeStopParser(rv);
656 if (aHasInternalSubset) {
657 // Consuming a huge internal subset translates to numerous
658 // allocations. In an effort to avoid too many allocations
659 // setting mInternalSubset's capacity to be 1K ( just a guesstimate! ).
660 mInInternalSubset = PR_TRUE;
661 mInternalSubset.SetCapacity(1024);
662 } else {
663 // Distinguish missing internal subset from an empty one
664 mInternalSubset.SetIsVoid(PR_TRUE);
667 return NS_OK;
670 nsresult
671 nsExpatDriver::HandleEndDoctypeDecl()
673 NS_ASSERTION(mSink, "content sink not found!");
675 mInInternalSubset = PR_FALSE;
677 if (mSink) {
678 // let the sink know any additional knowledge that we have about the
679 // document (currently, from bug 124570, we only expect to pass additional
680 // agent sheets needed to layout the XML vocabulary of the document)
681 nsCOMPtr<nsIURI> data;
682 if (mCatalogData && mCatalogData->mAgentSheet) {
683 NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet);
686 // Note: mInternalSubset already doesn't include the [] around it.
687 nsresult rv = mSink->HandleDoctypeDecl(mInternalSubset, mDoctypeName,
688 mSystemID, mPublicID, data);
689 MaybeStopParser(rv);
692 mInternalSubset.SetCapacity(0);
694 return NS_OK;
697 static NS_METHOD
698 ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
699 void* aClosure,
700 const PRUnichar* aFromSegment,
701 PRUint32 aToOffset,
702 PRUint32 aCount,
703 PRUint32 *aWriteCount)
705 // Pass the buffer to expat for parsing.
706 if (XML_Parse((XML_Parser)aClosure, (const char *)aFromSegment,
707 aCount * sizeof(PRUnichar), 0) == XML_STATUS_OK) {
708 *aWriteCount = aCount;
710 return NS_OK;
713 *aWriteCount = 0;
715 return NS_ERROR_FAILURE;
719 nsExpatDriver::HandleExternalEntityRef(const PRUnichar *openEntityNames,
720 const PRUnichar *base,
721 const PRUnichar *systemId,
722 const PRUnichar *publicId)
724 if (mInInternalSubset && !mInExternalDTD && openEntityNames) {
725 mInternalSubset.Append(PRUnichar('%'));
726 mInternalSubset.Append(nsDependentString(openEntityNames));
727 mInternalSubset.Append(PRUnichar(';'));
730 // Load the external entity into a buffer.
731 nsCOMPtr<nsIInputStream> in;
732 nsAutoString absURL;
733 nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base,
734 getter_AddRefs(in), absURL);
735 NS_ENSURE_SUCCESS(rv, 1);
737 nsCOMPtr<nsIUnicharInputStream> uniIn;
738 rv = nsSimpleUnicharStreamFactory::GetInstance()->
739 CreateInstanceFromUTF8Stream(in, getter_AddRefs(uniIn));
740 NS_ENSURE_SUCCESS(rv, 1);
742 int result = 1;
743 if (uniIn) {
744 XML_Parser entParser = XML_ExternalEntityParserCreate(mExpatParser, 0,
745 kUTF16);
746 if (entParser) {
747 XML_SetBase(entParser, absURL.get());
749 mInExternalDTD = PR_TRUE;
751 PRUint32 totalRead;
752 do {
753 rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser,
754 PRUint32(-1), &totalRead);
755 } while (NS_SUCCEEDED(rv) && totalRead > 0);
757 result = XML_Parse(entParser, nsnull, 0, 1);
759 mInExternalDTD = PR_FALSE;
761 XML_ParserFree(entParser);
765 return result;
768 nsresult
769 nsExpatDriver::OpenInputStreamFromExternalDTD(const PRUnichar* aFPIStr,
770 const PRUnichar* aURLStr,
771 const PRUnichar* aBaseURL,
772 nsIInputStream** aStream,
773 nsAString& aAbsURL)
775 nsCOMPtr<nsIURI> baseURI;
776 nsresult rv = NS_NewURI(getter_AddRefs(baseURI),
777 NS_ConvertUTF16toUTF8(aBaseURL));
778 NS_ENSURE_SUCCESS(rv, rv);
780 nsCOMPtr<nsIURI> uri;
781 rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nsnull,
782 baseURI);
783 NS_ENSURE_SUCCESS(rv, rv);
785 // check if it is alright to load this uri
786 PRBool isChrome = PR_FALSE;
787 uri->SchemeIs("chrome", &isChrome);
788 if (!isChrome) {
789 // since the url is not a chrome url, check to see if we can map the DTD
790 // to a known local DTD, or if a DTD file of the same name exists in the
791 // special DTD directory
792 if (aFPIStr) {
793 // see if the Formal Public Identifier (FPI) maps to a catalog entry
794 mCatalogData = LookupCatalogData(aFPIStr);
797 nsCOMPtr<nsIURI> localURI;
798 if (!IsLoadableDTD(mCatalogData, uri, getter_AddRefs(localURI))) {
799 return NS_ERROR_NOT_IMPLEMENTED;
802 localURI.swap(uri);
805 nsCOMPtr<nsIContentSink> sink = do_QueryInterface(mSink);
806 nsCOMPtr<nsIDocument> doc;
807 if (sink)
808 doc = do_QueryInterface(sink->GetTarget());
809 PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
810 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_DTD,
811 uri,
812 (doc ? doc->NodePrincipal() : nsnull),
813 doc,
814 EmptyCString(), //mime guess
815 nsnull, //extra
816 &shouldLoad);
817 if (NS_FAILED(rv)) return rv;
818 if (NS_CP_REJECTED(shouldLoad)) {
819 // Disallowed by content policy
820 return NS_ERROR_CONTENT_BLOCKED;
823 rv = NS_OpenURI(aStream, uri);
825 nsCAutoString absURL;
826 uri->GetSpec(absURL);
828 CopyUTF8toUTF16(absURL, aAbsURL);
830 return rv;
833 static nsresult
834 CreateErrorText(const PRUnichar* aDescription,
835 const PRUnichar* aSourceURL,
836 const PRUint32 aLineNumber,
837 const PRUint32 aColNumber,
838 nsString& aErrorString)
840 aErrorString.Truncate();
842 nsAutoString msg;
843 nsresult rv =
844 nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
845 "XMLParsingError", msg);
846 NS_ENSURE_SUCCESS(rv, rv);
848 // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$u, Column %4$u:
849 PRUnichar *message = nsTextFormatter::smprintf(msg.get(), aDescription,
850 aSourceURL, aLineNumber,
851 aColNumber);
852 if (!message) {
853 return NS_ERROR_OUT_OF_MEMORY;
856 aErrorString.Assign(message);
857 nsTextFormatter::smprintf_free(message);
859 return NS_OK;
862 static nsresult
863 AppendErrorPointer(const PRInt32 aColNumber,
864 const PRUnichar *aSourceLine,
865 nsString& aSourceString)
867 aSourceString.Append(PRUnichar('\n'));
869 // Last character will be '^'.
870 PRInt32 last = aColNumber - 1;
871 PRInt32 i;
872 PRUint32 minuses = 0;
873 for (i = 0; i < last; ++i) {
874 if (aSourceLine[i] == '\t') {
875 // Since this uses |white-space: pre;| a tab stop equals 8 spaces.
876 PRUint32 add = 8 - (minuses % 8);
877 aSourceString.AppendASCII("--------", add);
878 minuses += add;
880 else {
881 aSourceString.Append(PRUnichar('-'));
882 ++minuses;
885 aSourceString.Append(PRUnichar('^'));
887 return NS_OK;
890 nsresult
891 nsExpatDriver::HandleError()
893 PRInt32 code = XML_GetErrorCode(mExpatParser);
894 NS_ASSERTION(code > XML_ERROR_NONE, "unexpected XML error code");
896 // Map Expat error code to an error string
897 // XXX Deal with error returns.
898 nsAutoString description;
899 nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code,
900 description);
902 if (code == XML_ERROR_TAG_MISMATCH) {
904 * Expat can send the following:
905 * localName
906 * namespaceURI<separator>localName
907 * namespaceURI<separator>localName<separator>prefix
909 * and we use 0xFFFF for the <separator>.
912 const PRUnichar *mismatch = MOZ_XML_GetMismatchedTag(mExpatParser);
913 const PRUnichar *uriEnd = nsnull;
914 const PRUnichar *nameEnd = nsnull;
915 const PRUnichar *pos;
916 for (pos = mismatch; *pos; ++pos) {
917 if (*pos == kExpatSeparatorChar) {
918 if (uriEnd) {
919 nameEnd = pos;
921 else {
922 uriEnd = pos;
927 nsAutoString tagName;
928 if (uriEnd && nameEnd) {
929 // We have a prefix.
930 tagName.Append(nameEnd + 1, pos - nameEnd - 1);
931 tagName.Append(PRUnichar(':'));
933 const PRUnichar *nameStart = uriEnd ? uriEnd + 1 : mismatch;
934 tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
936 nsAutoString msg;
937 nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES,
938 "Expected", msg);
940 // . Expected: </%S>.
941 PRUnichar *message = nsTextFormatter::smprintf(msg.get(), tagName.get());
942 if (!message) {
943 return NS_ERROR_OUT_OF_MEMORY;
946 description.Append(message);
948 nsTextFormatter::smprintf_free(message);
951 // Adjust the column number so that it is one based rather than zero based.
952 PRUint32 colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
953 PRUint32 lineNumber = XML_GetCurrentLineNumber(mExpatParser);
955 nsAutoString errorText;
956 CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
957 colNumber, errorText);
959 NS_ASSERTION(mSink, "no sink?");
961 nsAutoString sourceText(mLastLine);
962 AppendErrorPointer(colNumber, mLastLine.get(), sourceText);
964 // Try to create and initialize the script error.
965 nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
966 nsresult rv = NS_ERROR_FAILURE;
967 if (serr) {
968 rv = serr->Init(description.get(),
969 mURISpec.get(),
970 mLastLine.get(),
971 lineNumber, colNumber,
972 nsIScriptError::errorFlag, "malformed-xml");
975 // If it didn't initialize, we can't do any logging.
976 PRBool shouldReportError = NS_SUCCEEDED(rv);
978 if (mSink && shouldReportError) {
979 rv = mSink->ReportError(errorText.get(),
980 sourceText.get(),
981 serr,
982 &shouldReportError);
983 if (NS_FAILED(rv)) {
984 shouldReportError = PR_TRUE;
988 if (shouldReportError) {
989 nsCOMPtr<nsIConsoleService> cs
990 (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
991 if (cs) {
992 cs->LogMessage(serr);
996 return NS_ERROR_HTMLPARSER_STOPPARSING;
999 void
1000 nsExpatDriver::ParseBuffer(const PRUnichar *aBuffer,
1001 PRUint32 aLength,
1002 PRBool aIsFinal,
1003 PRUint32 *aConsumed)
1005 NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
1006 NS_ASSERTION(mInternalState != NS_OK || aIsFinal || aBuffer,
1007 "Useless call, we won't call Expat");
1008 NS_PRECONDITION(!BlockedOrInterrupted() || !aBuffer,
1009 "Non-null buffer when resuming");
1010 NS_PRECONDITION(XML_GetCurrentByteIndex(mExpatParser) % sizeof(PRUnichar) == 0,
1011 "Consumed part of a PRUnichar?");
1013 if (mExpatParser && (mInternalState == NS_OK || BlockedOrInterrupted())) {
1014 PRInt32 parserBytesBefore = XML_GetCurrentByteIndex(mExpatParser);
1015 NS_ASSERTION(parserBytesBefore >= 0, "Unexpected value");
1017 XML_Status status;
1018 if (BlockedOrInterrupted()) {
1019 mInternalState = NS_OK; // Resume in case we're blocked.
1020 status = XML_ResumeParser(mExpatParser);
1022 else {
1023 status = XML_Parse(mExpatParser,
1024 reinterpret_cast<const char*>(aBuffer),
1025 aLength * sizeof(PRUnichar), aIsFinal);
1028 PRInt32 parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser);
1030 NS_ASSERTION(parserBytesConsumed >= 0, "Unexpected value");
1031 NS_ASSERTION(parserBytesConsumed >= parserBytesBefore,
1032 "How'd this happen?");
1033 NS_ASSERTION(parserBytesConsumed % sizeof(PRUnichar) == 0,
1034 "Consumed part of a PRUnichar?");
1036 // Consumed something.
1037 *aConsumed = (parserBytesConsumed - parserBytesBefore) / sizeof(PRUnichar);
1038 NS_ASSERTION(*aConsumed <= aLength + mExpatBuffered,
1039 "Too many bytes consumed?");
1041 NS_ASSERTION(status != XML_STATUS_SUSPENDED || BlockedOrInterrupted(),
1042 "Inconsistent expat suspension state.");
1044 if (status == XML_STATUS_ERROR) {
1045 mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
1048 else {
1049 *aConsumed = 0;
1053 NS_IMETHODIMP
1054 nsExpatDriver::ConsumeToken(nsScanner& aScanner, PRBool& aFlushTokens)
1056 // We keep the scanner pointing to the position where Expat will start
1057 // parsing.
1058 nsScannerIterator currentExpatPosition;
1059 aScanner.CurrentPosition(currentExpatPosition);
1061 // This is the start of the first buffer that we need to pass to Expat.
1062 nsScannerIterator start = currentExpatPosition;
1063 start.advance(mExpatBuffered);
1065 // This is the end of the last buffer (at this point, more data could come in
1066 // later).
1067 nsScannerIterator end;
1068 aScanner.EndReading(end);
1070 PR_LOG(gExpatDriverLog, PR_LOG_DEBUG,
1071 ("Remaining in expat's buffer: %i, remaining in scanner: %i.",
1072 mExpatBuffered, Distance(start, end)));
1074 PRBool flush = mIsFinalChunk;
1076 // We want to call Expat if we have more buffers, or if we know there won't
1077 // be more buffers (and so we want to flush the remaining data), or if we're
1078 // currently blocked and there's data in Expat's buffer.
1079 while (start != end || flush ||
1080 (BlockedOrInterrupted() && mExpatBuffered > 0)) {
1081 PRBool noMoreBuffers = start == end && mIsFinalChunk;
1082 PRBool blocked = BlockedOrInterrupted();
1084 // If we're resuming and we know there won't be more data we want to
1085 // flush the remaining data after we resumed the parser (so loop once
1086 // more).
1087 flush = blocked && noMoreBuffers;
1089 const PRUnichar *buffer;
1090 PRUint32 length;
1091 if (blocked || noMoreBuffers) {
1092 // If we're blocked we just resume Expat so we don't need a buffer, if
1093 // there aren't any more buffers we pass a null buffer to Expat.
1094 buffer = nsnull;
1095 length = 0;
1097 if (blocked) {
1098 PR_LOG(gExpatDriverLog, PR_LOG_DEBUG,
1099 ("Resuming Expat, will parse data remaining in Expat's "
1100 "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
1101 NS_ConvertUTF16toUTF8(currentExpatPosition.get(),
1102 mExpatBuffered).get()));
1104 else {
1105 NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end),
1106 "Didn't pass all the data to Expat?");
1107 PR_LOG(gExpatDriverLog, PR_LOG_DEBUG,
1108 ("Last call to Expat, will parse data remaining in Expat's "
1109 "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
1110 NS_ConvertUTF16toUTF8(currentExpatPosition.get(),
1111 mExpatBuffered).get()));
1114 else {
1115 buffer = start.get();
1116 length = PRUint32(start.size_forward());
1118 PR_LOG(gExpatDriverLog, PR_LOG_DEBUG,
1119 ("Calling Expat, will parse data remaining in Expat's buffer and "
1120 "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew "
1121 "data:\n-----\n%s\n-----\n",
1122 NS_ConvertUTF16toUTF8(currentExpatPosition.get(),
1123 mExpatBuffered).get(),
1124 NS_ConvertUTF16toUTF8(start.get(), length).get()));
1127 PRUint32 consumed;
1128 ParseBuffer(buffer, length, noMoreBuffers, &consumed);
1129 if (consumed > 0) {
1130 nsScannerIterator oldExpatPosition = currentExpatPosition;
1131 currentExpatPosition.advance(consumed);
1133 // We consumed some data, we want to store the last line of data that
1134 // was consumed in case we run into an error (to show the line in which
1135 // the error occurred).
1137 // The length of the last line that Expat has parsed.
1138 XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser);
1140 if (lastLineLength <= consumed) {
1141 // The length of the last line was less than what expat consumed, so
1142 // there was at least one line break in the consumed data. Store the
1143 // last line until the point where we stopped parsing.
1144 nsScannerIterator startLastLine = currentExpatPosition;
1145 startLastLine.advance(-((ptrdiff_t)lastLineLength));
1146 CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine);
1148 else {
1149 // There was no line break in the consumed data, append the consumed
1150 // data.
1151 AppendUnicodeTo(oldExpatPosition, currentExpatPosition, mLastLine);
1155 mExpatBuffered += length - consumed;
1157 if (BlockedOrInterrupted()) {
1158 PR_LOG(gExpatDriverLog, PR_LOG_DEBUG,
1159 ("Blocked or interrupted parser (probably for loading linked "
1160 "stylesheets or scripts)."));
1162 aScanner.SetPosition(currentExpatPosition, PR_TRUE);
1163 aScanner.Mark();
1165 return mInternalState;
1168 if (NS_FAILED(mInternalState)) {
1169 if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) {
1170 NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING,
1171 "Unexpected error");
1173 // Look for the next newline after the last one we consumed
1174 nsScannerIterator lastLine = currentExpatPosition;
1175 while (lastLine != end) {
1176 length = PRUint32(lastLine.size_forward());
1177 PRUint32 endOffset = 0;
1178 const PRUnichar *buffer = lastLine.get();
1179 while (endOffset < length && buffer[endOffset] != '\n' &&
1180 buffer[endOffset] != '\r') {
1181 ++endOffset;
1183 mLastLine.Append(Substring(buffer, buffer + endOffset));
1184 if (endOffset < length) {
1185 // We found a newline.
1186 break;
1189 lastLine.advance(length);
1192 HandleError();
1195 return mInternalState;
1198 // Either we have more buffers, or we were blocked (and we'll flush in the
1199 // next iteration), or we should have emptied Expat's buffer.
1200 NS_ASSERTION(!noMoreBuffers || blocked ||
1201 (mExpatBuffered == 0 && currentExpatPosition == end),
1202 "Unreachable data left in Expat's buffer");
1204 start.advance(length);
1207 aScanner.SetPosition(currentExpatPosition, PR_TRUE);
1208 aScanner.Mark();
1210 PR_LOG(gExpatDriverLog, PR_LOG_DEBUG,
1211 ("Remaining in expat's buffer: %i, remaining in scanner: %i.",
1212 mExpatBuffered, Distance(currentExpatPosition, end)));
1214 return NS_SUCCEEDED(mInternalState) ? kEOF : NS_OK;
1217 NS_IMETHODIMP
1218 nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
1219 nsITokenizer* aTokenizer,
1220 nsIContentSink* aSink)
1222 mSink = do_QueryInterface(aSink);
1223 if (!mSink) {
1224 NS_ERROR("nsExpatDriver didn't get an nsIExpatSink");
1225 // Make sure future calls to us bail out as needed
1226 mInternalState = NS_ERROR_UNEXPECTED;
1227 return mInternalState;
1230 static const XML_Memory_Handling_Suite memsuite =
1232 (void *(*)(size_t))PR_Malloc,
1233 (void *(*)(void *, size_t))PR_Realloc,
1234 PR_Free
1237 static const PRUnichar kExpatSeparator[] = { kExpatSeparatorChar, '\0' };
1239 mExpatParser = XML_ParserCreate_MM(kUTF16, &memsuite, kExpatSeparator);
1240 NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
1242 XML_SetReturnNSTriplet(mExpatParser, XML_TRUE);
1244 #ifdef XML_DTD
1245 XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1246 #endif
1248 mURISpec = aParserContext.mScanner->GetFilename();
1250 XML_SetBase(mExpatParser, mURISpec.get());
1252 // Set up the callbacks
1253 XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration);
1254 XML_SetElementHandler(mExpatParser, Driver_HandleStartElement,
1255 Driver_HandleEndElement);
1256 XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
1257 XML_SetProcessingInstructionHandler(mExpatParser,
1258 Driver_HandleProcessingInstruction);
1259 XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
1260 XML_SetExternalEntityRefHandler(mExpatParser,
1261 (XML_ExternalEntityRefHandler)
1262 Driver_HandleExternalEntityRef);
1263 XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
1264 XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
1265 XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
1266 Driver_HandleEndCdataSection);
1268 XML_SetParamEntityParsing(mExpatParser,
1269 XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
1270 XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
1271 Driver_HandleEndDoctypeDecl);
1273 // If the sink is an nsIExtendedExpatSink,
1274 // register some addtional handlers.
1275 mExtendedSink = do_QueryInterface(mSink);
1276 if (mExtendedSink) {
1277 XML_SetNamespaceDeclHandler(mExpatParser,
1278 Driver_HandleStartNamespaceDecl,
1279 Driver_HandleEndNamespaceDecl);
1280 XML_SetUnparsedEntityDeclHandler(mExpatParser,
1281 Driver_HandleUnparsedEntityDecl);
1282 XML_SetNotationDeclHandler(mExpatParser,
1283 Driver_HandleNotationDecl);
1286 // Set up the user data.
1287 XML_SetUserData(mExpatParser, this);
1289 return aSink->WillBuildModel();
1292 NS_IMETHODIMP
1293 nsExpatDriver::BuildModel(nsIParser* aParser,
1294 nsITokenizer* aTokenizer,
1295 nsITokenObserver* anObserver,
1296 nsIContentSink* aSink)
1298 return mInternalState;
1301 NS_IMETHODIMP
1302 nsExpatDriver::DidBuildModel(nsresult anErrorCode,
1303 PRBool aNotifySink,
1304 nsIParser* aParser,
1305 nsIContentSink* aSink)
1307 // Check for mSink is intentional. This would make sure
1308 // that DidBuildModel() is called only once on the sink.
1309 nsresult result = NS_OK;
1310 if (mSink) {
1311 result = aSink->DidBuildModel();
1312 mSink = nsnull;
1315 mExtendedSink = nsnull;
1317 return result;
1320 NS_IMETHODIMP
1321 nsExpatDriver::WillTokenize(PRBool aIsFinalChunk,
1322 nsTokenAllocator* aTokenAllocator)
1324 mIsFinalChunk = aIsFinalChunk;
1325 return NS_OK;
1328 NS_IMETHODIMP
1329 nsExpatDriver::WillResumeParse(nsIContentSink* aSink)
1331 return aSink ? aSink->WillResume() : NS_OK;
1334 NS_IMETHODIMP
1335 nsExpatDriver::WillInterruptParse(nsIContentSink* aSink)
1337 return aSink ? aSink->WillInterrupt() : NS_OK;
1340 NS_IMETHODIMP
1341 nsExpatDriver::DidTokenize(PRBool aIsFinalChunk)
1343 return NS_OK;
1346 NS_IMETHODIMP_(void)
1347 nsExpatDriver::Terminate()
1349 // XXX - not sure what happens to the unparsed data.
1350 if (mExpatParser) {
1351 XML_StopParser(mExpatParser, XML_FALSE);
1353 mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
1356 NS_IMETHODIMP_(PRInt32)
1357 nsExpatDriver::GetType()
1359 return NS_IPARSER_FLAG_XML;
1362 /*************************** Unused methods **********************************/
1364 NS_IMETHODIMP_(CToken*)
1365 nsExpatDriver::PushTokenFront(CToken* aToken)
1367 return 0;
1370 NS_IMETHODIMP_(CToken*)
1371 nsExpatDriver::PushToken(CToken* aToken)
1373 return 0;
1376 NS_IMETHODIMP_(CToken*)
1377 nsExpatDriver::PopToken(void)
1379 return 0;
1382 NS_IMETHODIMP_(CToken*)
1383 nsExpatDriver::PeekToken(void)
1385 return 0;
1388 NS_IMETHODIMP_(CToken*)
1389 nsExpatDriver::GetTokenAt(PRInt32 anIndex)
1391 return 0;
1394 NS_IMETHODIMP_(PRInt32)
1395 nsExpatDriver::GetCount(void)
1397 return 0;
1400 NS_IMETHODIMP_(nsTokenAllocator*)
1401 nsExpatDriver::GetTokenAllocator(void)
1403 return 0;
1406 NS_IMETHODIMP_(void)
1407 nsExpatDriver::PrependTokens(nsDeque& aDeque)
1411 NS_IMETHODIMP
1412 nsExpatDriver::CopyState(nsITokenizer* aTokenizer)
1414 return NS_OK;
1417 NS_IMETHODIMP
1418 nsExpatDriver::HandleToken(CToken* aToken,nsIParser* aParser)
1420 return NS_OK;
1423 NS_IMETHODIMP_(PRBool)
1424 nsExpatDriver::IsContainer(PRInt32 aTag) const
1426 return PR_TRUE;
1429 NS_IMETHODIMP_(PRBool)
1430 nsExpatDriver::CanContain(PRInt32 aParent,PRInt32 aChild) const
1432 return PR_TRUE;
1435 void
1436 nsExpatDriver::MaybeStopParser(nsresult aState)
1438 if (NS_FAILED(aState)) {
1439 // If we had a failure we want to override NS_ERROR_HTMLPARSER_INTERRUPTED
1440 // and we want to override NS_ERROR_HTMLPARSER_BLOCK but not with
1441 // NS_ERROR_HTMLPARSER_INTERRUPTED.
1442 if (NS_SUCCEEDED(mInternalState) ||
1443 mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
1444 (mInternalState == NS_ERROR_HTMLPARSER_BLOCK &&
1445 aState != NS_ERROR_HTMLPARSER_INTERRUPTED)) {
1446 mInternalState = aState;
1449 // If we get an error then we need to stop Expat (by calling XML_StopParser
1450 // with PR_FALSE as the last argument). If the parser should be blocked or
1451 // interrupted we need to pause Expat (by calling XML_StopParser with
1452 // PR_TRUE as the last argument).
1453 XML_StopParser(mExpatParser, BlockedOrInterrupted());
1455 else if (NS_SUCCEEDED(mInternalState)) {
1456 // Only clobber mInternalState with the success code if we didn't block or
1457 // interrupt before.
1458 mInternalState = aState;