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