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