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