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