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