Back to index

lightning-sunbird  0.9+nobinonly
txMozillaXSLTProcessor.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Peter Van der Beken <peterv@propagandism.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "txMozillaXSLTProcessor.h"
00040 #include "nsContentCID.h"
00041 #include "nsDOMError.h"
00042 #include "nsIChannel.h"
00043 #include "nsIContent.h"
00044 #include "nsIDOMElement.h"
00045 #include "nsIDOMText.h"
00046 #include "nsIDocument.h"
00047 #include "nsIDOMClassInfo.h"
00048 #include "nsIDOMDocument.h"
00049 #include "nsIDOMDocumentFragment.h"
00050 #include "nsIDOMNodeList.h"
00051 #include "nsIIOService.h"
00052 #include "nsILoadGroup.h"
00053 #include "nsIScriptLoader.h"
00054 #include "nsIStringBundle.h"
00055 #include "nsIURI.h"
00056 #include "nsNetUtil.h"
00057 #include "nsXPathResult.h"
00058 #include "txExecutionState.h"
00059 #include "txMozillaTextOutput.h"
00060 #include "txMozillaXMLOutput.h"
00061 #include "txURIUtils.h"
00062 #include "XMLUtils.h"
00063 #include "txUnknownHandler.h"
00064 #include "txXSLTProcessor.h"
00065 #include "nsIPrincipal.h"
00066 #include "jsapi.h"
00067 #include "nsIEventQueueService.h"
00068 #include "ExprParser.h"
00069 #include "nsIScriptSecurityManager.h"
00070 
00071 static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
00072 
00076 class txToDocHandlerFactory : public txAOutputHandlerFactory
00077 {
00078 public:
00079     txToDocHandlerFactory(txExecutionState* aEs,
00080                           nsIDOMDocument* aSourceDocument,
00081                           nsIDOMDocument* aResultDocument,
00082                           nsITransformObserver* aObserver)
00083         : mEs(aEs), mSourceDocument(aSourceDocument),
00084           mResultDocument(aResultDocument), mObserver(aObserver)
00085     {
00086     }
00087 
00088     virtual ~txToDocHandlerFactory()
00089     {
00090     }
00091 
00092     TX_DECL_TXAOUTPUTHANDLERFACTORY
00093 
00094 private:
00095     txExecutionState* mEs;
00096     nsCOMPtr<nsIDOMDocument> mSourceDocument;
00097     nsCOMPtr<nsIDOMDocument> mResultDocument;
00098     nsCOMPtr<nsITransformObserver> mObserver;
00099 };
00100 
00101 class txToFragmentHandlerFactory : public txAOutputHandlerFactory
00102 {
00103 public:
00104     txToFragmentHandlerFactory(nsIDOMDocumentFragment* aFragment)
00105         : mFragment(aFragment)
00106     {
00107     }
00108 
00109     virtual ~txToFragmentHandlerFactory()
00110     {
00111     }
00112 
00113     TX_DECL_TXAOUTPUTHANDLERFACTORY
00114 
00115 private:
00116     nsCOMPtr<nsIDOMDocumentFragment> mFragment;
00117 };
00118 
00119 nsresult
00120 txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
00121                                          txAXMLEventHandler** aHandler)
00122 {
00123     *aHandler = nsnull;
00124     switch (aFormat->mMethod) {
00125         case eMethodNotSet:
00126         case eXMLOutput:
00127         {
00128             *aHandler = new txUnknownHandler(mEs);
00129             break;
00130         }
00131 
00132         case eHTMLOutput:
00133         {
00134             *aHandler = new txMozillaXMLOutput(EmptyString(),
00135                                                kNameSpaceID_None,
00136                                                aFormat, mSourceDocument,
00137                                                mResultDocument, mObserver);
00138             break;
00139         }
00140 
00141         case eTextOutput:
00142         {
00143             *aHandler = new txMozillaTextOutput(mSourceDocument,
00144                                                 mResultDocument,
00145                                                 mObserver);
00146             break;
00147         }
00148     }
00149     NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
00150     return NS_OK;
00151 }
00152 
00153 nsresult
00154 txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
00155                                          const nsAString& aName,
00156                                          PRInt32 aNsID,
00157                                          txAXMLEventHandler** aHandler)
00158 {
00159     *aHandler = nsnull;
00160     switch (aFormat->mMethod) {
00161         case eMethodNotSet:
00162         {
00163             NS_ERROR("How can method not be known when root element is?");
00164             return NS_ERROR_UNEXPECTED;
00165         }
00166 
00167         case eXMLOutput:
00168         case eHTMLOutput:
00169         {
00170             *aHandler = new txMozillaXMLOutput(aName, aNsID, aFormat,
00171                                                mSourceDocument,
00172                                                mResultDocument,
00173                                                mObserver);
00174             break;
00175         }
00176 
00177         case eTextOutput:
00178         {
00179             *aHandler = new txMozillaTextOutput(mSourceDocument,
00180                                                 mResultDocument,
00181                                                 mObserver);
00182             break;
00183         }
00184     }
00185     NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
00186     return NS_OK;
00187 }
00188 
00189 nsresult
00190 txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
00191                                               txAXMLEventHandler** aHandler)
00192 {
00193     *aHandler = nsnull;
00194     switch (aFormat->mMethod) {
00195         case eMethodNotSet:
00196         {
00197             txOutputFormat format;
00198             format.merge(*aFormat);
00199             nsCOMPtr<nsIDOMDocument> domdoc;
00200             mFragment->GetOwnerDocument(getter_AddRefs(domdoc));
00201             NS_ASSERTION(domdoc, "unable to get ownerdocument");
00202             nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
00203 
00204             if (!doc || doc->IsCaseSensitive()) {
00205                 format.mMethod = eXMLOutput;
00206             } else {
00207                 format.mMethod = eHTMLOutput;
00208             }
00209 
00210             *aHandler = new txMozillaXMLOutput(&format, mFragment);
00211             break;
00212         }
00213 
00214         case eXMLOutput:
00215         case eHTMLOutput:
00216         {
00217             *aHandler = new txMozillaXMLOutput(aFormat, mFragment);
00218             break;
00219         }
00220 
00221         case eTextOutput:
00222         {
00223             *aHandler = new txMozillaTextOutput(mFragment);
00224             break;
00225         }
00226     }
00227     NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
00228     return NS_OK;
00229 }
00230 
00231 nsresult
00232 txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
00233                                               const nsAString& aName,
00234                                               PRInt32 aNsID,
00235                                               txAXMLEventHandler** aHandler)
00236 {
00237     *aHandler = nsnull;
00238     NS_ASSERTION(aFormat->mMethod != eMethodNotSet,
00239                  "How can method not be known when root element is?");
00240     NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED);
00241     return createHandlerWith(aFormat, aHandler);
00242 }
00243 
00248 NS_IMPL_ADDREF(txMozillaXSLTProcessor)
00249 NS_IMPL_RELEASE(txMozillaXSLTProcessor)
00250 NS_INTERFACE_MAP_BEGIN(txMozillaXSLTProcessor)
00251     NS_INTERFACE_MAP_ENTRY(nsIXSLTProcessor)
00252     NS_INTERFACE_MAP_ENTRY(nsIXSLTProcessorObsolete)
00253     NS_INTERFACE_MAP_ENTRY(nsIXSLTProcessorPrivate)
00254     NS_INTERFACE_MAP_ENTRY(nsIDocumentTransformer)
00255     NS_INTERFACE_MAP_ENTRY(nsIDocumentTransformer_1_8_BRANCH)
00256     NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
00257     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXSLTProcessor)
00258     NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(XSLTProcessor)
00259 NS_INTERFACE_MAP_END
00260 
00261 txMozillaXSLTProcessor::txMozillaXSLTProcessor() : mStylesheetDocument(nsnull),
00262                                                    mTransformResult(NS_OK),
00263                                                    mCompileResult(NS_OK),
00264                                                    mVariables(PR_TRUE),
00265                                                    mFlags(0)
00266 {
00267 }
00268 
00269 txMozillaXSLTProcessor::~txMozillaXSLTProcessor()
00270 {
00271     if (mStylesheetDocument) {
00272         mStylesheetDocument->RemoveObserver(this);
00273     }
00274 }
00275 
00276 NS_IMETHODIMP
00277 txMozillaXSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM,
00278                                           nsIDOMNode* aStyleDOM,
00279                                           nsIDOMDocument* aOutputDoc,
00280                                           nsISupports* aObserver)
00281 {
00282     NS_ENSURE_ARG(aSourceDOM);
00283     NS_ENSURE_ARG(aStyleDOM);
00284     NS_ENSURE_ARG(aOutputDoc);
00285     NS_ENSURE_FALSE(aObserver, NS_ERROR_NOT_IMPLEMENTED);
00286 
00287     if (!URIUtils::CanCallerAccess(aSourceDOM) ||
00288         !URIUtils::CanCallerAccess(aStyleDOM) ||
00289         !URIUtils::CanCallerAccess(aOutputDoc)) {
00290         return NS_ERROR_DOM_SECURITY_ERR;
00291     }
00292 
00293     PRUint16 type = 0;
00294     aStyleDOM->GetNodeType(&type);
00295     NS_ENSURE_TRUE(type == nsIDOMNode::ELEMENT_NODE ||
00296                    type == nsIDOMNode::DOCUMENT_NODE,
00297                    NS_ERROR_INVALID_ARG);
00298 
00299     nsresult rv = TX_CompileStylesheet(aStyleDOM, this, 
00300                                        getter_AddRefs(mStylesheet));
00301     NS_ENSURE_SUCCESS(rv, rv);
00302 
00303     mSource = aSourceDOM;
00304 
00305     return TransformToDoc(aOutputDoc, nsnull);
00306 }
00307 
00308 NS_IMETHODIMP
00309 txMozillaXSLTProcessor::SetTransformObserver(nsITransformObserver* aObserver)
00310 {
00311     mObserver = aObserver;
00312     return NS_OK;
00313 }
00314 
00315 nsresult
00316 txMozillaXSLTProcessor::SetSourceContentModel(nsIDOMNode* aSourceDOM)
00317 {
00318     mSource = aSourceDOM;
00319 
00320     if (NS_FAILED(mTransformResult)) {
00321         notifyError();
00322         return NS_OK;
00323     }
00324 
00325     if (mStylesheet) {
00326         return DoTransform();
00327     }
00328 
00329     return NS_OK;
00330 }
00331 
00332 NS_IMETHODIMP
00333 txMozillaXSLTProcessor::AddXSLTParamNamespace(const nsString& aPrefix,
00334                                               const nsString& aNamespace)
00335 {
00336     nsCOMPtr<nsIAtom> pre = do_GetAtom(aPrefix);
00337     return mParamNamespaceMap.mapNamespace(pre, aNamespace);
00338 }
00339 
00340 
00341 class txXSLTParamContext : public txIParseContext,
00342                            public txIEvalContext
00343 {
00344 public:
00345     txXSLTParamContext(txNamespaceMap *aResolver, txXPathNode& aContext,
00346                        txResultRecycler* aRecycler)
00347         : mResolver(aResolver),
00348           mContext(aContext),
00349           mRecycler(aRecycler)
00350     {
00351     }
00352 
00353     // txIParseContext
00354     nsresult resolveNamespacePrefix(nsIAtom* aPrefix, PRInt32& aID)
00355     {
00356         aID = mResolver->lookupNamespace(aPrefix);
00357         return aID == kNameSpaceID_Unknown ? NS_ERROR_DOM_NAMESPACE_ERR :
00358                                              NS_OK;
00359     }
00360     nsresult resolveFunctionCall(nsIAtom* aName, PRInt32 aID,
00361                                  FunctionCall*& aFunction)
00362     {
00363         return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
00364     }
00365     PRBool caseInsensitiveNameTests()
00366     {
00367         return PR_FALSE;
00368     }
00369     void SetErrorOffset(PRUint32 aOffset)
00370     {
00371     }
00372 
00373     // txIEvalContext
00374     nsresult getVariable(PRInt32 aNamespace, nsIAtom* aLName,
00375                          txAExprResult*& aResult)
00376     {
00377         aResult = nsnull;
00378         return NS_ERROR_INVALID_ARG;
00379     }
00380     PRBool isStripSpaceAllowed(const txXPathNode& aNode)
00381     {
00382         return PR_FALSE;
00383     }
00384     void* getPrivateContext()
00385     {
00386         return nsnull;
00387     }
00388     txResultRecycler* recycler()
00389     {
00390         return mRecycler;
00391     }
00392     void receiveError(const nsAString& aMsg, nsresult aRes)
00393     {
00394     }
00395     const txXPathNode& getContextNode()
00396     {
00397       return mContext;
00398     }
00399     PRUint32 size()
00400     {
00401       return 1;
00402     }
00403     PRUint32 position()
00404     {
00405       return 1;
00406     }
00407 
00408 private:
00409     txNamespaceMap *mResolver;
00410     txXPathNode& mContext;
00411     txResultRecycler* mRecycler;
00412     
00413 };
00414 
00415 
00416 NS_IMETHODIMP
00417 txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName,
00418                                      const nsString& aNamespace,
00419                                      const nsString& aSelect,
00420                                      const nsString& aValue,
00421                                      nsIDOMNode* aContext)
00422 {
00423     nsresult rv = NS_OK;
00424 
00425     if (aSelect.IsVoid() == aValue.IsVoid()) {
00426         // Ignore if neither or both are specified
00427         return NS_ERROR_FAILURE;
00428     }
00429 
00430     nsRefPtr<txAExprResult> value;
00431     if (!aSelect.IsVoid()) {
00432 
00433         // Set up context
00434         nsAutoPtr<txXPathNode> contextNode(
00435           txXPathNativeNode::createXPathNode(aContext));
00436         NS_ENSURE_TRUE(contextNode, NS_ERROR_OUT_OF_MEMORY);
00437 
00438         if (!mRecycler) {
00439             mRecycler = new txResultRecycler;
00440             NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY);
00441 
00442             rv = mRecycler->init();
00443             NS_ENSURE_SUCCESS(rv, rv);
00444         }
00445 
00446         txXSLTParamContext paramContext(&mParamNamespaceMap, *contextNode,
00447                                         mRecycler);
00448 
00449         // Parse
00450         nsAutoPtr<Expr> expr;
00451         rv = txExprParser::createExpr(aSelect, &paramContext,
00452                                       getter_Transfers(expr));
00453         NS_ENSURE_SUCCESS(rv, rv);
00454 
00455         // Evaluate
00456         rv = expr->evaluate(&paramContext, getter_AddRefs(value));
00457         NS_ENSURE_SUCCESS(rv, rv);
00458     }
00459     else {
00460         value = new StringResult(aValue, nsnull);
00461         NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
00462     }
00463 
00464     nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
00465     PRInt32 nsId = txNamespaceManager::getNamespaceID(aNamespace);
00466     NS_ENSURE_FALSE(nsId == kNameSpaceID_Unknown, NS_ERROR_FAILURE);
00467 
00468     txExpandedName varName(nsId, name);
00469     txVariable* var = (txVariable*)mVariables.get(varName);
00470     if (var) {
00471         var->setValue(value);
00472         
00473         return NS_OK;
00474     }
00475 
00476     var = new txVariable(value);
00477     NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
00478 
00479     return mVariables.add(varName, var);
00480 }
00481 
00482 PR_BEGIN_EXTERN_C
00483 void* PR_CALLBACK
00484 HandleTransformBlockerEvent(PLEvent *aEvent)
00485 {
00486     txMozillaXSLTProcessor *processor =
00487          NS_STATIC_CAST(txMozillaXSLTProcessor*, aEvent->owner);
00488     processor->TransformToDoc(nsnull, nsnull);
00489 
00490     return nsnull;
00491 }
00492 
00493 void PR_CALLBACK
00494 DestroyTransformBlockerEvent(PLEvent *aEvent)
00495 {
00496     txMozillaXSLTProcessor *processor =
00497          NS_STATIC_CAST(txMozillaXSLTProcessor*, aEvent->owner);
00498     nsCOMPtr<nsIDocument> document =
00499         do_QueryInterface(processor->GetSourceContentModel());
00500     document->UnblockOnload();
00501 
00502     NS_RELEASE(processor);
00503     delete aEvent;
00504 }
00505 PR_END_EXTERN_C
00506 
00507 nsresult
00508 txMozillaXSLTProcessor::DoTransform()
00509 {
00510     NS_ENSURE_TRUE(mSource, NS_ERROR_UNEXPECTED);
00511     NS_ENSURE_TRUE(mStylesheet, NS_ERROR_UNEXPECTED);
00512     NS_ASSERTION(mObserver, "no observer");
00513 
00514     nsresult rv;
00515     nsCOMPtr<nsIDocument> document = do_QueryInterface(mSource, &rv);
00516     NS_ENSURE_SUCCESS(rv, rv);
00517 
00518     nsCOMPtr<nsIEventQueueService> service =
00519         do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00520     NS_ENSURE_SUCCESS(rv, rv);
00521     nsCOMPtr<nsIEventQueue> eventQ;
00522     rv = service->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
00523                                        getter_AddRefs(eventQ));
00524     NS_ENSURE_SUCCESS(rv, rv);
00525 
00526     PLEvent* event = new PLEvent();
00527     if (!event) {
00528         return NS_ERROR_OUT_OF_MEMORY;
00529     }
00530 
00531     PL_InitEvent(event, this, HandleTransformBlockerEvent,
00532                  DestroyTransformBlockerEvent);
00533 
00534     document->BlockOnload();
00535 
00536     // After this point, event destruction will release |this| (in
00537     // DestroyTransformBlockerEvent)
00538     NS_ADDREF_THIS();
00539 
00540     rv = eventQ->PostEvent(event);
00541     if (NS_FAILED(rv)) {
00542         // XXX Maybe we should just display the source document in this case?
00543         //     Also, set up context information, see bug 204655.
00544         reportError(rv, nsnull, nsnull);
00545         PL_DestroyEvent(event);
00546     }
00547 
00548     return rv;
00549 }
00550 
00551 NS_IMETHODIMP
00552 txMozillaXSLTProcessor::ImportStylesheet(nsIDOMNode *aStyle)
00553 {
00554     NS_ENSURE_TRUE(aStyle, NS_ERROR_NULL_POINTER);
00555     
00556     // We don't support importing multiple stylesheets yet.
00557     NS_ENSURE_TRUE(!mStylesheetDocument && !mStylesheet,
00558                    NS_ERROR_NOT_IMPLEMENTED);
00559 
00560     if (!URIUtils::CanCallerAccess(aStyle)) {
00561         return NS_ERROR_DOM_SECURITY_ERR;
00562     }
00563     
00564     PRUint16 type = 0;
00565     aStyle->GetNodeType(&type);
00566     NS_ENSURE_TRUE(type == nsIDOMNode::ELEMENT_NODE ||
00567                    type == nsIDOMNode::DOCUMENT_NODE,
00568                    NS_ERROR_INVALID_ARG);
00569 
00570     nsresult rv = TX_CompileStylesheet(aStyle, this,
00571                                        getter_AddRefs(mStylesheet));
00572     // XXX set up exception context, bug 204658
00573     NS_ENSURE_SUCCESS(rv, rv);
00574 
00575     if (type == nsIDOMNode::ELEMENT_NODE) {
00576         nsCOMPtr<nsIDOMDocument> domDoc;
00577         aStyle->GetOwnerDocument(getter_AddRefs(domDoc));
00578         NS_ENSURE_TRUE(domDoc, NS_ERROR_UNEXPECTED);
00579 
00580         nsCOMPtr<nsIDocument> styleDoc = do_QueryInterface(domDoc);
00581         mStylesheetDocument = styleDoc;
00582         mEmbeddedStylesheetRoot = do_QueryInterface(aStyle);
00583     }
00584     else {
00585         nsCOMPtr<nsIDocument> styleDoc = do_QueryInterface(aStyle);
00586         mStylesheetDocument = styleDoc;
00587     }
00588 
00589     mStylesheetDocument->AddObserver(this);
00590 
00591     return NS_OK;
00592 }
00593 
00594 NS_IMETHODIMP
00595 txMozillaXSLTProcessor::TransformToDocument(nsIDOMNode *aSource,
00596                                             nsIDOMDocument **aResult)
00597 {
00598     NS_ENSURE_ARG(aSource);
00599     NS_ENSURE_ARG_POINTER(aResult);
00600     NS_ENSURE_SUCCESS(mCompileResult, mCompileResult);
00601 
00602     if (!URIUtils::CanCallerAccess(aSource)) {
00603         return NS_ERROR_DOM_SECURITY_ERR;
00604     }
00605 
00606     nsresult rv = ensureStylesheet();
00607     NS_ENSURE_SUCCESS(rv, rv);
00608 
00609     mSource = aSource;
00610 
00611     return TransformToDoc(nsnull, aResult);
00612 }
00613 
00614 nsresult
00615 txMozillaXSLTProcessor::TransformToDoc(nsIDOMDocument *aOutputDoc,
00616                                        nsIDOMDocument **aResult)
00617 {
00618     nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(mSource));
00619     if (!sourceNode) {
00620         return NS_ERROR_OUT_OF_MEMORY;
00621     }
00622 
00623     nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
00624     mSource->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
00625     if (!sourceDOMDocument) {
00626         sourceDOMDocument = do_QueryInterface(mSource);
00627     }
00628 
00629     txExecutionState es(mStylesheet, IsLoadDisabled());
00630 
00631     // XXX Need to add error observers
00632 
00633     txToDocHandlerFactory handlerFactory(&es, sourceDOMDocument, aOutputDoc,
00634                                          mObserver);
00635     es.mOutputHandlerFactory = &handlerFactory;
00636 
00637     es.init(*sourceNode, &mVariables);
00638 
00639     // Process root of XML source document
00640     nsresult rv = txXSLTProcessor::execute(es);
00641     es.end(rv);
00642     if (NS_SUCCEEDED(rv)) {
00643         if (aResult) {
00644             txAOutputXMLEventHandler* handler =
00645                 NS_STATIC_CAST(txAOutputXMLEventHandler*, es.mOutputHandler);
00646             handler->getOutputDocument(aResult);
00647         }
00648     }
00649     else if (mObserver) {
00650         // XXX set up context information, bug 204655
00651         reportError(rv, nsnull, nsnull);
00652     }
00653 
00654     return rv;
00655 }
00656 
00657 NS_IMETHODIMP
00658 txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource,
00659                                             nsIDOMDocument *aOutput,
00660                                             nsIDOMDocumentFragment **aResult)
00661 {
00662     NS_ENSURE_ARG(aSource);
00663     NS_ENSURE_ARG(aOutput);
00664     NS_ENSURE_ARG_POINTER(aResult);
00665     NS_ENSURE_SUCCESS(mCompileResult, mCompileResult);
00666 
00667     if (!URIUtils::CanCallerAccess(aSource) ||
00668         !URIUtils::CanCallerAccess(aOutput)) {
00669         return NS_ERROR_DOM_SECURITY_ERR;
00670     }
00671 
00672     nsresult rv = ensureStylesheet();
00673     NS_ENSURE_SUCCESS(rv, rv);
00674 
00675     nsAutoPtr<txXPathNode> sourceNode(txXPathNativeNode::createXPathNode(aSource));
00676     if (!sourceNode) {
00677         return NS_ERROR_OUT_OF_MEMORY;
00678     }
00679 
00680     txExecutionState es(mStylesheet, IsLoadDisabled());
00681 
00682     // XXX Need to add error observers
00683 
00684     rv = aOutput->CreateDocumentFragment(aResult);
00685     NS_ENSURE_SUCCESS(rv, rv);
00686     txToFragmentHandlerFactory handlerFactory(*aResult);
00687     es.mOutputHandlerFactory = &handlerFactory;
00688 
00689     es.init(*sourceNode, &mVariables);
00690 
00691     // Process root of XML source document
00692     rv = txXSLTProcessor::execute(es);
00693     // XXX setup exception context, bug 204658
00694     es.end(rv);
00695 
00696     return rv;
00697 }
00698 
00699 NS_IMETHODIMP
00700 txMozillaXSLTProcessor::SetParameter(const nsAString & aNamespaceURI,
00701                                      const nsAString & aLocalName,
00702                                      nsIVariant *aValue)
00703 {
00704     NS_ENSURE_ARG(aValue);
00705 
00706     nsCOMPtr<nsIVariant> value = aValue;
00707 
00708     PRUint16 dataType;
00709     value->GetDataType(&dataType);
00710     switch (dataType) {
00711         // Number
00712         case nsIDataType::VTYPE_INT8:
00713         case nsIDataType::VTYPE_INT16:
00714         case nsIDataType::VTYPE_INT32:
00715         case nsIDataType::VTYPE_INT64:
00716         case nsIDataType::VTYPE_UINT8:
00717         case nsIDataType::VTYPE_UINT16:
00718         case nsIDataType::VTYPE_UINT32:
00719         case nsIDataType::VTYPE_UINT64:
00720         case nsIDataType::VTYPE_FLOAT:
00721         case nsIDataType::VTYPE_DOUBLE:
00722 
00723         // Boolean
00724         case nsIDataType::VTYPE_BOOL:
00725 
00726         // String
00727         case nsIDataType::VTYPE_CHAR:
00728         case nsIDataType::VTYPE_WCHAR:
00729         case nsIDataType::VTYPE_DOMSTRING:
00730         case nsIDataType::VTYPE_CHAR_STR:
00731         case nsIDataType::VTYPE_WCHAR_STR:
00732         case nsIDataType::VTYPE_STRING_SIZE_IS:
00733         case nsIDataType::VTYPE_WSTRING_SIZE_IS:
00734         case nsIDataType::VTYPE_UTF8STRING:
00735         case nsIDataType::VTYPE_CSTRING:
00736         case nsIDataType::VTYPE_ASTRING:
00737         {
00738             break;
00739         }
00740 
00741         // Nodeset
00742         case nsIDataType::VTYPE_INTERFACE:
00743         case nsIDataType::VTYPE_INTERFACE_IS:
00744         {
00745             nsCOMPtr<nsISupports> supports;
00746             nsresult rv = value->GetAsISupports(getter_AddRefs(supports));
00747             NS_ENSURE_SUCCESS(rv, rv);
00748 
00749             nsCOMPtr<nsIDOMNode> node = do_QueryInterface(supports);
00750             if (node) {
00751                 if (!URIUtils::CanCallerAccess(node)) {
00752                     return NS_ERROR_DOM_SECURITY_ERR;
00753                 }
00754 
00755                 break;
00756             }
00757 
00758             nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(supports);
00759             if (xpathResult) {
00760                 nsRefPtr<txAExprResult> result;
00761                 nsresult rv = xpathResult->GetExprResult(getter_AddRefs(result));
00762                 NS_ENSURE_SUCCESS(rv, rv);
00763 
00764                 if (result->getResultType() == txAExprResult::NODESET) {
00765                     txNodeSet *nodeSet =
00766                         NS_STATIC_CAST(txNodeSet*,
00767                                        NS_STATIC_CAST(txAExprResult*, result));
00768 
00769                     nsCOMPtr<nsIDOMNode> node;
00770                     PRInt32 i, count = nodeSet->size();
00771                     for (i = 0; i < count; ++i) {
00772                         rv = txXPathNativeNode::getNode(nodeSet->get(i),
00773                                                         getter_AddRefs(node));
00774                         NS_ENSURE_SUCCESS(rv, rv);
00775 
00776                         if (!URIUtils::CanCallerAccess(node)) {
00777                             return NS_ERROR_DOM_SECURITY_ERR;
00778                         }
00779                     }
00780                 }
00781 
00782                 // Clone the nsXPathResult so that mutations don't affect this
00783                 // variable.
00784                 nsCOMPtr<nsIXPathResult> clone;
00785                 rv = xpathResult->Clone(getter_AddRefs(clone));
00786                 NS_ENSURE_SUCCESS(rv, rv);
00787 
00788                 nsCOMPtr<nsIWritableVariant> variant =
00789                     do_CreateInstance("@mozilla.org/variant;1", &rv);
00790                 NS_ENSURE_SUCCESS(rv, rv);
00791 
00792                 rv = variant->SetAsISupports(clone);
00793                 NS_ENSURE_SUCCESS(rv, rv);
00794 
00795                 value = variant;
00796 
00797                 break;
00798             }
00799 
00800             nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
00801             if (nodeList) {
00802                 PRUint32 length;
00803                 nodeList->GetLength(&length);
00804 
00805                 nsCOMPtr<nsIDOMNode> node;
00806                 PRUint32 i;
00807                 for (i = 0; i < length; ++i) {
00808                     nodeList->Item(i, getter_AddRefs(node));
00809 
00810                     if (!URIUtils::CanCallerAccess(node)) {
00811                         return NS_ERROR_DOM_SECURITY_ERR;
00812                     }
00813                 }
00814 
00815                 break;
00816             }
00817 
00818             // Random JS Objects will be converted to a string.
00819             nsCOMPtr<nsIXPConnectJSObjectHolder> holder =
00820                 do_QueryInterface(supports);
00821             if (holder) {
00822                 break;
00823             }
00824 
00825             // We don't know how to handle this type of param.
00826             return NS_ERROR_ILLEGAL_VALUE;
00827         }
00828 
00829         case nsIDataType::VTYPE_ARRAY:
00830         {
00831             PRUint16 type;
00832             nsIID iid;
00833             PRUint32 count;
00834             void* array;
00835             nsresult rv = value->GetAsArray(&type, &iid, &count, &array);
00836             NS_ENSURE_SUCCESS(rv, rv);
00837 
00838             if (type != nsIDataType::VTYPE_INTERFACE &&
00839                 type != nsIDataType::VTYPE_INTERFACE_IS) {
00840                 nsMemory::Free(array);
00841 
00842                 // We only support arrays of DOM nodes.
00843                 return NS_ERROR_ILLEGAL_VALUE;
00844             }
00845 
00846             nsISupports** values = NS_STATIC_CAST(nsISupports**, array);
00847 
00848             PRUint32 i;
00849             for (i = 0; i < count; ++i) {
00850                 nsISupports *supports = values[i];
00851                 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(supports);
00852 
00853                 if (node) {
00854                     rv = URIUtils::CanCallerAccess(node) ? NS_OK :
00855                          NS_ERROR_DOM_SECURITY_ERR;
00856                 }
00857                 else {
00858                     // We only support arrays of DOM nodes.
00859                     rv = NS_ERROR_ILLEGAL_VALUE;
00860                 }
00861 
00862                 if (NS_FAILED(rv)) {
00863                     while (i < count) {
00864                         NS_RELEASE(values[i]);
00865                         ++i;
00866                     }
00867                     nsMemory::Free(array);
00868 
00869                     return rv;
00870                 }
00871 
00872                 NS_RELEASE(supports);
00873             }
00874 
00875             nsMemory::Free(array);
00876 
00877             break;
00878         }
00879 
00880         default:
00881         {
00882             return NS_ERROR_FAILURE;
00883         }        
00884     }
00885 
00886     PRInt32 nsId = kNameSpaceID_Unknown;
00887     nsresult rv = gTxNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsId);
00888     NS_ENSURE_SUCCESS(rv, rv);
00889     nsCOMPtr<nsIAtom> localName = do_GetAtom(aLocalName);
00890     txExpandedName varName(nsId, localName);
00891 
00892     txVariable* var = (txVariable*)mVariables.get(varName);
00893     if (var) {
00894         var->setValue(value);
00895         return NS_OK;
00896     }
00897 
00898     var = new txVariable(value);
00899     NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
00900 
00901     return mVariables.add(varName, var);
00902 }
00903 
00904 NS_IMETHODIMP
00905 txMozillaXSLTProcessor::GetParameter(const nsAString& aNamespaceURI,
00906                                      const nsAString& aLocalName,
00907                                      nsIVariant **aResult)
00908 {
00909     PRInt32 nsId = kNameSpaceID_Unknown;
00910     nsresult rv = gTxNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsId);
00911     NS_ENSURE_SUCCESS(rv, rv);
00912     nsCOMPtr<nsIAtom> localName = do_GetAtom(aLocalName);
00913     txExpandedName varName(nsId, localName);
00914 
00915     txVariable* var = (txVariable*)mVariables.get(varName);
00916     if (var) {
00917         return var->getValue(aResult);
00918     }
00919     return NS_OK;
00920 }
00921 
00922 NS_IMETHODIMP
00923 txMozillaXSLTProcessor::RemoveParameter(const nsAString& aNamespaceURI,
00924                                         const nsAString& aLocalName)
00925 {
00926     PRInt32 nsId = kNameSpaceID_Unknown;
00927     nsresult rv = gTxNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsId);
00928     NS_ENSURE_SUCCESS(rv, rv);
00929     nsCOMPtr<nsIAtom> localName = do_GetAtom(aLocalName);
00930     txExpandedName varName(nsId, localName);
00931 
00932     mVariables.remove(varName);
00933     return NS_OK;
00934 }
00935 
00936 NS_IMETHODIMP
00937 txMozillaXSLTProcessor::ClearParameters()
00938 {
00939     mVariables.clear();
00940 
00941     return NS_OK;
00942 }
00943 
00944 NS_IMETHODIMP
00945 txMozillaXSLTProcessor::Reset()
00946 {
00947     if (mStylesheetDocument) {
00948         mStylesheetDocument->RemoveObserver(this);
00949     }
00950     mStylesheet = nsnull;
00951     mStylesheetDocument = nsnull;
00952     mEmbeddedStylesheetRoot = nsnull;
00953     mCompileResult = NS_OK;
00954     mVariables.clear();
00955 
00956     return NS_OK;
00957 }
00958 
00959 static
00960 PRBool
00961 IsCallerChrome()
00962 {
00963   nsCOMPtr<nsIScriptSecurityManager> secman =
00964     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
00965   PRBool is_caller_chrome = PR_FALSE;
00966   nsresult rv = secman->SubjectPrincipalIsSystem(&is_caller_chrome);
00967   if (NS_FAILED(rv)) {
00968     return PR_FALSE;
00969   }
00970 
00971   return is_caller_chrome;
00972 }
00973 
00974 NS_IMETHODIMP
00975 txMozillaXSLTProcessor::SetFlags(PRUint32 aFlags)
00976 {
00977     NS_ENSURE_TRUE(IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
00978 
00979     mFlags = aFlags;
00980 
00981     return NS_OK;
00982 }
00983 
00984 NS_IMETHODIMP
00985 txMozillaXSLTProcessor::GetFlags(PRUint32* aFlags)
00986 {
00987     NS_ENSURE_TRUE(IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
00988 
00989     *aFlags = mFlags;
00990 
00991     return NS_OK;
00992 }
00993 
00994 NS_IMETHODIMP
00995 txMozillaXSLTProcessor::LoadStyleSheet(nsIURI* aUri, nsILoadGroup* aLoadGroup,
00996                                        nsIPrincipal* aCallerPrincipal)
00997 {
00998     nsresult rv = TX_LoadSheet(aUri, this, aLoadGroup, aCallerPrincipal);
00999     if (NS_FAILED(rv) && mObserver) {
01000         // This is most likely a network or security error, just
01001         // use the uri as context.
01002         nsCAutoString spec;
01003         if (aUri) {
01004             aUri->GetSpec(spec);
01005             CopyUTF8toUTF16(spec, mSourceText);
01006         }
01007         reportError(rv, nsnull, nsnull);
01008     }
01009     return rv;
01010 }
01011 
01012 nsresult
01013 txMozillaXSLTProcessor::setStylesheet(txStylesheet* aStylesheet)
01014 {
01015     mStylesheet = aStylesheet;
01016     if (mSource) {
01017         return DoTransform();
01018     }
01019     return NS_OK;
01020 }
01021 
01022 void
01023 txMozillaXSLTProcessor::reportError(nsresult aResult,
01024                                     const PRUnichar *aErrorText,
01025                                     const PRUnichar *aSourceText)
01026 {
01027     if (!mObserver) {
01028         return;
01029     }
01030 
01031     mTransformResult = aResult;
01032 
01033     if (aErrorText) {
01034         mErrorText.Assign(aErrorText);
01035     }
01036     else {
01037         nsCOMPtr<nsIStringBundleService> sbs =
01038             do_GetService(NS_STRINGBUNDLE_CONTRACTID);
01039         if (sbs) {
01040             nsXPIDLString errorText;
01041             sbs->FormatStatusMessage(aResult, EmptyString().get(),
01042                                      getter_Copies(errorText));
01043 
01044             nsXPIDLString errorMessage;
01045             nsCOMPtr<nsIStringBundle> bundle;
01046             sbs->CreateBundle(XSLT_MSGS_URL, getter_AddRefs(bundle));
01047 
01048             if (bundle) {
01049                 const PRUnichar* error[] = { errorText.get() };
01050                 if (mStylesheet) {
01051                     bundle->FormatStringFromName(NS_LITERAL_STRING("TransformError").get(),
01052                                                  error, 1,
01053                                                  getter_Copies(errorMessage));
01054                 }
01055                 else {
01056                     bundle->FormatStringFromName(NS_LITERAL_STRING("LoadingError").get(),
01057                                                  error, 1,
01058                                                  getter_Copies(errorMessage));
01059                 }
01060             }
01061             mErrorText.Assign(errorMessage);
01062         }
01063     }
01064 
01065     if (aSourceText) {
01066         mSourceText.Assign(aSourceText);
01067     }
01068 
01069     if (mSource) {
01070         notifyError();
01071     }
01072 }
01073 
01074 void
01075 txMozillaXSLTProcessor::notifyError()
01076 {
01077     nsresult rv;
01078     nsCOMPtr<nsIDOMDocument> errorDocument = do_CreateInstance(kXMLDocumentCID,
01079                                                                &rv);
01080     if (NS_FAILED(rv)) {
01081         return;
01082     }
01083 
01084     // Set up the document
01085     nsCOMPtr<nsIDocument> document = do_QueryInterface(errorDocument);
01086     if (!document) {
01087         return;
01088     }
01089     URIUtils::ResetWithSource(document, mSource);
01090 
01091     NS_NAMED_LITERAL_STRING(ns, "http://www.mozilla.org/newlayout/xml/parsererror.xml");
01092 
01093     nsCOMPtr<nsIDOMElement> element;
01094     rv = errorDocument->CreateElementNS(ns, NS_LITERAL_STRING("parsererror"),
01095                                         getter_AddRefs(element));
01096     if (NS_FAILED(rv)) {
01097         return;
01098     }
01099 
01100     nsCOMPtr<nsIContent> rootContent = do_QueryInterface(element);
01101     if (!rootContent) {
01102         return;
01103     }
01104 
01105     rv = document->SetRootContent(rootContent);
01106     if (NS_FAILED(rv)) {
01107         return;
01108     }
01109 
01110     nsCOMPtr<nsIDOMText> text;
01111     rv = errorDocument->CreateTextNode(mErrorText, getter_AddRefs(text));
01112     if (NS_FAILED(rv)) {
01113         return;
01114     }
01115 
01116     nsCOMPtr<nsIDOMNode> resultNode;
01117     rv = element->AppendChild(text, getter_AddRefs(resultNode));
01118     if (NS_FAILED(rv)) {
01119         return;
01120     }
01121 
01122     if (!mSourceText.IsEmpty()) {
01123         nsCOMPtr<nsIDOMElement> sourceElement;
01124         rv = errorDocument->CreateElementNS(ns,
01125                                             NS_LITERAL_STRING("sourcetext"),
01126                                             getter_AddRefs(sourceElement));
01127         if (NS_FAILED(rv)) {
01128             return;
01129         }
01130     
01131         rv = element->AppendChild(sourceElement, getter_AddRefs(resultNode));
01132         if (NS_FAILED(rv)) {
01133             return;
01134         }
01135 
01136         rv = errorDocument->CreateTextNode(mSourceText, getter_AddRefs(text));
01137         if (NS_FAILED(rv)) {
01138             return;
01139         }
01140     
01141         rv = sourceElement->AppendChild(text, getter_AddRefs(resultNode));
01142         if (NS_FAILED(rv)) {
01143             return;
01144         }
01145     }
01146 
01147     mObserver->OnTransformDone(mTransformResult, errorDocument);
01148 }
01149 
01150 nsresult
01151 txMozillaXSLTProcessor::ensureStylesheet()
01152 {
01153     if (mStylesheet) {
01154         return NS_OK;
01155     }
01156 
01157     NS_ENSURE_TRUE(mStylesheetDocument, NS_ERROR_NOT_INITIALIZED);
01158 
01159     nsCOMPtr<nsIDOMNode> style = do_QueryInterface(mEmbeddedStylesheetRoot);
01160     if (!style) {
01161         style = do_QueryInterface(mStylesheetDocument);
01162     }
01163     return TX_CompileStylesheet(style, this, getter_AddRefs(mStylesheet));
01164 }
01165 
01166 NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(txMozillaXSLTProcessor)
01167 NS_IMPL_NSIDOCUMENTOBSERVER_REFLOW_STUB(txMozillaXSLTProcessor)
01168 NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(txMozillaXSLTProcessor)
01169 NS_IMPL_NSIDOCUMENTOBSERVER_STATE_STUB(txMozillaXSLTProcessor)
01170 
01171 void
01172 txMozillaXSLTProcessor::BeginUpdate(nsIDocument* aDocument,
01173                                     nsUpdateType aUpdateType)
01174 {
01175 }
01176 
01177 void
01178 txMozillaXSLTProcessor::EndUpdate(nsIDocument* aDocument,
01179                                   nsUpdateType aUpdateType)
01180 {
01181 }
01182 
01183 void
01184 txMozillaXSLTProcessor::DocumentWillBeDestroyed(nsIDocument* aDocument)
01185 {
01186     if (NS_FAILED(mCompileResult)) {
01187         return;
01188     }
01189 
01190     mCompileResult = ensureStylesheet();
01191     mStylesheetDocument = nsnull;
01192     mEmbeddedStylesheetRoot = nsnull;
01193 
01194     // This might not be neccesary, but just in case some element ends up
01195     // causing a notification as the document goes away we don't want to
01196     // invalidate the stylesheet.
01197     aDocument->RemoveObserver(this);
01198 }
01199 
01200 void
01201 txMozillaXSLTProcessor::CharacterDataChanged(nsIDocument* aDocument,
01202                                              nsIContent *aContent,
01203                                              PRBool aAppend)
01204 {
01205     mStylesheet = nsnull;
01206 }
01207 
01208 void
01209 txMozillaXSLTProcessor::AttributeChanged(nsIDocument* aDocument,
01210                                          nsIContent* aContent,
01211                                          PRInt32 aNameSpaceID,
01212                                          nsIAtom* aAttribute,
01213                                          PRInt32 aModType)
01214 {
01215     mStylesheet = nsnull;
01216 }
01217 
01218 void
01219 txMozillaXSLTProcessor::ContentAppended(nsIDocument* aDocument,
01220                                         nsIContent* aContainer,
01221                                         PRInt32 aNewIndexInContainer)
01222 {
01223     mStylesheet = nsnull;
01224 }
01225 
01226 void
01227 txMozillaXSLTProcessor::ContentInserted(nsIDocument* aDocument,
01228                                         nsIContent* aContainer,
01229                                         nsIContent* aChild,
01230                                         PRInt32 aIndexInContainer)
01231 {
01232     mStylesheet = nsnull;
01233 }
01234 
01235 void
01236 txMozillaXSLTProcessor::ContentRemoved(nsIDocument* aDocument,
01237                                        nsIContent* aContainer,
01238                                        nsIContent* aChild,
01239                                        PRInt32 aIndexInContainer)
01240 {
01241     mStylesheet = nsnull;
01242 }
01243 
01244 /* static*/
01245 nsresult
01246 txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult)
01247 {
01248     *aResult = nsnull;
01249 
01250     PRUint16 dataType;
01251     aValue->GetDataType(&dataType);
01252     switch (dataType) {
01253         // Number
01254         case nsIDataType::VTYPE_INT8:
01255         case nsIDataType::VTYPE_INT16:
01256         case nsIDataType::VTYPE_INT32:
01257         case nsIDataType::VTYPE_INT64:
01258         case nsIDataType::VTYPE_UINT8:
01259         case nsIDataType::VTYPE_UINT16:
01260         case nsIDataType::VTYPE_UINT32:
01261         case nsIDataType::VTYPE_UINT64:
01262         case nsIDataType::VTYPE_FLOAT:
01263         case nsIDataType::VTYPE_DOUBLE:
01264         {
01265             double value;
01266             nsresult rv = aValue->GetAsDouble(&value);
01267             NS_ENSURE_SUCCESS(rv, rv);
01268 
01269             *aResult = new NumberResult(value, nsnull);
01270             NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
01271 
01272             NS_ADDREF(*aResult);
01273 
01274             return NS_OK;
01275         }
01276 
01277         // Boolean
01278         case nsIDataType::VTYPE_BOOL:
01279         {
01280             PRBool value;
01281             nsresult rv = aValue->GetAsBool(&value);
01282             NS_ENSURE_SUCCESS(rv, rv);
01283 
01284             *aResult = new BooleanResult(value);
01285             NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
01286 
01287             NS_ADDREF(*aResult);
01288 
01289             return NS_OK;
01290         }
01291 
01292         // String
01293         case nsIDataType::VTYPE_CHAR:
01294         case nsIDataType::VTYPE_WCHAR:
01295         case nsIDataType::VTYPE_DOMSTRING:
01296         case nsIDataType::VTYPE_CHAR_STR:
01297         case nsIDataType::VTYPE_WCHAR_STR:
01298         case nsIDataType::VTYPE_STRING_SIZE_IS:
01299         case nsIDataType::VTYPE_WSTRING_SIZE_IS:
01300         case nsIDataType::VTYPE_UTF8STRING:
01301         case nsIDataType::VTYPE_CSTRING:
01302         case nsIDataType::VTYPE_ASTRING:
01303         {
01304             nsAutoString value;
01305             nsresult rv = aValue->GetAsAString(value);
01306             NS_ENSURE_SUCCESS(rv, rv);
01307 
01308             *aResult = new StringResult(value, nsnull);
01309             NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
01310 
01311             NS_ADDREF(*aResult);
01312 
01313             return NS_OK;
01314         }
01315 
01316         // Nodeset
01317         case nsIDataType::VTYPE_INTERFACE:
01318         case nsIDataType::VTYPE_INTERFACE_IS:
01319         {
01320             nsCOMPtr<nsISupports> supports;
01321             nsresult rv = aValue->GetAsISupports(getter_AddRefs(supports));
01322             NS_ENSURE_SUCCESS(rv, rv);
01323 
01324             nsCOMPtr<nsIDOMNode> node = do_QueryInterface(supports);
01325             if (node) {
01326                 nsAutoPtr<txXPathNode> xpathNode(txXPathNativeNode::createXPathNode(node));
01327                 if (!xpathNode) {
01328                     return NS_ERROR_FAILURE;
01329                 }
01330 
01331                 *aResult = new txNodeSet(*xpathNode, nsnull);
01332                 if (!*aResult) {
01333                     return NS_ERROR_OUT_OF_MEMORY;
01334                 }
01335 
01336                 NS_ADDREF(*aResult);
01337 
01338                 return NS_OK;
01339             }
01340 
01341             nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(supports);
01342             if (xpathResult) {
01343                 return xpathResult->GetExprResult(aResult);
01344             }
01345 
01346             nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
01347             if (nodeList) {
01348                 nsRefPtr<txNodeSet> nodeSet = new txNodeSet(nsnull);
01349                 if (!nodeSet) {
01350                     return NS_ERROR_OUT_OF_MEMORY;
01351                 }
01352 
01353                 PRUint32 length;
01354                 nodeList->GetLength(&length);
01355 
01356                 nsCOMPtr<nsIDOMNode> node;
01357                 PRUint32 i;
01358                 for (i = 0; i < length; ++i) {
01359                     nodeList->Item(i, getter_AddRefs(node));
01360 
01361                     nsAutoPtr<txXPathNode> xpathNode(
01362                         txXPathNativeNode::createXPathNode(node));
01363                     if (!xpathNode) {
01364                         return NS_ERROR_FAILURE;
01365                     }
01366 
01367                     nodeSet->add(*xpathNode);
01368                 }
01369 
01370                 NS_ADDREF(*aResult = nodeSet);
01371 
01372                 return NS_OK;
01373             }
01374 
01375             // Convert random JS Objects to a string.
01376             nsCOMPtr<nsIXPConnectJSObjectHolder> holder =
01377                 do_QueryInterface(supports);
01378             if (holder) {
01379                 nsCOMPtr<nsIXPConnect> xpc =
01380                     do_GetService(nsIXPConnect::GetCID(), &rv);
01381                 NS_ENSURE_SUCCESS(rv, rv);
01382                 
01383                 nsCOMPtr<nsIXPCNativeCallContext> cc;
01384                 rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
01385                 NS_ENSURE_SUCCESS(rv, rv);
01386 
01387                 JSContext* cx;
01388                 rv = cc->GetJSContext(&cx);
01389                 NS_ENSURE_SUCCESS(rv, rv);
01390 
01391                 JSObject *jsobj;
01392                 rv = holder->GetJSObject(&jsobj);
01393                 NS_ENSURE_SUCCESS(rv, rv);
01394 
01395                 JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj));
01396                 NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
01397 
01398                 const PRUnichar *strChars =
01399                     NS_REINTERPRET_CAST(const PRUnichar*,
01400                                         ::JS_GetStringChars(str));
01401                 nsDependentString value(strChars, ::JS_GetStringLength(str));
01402 
01403                 *aResult = new StringResult(value, nsnull);
01404                 if (!*aResult) {
01405                     return NS_ERROR_OUT_OF_MEMORY;
01406                 }
01407 
01408                 NS_ADDREF(*aResult);
01409 
01410                 return NS_OK;
01411             }
01412 
01413             break;
01414         }
01415 
01416         case nsIDataType::VTYPE_ARRAY:
01417         {
01418             PRUint16 type;
01419             nsIID iid;
01420             PRUint32 count;
01421             void* array;
01422             nsresult rv = aValue->GetAsArray(&type, &iid, &count, &array);
01423             NS_ENSURE_SUCCESS(rv, rv);
01424 
01425             NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
01426                          type == nsIDataType::VTYPE_INTERFACE_IS,
01427                          "Huh, we checked this in SetParameter?");
01428 
01429             nsISupports** values = NS_STATIC_CAST(nsISupports**, array);
01430 
01431             nsRefPtr<txNodeSet> nodeSet = new txNodeSet(nsnull);
01432             if (!nodeSet) {
01433                 NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, values);
01434 
01435                 return NS_ERROR_OUT_OF_MEMORY;
01436             }
01437 
01438             PRUint32 i;
01439             for (i = 0; i < count; ++i) {
01440                 nsISupports *supports = values[i];
01441                 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(supports);
01442                 NS_ASSERTION(node, "Huh, we checked this in SetParameter?");
01443 
01444                 nsAutoPtr<txXPathNode> xpathNode(
01445                     txXPathNativeNode::createXPathNode(node));
01446                 if (!xpathNode) {
01447                     while (i < count) {
01448                         NS_RELEASE(values[i++]);
01449                     }
01450                     nsMemory::Free(array);
01451 
01452                     return NS_ERROR_FAILURE;
01453                 }
01454 
01455                 nodeSet->add(*xpathNode);
01456 
01457                 NS_RELEASE(supports);
01458             }
01459 
01460             nsMemory::Free(array);
01461 
01462             NS_ADDREF(*aResult = nodeSet);
01463 
01464             return NS_OK;
01465         }
01466     }
01467 
01468     return NS_ERROR_ILLEGAL_VALUE;
01469 }