michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/XPathEvaluator.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsXPathExpression.h" michael@0: #include "nsXPathNSResolver.h" michael@0: #include "nsXPathResult.h" michael@0: #include "nsContentCID.h" michael@0: #include "txExpr.h" michael@0: #include "txExprParser.h" michael@0: #include "nsError.h" michael@0: #include "txURIUtils.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsDOMString.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsContentUtils.h" michael@0: #include "mozilla/dom/XPathEvaluatorBinding.h" michael@0: michael@0: extern nsresult michael@0: TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID, michael@0: nsIAtom *aName, nsISupports *aState, michael@0: FunctionCall **aFunction); michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: // txIParseContext implementation michael@0: class XPathEvaluatorParseContext : public txIParseContext michael@0: { michael@0: public: michael@0: XPathEvaluatorParseContext(nsIDOMXPathNSResolver* aResolver, michael@0: bool aIsCaseSensitive) michael@0: : mResolver(aResolver), michael@0: mLastError(NS_OK), michael@0: mIsCaseSensitive(aIsCaseSensitive) michael@0: { michael@0: } michael@0: michael@0: nsresult getError() michael@0: { michael@0: return mLastError; michael@0: } michael@0: michael@0: nsresult resolveNamespacePrefix(nsIAtom* aPrefix, int32_t& aID); michael@0: nsresult resolveFunctionCall(nsIAtom* aName, int32_t aID, michael@0: FunctionCall** aFunction); michael@0: bool caseInsensitiveNameTests(); michael@0: void SetErrorOffset(uint32_t aOffset); michael@0: michael@0: private: michael@0: nsIDOMXPathNSResolver* mResolver; michael@0: nsresult mLastError; michael@0: bool mIsCaseSensitive; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(XPathEvaluator, nsIDOMXPathEvaluator) michael@0: michael@0: XPathEvaluator::XPathEvaluator(nsIDocument* aDocument) michael@0: : mDocument(do_GetWeakReference(aDocument)) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XPathEvaluator::CreateNSResolver(nsIDOMNode *aNodeResolver, michael@0: nsIDOMXPathNSResolver **aResult) michael@0: { michael@0: NS_ENSURE_ARG(aNodeResolver); michael@0: if (!nsContentUtils::CanCallerAccess(aNodeResolver)) michael@0: return NS_ERROR_DOM_SECURITY_ERR; michael@0: michael@0: *aResult = new nsXPathNSResolver(aNodeResolver); michael@0: NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XPathEvaluator::Evaluate(const nsAString & aExpression, michael@0: nsIDOMNode *aContextNode, michael@0: nsIDOMXPathNSResolver *aResolver, michael@0: uint16_t aType, michael@0: nsISupports *aInResult, michael@0: nsISupports **aResult) michael@0: { michael@0: nsCOMPtr expression; michael@0: nsresult rv = CreateExpression(aExpression, aResolver, michael@0: getter_AddRefs(expression)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return expression->Evaluate(aContextNode, aType, aInResult, aResult); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: XPathEvaluator::CreateExpression(const nsAString & aExpression, michael@0: nsIDOMXPathNSResolver *aResolver, michael@0: nsIDOMXPathExpression **aResult) michael@0: { michael@0: nsresult rv; michael@0: if (!mRecycler) { michael@0: nsRefPtr recycler = new txResultRecycler; michael@0: NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: rv = recycler->init(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mRecycler = recycler; michael@0: } michael@0: michael@0: nsCOMPtr doc = do_QueryReferent(mDocument); michael@0: XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTML())); michael@0: michael@0: nsAutoPtr expression; michael@0: rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext, michael@0: getter_Transfers(expression)); michael@0: if (NS_FAILED(rv)) { michael@0: if (rv == NS_ERROR_DOM_NAMESPACE_ERR) { michael@0: return NS_ERROR_DOM_NAMESPACE_ERR; michael@0: } michael@0: michael@0: return NS_ERROR_DOM_INVALID_EXPRESSION_ERR; michael@0: } michael@0: michael@0: nsCOMPtr document = do_QueryReferent(mDocument); michael@0: michael@0: *aResult = new nsXPathExpression(expression, mRecycler, document); michael@0: if (!*aResult) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: JSObject* michael@0: XPathEvaluator::WrapObject(JSContext* aCx) michael@0: { michael@0: return dom::XPathEvaluatorBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: /* static */ michael@0: already_AddRefed michael@0: XPathEvaluator::Constructor(const GlobalObject& aGlobal, michael@0: ErrorResult& rv) michael@0: { michael@0: nsRefPtr newObj = new XPathEvaluator(nullptr); michael@0: return newObj.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: XPathEvaluator::CreateExpression(const nsAString& aExpression, michael@0: nsIDOMXPathNSResolver* aResolver, michael@0: ErrorResult& rv) michael@0: { michael@0: nsCOMPtr expr; michael@0: rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expr)); michael@0: return expr.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: XPathEvaluator::CreateNSResolver(nsINode* aNodeResolver, michael@0: ErrorResult& rv) michael@0: { michael@0: nsCOMPtr nodeResolver = do_QueryInterface(aNodeResolver); michael@0: nsCOMPtr res; michael@0: rv = CreateNSResolver(nodeResolver, getter_AddRefs(res)); michael@0: return res.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: XPathEvaluator::Evaluate(const nsAString& aExpression, nsINode* aContextNode, michael@0: nsIDOMXPathNSResolver* aResolver, uint16_t aType, michael@0: nsISupports* aResult, ErrorResult& rv) michael@0: { michael@0: nsCOMPtr contextNode = do_QueryInterface(aContextNode); michael@0: nsCOMPtr res; michael@0: rv = Evaluate(aExpression, contextNode, aResolver, aType, michael@0: aResult, getter_AddRefs(res)); michael@0: return res.forget(); michael@0: } michael@0: michael@0: michael@0: /* michael@0: * Implementation of txIParseContext private to XPathEvaluator, based on a michael@0: * nsIDOMXPathNSResolver michael@0: */ michael@0: michael@0: nsresult XPathEvaluatorParseContext::resolveNamespacePrefix michael@0: (nsIAtom* aPrefix, int32_t& aID) michael@0: { michael@0: aID = kNameSpaceID_Unknown; michael@0: michael@0: if (!mResolver) { michael@0: return NS_ERROR_DOM_NAMESPACE_ERR; michael@0: } michael@0: michael@0: nsAutoString prefix; michael@0: if (aPrefix) { michael@0: aPrefix->ToString(prefix); michael@0: } michael@0: michael@0: nsVoidableString ns; michael@0: nsresult rv = mResolver->LookupNamespaceURI(prefix, ns); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (DOMStringIsNull(ns)) { michael@0: return NS_ERROR_DOM_NAMESPACE_ERR; michael@0: } michael@0: michael@0: if (ns.IsEmpty()) { michael@0: aID = kNameSpaceID_None; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // get the namespaceID for the URI michael@0: return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID); michael@0: } michael@0: michael@0: nsresult michael@0: XPathEvaluatorParseContext::resolveFunctionCall(nsIAtom* aName, michael@0: int32_t aID, michael@0: FunctionCall** aFn) michael@0: { michael@0: return NS_ERROR_XPATH_UNKNOWN_FUNCTION; michael@0: } michael@0: michael@0: bool XPathEvaluatorParseContext::caseInsensitiveNameTests() michael@0: { michael@0: return !mIsCaseSensitive; michael@0: } michael@0: michael@0: void michael@0: XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset) michael@0: { michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla