From 08c98d6b62f4d3f1d3d780450abdf6867ded5b4d Mon Sep 17 00:00:00 2001 From: "peterv%propagandism.org" Date: Thu, 18 Aug 2005 09:14:10 +0000 Subject: [PATCH] Fix for bug 248025 (cannot add a DOM Node as an xsl:param using XSLTProcessor.setParameter()). r=Pike, sr=jst. --- .../source/xpath/nsXPathResult.cpp | 288 +++++++++-------- .../transformiix/source/xpath/nsXPathResult.h | 68 +++- .../source/xpath/txXPathTreeWalker.h | 11 + .../source/xslt/txMozillaXSLTProcessor.cpp | 295 +++++++++++++++++- 4 files changed, 494 insertions(+), 168 deletions(-) diff --git a/extensions/transformiix/source/xpath/nsXPathResult.cpp b/extensions/transformiix/source/xpath/nsXPathResult.cpp index 1f5be87ddaba..8dea3939b8b1 100644 --- a/extensions/transformiix/source/xpath/nsXPathResult.cpp +++ b/extensions/transformiix/source/xpath/nsXPathResult.cpp @@ -47,8 +47,7 @@ #include "nsIDOMDocument.h" #include "nsDOMString.h" -nsXPathResult::nsXPathResult() : mNumberValue(0), - mDocument(0), +nsXPathResult::nsXPathResult() : mDocument(nsnull), mCurrentPos(0), mResultType(ANY_TYPE), mInvalidIteratorState(PR_TRUE) @@ -57,7 +56,9 @@ nsXPathResult::nsXPathResult() : mNumberValue(0), nsXPathResult::~nsXPathResult() { - Reset(); + if (mDocument) { + mDocument->RemoveObserver(this); + } } NS_IMPL_ADDREF(nsXPathResult) @@ -73,125 +74,124 @@ NS_INTERFACE_MAP_END NS_IMETHODIMP nsXPathResult::GetResultType(PRUint16 *aResultType) { - NS_ENSURE_ARG(aResultType); *aResultType = mResultType; + return NS_OK; } NS_IMETHODIMP nsXPathResult::GetNumberValue(double *aNumberValue) { - if (mResultType != NUMBER_TYPE) + if (mResultType != NUMBER_TYPE) { return NS_ERROR_DOM_TYPE_ERR; + } + + *aNumberValue = mResult.get()->numberValue(); - NS_ENSURE_ARG(aNumberValue); - *aNumberValue = mNumberValue; return NS_OK; } NS_IMETHODIMP nsXPathResult::GetStringValue(nsAString &aStringValue) { - if (mResultType != STRING_TYPE) + if (mResultType != STRING_TYPE) { return NS_ERROR_DOM_TYPE_ERR; + } + + mResult.get()->stringValue(aStringValue); - if (mStringValue) - aStringValue.Assign(*mStringValue); - else - SetDOMStringToNull(aStringValue); return NS_OK; } NS_IMETHODIMP nsXPathResult::GetBooleanValue(PRBool *aBooleanValue) { - if (mResultType != BOOLEAN_TYPE) + if (mResultType != BOOLEAN_TYPE) { return NS_ERROR_DOM_TYPE_ERR; + } + + *aBooleanValue = mResult.get()->booleanValue(); - NS_ENSURE_ARG(aBooleanValue); - *aBooleanValue = mBooleanValue; return NS_OK; } NS_IMETHODIMP nsXPathResult::GetSingleNodeValue(nsIDOMNode **aSingleNodeValue) { - if (mResultType != FIRST_ORDERED_NODE_TYPE && - mResultType != ANY_UNORDERED_NODE_TYPE) + if (!isNode()) { return NS_ERROR_DOM_TYPE_ERR; + } + + txNodeSet *nodeSet = NS_STATIC_CAST(txNodeSet*, mResult.get()); + if (nodeSet->size() > 0) { + return txXPathNativeNode::getNode(nodeSet->get(0), aSingleNodeValue); + } + + *aSingleNodeValue = nsnull; - NS_ENSURE_ARG(aSingleNodeValue); - *aSingleNodeValue = mNode; - NS_IF_ADDREF(*aSingleNodeValue); return NS_OK; } NS_IMETHODIMP nsXPathResult::GetInvalidIteratorState(PRBool *aInvalidIteratorState) { - NS_ENSURE_ARG(aInvalidIteratorState); + *aInvalidIteratorState = isIterator() && mInvalidIteratorState; - if (mResultType != UNORDERED_NODE_ITERATOR_TYPE && - mResultType != ORDERED_NODE_ITERATOR_TYPE) { - *aInvalidIteratorState = PR_FALSE; - return NS_OK; - } - - *aInvalidIteratorState = mInvalidIteratorState; return NS_OK; } NS_IMETHODIMP nsXPathResult::GetSnapshotLength(PRUint32 *aSnapshotLength) { - if (mResultType != UNORDERED_NODE_SNAPSHOT_TYPE && - mResultType != ORDERED_NODE_SNAPSHOT_TYPE) + if (!isSnapshot()) { return NS_ERROR_DOM_TYPE_ERR; + } + + txNodeSet *nodeSet = NS_STATIC_CAST(txNodeSet*, mResult.get()); + *aSnapshotLength = (PRUint32)nodeSet->size(); - NS_ENSURE_ARG(aSnapshotLength); - *aSnapshotLength = 0; - if (mElements) - *aSnapshotLength = mElements->Count(); return NS_OK; } NS_IMETHODIMP nsXPathResult::IterateNext(nsIDOMNode **aResult) { - if (mResultType != UNORDERED_NODE_ITERATOR_TYPE && - mResultType != ORDERED_NODE_ITERATOR_TYPE) + if (!isIterator()) { return NS_ERROR_DOM_TYPE_ERR; - - if (mDocument) - mDocument->FlushPendingNotifications(Flush_Content); - - if (mInvalidIteratorState) - return NS_ERROR_DOM_INVALID_STATE_ERR; - - NS_ENSURE_ARG(aResult); - if (mElements && mCurrentPos < (PRUint32)mElements->Count()) { - *aResult = mElements->ObjectAt(mCurrentPos++); - NS_ADDREF(*aResult); - return NS_OK; } + + if (mDocument) { + mDocument->FlushPendingNotifications(Flush_Content); + } + + if (mInvalidIteratorState) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + txNodeSet *nodeSet = NS_STATIC_CAST(txNodeSet*, mResult.get()); + if (mCurrentPos < (PRUint32)nodeSet->size()) { + return txXPathNativeNode::getNode(nodeSet->get(mCurrentPos), aResult); + } + *aResult = nsnull; + return NS_OK; } NS_IMETHODIMP nsXPathResult::SnapshotItem(PRUint32 aIndex, nsIDOMNode **aResult) { - if (mResultType != UNORDERED_NODE_SNAPSHOT_TYPE && - mResultType != ORDERED_NODE_SNAPSHOT_TYPE) + if (!isSnapshot()) { return NS_ERROR_DOM_TYPE_ERR; - - NS_ENSURE_ARG(aResult); - if (mElements && aIndex < (PRUint32)mElements->Count()) { - *aResult = mElements->ObjectAt(aIndex); - NS_ADDREF(*aResult); - return NS_OK; } + + txNodeSet *nodeSet = NS_STATIC_CAST(txNodeSet*, mResult.get()); + if (aIndex < (PRUint32)nodeSet->size()) { + return txXPathNativeNode::getNode(nodeSet->get(aIndex), aResult); + } + *aResult = nsnull; + return NS_OK; } @@ -245,81 +245,48 @@ nsXPathResult::ContentRemoved(nsIDocument* aDocument, Invalidate(); } -NS_IMETHODIMP +nsresult nsXPathResult::SetExprResult(txAExprResult* aExprResult, PRUint16 aResultType) { - Reset(); + if (mDocument) { + mDocument->RemoveObserver(this); + mDocument = nsnull; + } mResultType = aResultType; + mResult.set(aExprResult); - if (mResultType == NUMBER_TYPE) { - mNumberValue = aExprResult->numberValue(); + if (!isIterator()) { return NS_OK; } - if (mResultType == STRING_TYPE) { - mStringValue = new nsString; - NS_ENSURE_TRUE(mStringValue, NS_ERROR_OUT_OF_MEMORY); - aExprResult->stringValue(*mStringValue); - return NS_OK; - } + mInvalidIteratorState = PR_FALSE; - if (mResultType == BOOLEAN_TYPE) { - mBooleanValue = aExprResult->booleanValue(); - return NS_OK; - } + txNodeSet* nodeSet = NS_STATIC_CAST(txNodeSet*, aExprResult); + nsCOMPtr node; + if (nodeSet->size() > 0) { + nsresult rv = txXPathNativeNode::getNode(nodeSet->get(0), + getter_AddRefs(node)); + NS_ENSURE_SUCCESS(rv, rv); - if (aExprResult->getResultType() == txAExprResult::NODESET) { - nsresult rv = NS_OK; - txNodeSet* nodeSet = NS_STATIC_CAST(txNodeSet*, aExprResult); - - if (mResultType == FIRST_ORDERED_NODE_TYPE || - mResultType == ANY_UNORDERED_NODE_TYPE) { - if (nodeSet->size() > 0) { - txXPathNativeNode::getNode(nodeSet->get(0), &mNode); - } + // If we support the document() function in DOM-XPath we need to + // observe all documents that we have resultnodes in. + nsCOMPtr document; + node->GetOwnerDocument(getter_AddRefs(document)); + if (document) { + mDocument = do_QueryInterface(document); } else { - if (mResultType == UNORDERED_NODE_ITERATOR_TYPE || - mResultType == ORDERED_NODE_ITERATOR_TYPE) { - mInvalidIteratorState = PR_FALSE; - } - - PRInt32 count = nodeSet->size(); - if (count == 0) - return NS_OK; - - mElements = new nsCOMArray; - NS_ENSURE_TRUE(mElements, NS_ERROR_OUT_OF_MEMORY); - - nsCOMPtr node; - PRInt32 i; - for (i = 0; i < count; ++i) { - txXPathNativeNode::getNode(nodeSet->get(i), getter_AddRefs(node)); - NS_ASSERTION(node, "node isn't an nsIDOMNode"); - mElements->AppendObject(node); - } - - // If we support the document() function in DOM-XPath we need to - // observe all documents that we have resultnodes in. - if (mResultType == UNORDERED_NODE_ITERATOR_TYPE || - mResultType == ORDERED_NODE_ITERATOR_TYPE) { - nsCOMPtr document; - node->GetOwnerDocument(getter_AddRefs(document)); - if (document) - mDocument = do_QueryInterface(document); - else - mDocument = do_QueryInterface(node); - - NS_ASSERTION(mDocument, "We need a document!"); - if (mDocument) - mDocument->AddObserver(this); - } + mDocument = do_QueryInterface(node); + } + + NS_ASSERTION(mDocument, "We need a document!"); + if (mDocument) { + mDocument->AddObserver(this); } - return rv; } - return NS_ERROR_DOM_TYPE_ERR; + return NS_OK; } void @@ -327,32 +294,79 @@ nsXPathResult::Invalidate() { if (mDocument) { mDocument->RemoveObserver(this); - mDocument = 0; + mDocument = nsnull; } mInvalidIteratorState = PR_TRUE; } -void -nsXPathResult::Reset() +nsresult +nsXPathResult::GetExprResult(txAExprResult** aExprResult) { - Invalidate(); - - if (mResultType == STRING_TYPE) { - delete mStringValue; - mStringValue = 0; - } - else if (mResultType == UNORDERED_NODE_ITERATOR_TYPE || - mResultType == ORDERED_NODE_ITERATOR_TYPE || - mResultType == UNORDERED_NODE_SNAPSHOT_TYPE || - mResultType == ORDERED_NODE_SNAPSHOT_TYPE) { - delete mElements; - mCurrentPos = 0; - } - else if (mResultType == FIRST_ORDERED_NODE_TYPE || - mResultType == ANY_UNORDERED_NODE_TYPE) { - NS_IF_RELEASE(mNode); + if (isIterator() && mInvalidIteratorState) { + return NS_ERROR_DOM_INVALID_STATE_ERR; } - mResultType = ANY_TYPE; - return; + *aExprResult = mResult.get(); + if (!*aExprResult) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + NS_ADDREF(*aExprResult); + + return NS_OK; +} + +nsresult +nsXPathResult::Clone(nsIXPathResult **aResult) +{ + *aResult = nsnull; + + if (isIterator() && mInvalidIteratorState) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + nsCOMPtr result = new nsXPathResult(); + if (!result) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = result->SetExprResult(mResult.get(), mResultType); + NS_ENSURE_SUCCESS(rv, rv); + + result.swap(*aResult); + + return NS_OK; +} + +void +txResultHolder::set(txAExprResult *aResult) +{ + releaseNodeSet(); + + // XXX This will keep the recycler alive, should we clear it? + mResult = aResult; + + if (mResult && mResult->getResultType() == txAExprResult::NODESET) { + txNodeSet *nodeSet = + NS_STATIC_CAST(txNodeSet*, + NS_STATIC_CAST(txAExprResult*, mResult)); + PRInt32 i, count = nodeSet->size(); + for (i = 0; i < count; ++i) { + txXPathNativeNode::addRef(nodeSet->get(i)); + } + } +} + +void +txResultHolder::releaseNodeSet() +{ + if (mResult && mResult->getResultType() == txAExprResult::NODESET) { + txNodeSet *nodeSet = + NS_STATIC_CAST(txNodeSet*, + NS_STATIC_CAST(txAExprResult*, mResult)); + PRInt32 i, count = nodeSet->size(); + for (i = 0; i < count; ++i) { + txXPathNativeNode::release(nodeSet->get(i)); + } + } } diff --git a/extensions/transformiix/source/xpath/nsXPathResult.h b/extensions/transformiix/source/xpath/nsXPathResult.h index e186607f0d18..ca58e6566a24 100644 --- a/extensions/transformiix/source/xpath/nsXPathResult.h +++ b/extensions/transformiix/source/xpath/nsXPathResult.h @@ -39,14 +39,13 @@ #ifndef nsXPathResult_h__ #define nsXPathResult_h__ +#include "ExprResult.h" #include "nsIDOMXPathResult.h" #include "nsIDocument.h" #include "nsIDocumentObserver.h" #include "nsCOMPtr.h" #include "nsCOMArray.h" -class txAExprResult; - // {15b9b301-2012-11d6-a7f2-e6d0a678995c} #define NS_IXPATHRESULT_IID \ { 0x15b9b301, 0x2012, 0x11d6, {0xa7, 0xf2, 0xe6, 0xd0, 0xa6, 0x78, 0x99, 0x5c }}; @@ -55,8 +54,34 @@ class nsIXPathResult : public nsISupports { public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_IXPATHRESULT_IID) - NS_IMETHOD SetExprResult(txAExprResult* aExprResult, - PRUint16 aResultType) = 0; + virtual nsresult SetExprResult(txAExprResult *aExprResult, + PRUint16 aResultType) = 0; + virtual nsresult GetExprResult(txAExprResult **aExprResult) = 0; + virtual nsresult Clone(nsIXPathResult **aResult) = 0; +}; + +/** + * Helper class to keep Mozilla node objects alive as long as the nodeset is + * alive. + */ +class txResultHolder +{ +public: + ~txResultHolder() + { + releaseNodeSet(); + } + + txAExprResult *get() + { + return mResult; + } + void set(txAExprResult *aResult); + +private: + void releaseNodeSet(); + + nsRefPtr mResult; }; /** @@ -80,19 +105,30 @@ public: NS_DECL_NSIDOCUMENTOBSERVER // nsIXPathResult interface - NS_IMETHOD SetExprResult(txAExprResult* aExprResult, - PRUint16 aResultType); -private: - void Invalidate(); - void Reset(); + nsresult SetExprResult(txAExprResult *aExprResult, PRUint16 aResultType); + nsresult GetExprResult(txAExprResult **aExprResult); + nsresult Clone(nsIXPathResult **aResult); - union { - double mNumberValue; - nsString* mStringValue; - PRBool mBooleanValue; - nsIDOMNode* mNode; - nsCOMArray* mElements; - }; +private: + PRBool isSnapshot() const + { + return mResultType == UNORDERED_NODE_SNAPSHOT_TYPE || + mResultType == ORDERED_NODE_SNAPSHOT_TYPE; + } + PRBool isIterator() const + { + return mResultType == UNORDERED_NODE_ITERATOR_TYPE || + mResultType == ORDERED_NODE_ITERATOR_TYPE; + } + PRBool isNode() const + { + return mResultType == FIRST_ORDERED_NODE_TYPE || + mResultType == ANY_UNORDERED_NODE_TYPE; + } + + void Invalidate(); + + txResultHolder mResult; nsCOMPtr mDocument; PRUint32 mCurrentPos; PRUint16 mResultType; diff --git a/extensions/transformiix/source/xpath/txXPathTreeWalker.h b/extensions/transformiix/source/xpath/txXPathTreeWalker.h index a00c4c9165cd..e86146c43b18 100644 --- a/extensions/transformiix/source/xpath/txXPathTreeWalker.h +++ b/extensions/transformiix/source/xpath/txXPathTreeWalker.h @@ -162,6 +162,17 @@ public: static nsresult getNode(const txXPathNode& aNode, nsIDOMNode** aResult); static nsIContent* getContent(const txXPathNode& aNode); static nsIDocument* getDocument(const txXPathNode& aNode); + static void addRef(const txXPathNode& aNode) + { + // Hopefully it's ok to access mContent through mDocument. + NS_ADDREF(aNode.mDocument); + } + static void release(const txXPathNode& aNode) + { + // Hopefully it's ok to access mContent through mDocument. + nsISupports *node = aNode.mDocument; + NS_RELEASE(node); + } }; #endif diff --git a/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp b/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp index 2625308a24db..bf45f7131f94 100644 --- a/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp +++ b/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp @@ -47,12 +47,14 @@ #include "nsIDOMClassInfo.h" #include "nsIDOMDocument.h" #include "nsIDOMDocumentFragment.h" +#include "nsIDOMNodeList.h" #include "nsIIOService.h" #include "nsILoadGroup.h" #include "nsIScriptLoader.h" #include "nsIStringBundle.h" #include "nsIURI.h" #include "nsNetUtil.h" +#include "nsXPathResult.h" #include "txExecutionState.h" #include "txMozillaTextOutput.h" #include "txMozillaXMLOutput.h" @@ -61,6 +63,7 @@ #include "txUnknownHandler.h" #include "txXSLTProcessor.h" #include "nsIPrincipal.h" +#include "jsapi.h" static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID); @@ -482,8 +485,11 @@ txMozillaXSLTProcessor::SetParameter(const nsAString & aNamespaceURI, nsIVariant *aValue) { NS_ENSURE_ARG(aValue); + + nsCOMPtr value = aValue; + PRUint16 dataType; - aValue->GetDataType(&dataType); + value->GetDataType(&dataType); switch (dataType) { // Number case nsIDataType::VTYPE_INT8: @@ -511,14 +517,145 @@ txMozillaXSLTProcessor::SetParameter(const nsAString & aNamespaceURI, case nsIDataType::VTYPE_UTF8STRING: case nsIDataType::VTYPE_CSTRING: case nsIDataType::VTYPE_ASTRING: + { + break; + } // Nodeset case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_INTERFACE_IS: + { + nsCOMPtr supports; + nsresult rv = value->GetAsISupports(getter_AddRefs(supports)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr node = do_QueryInterface(supports); + if (node) { + if (!URIUtils::CanCallerAccess(node)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + break; + } + + nsCOMPtr xpathResult = do_QueryInterface(supports); + if (xpathResult) { + nsRefPtr result; + nsresult rv = xpathResult->GetExprResult(getter_AddRefs(result)); + NS_ENSURE_SUCCESS(rv, rv); + + if (result->getResultType() == txAExprResult::NODESET) { + txNodeSet *nodeSet = + NS_STATIC_CAST(txNodeSet*, + NS_STATIC_CAST(txAExprResult*, result)); + + nsCOMPtr node; + PRInt32 i, count = nodeSet->size(); + for (i = 0; i < count; ++i) { + rv = txXPathNativeNode::getNode(nodeSet->get(i), + getter_AddRefs(node)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!URIUtils::CanCallerAccess(node)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + } + } + + // Clone the nsXPathResult so that mutations don't affect this + // variable. + nsCOMPtr clone; + rv = xpathResult->Clone(getter_AddRefs(clone)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr variant = + do_CreateInstance("@mozilla.org/variant;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = variant->SetAsISupports(clone); + NS_ENSURE_SUCCESS(rv, rv); + + value = variant; + + break; + } + + nsCOMPtr nodeList = do_QueryInterface(supports); + if (nodeList) { + PRUint32 length; + nodeList->GetLength(&length); + + nsCOMPtr node; + PRUint32 i; + for (i = 0; i < length; ++i) { + nodeList->Item(i, getter_AddRefs(node)); + + if (!URIUtils::CanCallerAccess(node)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + } + + break; + } + + // Random JS Objects will be converted to a string. + nsCOMPtr holder = + do_QueryInterface(supports); + if (holder) { + break; + } + + // We don't know how to handle this type of param. + return NS_ERROR_ILLEGAL_VALUE; + } + case nsIDataType::VTYPE_ARRAY: { - // This might still be an error, but we'll only - // find out later since we lazily evaluate. + PRUint16 type; + nsIID iid; + PRUint32 count; + void* array; + nsresult rv = value->GetAsArray(&type, &iid, &count, &array); + NS_ENSURE_SUCCESS(rv, rv); + + if (type != nsIDataType::VTYPE_INTERFACE && + type != nsIDataType::VTYPE_INTERFACE_IS) { + nsMemory::Free(array); + + // We only support arrays of DOM nodes. + return NS_ERROR_ILLEGAL_VALUE; + } + + nsISupports** values = NS_STATIC_CAST(nsISupports**, array); + + PRUint32 i; + for (i = 0; i < count; ++i) { + nsISupports *supports = values[i]; + nsCOMPtr node = do_QueryInterface(supports); + + if (node) { + rv = URIUtils::CanCallerAccess(node) ? NS_OK : + NS_ERROR_DOM_SECURITY_ERR; + } + else { + // We only support arrays of DOM nodes. + rv = NS_ERROR_ILLEGAL_VALUE; + } + + if (NS_FAILED(rv)) { + while (i < count) { + NS_RELEASE(values[i++]); + } + nsMemory::Free(array); + + return rv; + } + + NS_RELEASE(supports); + } + + nsMemory::Free(array); + break; } @@ -536,11 +673,11 @@ txMozillaXSLTProcessor::SetParameter(const nsAString & aNamespaceURI, txVariable* var = (txVariable*)mVariables.get(varName); if (var) { - var->setValue(aValue); + var->setValue(value); return NS_OK; } - var = new txVariable(aValue); + var = new txVariable(value); NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); return mVariables.add(varName, var); @@ -927,25 +1064,153 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult) case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_INTERFACE_IS: { - nsID *iid; nsCOMPtr supports; - nsresult rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports)); + nsresult rv = aValue->GetAsISupports(getter_AddRefs(supports)); NS_ENSURE_SUCCESS(rv, rv); - if (iid) { - // XXX Figure out what the user added and if we can do - // anything with it. - // nsIDOMNode, nsIDOMNodeList, nsIDOMXPathResult - nsMemory::Free(iid); + + nsCOMPtr node = do_QueryInterface(supports); + if (node) { + nsAutoPtr xpathNode(txXPathNativeNode::createXPathNode(node)); + if (!xpathNode) { + return NS_ERROR_FAILURE; + } + + *aResult = new txNodeSet(*xpathNode, nsnull); + if (!*aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult); + + return NS_OK; } + + nsCOMPtr xpathResult = do_QueryInterface(supports); + if (xpathResult) { + return xpathResult->GetExprResult(aResult); + } + + nsCOMPtr nodeList = do_QueryInterface(supports); + if (nodeList) { + nsRefPtr nodeSet = new txNodeSet(nsnull); + if (!nodeSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + PRUint32 length; + nodeList->GetLength(&length); + + nsCOMPtr node; + PRUint32 i; + for (i = 0; i < length; ++i) { + nodeList->Item(i, getter_AddRefs(node)); + + txXPathNode *xpathNode = + txXPathNativeNode::createXPathNode(node); + if (!xpathNode) { + return NS_ERROR_FAILURE; + } + + nodeSet->add(*xpathNode); + } + + NS_ADDREF(*aResult = nodeSet); + + return NS_OK; + } + + // Convert random JS Objects to a string. + nsCOMPtr holder = + do_QueryInterface(supports); + if (holder) { + nsCOMPtr xpc = + do_GetService(nsIXPConnect::GetCID(), &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr cc; + rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc)); + NS_ENSURE_SUCCESS(rv, rv); + + JSContext* cx; + rv = cc->GetJSContext(&cx); + NS_ENSURE_SUCCESS(rv, rv); + + JSObject *jsobj; + rv = holder->GetJSObject(&jsobj); + NS_ENSURE_SUCCESS(rv, rv); + + JSString *str = JS_ValueToString(cx, OBJECT_TO_JSVAL(jsobj)); + NS_ENSURE_TRUE(str, NS_ERROR_FAILURE); + + const PRUnichar *strChars = + NS_REINTERPRET_CAST(const PRUnichar*, + ::JS_GetStringChars(str)); + nsDependentString value(strChars, ::JS_GetStringLength(str)); + + *aResult = new StringResult(value, nsnull); + if (!*aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult); + + return NS_OK; + } + break; } case nsIDataType::VTYPE_ARRAY: { - // XXX Figure out what the user added and if we can do - // anything with it. Array of Nodes. - break; + PRUint16 type; + nsIID iid; + PRUint32 count; + void* array; + nsresult rv = aValue->GetAsArray(&type, &iid, &count, &array); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE || + type == nsIDataType::VTYPE_INTERFACE_IS, + "Huh, we checked this in SetParameter?"); + + nsISupports** values = NS_STATIC_CAST(nsISupports**, array); + + nsRefPtr nodeSet = new txNodeSet(nsnull); + if (!nodeSet) { + NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, values); + + return NS_ERROR_OUT_OF_MEMORY; + } + + PRUint32 i; + for (i = 0; i < count; ++i) { + nsISupports *supports = values[i]; + nsCOMPtr node = do_QueryInterface(supports); + NS_ASSERTION(node, "Huh, we checked this in SetParameter?"); + + txXPathNode *xpathNode = + txXPathNativeNode::createXPathNode(node); + if (!xpathNode) { + while (i < count) { + NS_RELEASE(values[i++]); + } + nsMemory::Free(array); + + return NS_ERROR_FAILURE; + } + + nodeSet->add(*xpathNode); + + NS_RELEASE(supports); + } + + nsMemory::Free(array); + + NS_ADDREF(*aResult = nodeSet); + + return NS_OK; } } + return NS_ERROR_ILLEGAL_VALUE; }