| /* |
| * XPath/XSLPattern query result node list implementation |
| * |
| * Copyright 2005 Mike McCormack |
| * Copyright 2007 Mikolaj Zalewski |
| * Copyright 2010 Adam Martinson for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define COBJMACROS |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #ifdef HAVE_LIBXML2 |
| # include <libxml/parser.h> |
| # include <libxml/xmlerror.h> |
| # include <libxml/xpath.h> |
| # include <libxml/xpathInternals.h> |
| #endif |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "ole2.h" |
| #include "msxml6.h" |
| #include "msxml2did.h" |
| |
| #include "msxml_private.h" |
| |
| #include "wine/debug.h" |
| |
| /* This file implements the object returned by a XPath query. Note that this is |
| * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c. |
| * They are different because the list returned by XPath queries: |
| * - is static - gives the results for the XML tree as it existed during the |
| * execution of the query |
| * - supports IXMLDOMSelection |
| * |
| */ |
| |
| #ifdef HAVE_LIBXML2 |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msxml); |
| |
| int registerNamespaces(xmlXPathContextPtr ctxt); |
| xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str); |
| |
| typedef struct |
| { |
| IEnumVARIANT IEnumVARIANT_iface; |
| LONG ref; |
| |
| IUnknown *outer; |
| BOOL own; |
| |
| LONG pos; |
| |
| const struct enumvariant_funcs *funcs; |
| } enumvariant; |
| |
| typedef struct |
| { |
| DispatchEx dispex; |
| IXMLDOMSelection IXMLDOMSelection_iface; |
| LONG ref; |
| xmlNodePtr node; |
| xmlXPathObjectPtr result; |
| int resultPos; |
| IEnumVARIANT *enumvariant; |
| } domselection; |
| |
| static HRESULT selection_get_item(IUnknown *iface, LONG index, VARIANT* item) |
| { |
| V_VT(item) = VT_DISPATCH; |
| return IXMLDOMSelection_get_item((IXMLDOMSelection*)iface, index, (IXMLDOMNode**)&V_DISPATCH(item)); |
| } |
| |
| static HRESULT selection_next(IUnknown *iface) |
| { |
| IXMLDOMNode *node; |
| HRESULT hr = IXMLDOMSelection_nextNode((IXMLDOMSelection*)iface, &node); |
| if (hr == S_OK) IXMLDOMNode_Release(node); |
| return hr; |
| } |
| |
| static const struct enumvariant_funcs selection_enumvariant = { |
| selection_get_item, |
| selection_next |
| }; |
| |
| static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface ) |
| { |
| return CONTAINING_RECORD(iface, domselection, IXMLDOMSelection_iface); |
| } |
| |
| static inline enumvariant *impl_from_IEnumVARIANT( IEnumVARIANT *iface ) |
| { |
| return CONTAINING_RECORD(iface, enumvariant, IEnumVARIANT_iface); |
| } |
| |
| static HRESULT WINAPI domselection_QueryInterface( |
| IXMLDOMSelection *iface, |
| REFIID riid, |
| void** ppvObject ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| |
| TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject); |
| |
| if(!ppvObject) |
| return E_INVALIDARG; |
| |
| if ( IsEqualGUID( riid, &IID_IUnknown ) || |
| IsEqualGUID( riid, &IID_IXMLDOMNodeList ) || |
| IsEqualGUID( riid, &IID_IXMLDOMSelection )) |
| { |
| *ppvObject = &This->IXMLDOMSelection_iface; |
| } |
| else if (IsEqualGUID( riid, &IID_IEnumVARIANT )) |
| { |
| if (!This->enumvariant) |
| { |
| HRESULT hr = create_enumvariant((IUnknown*)iface, FALSE, &selection_enumvariant, &This->enumvariant); |
| if (FAILED(hr)) return hr; |
| } |
| |
| return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject); |
| } |
| else if (dispex_query_interface(&This->dispex, riid, ppvObject)) |
| { |
| return *ppvObject ? S_OK : E_NOINTERFACE; |
| } |
| else |
| { |
| TRACE("interface %s not implemented\n", debugstr_guid(riid)); |
| *ppvObject = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IXMLDOMSelection_AddRef( iface ); |
| |
| return S_OK; |
| } |
| |
| static ULONG WINAPI domselection_AddRef( |
| IXMLDOMSelection *iface ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| ULONG ref = InterlockedIncrement( &This->ref ); |
| TRACE("(%p)->(%d)\n", This, ref); |
| return ref; |
| } |
| |
| static ULONG WINAPI domselection_Release( |
| IXMLDOMSelection *iface ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p)->(%d)\n", This, ref); |
| if ( ref == 0 ) |
| { |
| xmlXPathFreeObject(This->result); |
| xmldoc_release(This->node->doc); |
| if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant); |
| heap_free(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI domselection_GetTypeInfoCount( |
| IXMLDOMSelection *iface, |
| UINT* pctinfo ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); |
| } |
| |
| static HRESULT WINAPI domselection_GetTypeInfo( |
| IXMLDOMSelection *iface, |
| UINT iTInfo, |
| LCID lcid, |
| ITypeInfo** ppTInfo ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, |
| iTInfo, lcid, ppTInfo); |
| } |
| |
| static HRESULT WINAPI domselection_GetIDsOfNames( |
| IXMLDOMSelection *iface, |
| REFIID riid, |
| LPOLESTR* rgszNames, |
| UINT cNames, |
| LCID lcid, |
| DISPID* rgDispId ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, |
| riid, rgszNames, cNames, lcid, rgDispId); |
| } |
| |
| static HRESULT WINAPI domselection_Invoke( |
| IXMLDOMSelection *iface, |
| DISPID dispIdMember, |
| REFIID riid, |
| LCID lcid, |
| WORD wFlags, |
| DISPPARAMS* pDispParams, |
| VARIANT* pVarResult, |
| EXCEPINFO* pExcepInfo, |
| UINT* puArgErr ) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, |
| dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| } |
| |
| static HRESULT WINAPI domselection_get_item( |
| IXMLDOMSelection* iface, |
| LONG index, |
| IXMLDOMNode** listItem) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| |
| TRACE("(%p)->(%d %p)\n", This, index, listItem); |
| |
| if(!listItem) |
| return E_INVALIDARG; |
| |
| *listItem = NULL; |
| |
| if (index < 0 || index >= xmlXPathNodeSetGetLength(This->result->nodesetval)) |
| return S_FALSE; |
| |
| *listItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, index)); |
| This->resultPos = index + 1; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI domselection_get_length( |
| IXMLDOMSelection* iface, |
| LONG* listLength) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, listLength); |
| |
| if(!listLength) |
| return E_INVALIDARG; |
| |
| *listLength = xmlXPathNodeSetGetLength(This->result->nodesetval); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI domselection_nextNode( |
| IXMLDOMSelection* iface, |
| IXMLDOMNode** nextItem) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, nextItem ); |
| |
| if(!nextItem) |
| return E_INVALIDARG; |
| |
| *nextItem = NULL; |
| |
| if (This->resultPos >= xmlXPathNodeSetGetLength(This->result->nodesetval)) |
| return S_FALSE; |
| |
| *nextItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, This->resultPos)); |
| This->resultPos++; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI domselection_reset( |
| IXMLDOMSelection* iface) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| |
| TRACE("%p\n", This); |
| This->resultPos = 0; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI domselection_get__newEnum( |
| IXMLDOMSelection* iface, |
| IUnknown** enumv) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, enumv); |
| |
| return create_enumvariant((IUnknown*)iface, TRUE, &selection_enumvariant, (IEnumVARIANT**)enumv); |
| } |
| |
| static HRESULT WINAPI domselection_get_expr( |
| IXMLDOMSelection* iface, |
| BSTR *p) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p)\n", This, p); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_put_expr( |
| IXMLDOMSelection* iface, |
| BSTR p) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%s)\n", This, debugstr_w(p)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_get_context( |
| IXMLDOMSelection* iface, |
| IXMLDOMNode **node) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p)\n", This, node); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_putref_context( |
| IXMLDOMSelection* iface, |
| IXMLDOMNode *node) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p)\n", This, node); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_peekNode( |
| IXMLDOMSelection* iface, |
| IXMLDOMNode **node) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p)\n", This, node); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_matches( |
| IXMLDOMSelection* iface, |
| IXMLDOMNode *node, |
| IXMLDOMNode **out_node) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p %p)\n", This, node, out_node); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_removeNext( |
| IXMLDOMSelection* iface, |
| IXMLDOMNode **node) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p)\n", This, node); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_removeAll( |
| IXMLDOMSelection* iface) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_clone( |
| IXMLDOMSelection* iface, |
| IXMLDOMSelection **node) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%p)\n", This, node); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_getProperty( |
| IXMLDOMSelection* iface, |
| BSTR p, |
| VARIANT *var) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%s %p)\n", This, debugstr_w(p), var); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI domselection_setProperty( |
| IXMLDOMSelection* iface, |
| BSTR p, |
| VARIANT var) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( iface ); |
| FIXME("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&var)); |
| return E_NOTIMPL; |
| } |
| |
| static const struct IXMLDOMSelectionVtbl domselection_vtbl = |
| { |
| domselection_QueryInterface, |
| domselection_AddRef, |
| domselection_Release, |
| domselection_GetTypeInfoCount, |
| domselection_GetTypeInfo, |
| domselection_GetIDsOfNames, |
| domselection_Invoke, |
| domselection_get_item, |
| domselection_get_length, |
| domselection_nextNode, |
| domselection_reset, |
| domselection_get__newEnum, |
| domselection_get_expr, |
| domselection_put_expr, |
| domselection_get_context, |
| domselection_putref_context, |
| domselection_peekNode, |
| domselection_matches, |
| domselection_removeNext, |
| domselection_removeAll, |
| domselection_clone, |
| domselection_getProperty, |
| domselection_setProperty |
| }; |
| |
| /* IEnumVARIANT support */ |
| static HRESULT WINAPI enumvariant_QueryInterface( |
| IEnumVARIANT *iface, |
| REFIID riid, |
| void** ppvObject ) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); |
| |
| *ppvObject = NULL; |
| |
| if (IsEqualGUID( riid, &IID_IUnknown )) |
| { |
| if (This->own) |
| *ppvObject = &This->IEnumVARIANT_iface; |
| else |
| return IUnknown_QueryInterface(This->outer, riid, ppvObject); |
| } |
| else if (IsEqualGUID( riid, &IID_IEnumVARIANT )) |
| { |
| *ppvObject = &This->IEnumVARIANT_iface; |
| } |
| else |
| return IUnknown_QueryInterface(This->outer, riid, ppvObject); |
| |
| IEnumVARIANT_AddRef( iface ); |
| |
| return S_OK; |
| } |
| |
| static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface ) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| ULONG ref = InterlockedIncrement( &This->ref ); |
| TRACE("(%p)->(%d)\n", This, ref); |
| return ref; |
| } |
| |
| static ULONG WINAPI enumvariant_Release(IEnumVARIANT *iface ) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p)->(%d)\n", This, ref); |
| if ( ref == 0 ) |
| { |
| if (This->own) IUnknown_Release(This->outer); |
| heap_free(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI enumvariant_Next( |
| IEnumVARIANT *iface, |
| ULONG celt, |
| VARIANT *var, |
| ULONG *fetched) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| ULONG ret_count = 0; |
| |
| TRACE("(%p)->(%u %p %p)\n", This, celt, var, fetched); |
| |
| if (fetched) *fetched = 0; |
| |
| if (celt && !var) return E_INVALIDARG; |
| |
| for (; celt > 0; celt--, var++, This->pos++) |
| { |
| HRESULT hr = This->funcs->get_item(This->outer, This->pos, var); |
| if (hr != S_OK) |
| { |
| V_VT(var) = VT_EMPTY; |
| break; |
| } |
| ret_count++; |
| } |
| |
| if (fetched) (*fetched)++; |
| |
| /* we need to advance one step more for some reason */ |
| if (ret_count) |
| { |
| if (This->funcs->next) |
| This->funcs->next(This->outer); |
| } |
| |
| return celt == 0 ? S_OK : S_FALSE; |
| } |
| |
| static HRESULT WINAPI enumvariant_Skip( |
| IEnumVARIANT *iface, |
| ULONG celt) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| FIXME("(%p)->(%u): stub\n", This, celt); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI enumvariant_Reset(IEnumVARIANT *iface) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| FIXME("(%p): stub\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI enumvariant_Clone( |
| IEnumVARIANT *iface, IEnumVARIANT **ppenum) |
| { |
| enumvariant *This = impl_from_IEnumVARIANT( iface ); |
| FIXME("(%p)->(%p): stub\n", This, ppenum); |
| return E_NOTIMPL; |
| } |
| |
| static const struct IEnumVARIANTVtbl EnumVARIANTVtbl = |
| { |
| enumvariant_QueryInterface, |
| enumvariant_AddRef, |
| enumvariant_Release, |
| enumvariant_Next, |
| enumvariant_Skip, |
| enumvariant_Reset, |
| enumvariant_Clone |
| }; |
| |
| HRESULT create_enumvariant(IUnknown *outer, BOOL own, const struct enumvariant_funcs *funcs, IEnumVARIANT **penum) |
| { |
| enumvariant *This; |
| |
| This = heap_alloc(sizeof(enumvariant)); |
| if (!This) return E_OUTOFMEMORY; |
| |
| This->IEnumVARIANT_iface.lpVtbl = &EnumVARIANTVtbl; |
| This->ref = 0; |
| This->outer = outer; |
| This->own = own; |
| This->pos = 0; |
| This->funcs = funcs; |
| |
| if (This->own) |
| IUnknown_AddRef(This->outer); |
| |
| *penum = &This->IEnumVARIANT_iface; |
| IEnumVARIANT_AddRef(*penum); |
| return S_OK; |
| } |
| |
| static HRESULT domselection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid) |
| { |
| WCHAR *ptr; |
| int idx = 0; |
| |
| for(ptr = name; *ptr && isdigitW(*ptr); ptr++) |
| idx = idx*10 + (*ptr-'0'); |
| if(*ptr) |
| return DISP_E_UNKNOWNNAME; |
| |
| *dispid = DISPID_DOM_COLLECTION_BASE + idx; |
| TRACE("ret %x\n", *dispid); |
| return S_OK; |
| } |
| |
| static HRESULT domselection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, |
| VARIANT *res, EXCEPINFO *ei) |
| { |
| domselection *This = impl_from_IXMLDOMSelection( (IXMLDOMSelection*)iface ); |
| |
| TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei); |
| |
| V_VT(res) = VT_DISPATCH; |
| V_DISPATCH(res) = NULL; |
| |
| if (id < DISPID_DOM_COLLECTION_BASE || id > DISPID_DOM_COLLECTION_MAX) |
| return DISP_E_UNKNOWNNAME; |
| |
| switch(flags) |
| { |
| case INVOKE_PROPERTYGET: |
| { |
| IXMLDOMNode *disp = NULL; |
| |
| IXMLDOMSelection_get_item(&This->IXMLDOMSelection_iface, id - DISPID_DOM_COLLECTION_BASE, &disp); |
| V_DISPATCH(res) = (IDispatch*)disp; |
| break; |
| } |
| default: |
| { |
| FIXME("unimplemented flags %x\n", flags); |
| break; |
| } |
| } |
| |
| TRACE("ret %p\n", V_DISPATCH(res)); |
| |
| return S_OK; |
| } |
| |
| static const dispex_static_data_vtbl_t domselection_dispex_vtbl = { |
| domselection_get_dispid, |
| domselection_invoke |
| }; |
| |
| static const tid_t domselection_iface_tids[] = { |
| IXMLDOMSelection_tid, |
| 0 |
| }; |
| static dispex_static_data_t domselection_dispex = { |
| &domselection_dispex_vtbl, |
| IXMLDOMSelection_tid, |
| NULL, |
| domselection_iface_tids |
| }; |
| |
| #define XSLPATTERN_CHECK_ARGS(n) \ |
| if (nargs != n) { \ |
| FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \ |
| xmlXPathSetArityError(pctx); \ |
| return; \ |
| } |
| |
| |
| static void XSLPattern_index(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| XSLPATTERN_CHECK_ARGS(0); |
| |
| xmlXPathPositionFunction(pctx, 0); |
| xmlXPathReturnNumber(pctx, xmlXPathPopNumber(pctx) - 1.0); |
| } |
| |
| static void XSLPattern_end(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| double pos, last; |
| XSLPATTERN_CHECK_ARGS(0); |
| |
| xmlXPathPositionFunction(pctx, 0); |
| pos = xmlXPathPopNumber(pctx); |
| xmlXPathLastFunction(pctx, 0); |
| last = xmlXPathPopNumber(pctx); |
| xmlXPathReturnBoolean(pctx, pos == last); |
| } |
| |
| static void XSLPattern_nodeType(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| XSLPATTERN_CHECK_ARGS(0); |
| xmlXPathReturnNumber(pctx, pctx->context->node->type); |
| } |
| |
| static void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| xmlChar *arg1, *arg2; |
| XSLPATTERN_CHECK_ARGS(2); |
| |
| arg2 = xmlXPathPopString(pctx); |
| arg1 = xmlXPathPopString(pctx); |
| xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) == 0); |
| xmlFree(arg1); |
| xmlFree(arg2); |
| } |
| |
| static void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| xmlChar *arg1, *arg2; |
| XSLPATTERN_CHECK_ARGS(2); |
| |
| arg2 = xmlXPathPopString(pctx); |
| arg1 = xmlXPathPopString(pctx); |
| xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) != 0); |
| xmlFree(arg1); |
| xmlFree(arg2); |
| } |
| |
| static void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| xmlChar *arg1, *arg2; |
| XSLPATTERN_CHECK_ARGS(2); |
| |
| arg2 = xmlXPathPopString(pctx); |
| arg1 = xmlXPathPopString(pctx); |
| xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) < 0); |
| xmlFree(arg1); |
| xmlFree(arg2); |
| } |
| |
| static void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| xmlChar *arg1, *arg2; |
| XSLPATTERN_CHECK_ARGS(2); |
| |
| arg2 = xmlXPathPopString(pctx); |
| arg1 = xmlXPathPopString(pctx); |
| xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) <= 0); |
| xmlFree(arg1); |
| xmlFree(arg2); |
| } |
| |
| static void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| xmlChar *arg1, *arg2; |
| XSLPATTERN_CHECK_ARGS(2); |
| |
| arg2 = xmlXPathPopString(pctx); |
| arg1 = xmlXPathPopString(pctx); |
| xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) > 0); |
| xmlFree(arg1); |
| xmlFree(arg2); |
| } |
| |
| static void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx, int nargs) |
| { |
| xmlChar *arg1, *arg2; |
| XSLPATTERN_CHECK_ARGS(2); |
| |
| arg2 = xmlXPathPopString(pctx); |
| arg1 = xmlXPathPopString(pctx); |
| xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) >= 0); |
| xmlFree(arg1); |
| xmlFree(arg2); |
| } |
| |
| static void query_serror(void* ctx, xmlErrorPtr err) |
| { |
| LIBXML2_CALLBACK_SERROR(domselection_create, err); |
| } |
| |
| HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out) |
| { |
| domselection *This = heap_alloc(sizeof(domselection)); |
| xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc); |
| HRESULT hr; |
| |
| TRACE("(%p, %s, %p)\n", node, debugstr_a((char const*)query), out); |
| |
| *out = NULL; |
| if (!This || !ctxt || !query) |
| { |
| xmlXPathFreeContext(ctxt); |
| heap_free(This); |
| return E_OUTOFMEMORY; |
| } |
| |
| This->IXMLDOMSelection_iface.lpVtbl = &domselection_vtbl; |
| This->ref = 1; |
| This->resultPos = 0; |
| This->node = node; |
| This->enumvariant = NULL; |
| init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSelection_iface, &domselection_dispex); |
| xmldoc_add_ref(This->node->doc); |
| |
| ctxt->error = query_serror; |
| ctxt->node = node; |
| registerNamespaces(ctxt); |
| |
| if (is_xpathmode(This->node->doc)) |
| { |
| xmlXPathRegisterAllFunctions(ctxt); |
| This->result = xmlXPathEvalExpression(query, ctxt); |
| } |
| else |
| { |
| xmlChar* pattern_query = XSLPattern_to_XPath(ctxt, query); |
| |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction); |
| |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"index", XSLPattern_index); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"end", XSLPattern_end); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"nodeType", XSLPattern_nodeType); |
| |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IEq", XSLPattern_OP_IEq); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_INEq", XSLPattern_OP_INEq); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILt", XSLPattern_OP_ILt); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILEq", XSLPattern_OP_ILEq); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt); |
| xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq); |
| |
| This->result = xmlXPathEvalExpression(pattern_query, ctxt); |
| xmlFree(pattern_query); |
| } |
| |
| if (!This->result || This->result->type != XPATH_NODESET) |
| { |
| hr = E_FAIL; |
| goto cleanup; |
| } |
| |
| *out = (IXMLDOMNodeList*)&This->IXMLDOMSelection_iface; |
| hr = S_OK; |
| TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval)); |
| |
| cleanup: |
| if (This && FAILED(hr)) |
| IXMLDOMSelection_Release( &This->IXMLDOMSelection_iface ); |
| xmlXPathFreeContext(ctxt); |
| return hr; |
| } |
| |
| #endif |