1 /* -*- Mode: C++; tab-width: 4; 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 "txMozillaXSLTProcessor.h"
7 #include "nsContentCID.h"
8 #include "nsError.h"
9 #include "mozilla/dom/Element.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsIStringBundle.h"
12 #include "nsIURI.h"
13 #include "nsMemory.h"
14 #include "XPathResult.h"
15 #include "txExecutionState.h"
16 #include "txMozillaTextOutput.h"
17 #include "txMozillaXMLOutput.h"
18 #include "txURIUtils.h"
19 #include "txXMLUtils.h"
20 #include "txUnknownHandler.h"
21 #include "txXSLTProcessor.h"
22 #include "nsIPrincipal.h"
23 #include "nsThreadUtils.h"
24 #include "jsapi.h"
25 #include "txExprParser.h"
26 #include "nsErrorService.h"
27 #include "nsJSUtils.h"
28 #include "nsIXPConnect.h"
29 #include "nsVariant.h"
30 #include "nsTextNode.h"
31 #include "mozilla/Components.h"
32 #include "mozilla/dom/DocumentFragment.h"
33 #include "mozilla/dom/XSLTProcessorBinding.h"
34 
35 using namespace mozilla;
36 using namespace mozilla::dom;
37 
38 /**
39  * Output Handler Factories
40  */
41 class txToDocHandlerFactory : public txAOutputHandlerFactory {
42  public:
txToDocHandlerFactory(txExecutionState * aEs,Document * aSourceDocument,nsITransformObserver * aObserver,bool aDocumentIsData)43   txToDocHandlerFactory(txExecutionState* aEs, Document* aSourceDocument,
44                         nsITransformObserver* aObserver, bool aDocumentIsData)
45       : mEs(aEs),
46         mSourceDocument(aSourceDocument),
47         mObserver(aObserver),
48         mDocumentIsData(aDocumentIsData) {}
49 
50   TX_DECL_TXAOUTPUTHANDLERFACTORY
51 
52  private:
53   txExecutionState* mEs;
54   nsCOMPtr<Document> mSourceDocument;
55   nsCOMPtr<nsITransformObserver> mObserver;
56   bool mDocumentIsData;
57 };
58 
59 class txToFragmentHandlerFactory : public txAOutputHandlerFactory {
60  public:
txToFragmentHandlerFactory(DocumentFragment * aFragment)61   explicit txToFragmentHandlerFactory(DocumentFragment* aFragment)
62       : mFragment(aFragment) {}
63 
64   TX_DECL_TXAOUTPUTHANDLERFACTORY
65 
66  private:
67   RefPtr<DocumentFragment> mFragment;
68 };
69 
createHandlerWith(txOutputFormat * aFormat,txAXMLEventHandler ** aHandler)70 nsresult txToDocHandlerFactory::createHandlerWith(
71     txOutputFormat* aFormat, txAXMLEventHandler** aHandler) {
72   *aHandler = nullptr;
73   switch (aFormat->mMethod) {
74     case eMethodNotSet:
75     case eXMLOutput: {
76       *aHandler = new txUnknownHandler(mEs);
77       return NS_OK;
78     }
79 
80     case eHTMLOutput: {
81       UniquePtr<txMozillaXMLOutput> handler(
82           new txMozillaXMLOutput(aFormat, mObserver));
83 
84       nsresult rv = handler->createResultDocument(
85           u""_ns, kNameSpaceID_None, mSourceDocument, mDocumentIsData);
86       if (NS_SUCCEEDED(rv)) {
87         *aHandler = handler.release();
88       }
89 
90       return rv;
91     }
92 
93     case eTextOutput: {
94       UniquePtr<txMozillaTextOutput> handler(
95           new txMozillaTextOutput(mObserver));
96 
97       nsresult rv =
98           handler->createResultDocument(mSourceDocument, mDocumentIsData);
99       if (NS_SUCCEEDED(rv)) {
100         *aHandler = handler.release();
101       }
102 
103       return rv;
104     }
105   }
106 
107   MOZ_CRASH("Unknown output method");
108 
109   return NS_ERROR_FAILURE;
110 }
111 
createHandlerWith(txOutputFormat * aFormat,const nsAString & aName,int32_t aNsID,txAXMLEventHandler ** aHandler)112 nsresult txToDocHandlerFactory::createHandlerWith(
113     txOutputFormat* aFormat, const nsAString& aName, int32_t aNsID,
114     txAXMLEventHandler** aHandler) {
115   *aHandler = nullptr;
116   switch (aFormat->mMethod) {
117     case eMethodNotSet: {
118       NS_ERROR("How can method not be known when root element is?");
119       return NS_ERROR_UNEXPECTED;
120     }
121 
122     case eXMLOutput:
123     case eHTMLOutput: {
124       UniquePtr<txMozillaXMLOutput> handler(
125           new txMozillaXMLOutput(aFormat, mObserver));
126 
127       nsresult rv = handler->createResultDocument(aName, aNsID, mSourceDocument,
128                                                   mDocumentIsData);
129       if (NS_SUCCEEDED(rv)) {
130         *aHandler = handler.release();
131       }
132 
133       return rv;
134     }
135 
136     case eTextOutput: {
137       UniquePtr<txMozillaTextOutput> handler(
138           new txMozillaTextOutput(mObserver));
139 
140       nsresult rv =
141           handler->createResultDocument(mSourceDocument, mDocumentIsData);
142       if (NS_SUCCEEDED(rv)) {
143         *aHandler = handler.release();
144       }
145 
146       return rv;
147     }
148   }
149 
150   MOZ_CRASH("Unknown output method");
151 
152   return NS_ERROR_FAILURE;
153 }
154 
createHandlerWith(txOutputFormat * aFormat,txAXMLEventHandler ** aHandler)155 nsresult txToFragmentHandlerFactory::createHandlerWith(
156     txOutputFormat* aFormat, txAXMLEventHandler** aHandler) {
157   *aHandler = nullptr;
158   switch (aFormat->mMethod) {
159     case eMethodNotSet: {
160       txOutputFormat format;
161       format.merge(*aFormat);
162       nsCOMPtr<Document> doc = mFragment->OwnerDoc();
163 
164       if (doc->IsHTMLDocument()) {
165         format.mMethod = eHTMLOutput;
166       } else {
167         format.mMethod = eXMLOutput;
168       }
169 
170       *aHandler = new txMozillaXMLOutput(&format, mFragment, false);
171       break;
172     }
173 
174     case eXMLOutput:
175     case eHTMLOutput: {
176       *aHandler = new txMozillaXMLOutput(aFormat, mFragment, false);
177       break;
178     }
179 
180     case eTextOutput: {
181       *aHandler = new txMozillaTextOutput(mFragment);
182       break;
183     }
184   }
185   NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
186   return NS_OK;
187 }
188 
createHandlerWith(txOutputFormat * aFormat,const nsAString & aName,int32_t aNsID,txAXMLEventHandler ** aHandler)189 nsresult txToFragmentHandlerFactory::createHandlerWith(
190     txOutputFormat* aFormat, const nsAString& aName, int32_t aNsID,
191     txAXMLEventHandler** aHandler) {
192   *aHandler = nullptr;
193   NS_ASSERTION(aFormat->mMethod != eMethodNotSet,
194                "How can method not be known when root element is?");
195   NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED);
196   return createHandlerWith(aFormat, aHandler);
197 }
198 
199 class txVariable : public txIGlobalParameter {
200  public:
txVariable(nsIVariant * aValue,txAExprResult * aTxValue)201   explicit txVariable(nsIVariant* aValue, txAExprResult* aTxValue)
202       : mValue(aValue), mTxValue(aTxValue) {
203     NS_ASSERTION(aValue && aTxValue, "missing value");
204   }
txVariable(txAExprResult * aValue)205   explicit txVariable(txAExprResult* aValue) : mTxValue(aValue) {
206     NS_ASSERTION(aValue, "missing value");
207   }
getValue(txAExprResult ** aValue)208   nsresult getValue(txAExprResult** aValue) override {
209     NS_ASSERTION(mTxValue, "variablevalue is null");
210 
211     *aValue = mTxValue;
212     NS_ADDREF(*aValue);
213 
214     return NS_OK;
215   }
getValue(nsIVariant ** aValue)216   nsresult getValue(nsIVariant** aValue) {
217     *aValue = mValue;
218     NS_ADDREF(*aValue);
219     return NS_OK;
220   }
getValue()221   nsIVariant* getValue() { return mValue; }
setValue(nsIVariant * aValue,txAExprResult * aTxValue)222   void setValue(nsIVariant* aValue, txAExprResult* aTxValue) {
223     NS_ASSERTION(aValue && aTxValue, "setting variablevalue to null");
224     mValue = aValue;
225     mTxValue = aTxValue;
226   }
setValue(txAExprResult * aValue)227   void setValue(txAExprResult* aValue) {
228     NS_ASSERTION(aValue, "setting variablevalue to null");
229     mValue = nullptr;
230     mTxValue = aValue;
231   }
232 
233   static nsresult Convert(nsIVariant* aValue, txAExprResult** aResult);
234 
235   friend void ImplCycleCollectionUnlink(txVariable& aVariable);
236   friend void ImplCycleCollectionTraverse(
237       nsCycleCollectionTraversalCallback& aCallback, txVariable& aVariable,
238       const char* aName, uint32_t aFlags);
239 
240  private:
241   nsCOMPtr<nsIVariant> mValue;
242   RefPtr<txAExprResult> mTxValue;
243 };
244 
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback & aCallback,txVariable & aVariable,const char * aName,uint32_t aFlags)245 inline void ImplCycleCollectionTraverse(
246     nsCycleCollectionTraversalCallback& aCallback, txVariable& aVariable,
247     const char* aName, uint32_t aFlags) {
248   ImplCycleCollectionTraverse(aCallback, aVariable.mValue, aName, aFlags);
249 }
250 
ImplCycleCollectionUnlink(txOwningExpandedNameMap<txIGlobalParameter> & aMap)251 inline void ImplCycleCollectionUnlink(
252     txOwningExpandedNameMap<txIGlobalParameter>& aMap) {
253   aMap.clear();
254 }
255 
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback & aCallback,txOwningExpandedNameMap<txIGlobalParameter> & aMap,const char * aName,uint32_t aFlags=0)256 inline void ImplCycleCollectionTraverse(
257     nsCycleCollectionTraversalCallback& aCallback,
258     txOwningExpandedNameMap<txIGlobalParameter>& aMap, const char* aName,
259     uint32_t aFlags = 0) {
260   aFlags |= CycleCollectionEdgeNameArrayFlag;
261   txOwningExpandedNameMap<txIGlobalParameter>::iterator iter(aMap);
262   while (iter.next()) {
263     ImplCycleCollectionTraverse(
264         aCallback, *static_cast<txVariable*>(iter.value()), aName, aFlags);
265   }
266 }
267 
268 /**
269  * txMozillaXSLTProcessor
270  */
271 
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(txMozillaXSLTProcessor,mOwner,mEmbeddedStylesheetRoot,mSource,mVariables)272 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(txMozillaXSLTProcessor, mOwner,
273                                       mEmbeddedStylesheetRoot, mSource,
274                                       mVariables)
275 
276 NS_IMPL_CYCLE_COLLECTING_ADDREF(txMozillaXSLTProcessor)
277 NS_IMPL_CYCLE_COLLECTING_RELEASE(txMozillaXSLTProcessor)
278 
279 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(txMozillaXSLTProcessor)
280   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
281   NS_INTERFACE_MAP_ENTRY(nsIDocumentTransformer)
282   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
283   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentTransformer)
284 NS_INTERFACE_MAP_END
285 
286 txMozillaXSLTProcessor::txMozillaXSLTProcessor()
287     : mOwner(nullptr),
288       mStylesheetDocument(nullptr),
289       mTransformResult(NS_OK),
290       mCompileResult(NS_OK),
291       mFlags(0) {}
292 
txMozillaXSLTProcessor(nsISupports * aOwner)293 txMozillaXSLTProcessor::txMozillaXSLTProcessor(nsISupports* aOwner)
294     : mOwner(aOwner),
295       mStylesheetDocument(nullptr),
296       mTransformResult(NS_OK),
297       mCompileResult(NS_OK),
298       mFlags(0) {}
299 
~txMozillaXSLTProcessor()300 txMozillaXSLTProcessor::~txMozillaXSLTProcessor() {
301   if (mStylesheetDocument) {
302     mStylesheetDocument->RemoveMutationObserver(this);
303   }
304 }
305 
306 NS_IMETHODIMP
SetTransformObserver(nsITransformObserver * aObserver)307 txMozillaXSLTProcessor::SetTransformObserver(nsITransformObserver* aObserver) {
308   mObserver = aObserver;
309   return NS_OK;
310 }
311 
312 NS_IMETHODIMP
SetSourceContentModel(nsINode * aSource)313 txMozillaXSLTProcessor::SetSourceContentModel(nsINode* aSource) {
314   mSource = aSource;
315 
316   if (NS_FAILED(mTransformResult)) {
317     notifyError();
318     return NS_OK;
319   }
320 
321   if (mStylesheet) {
322     return DoTransform();
323   }
324 
325   return NS_OK;
326 }
327 
328 NS_IMETHODIMP
AddXSLTParamNamespace(const nsString & aPrefix,const nsString & aNamespace)329 txMozillaXSLTProcessor::AddXSLTParamNamespace(const nsString& aPrefix,
330                                               const nsString& aNamespace) {
331   RefPtr<nsAtom> pre = NS_Atomize(aPrefix);
332   return mParamNamespaceMap.mapNamespace(pre, aNamespace);
333 }
334 
335 class txXSLTParamContext : public txIParseContext, public txIEvalContext {
336  public:
txXSLTParamContext(txNamespaceMap * aResolver,const txXPathNode & aContext,txResultRecycler * aRecycler)337   txXSLTParamContext(txNamespaceMap* aResolver, const txXPathNode& aContext,
338                      txResultRecycler* aRecycler)
339       : mResolver(aResolver), mContext(aContext), mRecycler(aRecycler) {}
340 
341   // txIParseContext
resolveNamespacePrefix(nsAtom * aPrefix,int32_t & aID)342   nsresult resolveNamespacePrefix(nsAtom* aPrefix, int32_t& aID) override {
343     aID = mResolver->lookupNamespace(aPrefix);
344     return aID == kNameSpaceID_Unknown ? NS_ERROR_DOM_NAMESPACE_ERR : NS_OK;
345   }
resolveFunctionCall(nsAtom * aName,int32_t aID,FunctionCall ** aFunction)346   nsresult resolveFunctionCall(nsAtom* aName, int32_t aID,
347                                FunctionCall** aFunction) override {
348     return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
349   }
caseInsensitiveNameTests()350   bool caseInsensitiveNameTests() override { return false; }
SetErrorOffset(uint32_t aOffset)351   void SetErrorOffset(uint32_t aOffset) override {}
352 
353   // txIEvalContext
getVariable(int32_t aNamespace,nsAtom * aLName,txAExprResult * & aResult)354   nsresult getVariable(int32_t aNamespace, nsAtom* aLName,
355                        txAExprResult*& aResult) override {
356     aResult = nullptr;
357     return NS_ERROR_INVALID_ARG;
358   }
isStripSpaceAllowed(const txXPathNode & aNode,bool & aAllowed)359   nsresult isStripSpaceAllowed(const txXPathNode& aNode,
360                                bool& aAllowed) override {
361     aAllowed = false;
362 
363     return NS_OK;
364   }
getPrivateContext()365   void* getPrivateContext() override { return nullptr; }
recycler()366   txResultRecycler* recycler() override { return mRecycler; }
receiveError(const nsAString & aMsg,nsresult aRes)367   void receiveError(const nsAString& aMsg, nsresult aRes) override {}
getContextNode()368   const txXPathNode& getContextNode() override { return mContext; }
size()369   uint32_t size() override { return 1; }
position()370   uint32_t position() override { return 1; }
371 
372  private:
373   txNamespaceMap* mResolver;
374   const txXPathNode& mContext;
375   txResultRecycler* mRecycler;
376 };
377 
378 NS_IMETHODIMP
AddXSLTParam(const nsString & aName,const nsString & aNamespace,const nsString & aSelect,const nsString & aValue,nsINode * aContext)379 txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName,
380                                      const nsString& aNamespace,
381                                      const nsString& aSelect,
382                                      const nsString& aValue,
383                                      nsINode* aContext) {
384   nsresult rv = NS_OK;
385 
386   if (aSelect.IsVoid() == aValue.IsVoid()) {
387     // Ignore if neither or both are specified
388     return NS_ERROR_FAILURE;
389   }
390 
391   RefPtr<txAExprResult> value;
392   if (!aSelect.IsVoid()) {
393     // Set up context
394     UniquePtr<txXPathNode> contextNode(
395         txXPathNativeNode::createXPathNode(aContext));
396     NS_ENSURE_TRUE(contextNode, NS_ERROR_OUT_OF_MEMORY);
397 
398     if (!mRecycler) {
399       mRecycler = new txResultRecycler;
400     }
401 
402     txXSLTParamContext paramContext(&mParamNamespaceMap, *contextNode,
403                                     mRecycler);
404 
405     // Parse
406     UniquePtr<Expr> expr;
407     rv = txExprParser::createExpr(aSelect, &paramContext,
408                                   getter_Transfers(expr));
409     NS_ENSURE_SUCCESS(rv, rv);
410 
411     // Evaluate
412     rv = expr->evaluate(&paramContext, getter_AddRefs(value));
413     NS_ENSURE_SUCCESS(rv, rv);
414   } else {
415     value = new StringResult(aValue, nullptr);
416   }
417 
418   RefPtr<nsAtom> name = NS_Atomize(aName);
419   int32_t nsId = kNameSpaceID_Unknown;
420   rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespace, nsId);
421   NS_ENSURE_SUCCESS(rv, rv);
422 
423   txExpandedName varName(nsId, name);
424   txVariable* var = static_cast<txVariable*>(mVariables.get(varName));
425   if (var) {
426     var->setValue(value);
427 
428     return NS_OK;
429   }
430 
431   var = new txVariable(value);
432   NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
433 
434   return mVariables.add(varName, var);
435 }
436 
437 class nsTransformBlockerEvent : public mozilla::Runnable {
438  public:
439   RefPtr<txMozillaXSLTProcessor> mProcessor;
440 
nsTransformBlockerEvent(txMozillaXSLTProcessor * processor)441   explicit nsTransformBlockerEvent(txMozillaXSLTProcessor* processor)
442       : mozilla::Runnable("nsTransformBlockerEvent"), mProcessor(processor) {}
443 
~nsTransformBlockerEvent()444   ~nsTransformBlockerEvent() {
445     nsCOMPtr<Document> document =
446         mProcessor->GetSourceContentModel()->OwnerDoc();
447     document->UnblockOnload(true);
448   }
449 
Run()450   NS_IMETHOD Run() override {
451     mProcessor->TransformToDoc(nullptr, false);
452     return NS_OK;
453   }
454 };
455 
DoTransform()456 nsresult txMozillaXSLTProcessor::DoTransform() {
457   NS_ENSURE_TRUE(mSource, NS_ERROR_UNEXPECTED);
458   NS_ENSURE_TRUE(mStylesheet, NS_ERROR_UNEXPECTED);
459   NS_ASSERTION(mObserver, "no observer");
460   NS_ASSERTION(NS_IsMainThread(), "should only be on main thread");
461 
462   nsCOMPtr<nsIRunnable> event = new nsTransformBlockerEvent(this);
463   mSource->OwnerDoc()->BlockOnload();
464   nsresult rv = NS_DispatchToCurrentThread(event);
465   if (NS_FAILED(rv)) {
466     // XXX Maybe we should just display the source document in this case?
467     //     Also, set up context information, see bug 204655.
468     reportError(rv, nullptr, nullptr);
469   }
470 
471   return rv;
472 }
473 
ImportStylesheet(nsINode & aStyle,mozilla::ErrorResult & aRv)474 void txMozillaXSLTProcessor::ImportStylesheet(nsINode& aStyle,
475                                               mozilla::ErrorResult& aRv) {
476   // We don't support importing multiple stylesheets yet.
477   if (NS_WARN_IF(mStylesheetDocument || mStylesheet)) {
478     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
479     return;
480   }
481 
482   if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()->Subsumes(
483           aStyle.NodePrincipal())) {
484     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
485     return;
486   }
487 
488   if (NS_WARN_IF(!aStyle.IsElement() && !aStyle.IsDocument())) {
489     aRv.Throw(NS_ERROR_INVALID_ARG);
490     return;
491   }
492 
493   nsresult rv =
494       TX_CompileStylesheet(&aStyle, this, getter_AddRefs(mStylesheet));
495   // XXX set up exception context, bug 204658
496   if (NS_WARN_IF(NS_FAILED(rv))) {
497     aRv.Throw(rv);
498     return;
499   }
500 
501   mStylesheetDocument = aStyle.OwnerDoc();
502   if (aStyle.IsElement()) {
503     mEmbeddedStylesheetRoot = aStyle.AsElement();
504   }
505 
506   mStylesheetDocument->AddMutationObserver(this);
507 }
508 
TransformToDocument(nsINode & aSource,ErrorResult & aRv)509 already_AddRefed<Document> txMozillaXSLTProcessor::TransformToDocument(
510     nsINode& aSource, ErrorResult& aRv) {
511   if (NS_WARN_IF(NS_FAILED(mCompileResult))) {
512     aRv.Throw(mCompileResult);
513     return nullptr;
514   }
515 
516   if (!nsContentUtils::CanCallerAccess(&aSource)) {
517     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
518     return nullptr;
519   }
520 
521   nsresult rv = ensureStylesheet();
522   if (NS_WARN_IF(NS_FAILED(rv))) {
523     aRv.Throw(rv);
524     return nullptr;
525   }
526 
527   mSource = &aSource;
528 
529   nsCOMPtr<Document> doc;
530   rv = TransformToDoc(getter_AddRefs(doc), true);
531   if (NS_FAILED(rv)) {
532     aRv.Throw(rv);
533     return nullptr;
534   }
535   return doc.forget();
536 }
537 
TransformToDoc(Document ** aResult,bool aCreateDataDocument)538 nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult,
539                                                 bool aCreateDataDocument) {
540   UniquePtr<txXPathNode> sourceNode(
541       txXPathNativeNode::createXPathNode(mSource));
542   if (!sourceNode) {
543     return NS_ERROR_OUT_OF_MEMORY;
544   }
545 
546   txExecutionState es(mStylesheet, IsLoadDisabled());
547 
548   // XXX Need to add error observers
549 
550   // If aResult is non-null, we're a data document
551   txToDocHandlerFactory handlerFactory(&es, mSource->OwnerDoc(), mObserver,
552                                        aCreateDataDocument);
553   es.mOutputHandlerFactory = &handlerFactory;
554 
555   nsresult rv = es.init(*sourceNode, &mVariables);
556 
557   // Process root of XML source document
558   if (NS_SUCCEEDED(rv)) {
559     rv = txXSLTProcessor::execute(es);
560   }
561 
562   nsresult endRv = es.end(rv);
563   if (NS_SUCCEEDED(rv)) {
564     rv = endRv;
565   }
566 
567   if (NS_SUCCEEDED(rv)) {
568     if (aResult) {
569       txAOutputXMLEventHandler* handler =
570           static_cast<txAOutputXMLEventHandler*>(es.mOutputHandler);
571       nsCOMPtr<Document> doc;
572       handler->getOutputDocument(getter_AddRefs(doc));
573       MOZ_ASSERT(doc->GetReadyStateEnum() == Document::READYSTATE_INTERACTIVE,
574                  "Bad readyState");
575       doc->SetReadyStateInternal(Document::READYSTATE_COMPLETE);
576       doc.forget(aResult);
577     }
578   } else if (mObserver) {
579     // XXX set up context information, bug 204655
580     reportError(rv, nullptr, nullptr);
581   }
582 
583   return rv;
584 }
585 
TransformToFragment(nsINode & aSource,Document & aOutput,ErrorResult & aRv)586 already_AddRefed<DocumentFragment> txMozillaXSLTProcessor::TransformToFragment(
587     nsINode& aSource, Document& aOutput, ErrorResult& aRv) {
588   if (NS_WARN_IF(NS_FAILED(mCompileResult))) {
589     aRv.Throw(mCompileResult);
590     return nullptr;
591   }
592 
593   nsIPrincipal* subject =
594       nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
595   if (!subject->Subsumes(aSource.NodePrincipal()) ||
596       !subject->Subsumes(aOutput.NodePrincipal())) {
597     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
598     return nullptr;
599   }
600 
601   nsresult rv = ensureStylesheet();
602   if (NS_WARN_IF(NS_FAILED(rv))) {
603     aRv.Throw(rv);
604     return nullptr;
605   }
606 
607   UniquePtr<txXPathNode> sourceNode(
608       txXPathNativeNode::createXPathNode(&aSource));
609   if (!sourceNode) {
610     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
611     return nullptr;
612   }
613 
614   txExecutionState es(mStylesheet, IsLoadDisabled());
615 
616   // XXX Need to add error observers
617 
618   RefPtr<DocumentFragment> frag = aOutput.CreateDocumentFragment();
619   txToFragmentHandlerFactory handlerFactory(frag);
620   es.mOutputHandlerFactory = &handlerFactory;
621 
622   rv = es.init(*sourceNode, &mVariables);
623 
624   // Process root of XML source document
625   if (NS_SUCCEEDED(rv)) {
626     rv = txXSLTProcessor::execute(es);
627   }
628   // XXX setup exception context, bug 204658
629   nsresult endRv = es.end(rv);
630   if (NS_SUCCEEDED(rv)) {
631     rv = endRv;
632   }
633 
634   if (NS_FAILED(rv)) {
635     aRv.Throw(rv);
636     return nullptr;
637   }
638 
639   return frag.forget();
640 }
641 
SetParameter(const nsAString & aNamespaceURI,const nsAString & aLocalName,nsIVariant * aValue)642 nsresult txMozillaXSLTProcessor::SetParameter(const nsAString& aNamespaceURI,
643                                               const nsAString& aLocalName,
644                                               nsIVariant* aValue) {
645   NS_ENSURE_ARG(aValue);
646 
647   nsCOMPtr<nsIVariant> value = aValue;
648 
649   uint16_t dataType = value->GetDataType();
650   switch (dataType) {
651     // Number
652     case nsIDataType::VTYPE_INT8:
653     case nsIDataType::VTYPE_INT16:
654     case nsIDataType::VTYPE_INT32:
655     case nsIDataType::VTYPE_INT64:
656     case nsIDataType::VTYPE_UINT8:
657     case nsIDataType::VTYPE_UINT16:
658     case nsIDataType::VTYPE_UINT32:
659     case nsIDataType::VTYPE_UINT64:
660     case nsIDataType::VTYPE_FLOAT:
661     case nsIDataType::VTYPE_DOUBLE:
662 
663     // Boolean
664     case nsIDataType::VTYPE_BOOL:
665 
666     // String
667     case nsIDataType::VTYPE_CHAR:
668     case nsIDataType::VTYPE_WCHAR:
669     case nsIDataType::VTYPE_CHAR_STR:
670     case nsIDataType::VTYPE_WCHAR_STR:
671     case nsIDataType::VTYPE_STRING_SIZE_IS:
672     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
673     case nsIDataType::VTYPE_UTF8STRING:
674     case nsIDataType::VTYPE_CSTRING:
675     case nsIDataType::VTYPE_ASTRING: {
676       break;
677     }
678 
679     // Nodeset
680     case nsIDataType::VTYPE_INTERFACE:
681     case nsIDataType::VTYPE_INTERFACE_IS: {
682       nsCOMPtr<nsISupports> supports;
683       nsresult rv = value->GetAsISupports(getter_AddRefs(supports));
684       NS_ENSURE_SUCCESS(rv, rv);
685 
686       nsCOMPtr<nsINode> node = do_QueryInterface(supports);
687       if (node) {
688         if (!nsContentUtils::CanCallerAccess(node)) {
689           return NS_ERROR_DOM_SECURITY_ERR;
690         }
691 
692         break;
693       }
694 
695       nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(supports);
696       if (xpathResult) {
697         RefPtr<txAExprResult> result;
698         nsresult rv = xpathResult->GetExprResult(getter_AddRefs(result));
699         NS_ENSURE_SUCCESS(rv, rv);
700 
701         if (result->getResultType() == txAExprResult::NODESET) {
702           txNodeSet* nodeSet =
703               static_cast<txNodeSet*>(static_cast<txAExprResult*>(result));
704 
705           int32_t i, count = nodeSet->size();
706           for (i = 0; i < count; ++i) {
707             nsINode* node = txXPathNativeNode::getNode(nodeSet->get(i));
708             if (!nsContentUtils::CanCallerAccess(node)) {
709               return NS_ERROR_DOM_SECURITY_ERR;
710             }
711           }
712         }
713 
714         // Clone the XPathResult so that mutations don't affect this
715         // variable.
716         nsCOMPtr<nsIXPathResult> clone;
717         rv = xpathResult->Clone(getter_AddRefs(clone));
718         NS_ENSURE_SUCCESS(rv, rv);
719 
720         RefPtr<nsVariant> variant = new nsVariant();
721 
722         rv = variant->SetAsISupports(clone);
723         NS_ENSURE_SUCCESS(rv, rv);
724 
725         value = variant;
726 
727         break;
728       }
729 
730       nsCOMPtr<nsINodeList> nodeList = do_QueryInterface(supports);
731       if (nodeList) {
732         uint32_t length = nodeList->Length();
733 
734         uint32_t i;
735         for (i = 0; i < length; ++i) {
736           if (!nsContentUtils::CanCallerAccess(nodeList->Item(i))) {
737             return NS_ERROR_DOM_SECURITY_ERR;
738           }
739         }
740 
741         break;
742       }
743 
744       // Random JS Objects will be converted to a string.
745       nsCOMPtr<nsIXPConnectJSObjectHolder> holder = do_QueryInterface(supports);
746       if (holder) {
747         break;
748       }
749 
750       // We don't know how to handle this type of param.
751       return NS_ERROR_ILLEGAL_VALUE;
752     }
753 
754     case nsIDataType::VTYPE_ARRAY: {
755       uint16_t type;
756       nsIID iid;
757       uint32_t count;
758       void* array;
759       nsresult rv = value->GetAsArray(&type, &iid, &count, &array);
760       NS_ENSURE_SUCCESS(rv, rv);
761 
762       if (type != nsIDataType::VTYPE_INTERFACE &&
763           type != nsIDataType::VTYPE_INTERFACE_IS) {
764         free(array);
765 
766         // We only support arrays of DOM nodes.
767         return NS_ERROR_ILLEGAL_VALUE;
768       }
769 
770       nsISupports** values = static_cast<nsISupports**>(array);
771 
772       uint32_t i;
773       for (i = 0; i < count; ++i) {
774         nsISupports* supports = values[i];
775         nsCOMPtr<nsINode> node = do_QueryInterface(supports);
776 
777         if (node) {
778           rv = nsContentUtils::CanCallerAccess(node)
779                    ? NS_OK
780                    : NS_ERROR_DOM_SECURITY_ERR;
781         } else {
782           // We only support arrays of DOM nodes.
783           rv = NS_ERROR_ILLEGAL_VALUE;
784         }
785 
786         if (NS_FAILED(rv)) {
787           while (i < count) {
788             NS_IF_RELEASE(values[i]);
789             ++i;
790           }
791           free(array);
792 
793           return rv;
794         }
795 
796         NS_RELEASE(supports);
797       }
798 
799       free(array);
800 
801       break;
802     }
803 
804     default: {
805       return NS_ERROR_FAILURE;
806     }
807   }
808 
809   int32_t nsId = kNameSpaceID_Unknown;
810   nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
811       aNamespaceURI, nsId);
812   NS_ENSURE_SUCCESS(rv, rv);
813   RefPtr<nsAtom> localName = NS_Atomize(aLocalName);
814   txExpandedName varName(nsId, localName);
815 
816   RefPtr<txAExprResult> txValue;
817   rv = txVariable::Convert(value, getter_AddRefs(txValue));
818   NS_ENSURE_SUCCESS(rv, rv);
819 
820   txVariable* var = static_cast<txVariable*>(mVariables.get(varName));
821   if (var) {
822     var->setValue(value, txValue);
823     return NS_OK;
824   }
825 
826   var = new txVariable(value, txValue);
827   return mVariables.add(varName, var);
828 }
829 
GetParameter(const nsAString & aNamespaceURI,const nsAString & aLocalName,ErrorResult & aRv)830 already_AddRefed<nsIVariant> txMozillaXSLTProcessor::GetParameter(
831     const nsAString& aNamespaceURI, const nsAString& aLocalName,
832     ErrorResult& aRv) {
833   int32_t nsId = kNameSpaceID_Unknown;
834   nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
835       aNamespaceURI, nsId);
836   if (NS_WARN_IF(NS_FAILED(rv))) {
837     aRv.Throw(rv);
838     return nullptr;
839   }
840   RefPtr<nsAtom> localName = NS_Atomize(aLocalName);
841   txExpandedName varName(nsId, localName);
842 
843   txVariable* var = static_cast<txVariable*>(mVariables.get(varName));
844   if (!var) {
845     return nullptr;
846   }
847 
848   nsCOMPtr<nsIVariant> result;
849   rv = var->getValue(getter_AddRefs(result));
850   if (NS_FAILED(rv)) {
851     aRv.Throw(rv);
852     return nullptr;
853   }
854   return result.forget();
855 }
856 
RemoveParameter(const nsAString & aNamespaceURI,const nsAString & aLocalName,ErrorResult & aRv)857 void txMozillaXSLTProcessor::RemoveParameter(const nsAString& aNamespaceURI,
858                                              const nsAString& aLocalName,
859                                              ErrorResult& aRv) {
860   int32_t nsId = kNameSpaceID_Unknown;
861   nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
862       aNamespaceURI, nsId);
863   if (NS_WARN_IF(NS_FAILED(rv))) {
864     aRv.Throw(rv);
865     return;
866   }
867   RefPtr<nsAtom> localName = NS_Atomize(aLocalName);
868   txExpandedName varName(nsId, localName);
869 
870   mVariables.remove(varName);
871 }
872 
ClearParameters()873 void txMozillaXSLTProcessor::ClearParameters() { mVariables.clear(); }
874 
Reset()875 void txMozillaXSLTProcessor::Reset() {
876   if (mStylesheetDocument) {
877     mStylesheetDocument->RemoveMutationObserver(this);
878   }
879   mStylesheet = nullptr;
880   mStylesheetDocument = nullptr;
881   mEmbeddedStylesheetRoot = nullptr;
882   mCompileResult = NS_OK;
883   mVariables.clear();
884 }
885 
SetFlags(uint32_t aFlags,SystemCallerGuarantee)886 void txMozillaXSLTProcessor::SetFlags(uint32_t aFlags, SystemCallerGuarantee) {
887   mFlags = aFlags;
888 }
889 
Flags(SystemCallerGuarantee)890 uint32_t txMozillaXSLTProcessor::Flags(SystemCallerGuarantee) { return mFlags; }
891 
892 NS_IMETHODIMP
LoadStyleSheet(nsIURI * aUri,Document * aLoaderDocument)893 txMozillaXSLTProcessor::LoadStyleSheet(nsIURI* aUri,
894                                        Document* aLoaderDocument) {
895   mozilla::dom::ReferrerPolicy refpol = mozilla::dom::ReferrerPolicy::_empty;
896   if (mStylesheetDocument) {
897     refpol = mStylesheetDocument->GetReferrerPolicy();
898   }
899 
900   nsresult rv = TX_LoadSheet(aUri, this, aLoaderDocument, refpol);
901   if (NS_FAILED(rv) && mObserver) {
902     // This is most likely a network or security error, just
903     // use the uri as context.
904     nsAutoCString spec;
905     aUri->GetSpec(spec);
906     CopyUTF8toUTF16(spec, mSourceText);
907     nsresult status = NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_XSLT
908                           ? rv
909                           : NS_ERROR_XSLT_NETWORK_ERROR;
910     reportError(status, nullptr, nullptr);
911   }
912   return rv;
913 }
914 
setStylesheet(txStylesheet * aStylesheet)915 nsresult txMozillaXSLTProcessor::setStylesheet(txStylesheet* aStylesheet) {
916   mStylesheet = aStylesheet;
917   if (mSource) {
918     return DoTransform();
919   }
920   return NS_OK;
921 }
922 
reportError(nsresult aResult,const char16_t * aErrorText,const char16_t * aSourceText)923 void txMozillaXSLTProcessor::reportError(nsresult aResult,
924                                          const char16_t* aErrorText,
925                                          const char16_t* aSourceText) {
926   if (!mObserver) {
927     return;
928   }
929 
930   mTransformResult = aResult;
931 
932   if (aErrorText) {
933     mErrorText.Assign(aErrorText);
934   } else {
935     nsCOMPtr<nsIStringBundleService> sbs =
936         mozilla::components::StringBundle::Service();
937     if (sbs) {
938       nsString errorText;
939       sbs->FormatStatusMessage(aResult, u"", errorText);
940 
941       nsAutoString errorMessage;
942       nsCOMPtr<nsIStringBundle> bundle;
943       sbs->CreateBundle(XSLT_MSGS_URL, getter_AddRefs(bundle));
944 
945       if (bundle) {
946         AutoTArray<nsString, 1> error = {errorText};
947         if (mStylesheet) {
948           bundle->FormatStringFromName("TransformError", error, errorMessage);
949         } else {
950           bundle->FormatStringFromName("LoadingError", error, errorMessage);
951         }
952       }
953       mErrorText.Assign(errorMessage);
954     }
955   }
956 
957   if (aSourceText) {
958     mSourceText.Assign(aSourceText);
959   }
960 
961   if (mSource) {
962     notifyError();
963   }
964 }
965 
notifyError()966 void txMozillaXSLTProcessor::notifyError() {
967   nsCOMPtr<Document> document;
968   {
969     nsresult rv = NS_NewXMLDocument(getter_AddRefs(document));
970     NS_ENSURE_SUCCESS_VOID(rv);
971   }
972 
973   URIUtils::ResetWithSource(document, mSource);
974 
975   MOZ_ASSERT(
976       document->GetReadyStateEnum() == Document::READYSTATE_UNINITIALIZED,
977       "Bad readyState.");
978   document->SetReadyStateInternal(Document::READYSTATE_LOADING);
979 
980   constexpr auto ns =
981       u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns;
982 
983   IgnoredErrorResult rv;
984   ElementCreationOptionsOrString options;
985   options.SetAsString();
986 
987   nsCOMPtr<Element> element =
988       document->CreateElementNS(ns, u"parsererror"_ns, options, rv);
989   if (rv.Failed()) {
990     return;
991   }
992 
993   document->AppendChild(*element, rv);
994   if (rv.Failed()) {
995     return;
996   }
997 
998   RefPtr<nsTextNode> text = document->CreateTextNode(mErrorText);
999 
1000   element->AppendChild(*text, rv);
1001   if (rv.Failed()) {
1002     return;
1003   }
1004 
1005   if (!mSourceText.IsEmpty()) {
1006     ElementCreationOptionsOrString options;
1007     options.SetAsString();
1008 
1009     nsCOMPtr<Element> sourceElement =
1010         document->CreateElementNS(ns, u"sourcetext"_ns, options, rv);
1011     if (rv.Failed()) {
1012       return;
1013     }
1014 
1015     element->AppendChild(*sourceElement, rv);
1016     if (rv.Failed()) {
1017       return;
1018     }
1019 
1020     text = document->CreateTextNode(mSourceText);
1021 
1022     sourceElement->AppendChild(*text, rv);
1023     if (rv.Failed()) {
1024       return;
1025     }
1026   }
1027 
1028   MOZ_ASSERT(document->GetReadyStateEnum() == Document::READYSTATE_LOADING,
1029              "Bad readyState.");
1030   document->SetReadyStateInternal(Document::READYSTATE_INTERACTIVE);
1031 
1032   mObserver->OnTransformDone(mTransformResult, document);
1033 }
1034 
ensureStylesheet()1035 nsresult txMozillaXSLTProcessor::ensureStylesheet() {
1036   if (mStylesheet) {
1037     return NS_OK;
1038   }
1039 
1040   NS_ENSURE_TRUE(mStylesheetDocument, NS_ERROR_NOT_INITIALIZED);
1041 
1042   nsINode* style = mEmbeddedStylesheetRoot;
1043   if (!style) {
1044     style = mStylesheetDocument;
1045   }
1046 
1047   return TX_CompileStylesheet(style, this, getter_AddRefs(mStylesheet));
1048 }
1049 
NodeWillBeDestroyed(const nsINode * aNode)1050 void txMozillaXSLTProcessor::NodeWillBeDestroyed(const nsINode* aNode) {
1051   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
1052   if (NS_FAILED(mCompileResult)) {
1053     return;
1054   }
1055 
1056   mCompileResult = ensureStylesheet();
1057   mStylesheetDocument = nullptr;
1058   mEmbeddedStylesheetRoot = nullptr;
1059 }
1060 
CharacterDataChanged(nsIContent * aContent,const CharacterDataChangeInfo &)1061 void txMozillaXSLTProcessor::CharacterDataChanged(
1062     nsIContent* aContent, const CharacterDataChangeInfo&) {
1063   mStylesheet = nullptr;
1064 }
1065 
AttributeChanged(Element * aElement,int32_t aNameSpaceID,nsAtom * aAttribute,int32_t aModType,const nsAttrValue * aOldValue)1066 void txMozillaXSLTProcessor::AttributeChanged(Element* aElement,
1067                                               int32_t aNameSpaceID,
1068                                               nsAtom* aAttribute,
1069                                               int32_t aModType,
1070                                               const nsAttrValue* aOldValue) {
1071   mStylesheet = nullptr;
1072 }
1073 
ContentAppended(nsIContent * aFirstNewContent)1074 void txMozillaXSLTProcessor::ContentAppended(nsIContent* aFirstNewContent) {
1075   mStylesheet = nullptr;
1076 }
1077 
ContentInserted(nsIContent * aChild)1078 void txMozillaXSLTProcessor::ContentInserted(nsIContent* aChild) {
1079   mStylesheet = nullptr;
1080 }
1081 
ContentRemoved(nsIContent * aChild,nsIContent * aPreviousSibling)1082 void txMozillaXSLTProcessor::ContentRemoved(nsIContent* aChild,
1083                                             nsIContent* aPreviousSibling) {
1084   mStylesheet = nullptr;
1085 }
1086 
1087 /* virtual */
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)1088 JSObject* txMozillaXSLTProcessor::WrapObject(
1089     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
1090   return XSLTProcessor_Binding::Wrap(aCx, this, aGivenProto);
1091 }
1092 
GetDocGroup() const1093 DocGroup* txMozillaXSLTProcessor::GetDocGroup() const {
1094   return mStylesheetDocument ? mStylesheetDocument->GetDocGroup() : nullptr;
1095 }
1096 
1097 /* static */
Constructor(const GlobalObject & aGlobal)1098 already_AddRefed<txMozillaXSLTProcessor> txMozillaXSLTProcessor::Constructor(
1099     const GlobalObject& aGlobal) {
1100   RefPtr<txMozillaXSLTProcessor> processor =
1101       new txMozillaXSLTProcessor(aGlobal.GetAsSupports());
1102   return processor.forget();
1103 }
1104 
SetParameter(JSContext * aCx,const nsAString & aNamespaceURI,const nsAString & aLocalName,JS::Handle<JS::Value> aValue,mozilla::ErrorResult & aRv)1105 void txMozillaXSLTProcessor::SetParameter(JSContext* aCx,
1106                                           const nsAString& aNamespaceURI,
1107                                           const nsAString& aLocalName,
1108                                           JS::Handle<JS::Value> aValue,
1109                                           mozilla::ErrorResult& aRv) {
1110   nsCOMPtr<nsIVariant> val;
1111   aRv = nsContentUtils::XPConnect()->JSToVariant(aCx, aValue,
1112                                                  getter_AddRefs(val));
1113   if (aRv.Failed()) {
1114     return;
1115   }
1116   aRv = SetParameter(aNamespaceURI, aLocalName, val);
1117 }
1118 
1119 /* static*/
Startup()1120 nsresult txMozillaXSLTProcessor::Startup() {
1121   if (!txXSLTProcessor::init()) {
1122     return NS_ERROR_OUT_OF_MEMORY;
1123   }
1124 
1125   nsCOMPtr<nsIErrorService> errorService = nsErrorService::GetOrCreate();
1126   if (errorService) {
1127     errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_XSLT,
1128                                             XSLT_MSGS_URL);
1129   }
1130 
1131   return NS_OK;
1132 }
1133 
1134 /* static*/
Shutdown()1135 void txMozillaXSLTProcessor::Shutdown() {
1136   txXSLTProcessor::shutdown();
1137 
1138   nsCOMPtr<nsIErrorService> errorService = nsErrorService::GetOrCreate();
1139   if (errorService) {
1140     errorService->UnregisterErrorStringBundle(NS_ERROR_MODULE_XSLT);
1141   }
1142 }
1143 
1144 /* static*/
Convert(nsIVariant * aValue,txAExprResult ** aResult)1145 nsresult txVariable::Convert(nsIVariant* aValue, txAExprResult** aResult) {
1146   *aResult = nullptr;
1147 
1148   uint16_t dataType = aValue->GetDataType();
1149   switch (dataType) {
1150     // Number
1151     case nsIDataType::VTYPE_INT8:
1152     case nsIDataType::VTYPE_INT16:
1153     case nsIDataType::VTYPE_INT32:
1154     case nsIDataType::VTYPE_INT64:
1155     case nsIDataType::VTYPE_UINT8:
1156     case nsIDataType::VTYPE_UINT16:
1157     case nsIDataType::VTYPE_UINT32:
1158     case nsIDataType::VTYPE_UINT64:
1159     case nsIDataType::VTYPE_FLOAT:
1160     case nsIDataType::VTYPE_DOUBLE: {
1161       double value;
1162       nsresult rv = aValue->GetAsDouble(&value);
1163       NS_ENSURE_SUCCESS(rv, rv);
1164 
1165       *aResult = new NumberResult(value, nullptr);
1166       NS_ADDREF(*aResult);
1167 
1168       return NS_OK;
1169     }
1170 
1171     // Boolean
1172     case nsIDataType::VTYPE_BOOL: {
1173       bool value;
1174       nsresult rv = aValue->GetAsBool(&value);
1175       NS_ENSURE_SUCCESS(rv, rv);
1176 
1177       *aResult = new BooleanResult(value);
1178       NS_ADDREF(*aResult);
1179 
1180       return NS_OK;
1181     }
1182 
1183     // String
1184     case nsIDataType::VTYPE_CHAR:
1185     case nsIDataType::VTYPE_WCHAR:
1186     case nsIDataType::VTYPE_CHAR_STR:
1187     case nsIDataType::VTYPE_WCHAR_STR:
1188     case nsIDataType::VTYPE_STRING_SIZE_IS:
1189     case nsIDataType::VTYPE_WSTRING_SIZE_IS:
1190     case nsIDataType::VTYPE_UTF8STRING:
1191     case nsIDataType::VTYPE_CSTRING:
1192     case nsIDataType::VTYPE_ASTRING: {
1193       nsAutoString value;
1194       nsresult rv = aValue->GetAsAString(value);
1195       NS_ENSURE_SUCCESS(rv, rv);
1196 
1197       *aResult = new StringResult(value, nullptr);
1198       NS_ADDREF(*aResult);
1199 
1200       return NS_OK;
1201     }
1202 
1203     // Nodeset
1204     case nsIDataType::VTYPE_INTERFACE:
1205     case nsIDataType::VTYPE_INTERFACE_IS: {
1206       nsCOMPtr<nsISupports> supports;
1207       nsresult rv = aValue->GetAsISupports(getter_AddRefs(supports));
1208       NS_ENSURE_SUCCESS(rv, rv);
1209 
1210       nsCOMPtr<nsINode> node = do_QueryInterface(supports);
1211       if (node) {
1212         UniquePtr<txXPathNode> xpathNode(
1213             txXPathNativeNode::createXPathNode(node));
1214         if (!xpathNode) {
1215           return NS_ERROR_FAILURE;
1216         }
1217 
1218         *aResult = new txNodeSet(*xpathNode, nullptr);
1219         if (!*aResult) {
1220           return NS_ERROR_OUT_OF_MEMORY;
1221         }
1222 
1223         NS_ADDREF(*aResult);
1224 
1225         return NS_OK;
1226       }
1227 
1228       nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(supports);
1229       if (xpathResult) {
1230         return xpathResult->GetExprResult(aResult);
1231       }
1232 
1233       nsCOMPtr<nsINodeList> nodeList = do_QueryInterface(supports);
1234       if (nodeList) {
1235         RefPtr<txNodeSet> nodeSet = new txNodeSet(nullptr);
1236         if (!nodeSet) {
1237           return NS_ERROR_OUT_OF_MEMORY;
1238         }
1239 
1240         uint32_t length = nodeList->Length();
1241 
1242         uint32_t i;
1243         for (i = 0; i < length; ++i) {
1244           UniquePtr<txXPathNode> xpathNode(
1245               txXPathNativeNode::createXPathNode(nodeList->Item(i)));
1246           if (!xpathNode) {
1247             return NS_ERROR_FAILURE;
1248           }
1249 
1250           nodeSet->add(*xpathNode);
1251         }
1252 
1253         NS_ADDREF(*aResult = nodeSet);
1254 
1255         return NS_OK;
1256       }
1257 
1258       // Convert random JS Objects to a string.
1259       nsCOMPtr<nsIXPConnectJSObjectHolder> holder = do_QueryInterface(supports);
1260       if (holder) {
1261         JSContext* cx = nsContentUtils::GetCurrentJSContext();
1262         NS_ENSURE_TRUE(cx, NS_ERROR_NOT_AVAILABLE);
1263 
1264         JS::Rooted<JSObject*> jsobj(cx, holder->GetJSObject());
1265         NS_ENSURE_STATE(jsobj);
1266 
1267         JS::Rooted<JS::Value> v(cx, JS::ObjectValue(*jsobj));
1268         JS::Rooted<JSString*> str(cx, JS::ToString(cx, v));
1269         NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
1270 
1271         nsAutoJSString value;
1272         NS_ENSURE_TRUE(value.init(cx, str), NS_ERROR_FAILURE);
1273 
1274         *aResult = new StringResult(value, nullptr);
1275         NS_ADDREF(*aResult);
1276 
1277         return NS_OK;
1278       }
1279 
1280       break;
1281     }
1282 
1283     case nsIDataType::VTYPE_ARRAY: {
1284       uint16_t type;
1285       nsIID iid;
1286       uint32_t count;
1287       void* array;
1288       nsresult rv = aValue->GetAsArray(&type, &iid, &count, &array);
1289       NS_ENSURE_SUCCESS(rv, rv);
1290 
1291       NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
1292                        type == nsIDataType::VTYPE_INTERFACE_IS,
1293                    "Huh, we checked this in SetParameter?");
1294 
1295       nsISupports** values = static_cast<nsISupports**>(array);
1296 
1297       RefPtr<txNodeSet> nodeSet = new txNodeSet(nullptr);
1298 
1299       uint32_t i;
1300       for (i = 0; i < count; ++i) {
1301         nsISupports* supports = values[i];
1302         nsCOMPtr<nsINode> node = do_QueryInterface(supports);
1303         NS_ASSERTION(node, "Huh, we checked this in SetParameter?");
1304 
1305         UniquePtr<txXPathNode> xpathNode(
1306             txXPathNativeNode::createXPathNode(node));
1307         if (!xpathNode) {
1308           while (i < count) {
1309             NS_RELEASE(values[i]);
1310             ++i;
1311           }
1312           free(array);
1313 
1314           return NS_ERROR_FAILURE;
1315         }
1316 
1317         nodeSet->add(*xpathNode);
1318 
1319         NS_RELEASE(supports);
1320       }
1321 
1322       free(array);
1323 
1324       NS_ADDREF(*aResult = nodeSet);
1325 
1326       return NS_OK;
1327     }
1328   }
1329 
1330   return NS_ERROR_ILLEGAL_VALUE;
1331 }
1332