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