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