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 : * Steve Swanson <steve.swanson@mackichan.com>
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Blake Kaplan <mrbkap@gmail.com>
24 : * Robert Sayre <sayrer@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 : #include "nsCOMPtr.h"
40 : #include "nsXMLContentSink.h"
41 : #include "nsIFragmentContentSink.h"
42 : #include "nsIXMLContentSink.h"
43 : #include "nsContentSink.h"
44 : #include "nsIExpatSink.h"
45 : #include "nsIDTD.h"
46 : #include "nsIParser.h"
47 : #include "nsIDocument.h"
48 : #include "nsIDOMDocumentFragment.h"
49 : #include "nsIContent.h"
50 : #include "nsGkAtoms.h"
51 : #include "nsINodeInfo.h"
52 : #include "nsNodeInfoManager.h"
53 : #include "nsNullPrincipal.h"
54 : #include "nsContentCreatorFunctions.h"
55 : #include "nsDOMError.h"
56 : #include "nsIConsoleService.h"
57 : #include "nsIScriptError.h"
58 : #include "nsServiceManagerUtils.h"
59 : #include "nsContentUtils.h"
60 : #include "nsIScriptSecurityManager.h"
61 : #include "nsNetUtil.h"
62 : #include "nsTHashtable.h"
63 : #include "nsHashKeys.h"
64 : #include "nsTArray.h"
65 : #include "nsCycleCollectionParticipant.h"
66 : #include "nsIDocShell.h"
67 : #include "nsScriptLoader.h"
68 : #include "mozilla/css/Loader.h"
69 :
70 : using namespace mozilla::dom;
71 :
72 : class nsXMLFragmentContentSink : public nsXMLContentSink,
73 : public nsIFragmentContentSink
74 : {
75 : public:
76 : nsXMLFragmentContentSink();
77 : virtual ~nsXMLFragmentContentSink();
78 :
79 4 : NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
80 :
81 : // nsISupports
82 : NS_DECL_ISUPPORTS_INHERITED
83 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXMLFragmentContentSink,
84 : nsXMLContentSink)
85 :
86 : // nsIExpatSink
87 : NS_IMETHOD HandleDoctypeDecl(const nsAString & aSubset,
88 : const nsAString & aName,
89 : const nsAString & aSystemId,
90 : const nsAString & aPublicId,
91 : nsISupports* aCatalogData);
92 : NS_IMETHOD HandleProcessingInstruction(const PRUnichar *aTarget,
93 : const PRUnichar *aData);
94 : NS_IMETHOD HandleXMLDeclaration(const PRUnichar *aVersion,
95 : const PRUnichar *aEncoding,
96 : PRInt32 aStandalone);
97 : NS_IMETHOD ReportError(const PRUnichar* aErrorText,
98 : const PRUnichar* aSourceText,
99 : nsIScriptError *aError,
100 : bool *_retval);
101 :
102 : // nsIContentSink
103 : NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
104 : NS_IMETHOD DidBuildModel(bool aTerminated);
105 : NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
106 : virtual nsISupports *GetTarget();
107 : NS_IMETHOD DidProcessATokenImpl();
108 :
109 : // nsIXMLContentSink
110 :
111 : // nsIFragmentContentSink
112 : NS_IMETHOD FinishFragmentParsing(nsIDOMDocumentFragment** aFragment);
113 : NS_IMETHOD SetTargetDocument(nsIDocument* aDocument);
114 : NS_IMETHOD WillBuildContent();
115 : NS_IMETHOD DidBuildContent();
116 : NS_IMETHOD IgnoreFirstContainer();
117 : NS_IMETHOD SetPreventScriptExecution(bool aPreventScriptExecution);
118 :
119 : protected:
120 : virtual bool SetDocElement(PRInt32 aNameSpaceID,
121 : nsIAtom *aTagName,
122 : nsIContent *aContent);
123 : virtual nsresult CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
124 : nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
125 : nsIContent** aResult, bool* aAppendContent,
126 : mozilla::dom::FromParser aFromParser);
127 : virtual nsresult CloseElement(nsIContent* aContent);
128 :
129 : virtual void MaybeStartLayout(bool aIgnorePendingSheets);
130 :
131 : // nsContentSink overrides
132 : virtual nsresult ProcessStyleLink(nsIContent* aElement,
133 : const nsSubstring& aHref,
134 : bool aAlternate,
135 : const nsSubstring& aTitle,
136 : const nsSubstring& aType,
137 : const nsSubstring& aMedia);
138 : nsresult LoadXSLStyleSheet(nsIURI* aUrl);
139 : void StartLayout();
140 :
141 : nsCOMPtr<nsIDocument> mTargetDocument;
142 : // the fragment
143 : nsCOMPtr<nsIContent> mRoot;
144 : bool mParseError;
145 : };
146 :
147 : static nsresult
148 1 : NewXMLFragmentContentSinkHelper(nsIFragmentContentSink** aResult)
149 : {
150 1 : nsXMLFragmentContentSink* it = new nsXMLFragmentContentSink();
151 1 : if (!it) {
152 0 : return NS_ERROR_OUT_OF_MEMORY;
153 : }
154 :
155 1 : NS_ADDREF(*aResult = it);
156 :
157 1 : return NS_OK;
158 : }
159 :
160 : nsresult
161 1 : NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aResult)
162 : {
163 1 : return NewXMLFragmentContentSinkHelper(aResult);
164 : }
165 :
166 1 : nsXMLFragmentContentSink::nsXMLFragmentContentSink()
167 1 : : mParseError(false)
168 : {
169 1 : mRunsToCompletion = true;
170 1 : }
171 :
172 2 : nsXMLFragmentContentSink::~nsXMLFragmentContentSink()
173 : {
174 2 : }
175 :
176 10 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLFragmentContentSink)
177 7 : NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink)
178 6 : NS_INTERFACE_MAP_END_INHERITING(nsXMLContentSink)
179 :
180 8 : NS_IMPL_ADDREF_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink)
181 8 : NS_IMPL_RELEASE_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink)
182 :
183 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLFragmentContentSink)
184 :
185 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLFragmentContentSink,
186 : nsXMLContentSink)
187 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTargetDocument)
188 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
189 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
190 :
191 : NS_IMETHODIMP
192 1 : nsXMLFragmentContentSink::WillBuildModel(nsDTDMode aDTDMode)
193 : {
194 1 : if (mRoot) {
195 0 : return NS_OK;
196 : }
197 :
198 1 : mState = eXMLContentSinkState_InDocumentElement;
199 :
200 1 : NS_ASSERTION(mTargetDocument, "Need a document!");
201 :
202 2 : nsCOMPtr<nsIDOMDocumentFragment> frag;
203 1 : nsresult rv = NS_NewDocumentFragment(getter_AddRefs(frag), mNodeInfoManager);
204 1 : NS_ENSURE_SUCCESS(rv, rv);
205 :
206 1 : mRoot = do_QueryInterface(frag);
207 :
208 1 : return rv;
209 : }
210 :
211 : NS_IMETHODIMP
212 1 : nsXMLFragmentContentSink::DidBuildModel(bool aTerminated)
213 : {
214 2 : nsRefPtr<nsParserBase> kungFuDeathGrip(mParser);
215 :
216 : // Drop our reference to the parser to get rid of a circular
217 : // reference.
218 1 : mParser = nsnull;
219 :
220 1 : return NS_OK;
221 : }
222 :
223 : NS_IMETHODIMP
224 0 : nsXMLFragmentContentSink::SetDocumentCharset(nsACString& aCharset)
225 : {
226 0 : NS_NOTREACHED("fragments shouldn't set charset");
227 0 : return NS_OK;
228 : }
229 :
230 : nsISupports *
231 1 : nsXMLFragmentContentSink::GetTarget()
232 : {
233 1 : return mTargetDocument;
234 : }
235 :
236 : ////////////////////////////////////////////////////////////////////////
237 :
238 : bool
239 2 : nsXMLFragmentContentSink::SetDocElement(PRInt32 aNameSpaceID,
240 : nsIAtom* aTagName,
241 : nsIContent *aContent)
242 : {
243 : // this is a fragment, not a document
244 2 : return false;
245 : }
246 :
247 : nsresult
248 2 : nsXMLFragmentContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
249 : nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
250 : nsIContent** aResult, bool* aAppendContent,
251 : FromParser /*aFromParser*/)
252 : {
253 : // Claim to not be coming from parser, since we don't do any of the
254 : // fancy CloseElement stuff.
255 : nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount,
256 : aNodeInfo, aLineNumber,
257 : aResult, aAppendContent,
258 2 : NOT_FROM_PARSER);
259 :
260 : // When we aren't grabbing all of the content we, never open a doc
261 : // element, we run into trouble on the first element, so we don't append,
262 : // and simply push this onto the content stack.
263 2 : if (mContentStack.Length() == 0) {
264 1 : *aAppendContent = false;
265 : }
266 :
267 2 : return rv;
268 : }
269 :
270 : nsresult
271 2 : nsXMLFragmentContentSink::CloseElement(nsIContent* aContent)
272 : {
273 : // don't do fancy stuff in nsXMLContentSink
274 2 : if (mPreventScriptExecution && aContent->Tag() == nsGkAtoms::script &&
275 0 : (aContent->IsHTML() || aContent->IsSVG())) {
276 0 : nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
277 0 : NS_ASSERTION(sele, "script did QI correctly!");
278 0 : sele->PreventExecution();
279 : }
280 2 : return NS_OK;
281 : }
282 :
283 : void
284 2 : nsXMLFragmentContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
285 : {
286 : return;
287 : }
288 :
289 : ////////////////////////////////////////////////////////////////////////
290 :
291 : NS_IMETHODIMP
292 0 : nsXMLFragmentContentSink::HandleDoctypeDecl(const nsAString & aSubset,
293 : const nsAString & aName,
294 : const nsAString & aSystemId,
295 : const nsAString & aPublicId,
296 : nsISupports* aCatalogData)
297 : {
298 0 : NS_NOTREACHED("fragments shouldn't have doctype declarations");
299 :
300 0 : return NS_OK;
301 : }
302 :
303 : NS_IMETHODIMP
304 0 : nsXMLFragmentContentSink::HandleProcessingInstruction(const PRUnichar *aTarget,
305 : const PRUnichar *aData)
306 : {
307 0 : FlushText();
308 :
309 0 : nsresult result = NS_OK;
310 0 : const nsDependentString target(aTarget);
311 0 : const nsDependentString data(aData);
312 :
313 0 : nsCOMPtr<nsIContent> node;
314 :
315 0 : result = NS_NewXMLProcessingInstruction(getter_AddRefs(node),
316 0 : mNodeInfoManager, target, data);
317 0 : if (NS_SUCCEEDED(result)) {
318 : // no special processing here. that should happen when the fragment moves into the document
319 0 : result = AddContentAsLeaf(node);
320 : }
321 0 : return result;
322 : }
323 :
324 : NS_IMETHODIMP
325 0 : nsXMLFragmentContentSink::HandleXMLDeclaration(const PRUnichar *aVersion,
326 : const PRUnichar *aEncoding,
327 : PRInt32 aStandalone)
328 : {
329 0 : NS_NOTREACHED("fragments shouldn't have XML declarations");
330 0 : return NS_OK;
331 : }
332 :
333 : NS_IMETHODIMP
334 0 : nsXMLFragmentContentSink::ReportError(const PRUnichar* aErrorText,
335 : const PRUnichar* aSourceText,
336 : nsIScriptError *aError,
337 : bool *_retval)
338 : {
339 0 : NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
340 :
341 : // The expat driver should report the error.
342 0 : *_retval = true;
343 :
344 0 : mParseError = true;
345 :
346 : #ifdef DEBUG
347 : // Report the error to stderr.
348 : fprintf(stderr,
349 : "\n%s\n%s\n\n",
350 0 : NS_LossyConvertUTF16toASCII(aErrorText).get(),
351 0 : NS_LossyConvertUTF16toASCII(aSourceText).get());
352 : #endif
353 :
354 : // The following code is similar to the cleanup in nsXMLContentSink::ReportError()
355 0 : mState = eXMLContentSinkState_InProlog;
356 :
357 : // Clear the current content
358 0 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mRoot));
359 0 : if (node) {
360 0 : for (;;) {
361 0 : nsCOMPtr<nsIDOMNode> child, dummy;
362 0 : node->GetLastChild(getter_AddRefs(child));
363 0 : if (!child)
364 : break;
365 0 : node->RemoveChild(child, getter_AddRefs(dummy));
366 : }
367 : }
368 :
369 : // Clear any buffered-up text we have. It's enough to set the length to 0.
370 : // The buffer itself is allocated when we're created and deleted in our
371 : // destructor, so don't mess with it.
372 0 : mTextLength = 0;
373 :
374 0 : return NS_OK;
375 : }
376 :
377 : nsresult
378 0 : nsXMLFragmentContentSink::ProcessStyleLink(nsIContent* aElement,
379 : const nsSubstring& aHref,
380 : bool aAlternate,
381 : const nsSubstring& aTitle,
382 : const nsSubstring& aType,
383 : const nsSubstring& aMedia)
384 : {
385 : // don't process until moved to document
386 0 : return NS_OK;
387 : }
388 :
389 : nsresult
390 0 : nsXMLFragmentContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
391 : {
392 0 : NS_NOTREACHED("fragments shouldn't have XSL style sheets");
393 0 : return NS_ERROR_UNEXPECTED;
394 : }
395 :
396 : void
397 0 : nsXMLFragmentContentSink::StartLayout()
398 : {
399 0 : NS_NOTREACHED("fragments shouldn't layout");
400 0 : }
401 :
402 : ////////////////////////////////////////////////////////////////////////
403 :
404 : NS_IMETHODIMP
405 1 : nsXMLFragmentContentSink::FinishFragmentParsing(nsIDOMDocumentFragment** aFragment)
406 : {
407 1 : *aFragment = nsnull;
408 1 : mTargetDocument = nsnull;
409 1 : mNodeInfoManager = nsnull;
410 1 : mScriptLoader = nsnull;
411 1 : mCSSLoader = nsnull;
412 1 : mContentStack.Clear();
413 1 : mDocumentURI = nsnull;
414 1 : mDocShell = nsnull;
415 1 : if (mParseError) {
416 : //XXX PARSE_ERR from DOM3 Load and Save would be more appropriate
417 0 : mRoot = nsnull;
418 0 : mParseError = false;
419 0 : return NS_ERROR_DOM_SYNTAX_ERR;
420 1 : } else if (mRoot) {
421 1 : nsresult rv = CallQueryInterface(mRoot, aFragment);
422 1 : mRoot = nsnull;
423 1 : return rv;
424 : } else {
425 0 : return NS_OK;
426 : }
427 : }
428 :
429 : NS_IMETHODIMP
430 1 : nsXMLFragmentContentSink::SetTargetDocument(nsIDocument* aTargetDocument)
431 : {
432 1 : NS_ENSURE_ARG_POINTER(aTargetDocument);
433 :
434 1 : mTargetDocument = aTargetDocument;
435 1 : mNodeInfoManager = aTargetDocument->NodeInfoManager();
436 :
437 1 : return NS_OK;
438 : }
439 :
440 : NS_IMETHODIMP
441 1 : nsXMLFragmentContentSink::WillBuildContent()
442 : {
443 1 : PushContent(mRoot);
444 :
445 1 : return NS_OK;
446 : }
447 :
448 : NS_IMETHODIMP
449 1 : nsXMLFragmentContentSink::DidBuildContent()
450 : {
451 : // Note: we need to FlushText() here because if we don't, we might not get
452 : // an end element to do it for us, so make sure.
453 1 : if (!mParseError) {
454 1 : FlushText();
455 : }
456 1 : PopContent();
457 :
458 1 : return NS_OK;
459 : }
460 :
461 : NS_IMETHODIMP
462 0 : nsXMLFragmentContentSink::DidProcessATokenImpl()
463 : {
464 0 : return NS_OK;
465 : }
466 :
467 : NS_IMETHODIMP
468 0 : nsXMLFragmentContentSink::IgnoreFirstContainer()
469 : {
470 0 : NS_NOTREACHED("XML isn't as broken as HTML");
471 0 : return NS_ERROR_FAILURE;
472 : }
473 :
474 : NS_IMETHODIMP
475 1 : nsXMLFragmentContentSink::SetPreventScriptExecution(bool aPrevent)
476 : {
477 1 : mPreventScriptExecution = aPrevent;
478 1 : return NS_OK;
479 4392 : }
|