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