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