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