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