1 /* 2 * Node implementation 3 * 4 * Copyright 2005 Mike McCormack 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "precomp.h" 22 23 #ifdef HAVE_LIBXML2 24 # include <libxml/HTMLtree.h> 25 # ifdef SONAME_LIBXSLT 26 # ifdef HAVE_LIBXSLT_PATTERN_H 27 # include <libxslt/pattern.h> 28 # endif 29 # ifdef HAVE_LIBXSLT_TRANSFORM_H 30 # include <libxslt/transform.h> 31 # endif 32 # include <libxslt/imports.h> 33 # include <libxslt/variables.h> 34 # include <libxslt/xsltutils.h> 35 # include <libxslt/xsltInternals.h> 36 # endif 37 #endif 38 39 #ifdef HAVE_LIBXML2 40 41 #ifdef SONAME_LIBXSLT 42 extern void* libxslt_handle; 43 # define MAKE_FUNCPTR(f) extern typeof(f) * p##f 44 MAKE_FUNCPTR(xsltApplyStylesheet); 45 MAKE_FUNCPTR(xsltApplyStylesheetUser); 46 MAKE_FUNCPTR(xsltCleanupGlobals); 47 MAKE_FUNCPTR(xsltFreeStylesheet); 48 MAKE_FUNCPTR(xsltFreeTransformContext); 49 MAKE_FUNCPTR(xsltNewTransformContext); 50 MAKE_FUNCPTR(xsltNextImport); 51 MAKE_FUNCPTR(xsltParseStylesheetDoc); 52 MAKE_FUNCPTR(xsltQuoteUserParams); 53 MAKE_FUNCPTR(xsltSaveResultTo); 54 # undef MAKE_FUNCPTR 55 #else 56 WINE_DECLARE_DEBUG_CHANNEL(winediag); 57 #endif 58 59 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}}; 60 61 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type ) 62 { 63 xmlnode *This; 64 65 if ( !iface ) 66 return NULL; 67 This = get_node_obj( iface ); 68 if ( !This || !This->node ) 69 return NULL; 70 if ( type && This->node->type != type ) 71 return NULL; 72 return This->node; 73 } 74 75 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv) 76 { 77 if(IsEqualGUID(&IID_xmlnode, riid)) { 78 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv); 79 *ppv = This; 80 return TRUE; 81 } 82 83 return dispex_query_interface(&This->dispex, riid, ppv); 84 } 85 86 /* common ISupportErrorInfo implementation */ 87 typedef struct { 88 ISupportErrorInfo ISupportErrorInfo_iface; 89 LONG ref; 90 91 const tid_t* iids; 92 } SupportErrorInfo; 93 94 static inline SupportErrorInfo *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface) 95 { 96 return CONTAINING_RECORD(iface, SupportErrorInfo, ISupportErrorInfo_iface); 97 } 98 99 static HRESULT WINAPI SupportErrorInfo_QueryInterface(ISupportErrorInfo *iface, REFIID riid, void **obj) 100 { 101 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface); 102 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); 103 104 *obj = NULL; 105 106 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISupportErrorInfo)) { 107 *obj = iface; 108 ISupportErrorInfo_AddRef(iface); 109 return S_OK; 110 } 111 112 return E_NOINTERFACE; 113 } 114 115 static ULONG WINAPI SupportErrorInfo_AddRef(ISupportErrorInfo *iface) 116 { 117 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface); 118 ULONG ref = InterlockedIncrement(&This->ref); 119 TRACE("(%p)->(%d)\n", This, ref ); 120 return ref; 121 } 122 123 static ULONG WINAPI SupportErrorInfo_Release(ISupportErrorInfo *iface) 124 { 125 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface); 126 LONG ref = InterlockedDecrement(&This->ref); 127 128 TRACE("(%p)->(%d)\n", This, ref); 129 130 if (ref == 0) 131 heap_free(This); 132 133 return ref; 134 } 135 136 static HRESULT WINAPI SupportErrorInfo_InterfaceSupportsErrorInfo(ISupportErrorInfo *iface, REFIID riid) 137 { 138 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface); 139 enum tid_t const *tid; 140 141 TRACE("(%p)->(%s)\n", This, debugstr_guid(riid)); 142 143 tid = This->iids; 144 while (*tid != NULL_tid) 145 { 146 if (IsEqualGUID(riid, get_riid_from_tid(*tid))) 147 return S_OK; 148 tid++; 149 } 150 151 return S_FALSE; 152 } 153 154 static const struct ISupportErrorInfoVtbl SupportErrorInfoVtbl = { 155 SupportErrorInfo_QueryInterface, 156 SupportErrorInfo_AddRef, 157 SupportErrorInfo_Release, 158 SupportErrorInfo_InterfaceSupportsErrorInfo 159 }; 160 161 HRESULT node_create_supporterrorinfo(enum tid_t const *iids, void **obj) 162 { 163 SupportErrorInfo *This; 164 165 This = heap_alloc(sizeof(*This)); 166 if (!This) return E_OUTOFMEMORY; 167 168 This->ISupportErrorInfo_iface.lpVtbl = &SupportErrorInfoVtbl; 169 This->ref = 1; 170 This->iids = iids; 171 172 *obj = &This->ISupportErrorInfo_iface; 173 174 return S_OK; 175 } 176 177 xmlnode *get_node_obj(IXMLDOMNode *node) 178 { 179 xmlnode *obj = NULL; 180 HRESULT hres; 181 182 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj); 183 if (!obj) WARN("node is not our IXMLDOMNode implementation\n"); 184 return SUCCEEDED(hres) ? obj : NULL; 185 } 186 187 HRESULT node_get_nodeName(xmlnode *This, BSTR *name) 188 { 189 BSTR prefix, base; 190 HRESULT hr; 191 192 if (!name) 193 return E_INVALIDARG; 194 195 hr = node_get_base_name(This, &base); 196 if (hr != S_OK) return hr; 197 198 hr = node_get_prefix(This, &prefix); 199 if (hr == S_OK) 200 { 201 static const WCHAR colW = ':'; 202 WCHAR *ptr; 203 204 /* +1 for ':' */ 205 ptr = *name = SysAllocStringLen(NULL, SysStringLen(base) + SysStringLen(prefix) + 1); 206 memcpy(ptr, prefix, SysStringByteLen(prefix)); 207 ptr += SysStringLen(prefix); 208 memcpy(ptr++, &colW, sizeof(WCHAR)); 209 memcpy(ptr, base, SysStringByteLen(base)); 210 211 SysFreeString(base); 212 SysFreeString(prefix); 213 } 214 else 215 *name = base; 216 217 return S_OK; 218 } 219 220 HRESULT node_get_content(xmlnode *This, VARIANT *value) 221 { 222 xmlChar *content; 223 224 if(!value) 225 return E_INVALIDARG; 226 227 content = xmlNodeGetContent(This->node); 228 V_VT(value) = VT_BSTR; 229 V_BSTR(value) = bstr_from_xmlChar( content ); 230 xmlFree(content); 231 232 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value))); 233 return S_OK; 234 } 235 236 HRESULT node_set_content(xmlnode *This, LPCWSTR value) 237 { 238 xmlChar *str; 239 240 TRACE("(%p)->(%s)\n", This, debugstr_w(value)); 241 str = xmlchar_from_wchar(value); 242 if(!str) 243 return E_OUTOFMEMORY; 244 245 xmlNodeSetContent(This->node, str); 246 heap_free(str); 247 return S_OK; 248 } 249 250 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value) 251 { 252 xmlChar *str, *escaped; 253 254 TRACE("(%p)->(%s)\n", This, debugstr_w(value)); 255 str = xmlchar_from_wchar(value); 256 if(!str) 257 return E_OUTOFMEMORY; 258 259 escaped = xmlEncodeSpecialChars(NULL, str); 260 if(!escaped) 261 { 262 heap_free(str); 263 return E_OUTOFMEMORY; 264 } 265 266 xmlNodeSetContent(This->node, escaped); 267 268 heap_free(str); 269 xmlFree(escaped); 270 271 return S_OK; 272 } 273 274 HRESULT node_put_value(xmlnode *This, VARIANT *value) 275 { 276 HRESULT hr; 277 278 if (V_VT(value) != VT_BSTR) 279 { 280 VARIANT string_value; 281 282 VariantInit(&string_value); 283 hr = VariantChangeType(&string_value, value, 0, VT_BSTR); 284 if(FAILED(hr)) { 285 WARN("Couldn't convert to VT_BSTR\n"); 286 return hr; 287 } 288 289 hr = node_set_content(This, V_BSTR(&string_value)); 290 VariantClear(&string_value); 291 } 292 else 293 hr = node_set_content(This, V_BSTR(value)); 294 295 return hr; 296 } 297 298 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value) 299 { 300 HRESULT hr; 301 302 if (V_VT(value) != VT_BSTR) 303 { 304 VARIANT string_value; 305 306 VariantInit(&string_value); 307 hr = VariantChangeType(&string_value, value, 0, VT_BSTR); 308 if(FAILED(hr)) { 309 WARN("Couldn't convert to VT_BSTR\n"); 310 return hr; 311 } 312 313 hr = node_set_content_escaped(This, V_BSTR(&string_value)); 314 VariantClear(&string_value); 315 } 316 else 317 hr = node_set_content_escaped(This, V_BSTR(value)); 318 319 return hr; 320 } 321 322 static HRESULT get_node( 323 xmlnode *This, 324 const char *name, 325 xmlNodePtr node, 326 IXMLDOMNode **out ) 327 { 328 TRACE("(%p)->(%s %p %p)\n", This, name, node, out ); 329 330 if ( !out ) 331 return E_INVALIDARG; 332 333 /* if we don't have a doc, use our parent. */ 334 if(node && !node->doc && node->parent) 335 node->doc = node->parent->doc; 336 337 *out = create_node( node ); 338 if (!*out) 339 return S_FALSE; 340 return S_OK; 341 } 342 343 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent) 344 { 345 return get_node( This, "parent", This->node->parent, parent ); 346 } 347 348 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret) 349 { 350 if(!ret) 351 return E_INVALIDARG; 352 353 *ret = create_children_nodelist(This->node); 354 if(!*ret) 355 return E_OUTOFMEMORY; 356 357 return S_OK; 358 } 359 360 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret) 361 { 362 return get_node(This, "firstChild", This->node->children, ret); 363 } 364 365 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret) 366 { 367 return get_node(This, "lastChild", This->node->last, ret); 368 } 369 370 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret) 371 { 372 return get_node(This, "previous", This->node->prev, ret); 373 } 374 375 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret) 376 { 377 return get_node(This, "next", This->node->next, ret); 378 } 379 380 static int node_get_inst_cnt(xmlNodePtr node) 381 { 382 int ret = *(LONG *)&node->_private & NODE_PRIV_REFCOUNT_MASK; 383 xmlNodePtr child; 384 385 /* add attribute counts */ 386 if (node->type == XML_ELEMENT_NODE) 387 { 388 xmlAttrPtr prop = node->properties; 389 390 while (prop) 391 { 392 ret += node_get_inst_cnt((xmlNodePtr)prop); 393 prop = prop->next; 394 } 395 } 396 397 /* add children counts */ 398 child = node->children; 399 while (child) 400 { 401 ret += node_get_inst_cnt(child); 402 child = child->next; 403 } 404 405 return ret; 406 } 407 408 int xmlnode_get_inst_cnt(xmlnode *node) 409 { 410 return node_get_inst_cnt(node->node); 411 } 412 413 /* _private field holds a number of COM instances spawned from this libxml2 node 414 * most significant bits are used to store information about ignorrable whitespace nodes */ 415 void xmlnode_add_ref(xmlNodePtr node) 416 { 417 if (node->type == XML_DOCUMENT_NODE) return; 418 InterlockedIncrement((LONG*)&node->_private); 419 } 420 421 void xmlnode_release(xmlNodePtr node) 422 { 423 if (node->type == XML_DOCUMENT_NODE) return; 424 InterlockedDecrement((LONG*)&node->_private); 425 } 426 427 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child, 428 IXMLDOMNode **ret) 429 { 430 IXMLDOMNode *before = NULL; 431 xmlnode *node_obj; 432 int refcount = 0; 433 xmlDocPtr doc; 434 HRESULT hr; 435 436 if(!new_child) 437 return E_INVALIDARG; 438 439 node_obj = get_node_obj(new_child); 440 if(!node_obj) return E_FAIL; 441 442 switch(V_VT(ref_child)) 443 { 444 case VT_EMPTY: 445 case VT_NULL: 446 break; 447 448 case VT_UNKNOWN: 449 case VT_DISPATCH: 450 if (V_UNKNOWN(ref_child)) 451 { 452 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before); 453 if(FAILED(hr)) return hr; 454 } 455 break; 456 457 default: 458 FIXME("refChild var type %x\n", V_VT(ref_child)); 459 return E_FAIL; 460 } 461 462 TRACE("new child %p, This->node %p\n", node_obj->node, This->node); 463 464 if(!node_obj->node->parent) 465 if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK) 466 WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc); 467 468 refcount = xmlnode_get_inst_cnt(node_obj); 469 470 if(before) 471 { 472 xmlnode *before_node_obj = get_node_obj(before); 473 IXMLDOMNode_Release(before); 474 if(!before_node_obj) return E_FAIL; 475 } 476 477 /* unlink from current parent first */ 478 if(node_obj->parent) 479 { 480 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL); 481 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node); 482 } 483 doc = node_obj->node->doc; 484 485 if(before) 486 { 487 xmlNodePtr new_node; 488 xmlnode *before_node_obj = get_node_obj(before); 489 490 /* refs count including subtree */ 491 if (doc != before_node_obj->node->doc) 492 refcount = xmlnode_get_inst_cnt(node_obj); 493 494 if (refcount) xmldoc_add_refs(before_node_obj->node->doc, refcount); 495 new_node = xmlAddPrevSibling(before_node_obj->node, node_obj->node); 496 if (new_node != node_obj->node) 497 { 498 if (refcount != 1) 499 FIXME("referenced xmlNode was freed, expect crashes\n"); 500 xmlnode_add_ref(new_node); 501 node_obj->node = new_node; 502 } 503 if (refcount) xmldoc_release_refs(doc, refcount); 504 node_obj->parent = This->parent; 505 } 506 else 507 { 508 xmlNodePtr new_node; 509 510 if (doc != This->node->doc) 511 refcount = xmlnode_get_inst_cnt(node_obj); 512 513 if (refcount) xmldoc_add_refs(This->node->doc, refcount); 514 /* xmlAddChild doesn't unlink node from previous parent */ 515 xmlUnlinkNode(node_obj->node); 516 new_node = xmlAddChild(This->node, node_obj->node); 517 if (new_node != node_obj->node) 518 { 519 if (refcount != 1) 520 FIXME("referenced xmlNode was freed, expect crashes\n"); 521 xmlnode_add_ref(new_node); 522 node_obj->node = new_node; 523 } 524 if (refcount) xmldoc_release_refs(doc, refcount); 525 node_obj->parent = This->iface; 526 } 527 528 if(ret) 529 { 530 IXMLDOMNode_AddRef(new_child); 531 *ret = new_child; 532 } 533 534 TRACE("ret S_OK\n"); 535 return S_OK; 536 } 537 538 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild, 539 IXMLDOMNode **ret) 540 { 541 xmlnode *old_child, *new_child; 542 xmlDocPtr leaving_doc; 543 xmlNode *my_ancestor; 544 int refcount = 0; 545 546 /* Do not believe any documentation telling that newChild == NULL 547 means removal. It does certainly *not* apply to msxml3! */ 548 if(!newChild || !oldChild) 549 return E_INVALIDARG; 550 551 if(ret) 552 *ret = NULL; 553 554 old_child = get_node_obj(oldChild); 555 if(!old_child) return E_FAIL; 556 557 if(old_child->node->parent != This->node) 558 { 559 WARN("childNode %p is not a child of %p\n", oldChild, This); 560 return E_INVALIDARG; 561 } 562 563 new_child = get_node_obj(newChild); 564 if(!new_child) return E_FAIL; 565 566 my_ancestor = This->node; 567 while(my_ancestor) 568 { 569 if(my_ancestor == new_child->node) 570 { 571 WARN("tried to create loop\n"); 572 return E_FAIL; 573 } 574 my_ancestor = my_ancestor->parent; 575 } 576 577 if(!new_child->node->parent) 578 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK) 579 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc); 580 581 leaving_doc = new_child->node->doc; 582 583 if (leaving_doc != old_child->node->doc) 584 refcount = xmlnode_get_inst_cnt(new_child); 585 586 if (refcount) xmldoc_add_refs(old_child->node->doc, refcount); 587 xmlReplaceNode(old_child->node, new_child->node); 588 if (refcount) xmldoc_release_refs(leaving_doc, refcount); 589 new_child->parent = old_child->parent; 590 old_child->parent = NULL; 591 592 xmldoc_add_orphan(old_child->node->doc, old_child->node); 593 594 if(ret) 595 { 596 IXMLDOMNode_AddRef(oldChild); 597 *ret = oldChild; 598 } 599 600 return S_OK; 601 } 602 603 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild) 604 { 605 xmlnode *child_node; 606 607 if(!child) return E_INVALIDARG; 608 609 if(oldChild) 610 *oldChild = NULL; 611 612 child_node = get_node_obj(child); 613 if(!child_node) return E_FAIL; 614 615 if(child_node->node->parent != This->node) 616 { 617 WARN("childNode %p is not a child of %p\n", child, This); 618 return E_INVALIDARG; 619 } 620 621 xmlUnlinkNode(child_node->node); 622 child_node->parent = NULL; 623 xmldoc_add_orphan(child_node->node->doc, child_node->node); 624 625 if(oldChild) 626 { 627 IXMLDOMNode_AddRef(child); 628 *oldChild = child; 629 } 630 631 return S_OK; 632 } 633 634 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild) 635 { 636 DOMNodeType type; 637 VARIANT var; 638 HRESULT hr; 639 640 if (!child) 641 return E_INVALIDARG; 642 643 hr = IXMLDOMNode_get_nodeType(child, &type); 644 if(FAILED(hr) || type == NODE_ATTRIBUTE) { 645 if (outChild) *outChild = NULL; 646 return E_FAIL; 647 } 648 649 VariantInit(&var); 650 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild); 651 } 652 653 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret) 654 { 655 if (!ret) return E_INVALIDARG; 656 657 if (!This->node->children) 658 { 659 *ret = VARIANT_FALSE; 660 return S_FALSE; 661 } 662 663 *ret = VARIANT_TRUE; 664 return S_OK; 665 } 666 667 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc) 668 { 669 if(!doc) 670 return E_INVALIDARG; 671 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc); 672 } 673 674 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode) 675 { 676 IXMLDOMNode *node; 677 xmlNodePtr clone; 678 679 if(!cloneNode) return E_INVALIDARG; 680 681 clone = xmlCopyNode(This->node, deep ? 1 : 2); 682 if (clone) 683 { 684 xmlSetTreeDoc(clone, This->node->doc); 685 xmldoc_add_orphan(clone->doc, clone); 686 687 node = create_node(clone); 688 if (!node) 689 { 690 ERR("Copy failed\n"); 691 xmldoc_remove_orphan(clone->doc, clone); 692 xmlFreeNode(clone); 693 return E_FAIL; 694 } 695 696 *cloneNode = node; 697 } 698 else 699 { 700 ERR("Copy failed\n"); 701 return E_FAIL; 702 } 703 704 return S_OK; 705 } 706 707 static xmlChar* do_get_text(xmlNodePtr node, BOOL trim, DWORD *first, DWORD *last, BOOL *trail_ig_ws) 708 { 709 xmlNodePtr child; 710 xmlChar* str; 711 BOOL preserving = is_preserving_whitespace(node); 712 713 *first = -1; 714 *last = 0; 715 716 if (!node->children) 717 { 718 str = xmlNodeGetContent(node); 719 *trail_ig_ws = *(DWORD*)&node->_private & NODE_PRIV_CHILD_IGNORABLE_WS; 720 } 721 else 722 { 723 BOOL ig_ws = FALSE; 724 xmlChar* tmp; 725 DWORD pos = 0; 726 str = xmlStrdup(BAD_CAST ""); 727 728 if (node->type != XML_DOCUMENT_NODE) 729 ig_ws = *(DWORD*)&node->_private & NODE_PRIV_CHILD_IGNORABLE_WS; 730 *trail_ig_ws = FALSE; 731 732 for (child = node->children; child != NULL; child = child->next) 733 { 734 switch (child->type) 735 { 736 case XML_ELEMENT_NODE: { 737 DWORD node_first, node_last; 738 739 tmp = do_get_text(child, FALSE, &node_first, &node_last, trail_ig_ws); 740 741 if (node_first!=-1 && pos+node_first<*first) 742 *first = pos+node_first; 743 if (node_last && pos+node_last>*last) 744 *last = pos+node_last; 745 break; 746 } 747 case XML_TEXT_NODE: 748 tmp = xmlNodeGetContent(child); 749 if (!preserving && tmp[0]) 750 { 751 xmlChar *beg; 752 753 for (beg = tmp; *beg; beg++) 754 if (!isspace(*beg)) break; 755 756 if (!*beg) 757 { 758 ig_ws = TRUE; 759 xmlFree(tmp); 760 tmp = NULL; 761 } 762 } 763 break; 764 case XML_CDATA_SECTION_NODE: 765 case XML_ENTITY_REF_NODE: 766 case XML_ENTITY_NODE: 767 tmp = xmlNodeGetContent(child); 768 break; 769 default: 770 tmp = NULL; 771 break; 772 } 773 774 if ((tmp && *tmp) || child->type==XML_CDATA_SECTION_NODE) 775 { 776 if (ig_ws && str[0]) 777 { 778 str = xmlStrcat(str, BAD_CAST " "); 779 pos++; 780 } 781 if (tmp && *tmp) str = xmlStrcat(str, tmp); 782 if (child->type==XML_CDATA_SECTION_NODE && pos<*first) 783 *first = pos; 784 if (tmp && *tmp) pos += xmlStrlen(tmp); 785 if (child->type==XML_CDATA_SECTION_NODE && pos>*last) 786 *last = pos; 787 ig_ws = FALSE; 788 } 789 if (tmp) xmlFree(tmp); 790 791 if (!ig_ws) 792 { 793 ig_ws = *(DWORD*)&child->_private & NODE_PRIV_TRAILING_IGNORABLE_WS; 794 } 795 if (!ig_ws) 796 ig_ws = *trail_ig_ws; 797 *trail_ig_ws = FALSE; 798 } 799 800 *trail_ig_ws = ig_ws; 801 } 802 803 switch (node->type) 804 { 805 case XML_ELEMENT_NODE: 806 case XML_TEXT_NODE: 807 case XML_ENTITY_REF_NODE: 808 case XML_ENTITY_NODE: 809 case XML_DOCUMENT_NODE: 810 case XML_DOCUMENT_FRAG_NODE: 811 if (trim && !preserving) 812 { 813 xmlChar* ret; 814 int len; 815 816 if (!str) 817 break; 818 819 for (ret = str; *ret && isspace(*ret) && (*first)--; ret++) 820 if (*last) (*last)--; 821 for (len = xmlStrlen(ret)-1; len >= 0 && len >= *last; len--) 822 if(!isspace(ret[len])) break; 823 824 ret = xmlStrndup(ret, len+1); 825 xmlFree(str); 826 str = ret; 827 break; 828 } 829 break; 830 default: 831 break; 832 } 833 834 return str; 835 } 836 837 HRESULT node_get_text(const xmlnode *This, BSTR *text) 838 { 839 BSTR str = NULL; 840 xmlChar *content; 841 DWORD first, last; 842 BOOL tmp; 843 844 if (!text) return E_INVALIDARG; 845 846 content = do_get_text(This->node, TRUE, &first, &last, &tmp); 847 if (content) 848 { 849 str = bstr_from_xmlChar(content); 850 xmlFree(content); 851 } 852 853 /* Always return a string. */ 854 if (!str) str = SysAllocStringLen( NULL, 0 ); 855 856 TRACE("%p %s\n", This, debugstr_w(str) ); 857 *text = str; 858 859 return S_OK; 860 } 861 862 HRESULT node_put_text(xmlnode *This, BSTR text) 863 { 864 xmlChar *str, *str2; 865 866 TRACE("(%p)->(%s)\n", This, debugstr_w(text)); 867 868 str = xmlchar_from_wchar(text); 869 870 /* Escape the string. */ 871 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str); 872 heap_free(str); 873 874 xmlNodeSetContent(This->node, str2); 875 xmlFree(str2); 876 877 return S_OK; 878 } 879 880 BSTR EnsureCorrectEOL(BSTR sInput) 881 { 882 int nNum = 0; 883 BSTR sNew; 884 int nLen; 885 int i; 886 887 nLen = SysStringLen(sInput); 888 /* Count line endings */ 889 for(i=0; i < nLen; i++) 890 { 891 if(sInput[i] == '\n') 892 nNum++; 893 } 894 895 TRACE("len=%d, num=%d\n", nLen, nNum); 896 897 /* Add linefeed as needed */ 898 if(nNum > 0) 899 { 900 int nPlace = 0; 901 sNew = SysAllocStringLen(NULL, nLen + nNum); 902 for(i=0; i < nLen; i++) 903 { 904 if(sInput[i] == '\n') 905 { 906 sNew[i+nPlace] = '\r'; 907 nPlace++; 908 } 909 sNew[i+nPlace] = sInput[i]; 910 } 911 912 SysFreeString(sInput); 913 } 914 else 915 { 916 sNew = sInput; 917 } 918 919 TRACE("len %d\n", SysStringLen(sNew)); 920 921 return sNew; 922 } 923 924 /* 925 * We are trying to replicate the same behaviour as msxml by converting 926 * line endings to \r\n and using indents as \t. The problem is that msxml 927 * only formats nodes that have a line ending. Using libxml we cannot 928 * reproduce behaviour exactly. 929 * 930 */ 931 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BSTR *ret) 932 { 933 xmlBufferPtr xml_buf; 934 xmlNodePtr xmldecl; 935 int size; 936 937 if(!ret) 938 return E_INVALIDARG; 939 940 *ret = NULL; 941 942 xml_buf = xmlBufferCreate(); 943 if(!xml_buf) 944 return E_OUTOFMEMORY; 945 946 xmldecl = xmldoc_unlink_xmldecl( This->node->doc ); 947 948 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1); 949 if(size > 0) { 950 const xmlChar *buf_content; 951 BSTR content; 952 953 /* Attribute Nodes return a space in front of their name */ 954 buf_content = xmlBufferContent(xml_buf); 955 956 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0)); 957 if(ensure_eol) 958 content = EnsureCorrectEOL(content); 959 960 *ret = content; 961 }else { 962 *ret = SysAllocStringLen(NULL, 0); 963 } 964 965 xmlBufferFree(xml_buf); 966 xmldoc_link_xmldecl( This->node->doc, xmldecl ); 967 return *ret ? S_OK : E_OUTOFMEMORY; 968 } 969 970 #ifdef SONAME_LIBXSLT 971 972 /* duplicates xmlBufferWriteQuotedString() logic */ 973 static void xml_write_quotedstring(xmlOutputBufferPtr buf, const xmlChar *string) 974 { 975 const xmlChar *cur, *base; 976 977 if (xmlStrchr(string, '\"')) 978 { 979 if (xmlStrchr(string, '\'')) 980 { 981 xmlOutputBufferWrite(buf, 1, "\""); 982 base = cur = string; 983 984 while (*cur) 985 { 986 if (*cur == '"') 987 { 988 if (base != cur) 989 xmlOutputBufferWrite(buf, cur-base, (const char*)base); 990 xmlOutputBufferWrite(buf, 6, """); 991 cur++; 992 base = cur; 993 } 994 else 995 cur++; 996 } 997 if (base != cur) 998 xmlOutputBufferWrite(buf, cur-base, (const char*)base); 999 xmlOutputBufferWrite(buf, 1, "\""); 1000 } 1001 else 1002 { 1003 xmlOutputBufferWrite(buf, 1, "\'"); 1004 xmlOutputBufferWriteString(buf, (const char*)string); 1005 xmlOutputBufferWrite(buf, 1, "\'"); 1006 } 1007 } 1008 else 1009 { 1010 xmlOutputBufferWrite(buf, 1, "\""); 1011 xmlOutputBufferWriteString(buf, (const char*)string); 1012 xmlOutputBufferWrite(buf, 1, "\""); 1013 } 1014 } 1015 1016 static int XMLCALL transform_to_stream_write(void *context, const char *buffer, int len) 1017 { 1018 DWORD written; 1019 HRESULT hr = ISequentialStream_Write((ISequentialStream *)context, buffer, len, &written); 1020 return hr == S_OK ? written : -1; 1021 } 1022 1023 /* Output for method "text" */ 1024 static void transform_write_text(xmlDocPtr result, xsltStylesheetPtr style, xmlOutputBufferPtr output) 1025 { 1026 xmlNodePtr cur = result->children; 1027 while (cur) 1028 { 1029 if (cur->type == XML_TEXT_NODE) 1030 xmlOutputBufferWriteString(output, (const char*)cur->content); 1031 1032 /* skip to next node */ 1033 if (cur->children) 1034 { 1035 if ((cur->children->type != XML_ENTITY_DECL) && 1036 (cur->children->type != XML_ENTITY_REF_NODE) && 1037 (cur->children->type != XML_ENTITY_NODE)) 1038 { 1039 cur = cur->children; 1040 continue; 1041 } 1042 } 1043 1044 if (cur->next) { 1045 cur = cur->next; 1046 continue; 1047 } 1048 1049 do 1050 { 1051 cur = cur->parent; 1052 if (cur == NULL) 1053 break; 1054 if (cur == (xmlNodePtr) style->doc) { 1055 cur = NULL; 1056 break; 1057 } 1058 if (cur->next) { 1059 cur = cur->next; 1060 break; 1061 } 1062 } while (cur); 1063 } 1064 } 1065 1066 #undef XSLT_GET_IMPORT_PTR 1067 #define XSLT_GET_IMPORT_PTR(res, style, name) { \ 1068 xsltStylesheetPtr st = style; \ 1069 res = NULL; \ 1070 while (st != NULL) { \ 1071 if (st->name != NULL) { res = st->name; break; } \ 1072 st = pxsltNextImport(st); \ 1073 }} 1074 1075 #undef XSLT_GET_IMPORT_INT 1076 #define XSLT_GET_IMPORT_INT(res, style, name) { \ 1077 xsltStylesheetPtr st = style; \ 1078 res = -1; \ 1079 while (st != NULL) { \ 1080 if (st->name != -1) { res = st->name; break; } \ 1081 st = pxsltNextImport(st); \ 1082 }} 1083 1084 static void transform_write_xmldecl(xmlDocPtr result, xsltStylesheetPtr style, BOOL omit_encoding, xmlOutputBufferPtr output) 1085 { 1086 int omit_xmldecl, standalone; 1087 1088 XSLT_GET_IMPORT_INT(omit_xmldecl, style, omitXmlDeclaration); 1089 if (omit_xmldecl == 1) return; 1090 1091 XSLT_GET_IMPORT_INT(standalone, style, standalone); 1092 1093 xmlOutputBufferWriteString(output, "<?xml version="); 1094 if (result->version) 1095 { 1096 xmlOutputBufferWriteString(output, "\""); 1097 xmlOutputBufferWriteString(output, (const char *)result->version); 1098 xmlOutputBufferWriteString(output, "\""); 1099 } 1100 else 1101 xmlOutputBufferWriteString(output, "\"1.0\""); 1102 1103 if (!omit_encoding) 1104 { 1105 const xmlChar *encoding; 1106 1107 /* default encoding is UTF-16 */ 1108 XSLT_GET_IMPORT_PTR(encoding, style, encoding); 1109 xmlOutputBufferWriteString(output, " encoding="); 1110 xmlOutputBufferWriteString(output, "\""); 1111 xmlOutputBufferWriteString(output, encoding ? (const char *)encoding : "UTF-16"); 1112 xmlOutputBufferWriteString(output, "\""); 1113 } 1114 1115 /* standalone attribute */ 1116 if (standalone != -1) 1117 xmlOutputBufferWriteString(output, standalone == 0 ? " standalone=\"no\"" : " standalone=\"yes\""); 1118 1119 xmlOutputBufferWriteString(output, "?>"); 1120 } 1121 1122 static void htmldtd_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc) 1123 { 1124 xmlDtdPtr cur = doc->intSubset; 1125 1126 xmlOutputBufferWriteString(buf, "<!DOCTYPE "); 1127 xmlOutputBufferWriteString(buf, (const char *)cur->name); 1128 if (cur->ExternalID) 1129 { 1130 xmlOutputBufferWriteString(buf, " PUBLIC "); 1131 xml_write_quotedstring(buf, cur->ExternalID); 1132 if (cur->SystemID) 1133 { 1134 xmlOutputBufferWriteString(buf, " "); 1135 xml_write_quotedstring(buf, cur->SystemID); 1136 } 1137 } 1138 else if (cur->SystemID) 1139 { 1140 xmlOutputBufferWriteString(buf, " SYSTEM "); 1141 xml_write_quotedstring(buf, cur->SystemID); 1142 } 1143 xmlOutputBufferWriteString(buf, ">\n"); 1144 } 1145 1146 /* Duplicates htmlDocContentDumpFormatOutput() the way we need it - doesn't add trailing newline. */ 1147 static void htmldoc_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc, const char *encoding, int format) 1148 { 1149 xmlElementType type; 1150 1151 /* force HTML output */ 1152 type = doc->type; 1153 doc->type = XML_HTML_DOCUMENT_NODE; 1154 if (doc->intSubset) 1155 htmldtd_dumpcontent(buf, doc); 1156 if (doc->children) { 1157 xmlNodePtr cur = doc->children; 1158 while (cur) { 1159 htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format); 1160 cur = cur->next; 1161 } 1162 } 1163 doc->type = type; 1164 } 1165 1166 static inline BOOL transform_is_empty_resultdoc(xmlDocPtr result) 1167 { 1168 return !result->children || ((result->children->type == XML_DTD_NODE) && !result->children->next); 1169 } 1170 1171 static inline BOOL transform_is_valid_method(xsltStylesheetPtr style) 1172 { 1173 return !style->methodURI || !(style->method && xmlStrEqual(style->method, (const xmlChar *)"xhtml")); 1174 } 1175 1176 /* Helper to write transformation result to specified output buffer. */ 1177 static HRESULT node_transform_write(xsltStylesheetPtr style, xmlDocPtr result, BOOL omit_encoding, const char *encoding, xmlOutputBufferPtr output) 1178 { 1179 const xmlChar *method; 1180 int indent; 1181 1182 if (!transform_is_valid_method(style)) 1183 { 1184 ERR("unknown output method\n"); 1185 return E_FAIL; 1186 } 1187 1188 XSLT_GET_IMPORT_PTR(method, style, method) 1189 XSLT_GET_IMPORT_INT(indent, style, indent); 1190 1191 if (!method && (result->type == XML_HTML_DOCUMENT_NODE)) 1192 method = (const xmlChar *) "html"; 1193 1194 if (method && xmlStrEqual(method, (const xmlChar *)"html")) 1195 { 1196 htmlSetMetaEncoding(result, (const xmlChar *)encoding); 1197 if (indent == -1) 1198 indent = 1; 1199 htmldoc_dumpcontent(output, result, (const char*)encoding, indent); 1200 } 1201 else if (method && xmlStrEqual(method, (const xmlChar *)"xhtml")) 1202 { 1203 htmlSetMetaEncoding(result, (const xmlChar *) encoding); 1204 htmlDocContentDumpOutput(output, result, encoding); 1205 } 1206 else if (method && xmlStrEqual(method, (const xmlChar *)"text")) 1207 transform_write_text(result, style, output); 1208 else 1209 { 1210 transform_write_xmldecl(result, style, omit_encoding, output); 1211 1212 if (result->children) 1213 { 1214 xmlNodePtr child = result->children; 1215 1216 while (child) 1217 { 1218 xmlNodeDumpOutput(output, result, child, 0, indent == 1, encoding); 1219 if (indent && ((child->type == XML_DTD_NODE) || ((child->type == XML_COMMENT_NODE) && child->next))) 1220 xmlOutputBufferWriteString(output, "\r\n"); 1221 child = child->next; 1222 } 1223 } 1224 } 1225 1226 xmlOutputBufferFlush(output); 1227 return S_OK; 1228 } 1229 1230 /* For BSTR output is always UTF-16, without 'encoding' attribute */ 1231 static HRESULT node_transform_write_to_bstr(xsltStylesheetPtr style, xmlDocPtr result, BSTR *str) 1232 { 1233 HRESULT hr = S_OK; 1234 1235 if (transform_is_empty_resultdoc(result)) 1236 *str = SysAllocStringLen(NULL, 0); 1237 else 1238 { 1239 xmlOutputBufferPtr output = xmlAllocOutputBuffer(xmlFindCharEncodingHandler("UTF-16")); 1240 const xmlChar *content; 1241 size_t len; 1242 1243 *str = NULL; 1244 if (!output) 1245 return E_OUTOFMEMORY; 1246 1247 hr = node_transform_write(style, result, TRUE, "UTF-16", output); 1248 #ifdef LIBXML2_NEW_BUFFER 1249 content = xmlBufContent(output->conv); 1250 len = xmlBufUse(output->conv); 1251 #else 1252 content = xmlBufferContent(output->conv); 1253 len = xmlBufferLength(output->conv); 1254 #endif 1255 /* UTF-16 encoder places UTF-16 bom, we don't need it for BSTR */ 1256 content += sizeof(WCHAR); 1257 *str = SysAllocStringLen((WCHAR*)content, len/sizeof(WCHAR) - 1); 1258 xmlOutputBufferClose(output); 1259 } 1260 1261 return *str ? hr : E_OUTOFMEMORY; 1262 } 1263 1264 static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr result, ISequentialStream *stream) 1265 { 1266 static const xmlChar *utf16 = (const xmlChar*)"UTF-16"; 1267 xmlOutputBufferPtr output; 1268 const xmlChar *encoding; 1269 HRESULT hr; 1270 1271 if (transform_is_empty_resultdoc(result)) 1272 { 1273 WARN("empty result document\n"); 1274 return S_OK; 1275 } 1276 1277 if (style->methodURI && (!style->method || !xmlStrEqual(style->method, (const xmlChar *) "xhtml"))) 1278 { 1279 ERR("unknown output method\n"); 1280 return E_FAIL; 1281 } 1282 1283 /* default encoding is UTF-16 */ 1284 XSLT_GET_IMPORT_PTR(encoding, style, encoding); 1285 if (!encoding) 1286 encoding = utf16; 1287 1288 output = xmlOutputBufferCreateIO(transform_to_stream_write, NULL, stream, xmlFindCharEncodingHandler((const char*)encoding)); 1289 if (!output) 1290 return E_OUTOFMEMORY; 1291 1292 hr = node_transform_write(style, result, FALSE, (const char*)encoding, output); 1293 xmlOutputBufferClose(output); 1294 return hr; 1295 } 1296 1297 #endif 1298 1299 HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p, 1300 ISequentialStream *stream, const struct xslprocessor_params *params) 1301 { 1302 #ifdef SONAME_LIBXSLT 1303 xsltStylesheetPtr xsltSS; 1304 xmlDocPtr sheet_doc; 1305 HRESULT hr = S_OK; 1306 xmlnode *sheet; 1307 1308 if (!libxslt_handle) return E_NOTIMPL; 1309 if (!stylesheet || !p) return E_INVALIDARG; 1310 1311 *p = NULL; 1312 1313 sheet = get_node_obj(stylesheet); 1314 if(!sheet) return E_FAIL; 1315 1316 sheet_doc = xmlCopyDoc(sheet->node->doc, 1); 1317 xsltSS = pxsltParseStylesheetDoc(sheet_doc); 1318 if (xsltSS) 1319 { 1320 const char **xslparams = NULL; 1321 xmlDocPtr result; 1322 unsigned int i; 1323 1324 /* convert our parameter list to libxml2 format */ 1325 if (params && params->count) 1326 { 1327 struct xslprocessor_par *par; 1328 1329 i = 0; 1330 xslparams = heap_alloc((params->count*2 + 1)*sizeof(char*)); 1331 LIST_FOR_EACH_ENTRY(par, ¶ms->list, struct xslprocessor_par, entry) 1332 { 1333 xslparams[i++] = (char*)xmlchar_from_wchar(par->name); 1334 xslparams[i++] = (char*)xmlchar_from_wchar(par->value); 1335 } 1336 xslparams[i] = NULL; 1337 } 1338 1339 if (xslparams) 1340 { 1341 xsltTransformContextPtr ctxt = pxsltNewTransformContext(xsltSS, This->node->doc); 1342 1343 /* push parameters to user context */ 1344 pxsltQuoteUserParams(ctxt, xslparams); 1345 result = pxsltApplyStylesheetUser(xsltSS, This->node->doc, NULL, NULL, NULL, ctxt); 1346 pxsltFreeTransformContext(ctxt); 1347 1348 for (i = 0; i < params->count*2; i++) 1349 heap_free((char*)xslparams[i]); 1350 heap_free(xslparams); 1351 } 1352 else 1353 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL); 1354 1355 if (result) 1356 { 1357 if (stream) 1358 hr = node_transform_write_to_stream(xsltSS, result, stream); 1359 else 1360 hr = node_transform_write_to_bstr(xsltSS, result, p); 1361 xmlFreeDoc(result); 1362 } 1363 1364 pxsltFreeStylesheet(xsltSS); 1365 } 1366 else 1367 xmlFreeDoc(sheet_doc); 1368 1369 if(!*p) *p = SysAllocStringLen(NULL, 0); 1370 1371 return hr; 1372 #else 1373 ERR_(winediag)("libxslt headers were not found at compile time. Expect problems.\n"); 1374 1375 return E_NOTIMPL; 1376 #endif 1377 } 1378 1379 HRESULT node_transform_node(const xmlnode *node, IXMLDOMNode *stylesheet, BSTR *p) 1380 { 1381 return node_transform_node_params(node, stylesheet, p, NULL, NULL); 1382 } 1383 1384 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes) 1385 { 1386 xmlChar* str; 1387 HRESULT hr; 1388 1389 if (!query || !nodes) return E_INVALIDARG; 1390 1391 str = xmlchar_from_wchar(query); 1392 hr = create_selection(This->node, str, nodes); 1393 heap_free(str); 1394 1395 return hr; 1396 } 1397 1398 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node) 1399 { 1400 IXMLDOMNodeList *list; 1401 HRESULT hr; 1402 1403 hr = node_select_nodes(This, query, &list); 1404 if (hr == S_OK) 1405 { 1406 hr = IXMLDOMNodeList_nextNode(list, node); 1407 IXMLDOMNodeList_Release(list); 1408 } 1409 return hr; 1410 } 1411 1412 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI) 1413 { 1414 xmlNsPtr ns = This->node->ns; 1415 1416 if(!namespaceURI) 1417 return E_INVALIDARG; 1418 1419 *namespaceURI = NULL; 1420 1421 if (ns && ns->href) 1422 *namespaceURI = bstr_from_xmlChar(ns->href); 1423 1424 TRACE("uri: %s\n", debugstr_w(*namespaceURI)); 1425 1426 return *namespaceURI ? S_OK : S_FALSE; 1427 } 1428 1429 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix) 1430 { 1431 xmlNsPtr ns = This->node->ns; 1432 1433 if (!prefix) return E_INVALIDARG; 1434 1435 *prefix = NULL; 1436 1437 if (ns && ns->prefix) 1438 *prefix = bstr_from_xmlChar(ns->prefix); 1439 1440 TRACE("prefix: %s\n", debugstr_w(*prefix)); 1441 1442 return *prefix ? S_OK : S_FALSE; 1443 } 1444 1445 HRESULT node_get_base_name(xmlnode *This, BSTR *name) 1446 { 1447 if (!name) return E_INVALIDARG; 1448 1449 *name = bstr_from_xmlChar(This->node->name); 1450 if (!*name) return E_OUTOFMEMORY; 1451 1452 TRACE("returning %s\n", debugstr_w(*name)); 1453 1454 return S_OK; 1455 } 1456 1457 void destroy_xmlnode(xmlnode *This) 1458 { 1459 if(This->node) 1460 { 1461 xmlnode_release(This->node); 1462 xmldoc_release(This->node->doc); 1463 } 1464 } 1465 1466 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data) 1467 { 1468 if(node) 1469 { 1470 xmlnode_add_ref(node); 1471 xmldoc_add_ref(node->doc); 1472 } 1473 1474 This->node = node; 1475 This->iface = node_iface; 1476 This->parent = NULL; 1477 1478 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data); 1479 } 1480 1481 typedef struct { 1482 xmlnode node; 1483 IXMLDOMNode IXMLDOMNode_iface; 1484 LONG ref; 1485 } unknode; 1486 1487 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface) 1488 { 1489 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface); 1490 } 1491 1492 static HRESULT WINAPI unknode_QueryInterface( 1493 IXMLDOMNode *iface, 1494 REFIID riid, 1495 void** ppvObject ) 1496 { 1497 unknode *This = unknode_from_IXMLDOMNode( iface ); 1498 1499 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); 1500 1501 if (IsEqualGUID(riid, &IID_IUnknown)) { 1502 *ppvObject = iface; 1503 }else if (IsEqualGUID( riid, &IID_IDispatch) || 1504 IsEqualGUID( riid, &IID_IXMLDOMNode)) { 1505 *ppvObject = &This->IXMLDOMNode_iface; 1506 }else if(node_query_interface(&This->node, riid, ppvObject)) { 1507 return *ppvObject ? S_OK : E_NOINTERFACE; 1508 }else { 1509 FIXME("interface %s not implemented\n", debugstr_guid(riid)); 1510 *ppvObject = NULL; 1511 return E_NOINTERFACE; 1512 } 1513 1514 IUnknown_AddRef((IUnknown*)*ppvObject); 1515 return S_OK; 1516 } 1517 1518 static ULONG WINAPI unknode_AddRef( 1519 IXMLDOMNode *iface ) 1520 { 1521 unknode *This = unknode_from_IXMLDOMNode( iface ); 1522 1523 return InterlockedIncrement(&This->ref); 1524 } 1525 1526 static ULONG WINAPI unknode_Release( 1527 IXMLDOMNode *iface ) 1528 { 1529 unknode *This = unknode_from_IXMLDOMNode( iface ); 1530 LONG ref; 1531 1532 ref = InterlockedDecrement( &This->ref ); 1533 if(!ref) { 1534 destroy_xmlnode(&This->node); 1535 heap_free(This); 1536 } 1537 1538 return ref; 1539 } 1540 1541 static HRESULT WINAPI unknode_GetTypeInfoCount( 1542 IXMLDOMNode *iface, 1543 UINT* pctinfo ) 1544 { 1545 unknode *This = unknode_from_IXMLDOMNode( iface ); 1546 1547 TRACE("(%p)->(%p)\n", This, pctinfo); 1548 1549 *pctinfo = 1; 1550 1551 return S_OK; 1552 } 1553 1554 static HRESULT WINAPI unknode_GetTypeInfo( 1555 IXMLDOMNode *iface, 1556 UINT iTInfo, 1557 LCID lcid, 1558 ITypeInfo** ppTInfo ) 1559 { 1560 unknode *This = unknode_from_IXMLDOMNode( iface ); 1561 HRESULT hr; 1562 1563 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 1564 1565 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo); 1566 1567 return hr; 1568 } 1569 1570 static HRESULT WINAPI unknode_GetIDsOfNames( 1571 IXMLDOMNode *iface, 1572 REFIID riid, 1573 LPOLESTR* rgszNames, 1574 UINT cNames, 1575 LCID lcid, 1576 DISPID* rgDispId ) 1577 { 1578 unknode *This = unknode_from_IXMLDOMNode( iface ); 1579 1580 ITypeInfo *typeinfo; 1581 HRESULT hr; 1582 1583 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, 1584 lcid, rgDispId); 1585 1586 if(!rgszNames || cNames == 0 || !rgDispId) 1587 return E_INVALIDARG; 1588 1589 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo); 1590 if(SUCCEEDED(hr)) 1591 { 1592 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); 1593 ITypeInfo_Release(typeinfo); 1594 } 1595 1596 return hr; 1597 } 1598 1599 static HRESULT WINAPI unknode_Invoke( 1600 IXMLDOMNode *iface, 1601 DISPID dispIdMember, 1602 REFIID riid, 1603 LCID lcid, 1604 WORD wFlags, 1605 DISPPARAMS* pDispParams, 1606 VARIANT* pVarResult, 1607 EXCEPINFO* pExcepInfo, 1608 UINT* puArgErr ) 1609 { 1610 unknode *This = unknode_from_IXMLDOMNode( iface ); 1611 ITypeInfo *typeinfo; 1612 HRESULT hr; 1613 1614 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 1615 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 1616 1617 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo); 1618 if(SUCCEEDED(hr)) 1619 { 1620 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams, 1621 pVarResult, pExcepInfo, puArgErr); 1622 ITypeInfo_Release(typeinfo); 1623 } 1624 1625 return hr; 1626 } 1627 1628 static HRESULT WINAPI unknode_get_nodeName( 1629 IXMLDOMNode *iface, 1630 BSTR* p ) 1631 { 1632 unknode *This = unknode_from_IXMLDOMNode( iface ); 1633 1634 FIXME("(%p)->(%p)\n", This, p); 1635 1636 return node_get_nodeName(&This->node, p); 1637 } 1638 1639 static HRESULT WINAPI unknode_get_nodeValue( 1640 IXMLDOMNode *iface, 1641 VARIANT* value) 1642 { 1643 unknode *This = unknode_from_IXMLDOMNode( iface ); 1644 1645 FIXME("(%p)->(%p)\n", This, value); 1646 1647 if(!value) 1648 return E_INVALIDARG; 1649 1650 V_VT(value) = VT_NULL; 1651 return S_FALSE; 1652 } 1653 1654 static HRESULT WINAPI unknode_put_nodeValue( 1655 IXMLDOMNode *iface, 1656 VARIANT value) 1657 { 1658 unknode *This = unknode_from_IXMLDOMNode( iface ); 1659 FIXME("(%p)->(v%d)\n", This, V_VT(&value)); 1660 return E_FAIL; 1661 } 1662 1663 static HRESULT WINAPI unknode_get_nodeType( 1664 IXMLDOMNode *iface, 1665 DOMNodeType* domNodeType ) 1666 { 1667 unknode *This = unknode_from_IXMLDOMNode( iface ); 1668 1669 FIXME("(%p)->(%p)\n", This, domNodeType); 1670 1671 switch (This->node.node->type) 1672 { 1673 case XML_ELEMENT_NODE: 1674 case XML_ATTRIBUTE_NODE: 1675 case XML_TEXT_NODE: 1676 case XML_CDATA_SECTION_NODE: 1677 case XML_ENTITY_REF_NODE: 1678 case XML_ENTITY_NODE: 1679 case XML_PI_NODE: 1680 case XML_COMMENT_NODE: 1681 case XML_DOCUMENT_NODE: 1682 case XML_DOCUMENT_TYPE_NODE: 1683 case XML_DOCUMENT_FRAG_NODE: 1684 case XML_NOTATION_NODE: 1685 /* we only care about this set of types, libxml2 type values are 1686 exactly what we need */ 1687 *domNodeType = (DOMNodeType)This->node.node->type; 1688 break; 1689 default: 1690 *domNodeType = NODE_INVALID; 1691 break; 1692 } 1693 1694 return S_OK; 1695 } 1696 1697 static HRESULT WINAPI unknode_get_parentNode( 1698 IXMLDOMNode *iface, 1699 IXMLDOMNode** parent ) 1700 { 1701 unknode *This = unknode_from_IXMLDOMNode( iface ); 1702 FIXME("(%p)->(%p)\n", This, parent); 1703 if (!parent) return E_INVALIDARG; 1704 *parent = NULL; 1705 return S_FALSE; 1706 } 1707 1708 static HRESULT WINAPI unknode_get_childNodes( 1709 IXMLDOMNode *iface, 1710 IXMLDOMNodeList** outList) 1711 { 1712 unknode *This = unknode_from_IXMLDOMNode( iface ); 1713 1714 TRACE("(%p)->(%p)\n", This, outList); 1715 1716 return node_get_child_nodes(&This->node, outList); 1717 } 1718 1719 static HRESULT WINAPI unknode_get_firstChild( 1720 IXMLDOMNode *iface, 1721 IXMLDOMNode** domNode) 1722 { 1723 unknode *This = unknode_from_IXMLDOMNode( iface ); 1724 1725 TRACE("(%p)->(%p)\n", This, domNode); 1726 1727 return node_get_first_child(&This->node, domNode); 1728 } 1729 1730 static HRESULT WINAPI unknode_get_lastChild( 1731 IXMLDOMNode *iface, 1732 IXMLDOMNode** domNode) 1733 { 1734 unknode *This = unknode_from_IXMLDOMNode( iface ); 1735 1736 TRACE("(%p)->(%p)\n", This, domNode); 1737 1738 return node_get_last_child(&This->node, domNode); 1739 } 1740 1741 static HRESULT WINAPI unknode_get_previousSibling( 1742 IXMLDOMNode *iface, 1743 IXMLDOMNode** domNode) 1744 { 1745 unknode *This = unknode_from_IXMLDOMNode( iface ); 1746 1747 TRACE("(%p)->(%p)\n", This, domNode); 1748 1749 return node_get_previous_sibling(&This->node, domNode); 1750 } 1751 1752 static HRESULT WINAPI unknode_get_nextSibling( 1753 IXMLDOMNode *iface, 1754 IXMLDOMNode** domNode) 1755 { 1756 unknode *This = unknode_from_IXMLDOMNode( iface ); 1757 1758 TRACE("(%p)->(%p)\n", This, domNode); 1759 1760 return node_get_next_sibling(&This->node, domNode); 1761 } 1762 1763 static HRESULT WINAPI unknode_get_attributes( 1764 IXMLDOMNode *iface, 1765 IXMLDOMNamedNodeMap** attributeMap) 1766 { 1767 unknode *This = unknode_from_IXMLDOMNode( iface ); 1768 1769 FIXME("(%p)->(%p)\n", This, attributeMap); 1770 1771 return return_null_ptr((void**)attributeMap); 1772 } 1773 1774 static HRESULT WINAPI unknode_insertBefore( 1775 IXMLDOMNode *iface, 1776 IXMLDOMNode* newNode, VARIANT refChild, 1777 IXMLDOMNode** outOldNode) 1778 { 1779 unknode *This = unknode_from_IXMLDOMNode( iface ); 1780 1781 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode); 1782 1783 return node_insert_before(&This->node, newNode, &refChild, outOldNode); 1784 } 1785 1786 static HRESULT WINAPI unknode_replaceChild( 1787 IXMLDOMNode *iface, 1788 IXMLDOMNode* newNode, 1789 IXMLDOMNode* oldNode, 1790 IXMLDOMNode** outOldNode) 1791 { 1792 unknode *This = unknode_from_IXMLDOMNode( iface ); 1793 1794 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode); 1795 1796 return node_replace_child(&This->node, newNode, oldNode, outOldNode); 1797 } 1798 1799 static HRESULT WINAPI unknode_removeChild( 1800 IXMLDOMNode *iface, 1801 IXMLDOMNode* domNode, IXMLDOMNode** oldNode) 1802 { 1803 unknode *This = unknode_from_IXMLDOMNode( iface ); 1804 return node_remove_child(&This->node, domNode, oldNode); 1805 } 1806 1807 static HRESULT WINAPI unknode_appendChild( 1808 IXMLDOMNode *iface, 1809 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode) 1810 { 1811 unknode *This = unknode_from_IXMLDOMNode( iface ); 1812 return node_append_child(&This->node, newNode, outNewNode); 1813 } 1814 1815 static HRESULT WINAPI unknode_hasChildNodes( 1816 IXMLDOMNode *iface, 1817 VARIANT_BOOL* pbool) 1818 { 1819 unknode *This = unknode_from_IXMLDOMNode( iface ); 1820 return node_has_childnodes(&This->node, pbool); 1821 } 1822 1823 static HRESULT WINAPI unknode_get_ownerDocument( 1824 IXMLDOMNode *iface, 1825 IXMLDOMDocument** domDocument) 1826 { 1827 unknode *This = unknode_from_IXMLDOMNode( iface ); 1828 return node_get_owner_doc(&This->node, domDocument); 1829 } 1830 1831 static HRESULT WINAPI unknode_cloneNode( 1832 IXMLDOMNode *iface, 1833 VARIANT_BOOL pbool, IXMLDOMNode** outNode) 1834 { 1835 unknode *This = unknode_from_IXMLDOMNode( iface ); 1836 return node_clone(&This->node, pbool, outNode ); 1837 } 1838 1839 static HRESULT WINAPI unknode_get_nodeTypeString( 1840 IXMLDOMNode *iface, 1841 BSTR* p) 1842 { 1843 unknode *This = unknode_from_IXMLDOMNode( iface ); 1844 1845 FIXME("(%p)->(%p)\n", This, p); 1846 1847 return node_get_nodeName(&This->node, p); 1848 } 1849 1850 static HRESULT WINAPI unknode_get_text( 1851 IXMLDOMNode *iface, 1852 BSTR* p) 1853 { 1854 unknode *This = unknode_from_IXMLDOMNode( iface ); 1855 return node_get_text(&This->node, p); 1856 } 1857 1858 static HRESULT WINAPI unknode_put_text( 1859 IXMLDOMNode *iface, 1860 BSTR p) 1861 { 1862 unknode *This = unknode_from_IXMLDOMNode( iface ); 1863 return node_put_text(&This->node, p); 1864 } 1865 1866 static HRESULT WINAPI unknode_get_specified( 1867 IXMLDOMNode *iface, 1868 VARIANT_BOOL* isSpecified) 1869 { 1870 unknode *This = unknode_from_IXMLDOMNode( iface ); 1871 FIXME("(%p)->(%p) stub!\n", This, isSpecified); 1872 *isSpecified = VARIANT_TRUE; 1873 return S_OK; 1874 } 1875 1876 static HRESULT WINAPI unknode_get_definition( 1877 IXMLDOMNode *iface, 1878 IXMLDOMNode** definitionNode) 1879 { 1880 unknode *This = unknode_from_IXMLDOMNode( iface ); 1881 FIXME("(%p)->(%p)\n", This, definitionNode); 1882 return E_NOTIMPL; 1883 } 1884 1885 static HRESULT WINAPI unknode_get_nodeTypedValue( 1886 IXMLDOMNode *iface, 1887 VARIANT* var1) 1888 { 1889 unknode *This = unknode_from_IXMLDOMNode( iface ); 1890 FIXME("(%p)->(%p)\n", This, var1); 1891 return return_null_var(var1); 1892 } 1893 1894 static HRESULT WINAPI unknode_put_nodeTypedValue( 1895 IXMLDOMNode *iface, 1896 VARIANT typedValue) 1897 { 1898 unknode *This = unknode_from_IXMLDOMNode( iface ); 1899 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue)); 1900 return E_NOTIMPL; 1901 } 1902 1903 static HRESULT WINAPI unknode_get_dataType( 1904 IXMLDOMNode *iface, 1905 VARIANT* var1) 1906 { 1907 unknode *This = unknode_from_IXMLDOMNode( iface ); 1908 TRACE("(%p)->(%p)\n", This, var1); 1909 return return_null_var(var1); 1910 } 1911 1912 static HRESULT WINAPI unknode_put_dataType( 1913 IXMLDOMNode *iface, 1914 BSTR p) 1915 { 1916 unknode *This = unknode_from_IXMLDOMNode( iface ); 1917 1918 FIXME("(%p)->(%s)\n", This, debugstr_w(p)); 1919 1920 if(!p) 1921 return E_INVALIDARG; 1922 1923 return E_FAIL; 1924 } 1925 1926 static HRESULT WINAPI unknode_get_xml( 1927 IXMLDOMNode *iface, 1928 BSTR* p) 1929 { 1930 unknode *This = unknode_from_IXMLDOMNode( iface ); 1931 1932 FIXME("(%p)->(%p)\n", This, p); 1933 1934 return node_get_xml(&This->node, FALSE, p); 1935 } 1936 1937 static HRESULT WINAPI unknode_transformNode( 1938 IXMLDOMNode *iface, 1939 IXMLDOMNode* domNode, BSTR* p) 1940 { 1941 unknode *This = unknode_from_IXMLDOMNode( iface ); 1942 return node_transform_node(&This->node, domNode, p); 1943 } 1944 1945 static HRESULT WINAPI unknode_selectNodes( 1946 IXMLDOMNode *iface, 1947 BSTR p, IXMLDOMNodeList** outList) 1948 { 1949 unknode *This = unknode_from_IXMLDOMNode( iface ); 1950 return node_select_nodes(&This->node, p, outList); 1951 } 1952 1953 static HRESULT WINAPI unknode_selectSingleNode( 1954 IXMLDOMNode *iface, 1955 BSTR p, IXMLDOMNode** outNode) 1956 { 1957 unknode *This = unknode_from_IXMLDOMNode( iface ); 1958 return node_select_singlenode(&This->node, p, outNode); 1959 } 1960 1961 static HRESULT WINAPI unknode_get_parsed( 1962 IXMLDOMNode *iface, 1963 VARIANT_BOOL* isParsed) 1964 { 1965 unknode *This = unknode_from_IXMLDOMNode( iface ); 1966 FIXME("(%p)->(%p) stub!\n", This, isParsed); 1967 *isParsed = VARIANT_TRUE; 1968 return S_OK; 1969 } 1970 1971 static HRESULT WINAPI unknode_get_namespaceURI( 1972 IXMLDOMNode *iface, 1973 BSTR* p) 1974 { 1975 unknode *This = unknode_from_IXMLDOMNode( iface ); 1976 TRACE("(%p)->(%p)\n", This, p); 1977 return node_get_namespaceURI(&This->node, p); 1978 } 1979 1980 static HRESULT WINAPI unknode_get_prefix( 1981 IXMLDOMNode *iface, 1982 BSTR* p) 1983 { 1984 unknode *This = unknode_from_IXMLDOMNode( iface ); 1985 return node_get_prefix(&This->node, p); 1986 } 1987 1988 static HRESULT WINAPI unknode_get_baseName( 1989 IXMLDOMNode *iface, 1990 BSTR* p) 1991 { 1992 unknode *This = unknode_from_IXMLDOMNode( iface ); 1993 return node_get_base_name(&This->node, p); 1994 } 1995 1996 static HRESULT WINAPI unknode_transformNodeToObject( 1997 IXMLDOMNode *iface, 1998 IXMLDOMNode* domNode, VARIANT var1) 1999 { 2000 unknode *This = unknode_from_IXMLDOMNode( iface ); 2001 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1)); 2002 return E_NOTIMPL; 2003 } 2004 2005 static const struct IXMLDOMNodeVtbl unknode_vtbl = 2006 { 2007 unknode_QueryInterface, 2008 unknode_AddRef, 2009 unknode_Release, 2010 unknode_GetTypeInfoCount, 2011 unknode_GetTypeInfo, 2012 unknode_GetIDsOfNames, 2013 unknode_Invoke, 2014 unknode_get_nodeName, 2015 unknode_get_nodeValue, 2016 unknode_put_nodeValue, 2017 unknode_get_nodeType, 2018 unknode_get_parentNode, 2019 unknode_get_childNodes, 2020 unknode_get_firstChild, 2021 unknode_get_lastChild, 2022 unknode_get_previousSibling, 2023 unknode_get_nextSibling, 2024 unknode_get_attributes, 2025 unknode_insertBefore, 2026 unknode_replaceChild, 2027 unknode_removeChild, 2028 unknode_appendChild, 2029 unknode_hasChildNodes, 2030 unknode_get_ownerDocument, 2031 unknode_cloneNode, 2032 unknode_get_nodeTypeString, 2033 unknode_get_text, 2034 unknode_put_text, 2035 unknode_get_specified, 2036 unknode_get_definition, 2037 unknode_get_nodeTypedValue, 2038 unknode_put_nodeTypedValue, 2039 unknode_get_dataType, 2040 unknode_put_dataType, 2041 unknode_get_xml, 2042 unknode_transformNode, 2043 unknode_selectNodes, 2044 unknode_selectSingleNode, 2045 unknode_get_parsed, 2046 unknode_get_namespaceURI, 2047 unknode_get_prefix, 2048 unknode_get_baseName, 2049 unknode_transformNodeToObject 2050 }; 2051 2052 IXMLDOMNode *create_node( xmlNodePtr node ) 2053 { 2054 IUnknown *pUnk; 2055 IXMLDOMNode *ret; 2056 HRESULT hr; 2057 2058 if ( !node ) 2059 return NULL; 2060 2061 TRACE("type %d\n", node->type); 2062 switch(node->type) 2063 { 2064 case XML_ELEMENT_NODE: 2065 pUnk = create_element( node ); 2066 break; 2067 case XML_ATTRIBUTE_NODE: 2068 pUnk = create_attribute( node ); 2069 break; 2070 case XML_TEXT_NODE: 2071 pUnk = create_text( node ); 2072 break; 2073 case XML_CDATA_SECTION_NODE: 2074 pUnk = create_cdata( node ); 2075 break; 2076 case XML_ENTITY_REF_NODE: 2077 pUnk = create_doc_entity_ref( node ); 2078 break; 2079 case XML_PI_NODE: 2080 pUnk = create_pi( node ); 2081 break; 2082 case XML_COMMENT_NODE: 2083 pUnk = create_comment( node ); 2084 break; 2085 case XML_DOCUMENT_NODE: 2086 pUnk = create_domdoc( node ); 2087 break; 2088 case XML_DOCUMENT_FRAG_NODE: 2089 pUnk = create_doc_fragment( node ); 2090 break; 2091 case XML_DTD_NODE: 2092 case XML_DOCUMENT_TYPE_NODE: 2093 pUnk = create_doc_type( node ); 2094 break; 2095 case XML_ENTITY_NODE: 2096 case XML_NOTATION_NODE: { 2097 unknode *new_node; 2098 2099 FIXME("only creating basic node for type %d\n", node->type); 2100 2101 new_node = heap_alloc(sizeof(unknode)); 2102 if(!new_node) 2103 return NULL; 2104 2105 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl; 2106 new_node->ref = 1; 2107 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL); 2108 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface; 2109 break; 2110 } 2111 default: 2112 ERR("Called for unsupported node type %d\n", node->type); 2113 return NULL; 2114 } 2115 2116 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret); 2117 IUnknown_Release(pUnk); 2118 if(FAILED(hr)) return NULL; 2119 return ret; 2120 } 2121 #endif 2122