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