xref: /reactos/dll/win32/msxml3/selection.c (revision bd712186)
1 /*
2  *    XPath/XSLPattern query result node list implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2007 Mikolaj Zalewski
6  * Copyright 2010 Adam Martinson for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #define COBJMACROS
24 
25 #include "config.h"
26 
27 #include <stdarg.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/xpath.h>
32 # include <libxml/xpathInternals.h>
33 #endif
34 
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winuser.h"
38 #include "ole2.h"
39 #include "msxml6.h"
40 #include "msxml2did.h"
41 
42 #include "msxml_private.h"
43 
44 #include "wine/debug.h"
45 
46 /* This file implements the object returned by a XPath query. Note that this is
47  * not the IXMLDOMNodeList returned by childNodes - it's implemented in nodelist.c.
48  * They are different because the list returned by XPath queries:
49  *  - is static - gives the results for the XML tree as it existed during the
50  *    execution of the query
51  *  - supports IXMLDOMSelection
52  *
53  */
54 
55 #ifdef HAVE_LIBXML2
56 
57 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 
59 int registerNamespaces(xmlXPathContextPtr ctxt);
60 xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
61 
62 typedef struct
63 {
64     IEnumVARIANT IEnumVARIANT_iface;
65     LONG ref;
66 
67     IUnknown *outer;
68     BOOL own;
69 
70     LONG pos;
71 
72     const struct enumvariant_funcs *funcs;
73 } enumvariant;
74 
75 typedef struct
76 {
77     DispatchEx dispex;
78     IXMLDOMSelection IXMLDOMSelection_iface;
79     LONG ref;
80     xmlNodePtr node;
81     xmlXPathObjectPtr result;
82     int resultPos;
83     IEnumVARIANT *enumvariant;
84 } domselection;
85 
86 static HRESULT selection_get_item(IUnknown *iface, LONG index, VARIANT* item)
87 {
88     V_VT(item) = VT_DISPATCH;
89     return IXMLDOMSelection_get_item((IXMLDOMSelection*)iface, index, (IXMLDOMNode**)&V_DISPATCH(item));
90 }
91 
92 static HRESULT selection_next(IUnknown *iface)
93 {
94     IXMLDOMNode *node;
95     HRESULT hr = IXMLDOMSelection_nextNode((IXMLDOMSelection*)iface, &node);
96     if (hr == S_OK) IXMLDOMNode_Release(node);
97     return hr;
98 }
99 
100 static const struct enumvariant_funcs selection_enumvariant = {
101     selection_get_item,
102     selection_next
103 };
104 
105 static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface )
106 {
107     return CONTAINING_RECORD(iface, domselection, IXMLDOMSelection_iface);
108 }
109 
110 static inline enumvariant *impl_from_IEnumVARIANT( IEnumVARIANT *iface )
111 {
112     return CONTAINING_RECORD(iface, enumvariant, IEnumVARIANT_iface);
113 }
114 
115 static HRESULT WINAPI domselection_QueryInterface(
116     IXMLDOMSelection *iface,
117     REFIID riid,
118     void** ppvObject )
119 {
120     domselection *This = impl_from_IXMLDOMSelection( iface );
121 
122     TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
123 
124     if(!ppvObject)
125         return E_INVALIDARG;
126 
127     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
128          IsEqualGUID( riid, &IID_IXMLDOMNodeList ) ||
129          IsEqualGUID( riid, &IID_IXMLDOMSelection ))
130     {
131         *ppvObject = &This->IXMLDOMSelection_iface;
132     }
133     else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
134     {
135         if (!This->enumvariant)
136         {
137             HRESULT hr = create_enumvariant((IUnknown*)iface, FALSE, &selection_enumvariant, &This->enumvariant);
138             if (FAILED(hr)) return hr;
139         }
140 
141         return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject);
142     }
143     else if (dispex_query_interface(&This->dispex, riid, ppvObject))
144     {
145         return *ppvObject ? S_OK : E_NOINTERFACE;
146     }
147     else
148     {
149         TRACE("interface %s not implemented\n", debugstr_guid(riid));
150         *ppvObject = NULL;
151         return E_NOINTERFACE;
152     }
153 
154     IXMLDOMSelection_AddRef( iface );
155 
156     return S_OK;
157 }
158 
159 static ULONG WINAPI domselection_AddRef(
160     IXMLDOMSelection *iface )
161 {
162     domselection *This = impl_from_IXMLDOMSelection( iface );
163     ULONG ref = InterlockedIncrement( &This->ref );
164     TRACE("(%p)->(%d)\n", This, ref);
165     return ref;
166 }
167 
168 static ULONG WINAPI domselection_Release(
169     IXMLDOMSelection *iface )
170 {
171     domselection *This = impl_from_IXMLDOMSelection( iface );
172     ULONG ref = InterlockedDecrement(&This->ref);
173 
174     TRACE("(%p)->(%d)\n", This, ref);
175     if ( ref == 0 )
176     {
177         xmlXPathFreeObject(This->result);
178         xmldoc_release(This->node->doc);
179         if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
180         heap_free(This);
181     }
182 
183     return ref;
184 }
185 
186 static HRESULT WINAPI domselection_GetTypeInfoCount(
187     IXMLDOMSelection *iface,
188     UINT* pctinfo )
189 {
190     domselection *This = impl_from_IXMLDOMSelection( iface );
191     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
192 }
193 
194 static HRESULT WINAPI domselection_GetTypeInfo(
195     IXMLDOMSelection *iface,
196     UINT iTInfo,
197     LCID lcid,
198     ITypeInfo** ppTInfo )
199 {
200     domselection *This = impl_from_IXMLDOMSelection( iface );
201     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
202         iTInfo, lcid, ppTInfo);
203 }
204 
205 static HRESULT WINAPI domselection_GetIDsOfNames(
206     IXMLDOMSelection *iface,
207     REFIID riid,
208     LPOLESTR* rgszNames,
209     UINT cNames,
210     LCID lcid,
211     DISPID* rgDispId )
212 {
213     domselection *This = impl_from_IXMLDOMSelection( iface );
214     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
215         riid, rgszNames, cNames, lcid, rgDispId);
216 }
217 
218 static HRESULT WINAPI domselection_Invoke(
219     IXMLDOMSelection *iface,
220     DISPID dispIdMember,
221     REFIID riid,
222     LCID lcid,
223     WORD wFlags,
224     DISPPARAMS* pDispParams,
225     VARIANT* pVarResult,
226     EXCEPINFO* pExcepInfo,
227     UINT* puArgErr )
228 {
229     domselection *This = impl_from_IXMLDOMSelection( iface );
230     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
231         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
232 }
233 
234 static HRESULT WINAPI domselection_get_item(
235         IXMLDOMSelection* iface,
236         LONG index,
237         IXMLDOMNode** listItem)
238 {
239     domselection *This = impl_from_IXMLDOMSelection( iface );
240 
241     TRACE("(%p)->(%d %p)\n", This, index, listItem);
242 
243     if(!listItem)
244         return E_INVALIDARG;
245 
246     *listItem = NULL;
247 
248     if (index < 0 || index >= xmlXPathNodeSetGetLength(This->result->nodesetval))
249         return S_FALSE;
250 
251     *listItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, index));
252     This->resultPos = index + 1;
253 
254     return S_OK;
255 }
256 
257 static HRESULT WINAPI domselection_get_length(
258         IXMLDOMSelection* iface,
259         LONG* listLength)
260 {
261     domselection *This = impl_from_IXMLDOMSelection( iface );
262 
263     TRACE("(%p)->(%p)\n", This, listLength);
264 
265     if(!listLength)
266         return E_INVALIDARG;
267 
268     *listLength = xmlXPathNodeSetGetLength(This->result->nodesetval);
269     return S_OK;
270 }
271 
272 static HRESULT WINAPI domselection_nextNode(
273         IXMLDOMSelection* iface,
274         IXMLDOMNode** nextItem)
275 {
276     domselection *This = impl_from_IXMLDOMSelection( iface );
277 
278     TRACE("(%p)->(%p)\n", This, nextItem );
279 
280     if(!nextItem)
281         return E_INVALIDARG;
282 
283     *nextItem = NULL;
284 
285     if (This->resultPos >= xmlXPathNodeSetGetLength(This->result->nodesetval))
286         return S_FALSE;
287 
288     *nextItem = create_node(xmlXPathNodeSetItem(This->result->nodesetval, This->resultPos));
289     This->resultPos++;
290     return S_OK;
291 }
292 
293 static HRESULT WINAPI domselection_reset(
294         IXMLDOMSelection* iface)
295 {
296     domselection *This = impl_from_IXMLDOMSelection( iface );
297 
298     TRACE("%p\n", This);
299     This->resultPos = 0;
300     return S_OK;
301 }
302 
303 static HRESULT WINAPI domselection_get__newEnum(
304         IXMLDOMSelection* iface,
305         IUnknown** enumv)
306 {
307     domselection *This = impl_from_IXMLDOMSelection( iface );
308 
309     TRACE("(%p)->(%p)\n", This, enumv);
310 
311     return create_enumvariant((IUnknown*)iface, TRUE, &selection_enumvariant, (IEnumVARIANT**)enumv);
312 }
313 
314 static HRESULT WINAPI domselection_get_expr(
315         IXMLDOMSelection* iface,
316         BSTR *p)
317 {
318     domselection *This = impl_from_IXMLDOMSelection( iface );
319     FIXME("(%p)->(%p)\n", This, p);
320     return E_NOTIMPL;
321 }
322 
323 static HRESULT WINAPI domselection_put_expr(
324         IXMLDOMSelection* iface,
325         BSTR p)
326 {
327     domselection *This = impl_from_IXMLDOMSelection( iface );
328     FIXME("(%p)->(%s)\n", This, debugstr_w(p));
329     return E_NOTIMPL;
330 }
331 
332 static HRESULT WINAPI domselection_get_context(
333         IXMLDOMSelection* iface,
334         IXMLDOMNode **node)
335 {
336     domselection *This = impl_from_IXMLDOMSelection( iface );
337     FIXME("(%p)->(%p)\n", This, node);
338     return E_NOTIMPL;
339 }
340 
341 static HRESULT WINAPI domselection_putref_context(
342         IXMLDOMSelection* iface,
343         IXMLDOMNode *node)
344 {
345     domselection *This = impl_from_IXMLDOMSelection( iface );
346     FIXME("(%p)->(%p)\n", This, node);
347     return E_NOTIMPL;
348 }
349 
350 static HRESULT WINAPI domselection_peekNode(
351         IXMLDOMSelection* iface,
352         IXMLDOMNode **node)
353 {
354     domselection *This = impl_from_IXMLDOMSelection( iface );
355     FIXME("(%p)->(%p)\n", This, node);
356     return E_NOTIMPL;
357 }
358 
359 static HRESULT WINAPI domselection_matches(
360         IXMLDOMSelection* iface,
361         IXMLDOMNode *node,
362         IXMLDOMNode **out_node)
363 {
364     domselection *This = impl_from_IXMLDOMSelection( iface );
365     FIXME("(%p)->(%p %p)\n", This, node, out_node);
366     return E_NOTIMPL;
367 }
368 
369 static HRESULT WINAPI domselection_removeNext(
370         IXMLDOMSelection* iface,
371         IXMLDOMNode **node)
372 {
373     domselection *This = impl_from_IXMLDOMSelection( iface );
374     FIXME("(%p)->(%p)\n", This, node);
375     return E_NOTIMPL;
376 }
377 
378 static HRESULT WINAPI domselection_removeAll(
379         IXMLDOMSelection* iface)
380 {
381     domselection *This = impl_from_IXMLDOMSelection( iface );
382     FIXME("(%p)\n", This);
383     return E_NOTIMPL;
384 }
385 
386 static HRESULT WINAPI domselection_clone(
387         IXMLDOMSelection* iface,
388         IXMLDOMSelection **node)
389 {
390     domselection *This = impl_from_IXMLDOMSelection( iface );
391     FIXME("(%p)->(%p)\n", This, node);
392     return E_NOTIMPL;
393 }
394 
395 static HRESULT WINAPI domselection_getProperty(
396         IXMLDOMSelection* iface,
397         BSTR p,
398         VARIANT *var)
399 {
400     domselection *This = impl_from_IXMLDOMSelection( iface );
401     FIXME("(%p)->(%s %p)\n", This, debugstr_w(p), var);
402     return E_NOTIMPL;
403 }
404 
405 static HRESULT WINAPI domselection_setProperty(
406         IXMLDOMSelection* iface,
407         BSTR p,
408         VARIANT var)
409 {
410     domselection *This = impl_from_IXMLDOMSelection( iface );
411     FIXME("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&var));
412     return E_NOTIMPL;
413 }
414 
415 static const struct IXMLDOMSelectionVtbl domselection_vtbl =
416 {
417     domselection_QueryInterface,
418     domselection_AddRef,
419     domselection_Release,
420     domselection_GetTypeInfoCount,
421     domselection_GetTypeInfo,
422     domselection_GetIDsOfNames,
423     domselection_Invoke,
424     domselection_get_item,
425     domselection_get_length,
426     domselection_nextNode,
427     domselection_reset,
428     domselection_get__newEnum,
429     domselection_get_expr,
430     domselection_put_expr,
431     domselection_get_context,
432     domselection_putref_context,
433     domselection_peekNode,
434     domselection_matches,
435     domselection_removeNext,
436     domselection_removeAll,
437     domselection_clone,
438     domselection_getProperty,
439     domselection_setProperty
440 };
441 
442 /* IEnumVARIANT support */
443 static HRESULT WINAPI enumvariant_QueryInterface(
444     IEnumVARIANT *iface,
445     REFIID riid,
446     void** ppvObject )
447 {
448     enumvariant *This = impl_from_IEnumVARIANT( iface );
449 
450     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
451 
452     *ppvObject = NULL;
453 
454     if (IsEqualGUID( riid, &IID_IUnknown ))
455     {
456         if (This->own)
457             *ppvObject = &This->IEnumVARIANT_iface;
458         else
459             return IUnknown_QueryInterface(This->outer, riid, ppvObject);
460     }
461     else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
462     {
463         *ppvObject = &This->IEnumVARIANT_iface;
464     }
465     else
466         return IUnknown_QueryInterface(This->outer, riid, ppvObject);
467 
468     IEnumVARIANT_AddRef( iface );
469 
470     return S_OK;
471 }
472 
473 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface )
474 {
475     enumvariant *This = impl_from_IEnumVARIANT( iface );
476     ULONG ref = InterlockedIncrement( &This->ref );
477     TRACE("(%p)->(%d)\n", This, ref);
478     return ref;
479 }
480 
481 static ULONG WINAPI enumvariant_Release(IEnumVARIANT *iface )
482 {
483     enumvariant *This = impl_from_IEnumVARIANT( iface );
484     ULONG ref = InterlockedDecrement(&This->ref);
485 
486     TRACE("(%p)->(%d)\n", This, ref);
487     if ( ref == 0 )
488     {
489         if (This->own) IUnknown_Release(This->outer);
490         heap_free(This);
491     }
492 
493     return ref;
494 }
495 
496 static HRESULT WINAPI enumvariant_Next(
497     IEnumVARIANT *iface,
498     ULONG celt,
499     VARIANT *var,
500     ULONG *fetched)
501 {
502     enumvariant *This = impl_from_IEnumVARIANT( iface );
503     ULONG ret_count = 0;
504 
505     TRACE("(%p)->(%u %p %p)\n", This, celt, var, fetched);
506 
507     if (fetched) *fetched = 0;
508 
509     if (celt && !var) return E_INVALIDARG;
510 
511     for (; celt > 0; celt--, var++, This->pos++)
512     {
513         HRESULT hr = This->funcs->get_item(This->outer, This->pos, var);
514         if (hr != S_OK)
515         {
516             V_VT(var) = VT_EMPTY;
517             break;
518         }
519         ret_count++;
520     }
521 
522     if (fetched) (*fetched)++;
523 
524     /* we need to advance one step more for some reason */
525     if (ret_count)
526     {
527         if (This->funcs->next)
528             This->funcs->next(This->outer);
529     }
530 
531     return celt == 0 ? S_OK : S_FALSE;
532 }
533 
534 static HRESULT WINAPI enumvariant_Skip(
535     IEnumVARIANT *iface,
536     ULONG celt)
537 {
538     enumvariant *This = impl_from_IEnumVARIANT( iface );
539     FIXME("(%p)->(%u): stub\n", This, celt);
540     return E_NOTIMPL;
541 }
542 
543 static HRESULT WINAPI enumvariant_Reset(IEnumVARIANT *iface)
544 {
545     enumvariant *This = impl_from_IEnumVARIANT( iface );
546     FIXME("(%p): stub\n", This);
547     return E_NOTIMPL;
548 }
549 
550 static HRESULT WINAPI enumvariant_Clone(
551     IEnumVARIANT *iface, IEnumVARIANT **ppenum)
552 {
553     enumvariant *This = impl_from_IEnumVARIANT( iface );
554     FIXME("(%p)->(%p): stub\n", This, ppenum);
555     return E_NOTIMPL;
556 }
557 
558 static const struct IEnumVARIANTVtbl EnumVARIANTVtbl =
559 {
560     enumvariant_QueryInterface,
561     enumvariant_AddRef,
562     enumvariant_Release,
563     enumvariant_Next,
564     enumvariant_Skip,
565     enumvariant_Reset,
566     enumvariant_Clone
567 };
568 
569 HRESULT create_enumvariant(IUnknown *outer, BOOL own, const struct enumvariant_funcs *funcs, IEnumVARIANT **penum)
570 {
571     enumvariant *This;
572 
573     This = heap_alloc(sizeof(enumvariant));
574     if (!This) return E_OUTOFMEMORY;
575 
576     This->IEnumVARIANT_iface.lpVtbl = &EnumVARIANTVtbl;
577     This->ref = 0;
578     This->outer = outer;
579     This->own = own;
580     This->pos = 0;
581     This->funcs = funcs;
582 
583     if (This->own)
584         IUnknown_AddRef(This->outer);
585 
586     *penum = &This->IEnumVARIANT_iface;
587     IEnumVARIANT_AddRef(*penum);
588     return S_OK;
589 }
590 
591 static HRESULT domselection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
592 {
593     WCHAR *ptr;
594     int idx = 0;
595 
596     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
597         idx = idx*10 + (*ptr-'0');
598     if(*ptr)
599         return DISP_E_UNKNOWNNAME;
600 
601     *dispid = DISPID_DOM_COLLECTION_BASE + idx;
602     TRACE("ret %x\n", *dispid);
603     return S_OK;
604 }
605 
606 static HRESULT domselection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
607         VARIANT *res, EXCEPINFO *ei)
608 {
609     domselection *This = impl_from_IXMLDOMSelection( (IXMLDOMSelection*)iface );
610 
611     TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
612 
613     V_VT(res) = VT_DISPATCH;
614     V_DISPATCH(res) = NULL;
615 
616     if (id < DISPID_DOM_COLLECTION_BASE || id > DISPID_DOM_COLLECTION_MAX)
617         return DISP_E_UNKNOWNNAME;
618 
619     switch(flags)
620     {
621         case INVOKE_PROPERTYGET:
622         {
623             IXMLDOMNode *disp = NULL;
624 
625             IXMLDOMSelection_get_item(&This->IXMLDOMSelection_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
626             V_DISPATCH(res) = (IDispatch*)disp;
627             break;
628         }
629         default:
630         {
631             FIXME("unimplemented flags %x\n", flags);
632             break;
633         }
634     }
635 
636     TRACE("ret %p\n", V_DISPATCH(res));
637 
638     return S_OK;
639 }
640 
641 static const dispex_static_data_vtbl_t domselection_dispex_vtbl = {
642     domselection_get_dispid,
643     domselection_invoke
644 };
645 
646 static const tid_t domselection_iface_tids[] = {
647     IXMLDOMSelection_tid,
648     0
649 };
650 static dispex_static_data_t domselection_dispex = {
651     &domselection_dispex_vtbl,
652     IXMLDOMSelection_tid,
653     NULL,
654     domselection_iface_tids
655 };
656 
657 #define XSLPATTERN_CHECK_ARGS(n) \
658     if (nargs != n) { \
659         FIXME("XSLPattern syntax error: Expected %i arguments, got %i\n", n, nargs); \
660         xmlXPathSetArityError(pctx); \
661         return; \
662     }
663 
664 
665 static void XSLPattern_index(xmlXPathParserContextPtr pctx, int nargs)
666 {
667     XSLPATTERN_CHECK_ARGS(0);
668 
669     xmlXPathPositionFunction(pctx, 0);
670     xmlXPathReturnNumber(pctx, xmlXPathPopNumber(pctx) - 1.0);
671 }
672 
673 static void XSLPattern_end(xmlXPathParserContextPtr pctx, int nargs)
674 {
675     double pos, last;
676     XSLPATTERN_CHECK_ARGS(0);
677 
678     xmlXPathPositionFunction(pctx, 0);
679     pos = xmlXPathPopNumber(pctx);
680     xmlXPathLastFunction(pctx, 0);
681     last = xmlXPathPopNumber(pctx);
682     xmlXPathReturnBoolean(pctx, pos == last);
683 }
684 
685 static void XSLPattern_nodeType(xmlXPathParserContextPtr pctx, int nargs)
686 {
687     XSLPATTERN_CHECK_ARGS(0);
688     xmlXPathReturnNumber(pctx, pctx->context->node->type);
689 }
690 
691 static void XSLPattern_OP_IEq(xmlXPathParserContextPtr pctx, int nargs)
692 {
693     xmlChar *arg1, *arg2;
694     XSLPATTERN_CHECK_ARGS(2);
695 
696     arg2 = xmlXPathPopString(pctx);
697     arg1 = xmlXPathPopString(pctx);
698     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) == 0);
699     xmlFree(arg1);
700     xmlFree(arg2);
701 }
702 
703 static void XSLPattern_OP_INEq(xmlXPathParserContextPtr pctx, int nargs)
704 {
705     xmlChar *arg1, *arg2;
706     XSLPATTERN_CHECK_ARGS(2);
707 
708     arg2 = xmlXPathPopString(pctx);
709     arg1 = xmlXPathPopString(pctx);
710     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) != 0);
711     xmlFree(arg1);
712     xmlFree(arg2);
713 }
714 
715 static void XSLPattern_OP_ILt(xmlXPathParserContextPtr pctx, int nargs)
716 {
717     xmlChar *arg1, *arg2;
718     XSLPATTERN_CHECK_ARGS(2);
719 
720     arg2 = xmlXPathPopString(pctx);
721     arg1 = xmlXPathPopString(pctx);
722     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) < 0);
723     xmlFree(arg1);
724     xmlFree(arg2);
725 }
726 
727 static void XSLPattern_OP_ILEq(xmlXPathParserContextPtr pctx, int nargs)
728 {
729     xmlChar *arg1, *arg2;
730     XSLPATTERN_CHECK_ARGS(2);
731 
732     arg2 = xmlXPathPopString(pctx);
733     arg1 = xmlXPathPopString(pctx);
734     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) <= 0);
735     xmlFree(arg1);
736     xmlFree(arg2);
737 }
738 
739 static void XSLPattern_OP_IGt(xmlXPathParserContextPtr pctx, int nargs)
740 {
741     xmlChar *arg1, *arg2;
742     XSLPATTERN_CHECK_ARGS(2);
743 
744     arg2 = xmlXPathPopString(pctx);
745     arg1 = xmlXPathPopString(pctx);
746     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) > 0);
747     xmlFree(arg1);
748     xmlFree(arg2);
749 }
750 
751 static void XSLPattern_OP_IGEq(xmlXPathParserContextPtr pctx, int nargs)
752 {
753     xmlChar *arg1, *arg2;
754     XSLPATTERN_CHECK_ARGS(2);
755 
756     arg2 = xmlXPathPopString(pctx);
757     arg1 = xmlXPathPopString(pctx);
758     xmlXPathReturnBoolean(pctx, xmlStrcasecmp(arg1, arg2) >= 0);
759     xmlFree(arg1);
760     xmlFree(arg2);
761 }
762 
763 static void query_serror(void* ctx, xmlErrorPtr err)
764 {
765     LIBXML2_CALLBACK_SERROR(domselection_create, err);
766 }
767 
768 HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out)
769 {
770     domselection *This = heap_alloc(sizeof(domselection));
771     xmlXPathContextPtr ctxt = xmlXPathNewContext(node->doc);
772     HRESULT hr;
773 
774     TRACE("(%p, %s, %p)\n", node, debugstr_a((char const*)query), out);
775 
776     *out = NULL;
777     if (!This || !ctxt || !query)
778     {
779         xmlXPathFreeContext(ctxt);
780         heap_free(This);
781         return E_OUTOFMEMORY;
782     }
783 
784     This->IXMLDOMSelection_iface.lpVtbl = &domselection_vtbl;
785     This->ref = 1;
786     This->resultPos = 0;
787     This->node = node;
788     This->enumvariant = NULL;
789     init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSelection_iface, &domselection_dispex);
790     xmldoc_add_ref(This->node->doc);
791 
792     ctxt->error = query_serror;
793     ctxt->node = node;
794     registerNamespaces(ctxt);
795 
796     if (is_xpathmode(This->node->doc))
797     {
798         xmlXPathRegisterAllFunctions(ctxt);
799         This->result = xmlXPathEvalExpression(query, ctxt);
800     }
801     else
802     {
803         xmlChar* pattern_query = XSLPattern_to_XPath(ctxt, query);
804 
805         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"not", xmlXPathNotFunction);
806         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"boolean", xmlXPathBooleanFunction);
807 
808         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"index", XSLPattern_index);
809         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"end", XSLPattern_end);
810         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"nodeType", XSLPattern_nodeType);
811 
812         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IEq", XSLPattern_OP_IEq);
813         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_INEq", XSLPattern_OP_INEq);
814         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILt", XSLPattern_OP_ILt);
815         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_ILEq", XSLPattern_OP_ILEq);
816         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGt", XSLPattern_OP_IGt);
817         xmlXPathRegisterFunc(ctxt, (xmlChar const*)"OP_IGEq", XSLPattern_OP_IGEq);
818 
819         This->result = xmlXPathEvalExpression(pattern_query, ctxt);
820         xmlFree(pattern_query);
821     }
822 
823     if (!This->result || This->result->type != XPATH_NODESET)
824     {
825         hr = E_FAIL;
826         goto cleanup;
827     }
828 
829     *out = (IXMLDOMNodeList*)&This->IXMLDOMSelection_iface;
830     hr = S_OK;
831     TRACE("found %d matches\n", xmlXPathNodeSetGetLength(This->result->nodesetval));
832 
833 cleanup:
834     if (FAILED(hr))
835         IXMLDOMSelection_Release( &This->IXMLDOMSelection_iface );
836     xmlXPathFreeContext(ctxt);
837     return hr;
838 }
839 
840 #endif
841