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, ¶mContext,
408 getter_Transfers(expr));
409 NS_ENSURE_SUCCESS(rv, rv);
410
411 // Evaluate
412 rv = expr->evaluate(¶mContext, 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