Coverage Report

Created: 2018-09-25 14:53

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