1 /* 2 * DOM Document 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 #define COBJMACROS 22 23 #include "config.h" 24 25 #include <stdarg.h> 26 #ifdef HAVE_LIBXML2 27 # include <libxml/parser.h> 28 # include <libxml/xmlerror.h> 29 #endif 30 31 #include "windef.h" 32 #include "winbase.h" 33 #include "winuser.h" 34 #include "winnls.h" 35 #include "ole2.h" 36 #include "msxml6.h" 37 38 #include "msxml_private.h" 39 40 #include "wine/debug.h" 41 42 #ifdef HAVE_LIBXML2 43 44 WINE_DEFAULT_DEBUG_CHANNEL(msxml); 45 46 static const xmlChar DT_prefix[] = "dt"; 47 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes"; 48 49 typedef struct _domelem 50 { 51 xmlnode node; 52 IXMLDOMElement IXMLDOMElement_iface; 53 LONG ref; 54 } domelem; 55 56 static const struct nodemap_funcs domelem_attr_map; 57 58 static const tid_t domelem_se_tids[] = { 59 IXMLDOMNode_tid, 60 IXMLDOMElement_tid, 61 NULL_tid 62 }; 63 64 static inline domelem *impl_from_IXMLDOMElement( IXMLDOMElement *iface ) 65 { 66 return CONTAINING_RECORD(iface, domelem, IXMLDOMElement_iface); 67 } 68 69 static inline xmlNodePtr get_element( const domelem *This ) 70 { 71 return This->node.node; 72 } 73 74 static HRESULT WINAPI domelem_QueryInterface( 75 IXMLDOMElement *iface, 76 REFIID riid, 77 void** ppvObject ) 78 { 79 domelem *This = impl_from_IXMLDOMElement( iface ); 80 81 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); 82 83 if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) || 84 IsEqualGUID( riid, &IID_IXMLDOMNode ) || 85 IsEqualGUID( riid, &IID_IDispatch ) || 86 IsEqualGUID( riid, &IID_IUnknown ) ) 87 { 88 *ppvObject = &This->IXMLDOMElement_iface; 89 } 90 else if(node_query_interface(&This->node, riid, ppvObject)) 91 { 92 return *ppvObject ? S_OK : E_NOINTERFACE; 93 } 94 else if(IsEqualGUID( riid, &IID_ISupportErrorInfo )) 95 { 96 return node_create_supporterrorinfo(domelem_se_tids, ppvObject); 97 } 98 else 99 { 100 TRACE("interface %s not implemented\n", debugstr_guid(riid)); 101 *ppvObject = NULL; 102 return E_NOINTERFACE; 103 } 104 105 IUnknown_AddRef( (IUnknown*)*ppvObject ); 106 return S_OK; 107 } 108 109 static ULONG WINAPI domelem_AddRef( 110 IXMLDOMElement *iface ) 111 { 112 domelem *This = impl_from_IXMLDOMElement( iface ); 113 LONG ref = InterlockedIncrement(&This->ref); 114 115 TRACE("(%p)->(%d)\n", This, ref); 116 117 return ref; 118 } 119 120 static ULONG WINAPI domelem_Release( 121 IXMLDOMElement *iface ) 122 { 123 domelem *This = impl_from_IXMLDOMElement( iface ); 124 ULONG ref = InterlockedDecrement(&This->ref); 125 126 TRACE("(%p)->(%d)\n", This, ref); 127 128 if(!ref) { 129 destroy_xmlnode(&This->node); 130 heap_free(This); 131 } 132 133 return ref; 134 } 135 136 static HRESULT WINAPI domelem_GetTypeInfoCount( 137 IXMLDOMElement *iface, 138 UINT* pctinfo ) 139 { 140 domelem *This = impl_from_IXMLDOMElement( iface ); 141 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo); 142 } 143 144 static HRESULT WINAPI domelem_GetTypeInfo( 145 IXMLDOMElement *iface, 146 UINT iTInfo, LCID lcid, 147 ITypeInfo** ppTInfo ) 148 { 149 domelem *This = impl_from_IXMLDOMElement( iface ); 150 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, 151 iTInfo, lcid, ppTInfo); 152 } 153 154 static HRESULT WINAPI domelem_GetIDsOfNames( 155 IXMLDOMElement *iface, 156 REFIID riid, LPOLESTR* rgszNames, 157 UINT cNames, LCID lcid, DISPID* rgDispId ) 158 { 159 domelem *This = impl_from_IXMLDOMElement( iface ); 160 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface, 161 riid, rgszNames, cNames, lcid, rgDispId); 162 } 163 164 static HRESULT WINAPI domelem_Invoke( 165 IXMLDOMElement *iface, 166 DISPID dispIdMember, REFIID riid, LCID lcid, 167 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, 168 EXCEPINFO* pExcepInfo, UINT* puArgErr ) 169 { 170 domelem *This = impl_from_IXMLDOMElement( iface ); 171 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface, 172 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 173 } 174 175 static HRESULT WINAPI domelem_get_nodeName( 176 IXMLDOMElement *iface, 177 BSTR* p ) 178 { 179 domelem *This = impl_from_IXMLDOMElement( iface ); 180 181 TRACE("(%p)->(%p)\n", This, p); 182 183 return node_get_nodeName(&This->node, p); 184 } 185 186 static HRESULT WINAPI domelem_get_nodeValue( 187 IXMLDOMElement *iface, 188 VARIANT* value) 189 { 190 domelem *This = impl_from_IXMLDOMElement( iface ); 191 192 TRACE("(%p)->(%p)\n", This, value); 193 194 if(!value) 195 return E_INVALIDARG; 196 197 V_VT(value) = VT_NULL; 198 V_BSTR(value) = NULL; /* tests show that we should do this */ 199 return S_FALSE; 200 } 201 202 static HRESULT WINAPI domelem_put_nodeValue( 203 IXMLDOMElement *iface, 204 VARIANT value) 205 { 206 domelem *This = impl_from_IXMLDOMElement( iface ); 207 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value)); 208 return E_FAIL; 209 } 210 211 static HRESULT WINAPI domelem_get_nodeType( 212 IXMLDOMElement *iface, 213 DOMNodeType* domNodeType ) 214 { 215 domelem *This = impl_from_IXMLDOMElement( iface ); 216 217 TRACE("(%p)->(%p)\n", This, domNodeType); 218 219 *domNodeType = NODE_ELEMENT; 220 return S_OK; 221 } 222 223 static HRESULT WINAPI domelem_get_parentNode( 224 IXMLDOMElement *iface, 225 IXMLDOMNode** parent ) 226 { 227 domelem *This = impl_from_IXMLDOMElement( iface ); 228 229 TRACE("(%p)->(%p)\n", This, parent); 230 231 return node_get_parent(&This->node, parent); 232 } 233 234 static HRESULT WINAPI domelem_get_childNodes( 235 IXMLDOMElement *iface, 236 IXMLDOMNodeList** outList) 237 { 238 domelem *This = impl_from_IXMLDOMElement( iface ); 239 240 TRACE("(%p)->(%p)\n", This, outList); 241 242 return node_get_child_nodes(&This->node, outList); 243 } 244 245 static HRESULT WINAPI domelem_get_firstChild( 246 IXMLDOMElement *iface, 247 IXMLDOMNode** domNode) 248 { 249 domelem *This = impl_from_IXMLDOMElement( iface ); 250 251 TRACE("(%p)->(%p)\n", This, domNode); 252 253 return node_get_first_child(&This->node, domNode); 254 } 255 256 static HRESULT WINAPI domelem_get_lastChild( 257 IXMLDOMElement *iface, 258 IXMLDOMNode** domNode) 259 { 260 domelem *This = impl_from_IXMLDOMElement( iface ); 261 262 TRACE("(%p)->(%p)\n", This, domNode); 263 264 return node_get_last_child(&This->node, domNode); 265 } 266 267 static HRESULT WINAPI domelem_get_previousSibling( 268 IXMLDOMElement *iface, 269 IXMLDOMNode** domNode) 270 { 271 domelem *This = impl_from_IXMLDOMElement( iface ); 272 273 TRACE("(%p)->(%p)\n", This, domNode); 274 275 return node_get_previous_sibling(&This->node, domNode); 276 } 277 278 static HRESULT WINAPI domelem_get_nextSibling( 279 IXMLDOMElement *iface, 280 IXMLDOMNode** domNode) 281 { 282 domelem *This = impl_from_IXMLDOMElement( iface ); 283 284 TRACE("(%p)->(%p)\n", This, domNode); 285 286 return node_get_next_sibling(&This->node, domNode); 287 } 288 289 static HRESULT WINAPI domelem_get_attributes( 290 IXMLDOMElement *iface, 291 IXMLDOMNamedNodeMap** map) 292 { 293 domelem *This = impl_from_IXMLDOMElement( iface ); 294 295 TRACE("(%p)->(%p)\n", This, map); 296 297 *map = create_nodemap(This->node.node, &domelem_attr_map); 298 return S_OK; 299 } 300 301 static HRESULT WINAPI domelem_insertBefore( 302 IXMLDOMElement *iface, 303 IXMLDOMNode* newNode, VARIANT refChild, 304 IXMLDOMNode** old_node) 305 { 306 domelem *This = impl_from_IXMLDOMElement( iface ); 307 DOMNodeType type; 308 HRESULT hr; 309 310 TRACE("(%p)->(%p %s %p)\n", This, newNode, debugstr_variant(&refChild), old_node); 311 312 hr = IXMLDOMNode_get_nodeType(newNode, &type); 313 if (hr != S_OK) return hr; 314 315 TRACE("new node type %d\n", type); 316 switch (type) 317 { 318 case NODE_DOCUMENT: 319 case NODE_DOCUMENT_TYPE: 320 case NODE_ENTITY: 321 case NODE_NOTATION: 322 if (old_node) *old_node = NULL; 323 return E_FAIL; 324 default: 325 return node_insert_before(&This->node, newNode, &refChild, old_node); 326 } 327 } 328 329 static HRESULT WINAPI domelem_replaceChild( 330 IXMLDOMElement *iface, 331 IXMLDOMNode* newNode, 332 IXMLDOMNode* oldNode, 333 IXMLDOMNode** outOldNode) 334 { 335 domelem *This = impl_from_IXMLDOMElement( iface ); 336 337 TRACE("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode); 338 339 return node_replace_child(&This->node, newNode, oldNode, outOldNode); 340 } 341 342 static HRESULT WINAPI domelem_removeChild( 343 IXMLDOMElement *iface, 344 IXMLDOMNode *child, IXMLDOMNode **oldChild) 345 { 346 domelem *This = impl_from_IXMLDOMElement( iface ); 347 TRACE("(%p)->(%p %p)\n", This, child, oldChild); 348 return node_remove_child(&This->node, child, oldChild); 349 } 350 351 static HRESULT WINAPI domelem_appendChild( 352 IXMLDOMElement *iface, 353 IXMLDOMNode *child, IXMLDOMNode **outChild) 354 { 355 domelem *This = impl_from_IXMLDOMElement( iface ); 356 TRACE("(%p)->(%p %p)\n", This, child, outChild); 357 return node_append_child(&This->node, child, outChild); 358 } 359 360 static HRESULT WINAPI domelem_hasChildNodes( 361 IXMLDOMElement *iface, 362 VARIANT_BOOL *ret) 363 { 364 domelem *This = impl_from_IXMLDOMElement( iface ); 365 TRACE("(%p)->(%p)\n", This, ret); 366 return node_has_childnodes(&This->node, ret); 367 } 368 369 static HRESULT WINAPI domelem_get_ownerDocument( 370 IXMLDOMElement *iface, 371 IXMLDOMDocument **doc) 372 { 373 domelem *This = impl_from_IXMLDOMElement( iface ); 374 TRACE("(%p)->(%p)\n", This, doc); 375 return node_get_owner_doc(&This->node, doc); 376 } 377 378 static HRESULT WINAPI domelem_cloneNode( 379 IXMLDOMElement *iface, 380 VARIANT_BOOL deep, IXMLDOMNode** outNode) 381 { 382 domelem *This = impl_from_IXMLDOMElement( iface ); 383 TRACE("(%p)->(%d %p)\n", This, deep, outNode); 384 return node_clone( &This->node, deep, outNode ); 385 } 386 387 static HRESULT WINAPI domelem_get_nodeTypeString( 388 IXMLDOMElement *iface, 389 BSTR* p) 390 { 391 domelem *This = impl_from_IXMLDOMElement( iface ); 392 static const WCHAR elementW[] = {'e','l','e','m','e','n','t',0}; 393 394 TRACE("(%p)->(%p)\n", This, p); 395 396 return return_bstr(elementW, p); 397 } 398 399 static HRESULT WINAPI domelem_get_text( 400 IXMLDOMElement *iface, 401 BSTR* p) 402 { 403 domelem *This = impl_from_IXMLDOMElement( iface ); 404 TRACE("(%p)->(%p)\n", This, p); 405 return node_get_text(&This->node, p); 406 } 407 408 static HRESULT WINAPI domelem_put_text( 409 IXMLDOMElement *iface, 410 BSTR p) 411 { 412 domelem *This = impl_from_IXMLDOMElement( iface ); 413 TRACE("(%p)->(%s)\n", This, debugstr_w(p)); 414 return node_put_text( &This->node, p ); 415 } 416 417 static HRESULT WINAPI domelem_get_specified( 418 IXMLDOMElement *iface, 419 VARIANT_BOOL* isSpecified) 420 { 421 domelem *This = impl_from_IXMLDOMElement( iface ); 422 FIXME("(%p)->(%p) stub!\n", This, isSpecified); 423 *isSpecified = VARIANT_TRUE; 424 return S_OK; 425 } 426 427 static HRESULT WINAPI domelem_get_definition( 428 IXMLDOMElement *iface, 429 IXMLDOMNode** definitionNode) 430 { 431 domelem *This = impl_from_IXMLDOMElement( iface ); 432 FIXME("(%p)->(%p)\n", This, definitionNode); 433 return E_NOTIMPL; 434 } 435 436 static inline BYTE hex_to_byte(xmlChar c) 437 { 438 if(c <= '9') return c-'0'; 439 if(c <= 'F') return c-'A'+10; 440 return c-'a'+10; 441 } 442 443 static inline BYTE base64_to_byte(xmlChar c) 444 { 445 if(c == '+') return 62; 446 if(c == '/') return 63; 447 if(c <= '9') return c-'0'+52; 448 if(c <= 'Z') return c-'A'; 449 return c-'a'+26; 450 } 451 452 static inline HRESULT variant_from_dt(XDR_DT dt, xmlChar* str, VARIANT* v) 453 { 454 VARIANT src; 455 HRESULT hr = S_OK; 456 BOOL handled = FALSE; 457 458 VariantInit(&src); 459 460 switch (dt) 461 { 462 case DT_INVALID: 463 case DT_STRING: 464 case DT_NMTOKEN: 465 case DT_NMTOKENS: 466 case DT_NUMBER: 467 case DT_URI: 468 case DT_UUID: 469 { 470 V_VT(v) = VT_BSTR; 471 V_BSTR(v) = bstr_from_xmlChar(str); 472 473 if(!V_BSTR(v)) 474 return E_OUTOFMEMORY; 475 handled = TRUE; 476 } 477 break; 478 case DT_DATE: 479 case DT_DATE_TZ: 480 case DT_DATETIME: 481 case DT_DATETIME_TZ: 482 case DT_TIME: 483 case DT_TIME_TZ: 484 { 485 WCHAR *p, *e; 486 SYSTEMTIME st; 487 DOUBLE date = 0.0; 488 489 st.wYear = 1899; 490 st.wMonth = 12; 491 st.wDay = 30; 492 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; 493 494 V_VT(&src) = VT_BSTR; 495 V_BSTR(&src) = bstr_from_xmlChar(str); 496 497 if(!V_BSTR(&src)) 498 return E_OUTOFMEMORY; 499 500 p = V_BSTR(&src); 501 e = p + SysStringLen(V_BSTR(&src)); 502 503 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */ 504 { 505 st.wYear = atoiW(p); 506 st.wMonth = atoiW(p+5); 507 st.wDay = atoiW(p+8); 508 p += 10; 509 510 if(*p == 'T') p++; 511 } 512 513 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */ 514 { 515 st.wHour = atoiW(p); 516 st.wMinute = atoiW(p+3); 517 st.wSecond = atoiW(p+6); 518 p += 8; 519 520 if(*p == '.') 521 { 522 p++; 523 while(isdigitW(*p)) p++; 524 } 525 } 526 527 SystemTimeToVariantTime(&st, &date); 528 V_VT(v) = VT_DATE; 529 V_DATE(v) = date; 530 531 if(*p == '+') /* parse timezone offset (+hh:mm) */ 532 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440; 533 else if(*p == '-') /* parse timezone offset (-hh:mm) */ 534 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440; 535 536 VariantClear(&src); 537 handled = TRUE; 538 } 539 break; 540 case DT_BIN_HEX: 541 { 542 SAFEARRAYBOUND sab; 543 int i, len; 544 545 len = xmlStrlen(str)/2; 546 sab.lLbound = 0; 547 sab.cElements = len; 548 549 V_VT(v) = (VT_ARRAY|VT_UI1); 550 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab); 551 552 if(!V_ARRAY(v)) 553 return E_OUTOFMEMORY; 554 555 for(i=0; i<len; i++) 556 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4) 557 + hex_to_byte(str[2*i+1]); 558 handled = TRUE; 559 } 560 break; 561 case DT_BIN_BASE64: 562 { 563 SAFEARRAYBOUND sab; 564 xmlChar *c1, *c2; 565 int i, len; 566 567 /* remove all formatting chars */ 568 c1 = c2 = str; 569 len = 0; 570 while (*c2) 571 { 572 if ( *c2 == ' ' || *c2 == '\t' || 573 *c2 == '\n' || *c2 == '\r' ) 574 { 575 c2++; 576 continue; 577 } 578 *c1++ = *c2++; 579 len++; 580 } 581 582 /* skip padding */ 583 if(str[len-2] == '=') i = 2; 584 else if(str[len-1] == '=') i = 1; 585 else i = 0; 586 587 sab.lLbound = 0; 588 sab.cElements = len/4*3-i; 589 590 V_VT(v) = (VT_ARRAY|VT_UI1); 591 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab); 592 593 if(!V_ARRAY(v)) 594 return E_OUTOFMEMORY; 595 596 for(i=0; i<len/4; i++) 597 { 598 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2) 599 + (base64_to_byte(str[4*i+1])>>4); 600 if(3*i+1 < sab.cElements) 601 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4) 602 + (base64_to_byte(str[4*i+2])>>2); 603 if(3*i+2 < sab.cElements) 604 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6) 605 + base64_to_byte(str[4*i+3]); 606 } 607 handled = TRUE; 608 } 609 break; 610 case DT_BOOLEAN: 611 V_VT(v) = VT_BOOL; 612 break; 613 case DT_FIXED_14_4: 614 V_VT(v) = VT_CY; 615 break; 616 case DT_I1: 617 V_VT(v) = VT_I1; 618 break; 619 case DT_I2: 620 V_VT(v) = VT_I2; 621 break; 622 case DT_I4: 623 case DT_INT: 624 V_VT(v) = VT_I4; 625 break; 626 case DT_I8: 627 V_VT(v) = VT_I8; 628 break; 629 case DT_R4: 630 V_VT(v) = VT_R4; 631 break; 632 case DT_FLOAT: 633 case DT_R8: 634 V_VT(v) = VT_R8; 635 break; 636 case DT_UI1: 637 V_VT(v) = VT_UI1; 638 break; 639 case DT_UI2: 640 V_VT(v) = VT_UI2; 641 break; 642 case DT_UI4: 643 V_VT(v) = VT_UI4; 644 break; 645 case DT_UI8: 646 V_VT(v) = VT_UI8; 647 break; 648 case DT_CHAR: 649 case DT_ENTITY: 650 case DT_ENTITIES: 651 case DT_ENUMERATION: 652 case DT_ID: 653 case DT_IDREF: 654 case DT_IDREFS: 655 case DT_NOTATION: 656 FIXME("need to handle dt:%s\n", debugstr_dt(dt)); 657 V_VT(v) = VT_BSTR; 658 V_BSTR(v) = bstr_from_xmlChar(str); 659 if (!V_BSTR(v)) 660 return E_OUTOFMEMORY; 661 handled = TRUE; 662 break; 663 default: 664 WARN("unknown type %d\n", dt); 665 } 666 667 if (!handled) 668 { 669 V_VT(&src) = VT_BSTR; 670 V_BSTR(&src) = bstr_from_xmlChar(str); 671 672 if(!V_BSTR(&src)) 673 return E_OUTOFMEMORY; 674 675 hr = VariantChangeTypeEx(v, &src, 676 MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v)); 677 VariantClear(&src); 678 } 679 return hr; 680 } 681 682 static XDR_DT element_get_dt(xmlNodePtr node) 683 { 684 XDR_DT dt = DT_INVALID; 685 686 TRACE("(%p)\n", node); 687 if(node->type != XML_ELEMENT_NODE) 688 { 689 FIXME("invalid element node\n"); 690 return dt; 691 } 692 693 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI)) 694 { 695 dt = str_to_dt(node->name, -1); 696 } 697 else 698 { 699 xmlChar* pVal = xmlGetNsProp(node, BAD_CAST "dt", DT_nsURI); 700 if (pVal) 701 { 702 dt = str_to_dt(pVal, -1); 703 xmlFree(pVal); 704 } 705 else if (node->doc) 706 { 707 IXMLDOMDocument3* doc = (IXMLDOMDocument3*)create_domdoc((xmlNodePtr)node->doc); 708 if (doc) 709 { 710 VARIANT v; 711 VariantInit(&v); 712 713 if (IXMLDOMDocument3_get_schemas(doc, &v) == S_OK && 714 V_VT(&v) == VT_DISPATCH) 715 { 716 dt = SchemaCache_get_node_dt((IXMLDOMSchemaCollection2*)V_DISPATCH(&v), node); 717 } 718 VariantClear(&v); 719 IXMLDOMDocument3_Release(doc); 720 } 721 } 722 } 723 724 TRACE("=> dt:%s\n", debugstr_dt(dt)); 725 return dt; 726 } 727 728 static HRESULT WINAPI domelem_get_nodeTypedValue( 729 IXMLDOMElement *iface, 730 VARIANT* v) 731 { 732 domelem *This = impl_from_IXMLDOMElement( iface ); 733 XDR_DT dt; 734 xmlChar* content; 735 HRESULT hr; 736 737 TRACE("(%p)->(%p)\n", This, v); 738 739 if(!v) return E_INVALIDARG; 740 741 V_VT(v) = VT_NULL; 742 743 dt = element_get_dt(get_element(This)); 744 content = xmlNodeGetContent(get_element(This)); 745 hr = variant_from_dt(dt, content, v); 746 xmlFree(content); 747 748 return hr; 749 } 750 751 static HRESULT encode_base64(const BYTE *buf, int len, BSTR *ret) 752 { 753 static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 754 const BYTE *d = buf; 755 int bytes, pad_bytes, div; 756 DWORD needed; 757 WCHAR *ptr; 758 759 bytes = (len*8 + 5)/6; 760 pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0; 761 762 TRACE("%d, bytes is %d, pad bytes is %d\n", len, bytes, pad_bytes); 763 needed = bytes + pad_bytes + 1; 764 765 *ret = SysAllocStringLen(NULL, needed); 766 if (!*ret) return E_OUTOFMEMORY; 767 768 /* Three bytes of input give 4 chars of output */ 769 div = len / 3; 770 771 ptr = *ret; 772 while (div > 0) 773 { 774 /* first char is the first 6 bits of the first byte*/ 775 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; 776 /* second char is the last 2 bits of the first byte and the first 4 777 * bits of the second byte */ 778 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; 779 /* third char is the last 4 bits of the second byte and the first 2 780 * bits of the third byte */ 781 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)]; 782 /* fourth char is the remaining 6 bits of the third byte */ 783 *ptr++ = b64[ d[2] & 0x3f]; 784 d += 3; 785 div--; 786 } 787 788 switch (pad_bytes) 789 { 790 case 1: 791 /* first char is the first 6 bits of the first byte*/ 792 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; 793 /* second char is the last 2 bits of the first byte and the first 4 794 * bits of the second byte */ 795 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; 796 /* third char is the last 4 bits of the second byte padded with 797 * two zeroes */ 798 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ]; 799 /* fourth char is a = to indicate one byte of padding */ 800 *ptr++ = '='; 801 break; 802 case 2: 803 /* first char is the first 6 bits of the first byte*/ 804 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; 805 /* second char is the last 2 bits of the first byte padded with 806 * four zeroes*/ 807 *ptr++ = b64[ ((d[0] << 4) & 0x30)]; 808 /* third char is = to indicate padding */ 809 *ptr++ = '='; 810 /* fourth char is = to indicate padding */ 811 *ptr++ = '='; 812 break; 813 } 814 815 return S_OK; 816 } 817 818 static HRESULT encode_binhex(const BYTE *buf, int len, BSTR *ret) 819 { 820 static const char byte_to_hex[16] = "0123456789abcdef"; 821 int i; 822 823 *ret = SysAllocStringLen(NULL, len*2); 824 if (!*ret) return E_OUTOFMEMORY; 825 826 for (i = 0; i < len; i++) 827 { 828 (*ret)[2*i] = byte_to_hex[buf[i] >> 4]; 829 (*ret)[2*i+1] = byte_to_hex[0x0f & buf[i]]; 830 } 831 832 return S_OK; 833 } 834 835 static HRESULT WINAPI domelem_put_nodeTypedValue( 836 IXMLDOMElement *iface, 837 VARIANT value) 838 { 839 domelem *This = impl_from_IXMLDOMElement( iface ); 840 XDR_DT dt; 841 HRESULT hr; 842 843 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value)); 844 845 dt = element_get_dt(get_element(This)); 846 switch (dt) 847 { 848 /* for untyped node coerce to BSTR and set */ 849 case DT_INVALID: 850 if (V_VT(&value) != VT_BSTR) 851 { 852 VARIANT content; 853 VariantInit(&content); 854 hr = VariantChangeType(&content, &value, 0, VT_BSTR); 855 if (hr == S_OK) 856 { 857 hr = node_set_content(&This->node, V_BSTR(&content)); 858 VariantClear(&content); 859 } 860 } 861 else 862 hr = node_set_content(&This->node, V_BSTR(&value)); 863 break; 864 case DT_BIN_BASE64: 865 if (V_VT(&value) == VT_BSTR) 866 hr = node_set_content(&This->node, V_BSTR(&value)); 867 else if (V_VT(&value) == (VT_UI1|VT_ARRAY)) 868 { 869 UINT dim = SafeArrayGetDim(V_ARRAY(&value)); 870 LONG lbound, ubound; 871 BSTR encoded; 872 BYTE *ptr; 873 int len; 874 875 if (dim > 1) 876 FIXME("unexpected array dimension count %u\n", dim); 877 878 SafeArrayGetUBound(V_ARRAY(&value), 1, &ubound); 879 SafeArrayGetLBound(V_ARRAY(&value), 1, &lbound); 880 881 len = (ubound - lbound + 1)*SafeArrayGetElemsize(V_ARRAY(&value)); 882 883 hr = SafeArrayAccessData(V_ARRAY(&value), (void*)&ptr); 884 if (FAILED(hr)) return hr; 885 886 hr = encode_base64(ptr, len, &encoded); 887 SafeArrayUnaccessData(V_ARRAY(&value)); 888 if (FAILED(hr)) return hr; 889 890 hr = node_set_content(&This->node, encoded); 891 SysFreeString(encoded); 892 } 893 else 894 { 895 FIXME("unhandled variant type %d for dt:%s\n", V_VT(&value), debugstr_dt(dt)); 896 return E_NOTIMPL; 897 } 898 break; 899 case DT_BIN_HEX: 900 if (V_VT(&value) == (VT_UI1|VT_ARRAY)) 901 { 902 UINT dim = SafeArrayGetDim(V_ARRAY(&value)); 903 LONG lbound, ubound; 904 BSTR encoded; 905 BYTE *ptr; 906 int len; 907 908 if (dim > 1) 909 FIXME("unexpected array dimension count %u\n", dim); 910 911 SafeArrayGetUBound(V_ARRAY(&value), 1, &ubound); 912 SafeArrayGetLBound(V_ARRAY(&value), 1, &lbound); 913 914 len = (ubound - lbound + 1)*SafeArrayGetElemsize(V_ARRAY(&value)); 915 916 hr = SafeArrayAccessData(V_ARRAY(&value), (void*)&ptr); 917 if (FAILED(hr)) return hr; 918 919 hr = encode_binhex(ptr, len, &encoded); 920 SafeArrayUnaccessData(V_ARRAY(&value)); 921 if (FAILED(hr)) return hr; 922 923 hr = node_set_content(&This->node, encoded); 924 SysFreeString(encoded); 925 } 926 else 927 { 928 FIXME("unhandled variant type %d for dt:%s\n", V_VT(&value), debugstr_dt(dt)); 929 return E_NOTIMPL; 930 } 931 break; 932 default: 933 FIXME("not implemented for dt:%s\n", debugstr_dt(dt)); 934 return E_NOTIMPL; 935 } 936 937 return hr; 938 } 939 940 static HRESULT WINAPI domelem_get_dataType( 941 IXMLDOMElement *iface, 942 VARIANT* typename) 943 { 944 domelem *This = impl_from_IXMLDOMElement( iface ); 945 XDR_DT dt; 946 947 TRACE("(%p)->(%p)\n", This, typename); 948 949 if (!typename) 950 return E_INVALIDARG; 951 952 dt = element_get_dt(get_element(This)); 953 switch (dt) 954 { 955 case DT_BIN_BASE64: 956 case DT_BIN_HEX: 957 case DT_BOOLEAN: 958 case DT_CHAR: 959 case DT_DATE: 960 case DT_DATE_TZ: 961 case DT_DATETIME: 962 case DT_DATETIME_TZ: 963 case DT_FIXED_14_4: 964 case DT_FLOAT: 965 case DT_I1: 966 case DT_I2: 967 case DT_I4: 968 case DT_I8: 969 case DT_INT: 970 case DT_NUMBER: 971 case DT_R4: 972 case DT_R8: 973 case DT_TIME: 974 case DT_TIME_TZ: 975 case DT_UI1: 976 case DT_UI2: 977 case DT_UI4: 978 case DT_UI8: 979 case DT_URI: 980 case DT_UUID: 981 V_VT(typename) = VT_BSTR; 982 V_BSTR(typename) = SysAllocString(dt_to_bstr(dt)); 983 984 if (!V_BSTR(typename)) 985 return E_OUTOFMEMORY; 986 break; 987 default: 988 /* Other types (DTD equivalents) do not return anything here, 989 * but the pointer part of the VARIANT is set to NULL */ 990 V_VT(typename) = VT_NULL; 991 V_BSTR(typename) = NULL; 992 break; 993 } 994 return (V_VT(typename) != VT_NULL) ? S_OK : S_FALSE; 995 } 996 997 static HRESULT WINAPI domelem_put_dataType( 998 IXMLDOMElement *iface, 999 BSTR dtName) 1000 { 1001 domelem *This = impl_from_IXMLDOMElement( iface ); 1002 HRESULT hr = E_FAIL; 1003 xmlChar *str; 1004 XDR_DT dt; 1005 1006 TRACE("(%p)->(%s)\n", This, debugstr_w(dtName)); 1007 1008 if(dtName == NULL) 1009 return E_INVALIDARG; 1010 1011 dt = bstr_to_dt(dtName, -1); 1012 1013 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type. 1014 This applies to changing types (string->bool) or setting a new one 1015 */ 1016 str = xmlNodeGetContent(get_element(This)); 1017 hr = dt_validate(dt, str); 1018 xmlFree(str); 1019 1020 /* Check all supported types. */ 1021 if (hr == S_OK) 1022 { 1023 switch (dt) 1024 { 1025 case DT_BIN_BASE64: 1026 case DT_BIN_HEX: 1027 case DT_BOOLEAN: 1028 case DT_CHAR: 1029 case DT_DATE: 1030 case DT_DATE_TZ: 1031 case DT_DATETIME: 1032 case DT_DATETIME_TZ: 1033 case DT_FIXED_14_4: 1034 case DT_FLOAT: 1035 case DT_I1: 1036 case DT_I2: 1037 case DT_I4: 1038 case DT_I8: 1039 case DT_INT: 1040 case DT_NMTOKEN: 1041 case DT_NMTOKENS: 1042 case DT_NUMBER: 1043 case DT_R4: 1044 case DT_R8: 1045 case DT_STRING: 1046 case DT_TIME: 1047 case DT_TIME_TZ: 1048 case DT_UI1: 1049 case DT_UI2: 1050 case DT_UI4: 1051 case DT_UI8: 1052 case DT_URI: 1053 case DT_UUID: 1054 { 1055 xmlAttrPtr attr = xmlHasNsProp(get_element(This), DT_prefix, DT_nsURI); 1056 if (attr) 1057 { 1058 attr = xmlSetNsProp(get_element(This), attr->ns, DT_prefix, dt_to_str(dt)); 1059 hr = S_OK; 1060 } 1061 else 1062 { 1063 xmlNsPtr ns = xmlNewNs(get_element(This), DT_nsURI, DT_prefix); 1064 if (ns) 1065 { 1066 attr = xmlNewNsProp(get_element(This), ns, DT_prefix, dt_to_str(dt)); 1067 if (attr) 1068 { 1069 xmlAddChild(get_element(This), (xmlNodePtr)attr); 1070 hr = S_OK; 1071 } 1072 else 1073 ERR("Failed to create Attribute\n"); 1074 } 1075 else 1076 ERR("Failed to create Namespace\n"); 1077 } 1078 } 1079 break; 1080 default: 1081 FIXME("need to handle dt:%s\n", debugstr_dt(dt)); 1082 break; 1083 } 1084 } 1085 1086 return hr; 1087 } 1088 1089 static HRESULT WINAPI domelem_get_xml( 1090 IXMLDOMElement *iface, 1091 BSTR* p) 1092 { 1093 domelem *This = impl_from_IXMLDOMElement( iface ); 1094 1095 TRACE("(%p)->(%p)\n", This, p); 1096 1097 return node_get_xml(&This->node, TRUE, p); 1098 } 1099 1100 static HRESULT WINAPI domelem_transformNode( 1101 IXMLDOMElement *iface, 1102 IXMLDOMNode *node, BSTR *p) 1103 { 1104 domelem *This = impl_from_IXMLDOMElement( iface ); 1105 TRACE("(%p)->(%p %p)\n", This, node, p); 1106 return node_transform_node(&This->node, node, p); 1107 } 1108 1109 static HRESULT WINAPI domelem_selectNodes( 1110 IXMLDOMElement *iface, 1111 BSTR p, IXMLDOMNodeList** outList) 1112 { 1113 domelem *This = impl_from_IXMLDOMElement( iface ); 1114 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList); 1115 return node_select_nodes(&This->node, p, outList); 1116 } 1117 1118 static HRESULT WINAPI domelem_selectSingleNode( 1119 IXMLDOMElement *iface, 1120 BSTR p, IXMLDOMNode** outNode) 1121 { 1122 domelem *This = impl_from_IXMLDOMElement( iface ); 1123 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode); 1124 return node_select_singlenode(&This->node, p, outNode); 1125 } 1126 1127 static HRESULT WINAPI domelem_get_parsed( 1128 IXMLDOMElement *iface, 1129 VARIANT_BOOL* isParsed) 1130 { 1131 domelem *This = impl_from_IXMLDOMElement( iface ); 1132 FIXME("(%p)->(%p) stub!\n", This, isParsed); 1133 *isParsed = VARIANT_TRUE; 1134 return S_OK; 1135 } 1136 1137 static HRESULT WINAPI domelem_get_namespaceURI( 1138 IXMLDOMElement *iface, 1139 BSTR* p) 1140 { 1141 domelem *This = impl_from_IXMLDOMElement( iface ); 1142 TRACE("(%p)->(%p)\n", This, p); 1143 return node_get_namespaceURI(&This->node, p); 1144 } 1145 1146 static HRESULT WINAPI domelem_get_prefix( 1147 IXMLDOMElement *iface, 1148 BSTR* prefix) 1149 { 1150 domelem *This = impl_from_IXMLDOMElement( iface ); 1151 TRACE("(%p)->(%p)\n", This, prefix); 1152 return node_get_prefix( &This->node, prefix ); 1153 } 1154 1155 static HRESULT WINAPI domelem_get_baseName( 1156 IXMLDOMElement *iface, 1157 BSTR* name) 1158 { 1159 domelem *This = impl_from_IXMLDOMElement( iface ); 1160 TRACE("(%p)->(%p)\n", This, name); 1161 return node_get_base_name( &This->node, name ); 1162 } 1163 1164 static HRESULT WINAPI domelem_transformNodeToObject( 1165 IXMLDOMElement *iface, 1166 IXMLDOMNode* domNode, VARIANT var1) 1167 { 1168 domelem *This = impl_from_IXMLDOMElement( iface ); 1169 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1)); 1170 return E_NOTIMPL; 1171 } 1172 1173 static HRESULT WINAPI domelem_get_tagName( 1174 IXMLDOMElement *iface, 1175 BSTR* p) 1176 { 1177 domelem *This = impl_from_IXMLDOMElement( iface ); 1178 xmlNodePtr element; 1179 const xmlChar *prefix; 1180 xmlChar *qname; 1181 1182 TRACE("(%p)->(%p)\n", This, p ); 1183 1184 if (!p) return E_INVALIDARG; 1185 1186 element = get_element( This ); 1187 if ( !element ) 1188 return E_FAIL; 1189 1190 prefix = element->ns ? element->ns->prefix : NULL; 1191 qname = xmlBuildQName(element->name, prefix, NULL, 0); 1192 1193 *p = bstr_from_xmlChar(qname); 1194 if (qname != element->name) xmlFree(qname); 1195 1196 return *p ? S_OK : E_OUTOFMEMORY; 1197 } 1198 1199 static HRESULT WINAPI domelem_getAttribute( 1200 IXMLDOMElement *iface, 1201 BSTR name, VARIANT* value) 1202 { 1203 domelem *This = impl_from_IXMLDOMElement( iface ); 1204 xmlNodePtr element; 1205 xmlChar *xml_name, *xml_value = NULL; 1206 xmlChar *local, *prefix; 1207 HRESULT hr = S_FALSE; 1208 xmlNsPtr ns; 1209 1210 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value); 1211 1212 if(!value || !name) 1213 return E_INVALIDARG; 1214 1215 element = get_element( This ); 1216 if ( !element ) 1217 return E_FAIL; 1218 1219 V_BSTR(value) = NULL; 1220 V_VT(value) = VT_NULL; 1221 1222 xml_name = xmlchar_from_wchar( name ); 1223 1224 if(!xmlValidateNameValue(xml_name)) 1225 hr = E_FAIL; 1226 else 1227 { 1228 if ((local = xmlSplitQName2(xml_name, &prefix))) 1229 { 1230 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) 1231 { 1232 ns = xmlSearchNs(element->doc, element, local); 1233 if (ns) 1234 xml_value = xmlStrdup(ns->href); 1235 } 1236 else 1237 { 1238 ns = xmlSearchNs(element->doc, element, prefix); 1239 if (ns) 1240 xml_value = xmlGetNsProp(element, local, ns->href); 1241 } 1242 1243 xmlFree(prefix); 1244 xmlFree(local); 1245 } 1246 else 1247 xml_value = xmlGetNsProp(element, xml_name, NULL); 1248 } 1249 1250 heap_free(xml_name); 1251 if(xml_value) 1252 { 1253 V_VT(value) = VT_BSTR; 1254 V_BSTR(value) = bstr_from_xmlChar( xml_value ); 1255 xmlFree(xml_value); 1256 hr = S_OK; 1257 } 1258 1259 return hr; 1260 } 1261 1262 static HRESULT WINAPI domelem_setAttribute( 1263 IXMLDOMElement *iface, 1264 BSTR name, VARIANT value) 1265 { 1266 domelem *This = impl_from_IXMLDOMElement( iface ); 1267 xmlChar *xml_name, *xml_value, *local, *prefix; 1268 xmlNodePtr element; 1269 HRESULT hr = S_OK; 1270 1271 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_variant(&value)); 1272 1273 element = get_element( This ); 1274 if ( !element ) 1275 return E_FAIL; 1276 1277 if (V_VT(&value) != VT_BSTR) 1278 { 1279 VARIANT var; 1280 1281 VariantInit(&var); 1282 hr = VariantChangeType(&var, &value, 0, VT_BSTR); 1283 if (hr != S_OK) 1284 { 1285 FIXME("VariantChangeType failed\n"); 1286 return hr; 1287 } 1288 1289 xml_value = xmlchar_from_wchar(V_BSTR(&var)); 1290 VariantClear(&var); 1291 } 1292 else 1293 xml_value = xmlchar_from_wchar(V_BSTR(&value)); 1294 1295 xml_name = xmlchar_from_wchar( name ); 1296 1297 if ((local = xmlSplitQName2(xml_name, &prefix))) 1298 { 1299 static const xmlChar* xmlnsA = (const xmlChar*)"xmlns"; 1300 xmlNsPtr ns = NULL; 1301 1302 /* it's not allowed to modify existing namespace definition */ 1303 if (xmlStrEqual(prefix, xmlnsA)) 1304 ns = xmlSearchNs(element->doc, element, local); 1305 1306 xmlFree(prefix); 1307 xmlFree(local); 1308 1309 if (ns) 1310 { 1311 int cmp = xmlStrEqual(ns->href, xml_value); 1312 heap_free(xml_value); 1313 heap_free(xml_name); 1314 return cmp ? S_OK : E_INVALIDARG; 1315 } 1316 } 1317 1318 if (!xmlSetNsProp(element, NULL, xml_name, xml_value)) 1319 hr = E_FAIL; 1320 1321 heap_free(xml_value); 1322 heap_free(xml_name); 1323 1324 return hr; 1325 } 1326 1327 static HRESULT WINAPI domelem_removeAttribute( 1328 IXMLDOMElement *iface, 1329 BSTR p) 1330 { 1331 domelem *This = impl_from_IXMLDOMElement( iface ); 1332 IXMLDOMNamedNodeMap *attr; 1333 HRESULT hr; 1334 1335 TRACE("(%p)->(%s)\n", This, debugstr_w(p)); 1336 1337 hr = IXMLDOMElement_get_attributes(iface, &attr); 1338 if (hr != S_OK) return hr; 1339 1340 hr = IXMLDOMNamedNodeMap_removeNamedItem(attr, p, NULL); 1341 IXMLDOMNamedNodeMap_Release(attr); 1342 1343 return hr; 1344 } 1345 1346 static HRESULT WINAPI domelem_getAttributeNode( 1347 IXMLDOMElement *iface, 1348 BSTR p, IXMLDOMAttribute** attributeNode ) 1349 { 1350 domelem *This = impl_from_IXMLDOMElement( iface ); 1351 xmlChar *local, *prefix, *nameA; 1352 HRESULT hr = S_FALSE; 1353 xmlNodePtr element; 1354 xmlAttrPtr attr; 1355 1356 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), attributeNode); 1357 1358 element = get_element( This ); 1359 if (!element) return E_FAIL; 1360 1361 if (attributeNode) *attributeNode = NULL; 1362 1363 nameA = xmlchar_from_wchar(p); 1364 if (!xmlValidateNameValue(nameA)) 1365 { 1366 heap_free(nameA); 1367 return E_FAIL; 1368 } 1369 1370 if (!attributeNode) 1371 { 1372 heap_free(nameA); 1373 return S_FALSE; 1374 } 1375 1376 *attributeNode = NULL; 1377 1378 local = xmlSplitQName2(nameA, &prefix); 1379 1380 if (local) 1381 { 1382 /* try to get namespace for supplied qualified name */ 1383 xmlNsPtr ns = xmlSearchNs(element->doc, element, prefix); 1384 xmlFree(prefix); 1385 1386 attr = xmlHasNsProp(element, local, ns ? ns->href : NULL); 1387 xmlFree(local); 1388 } 1389 else 1390 { 1391 attr = xmlHasProp(element, nameA); 1392 /* attribute has attached namespace and we requested non-qualified 1393 name - it's a failure case */ 1394 if (attr && attr->ns) attr = NULL; 1395 } 1396 1397 heap_free(nameA); 1398 1399 if (attr) 1400 { 1401 IUnknown *unk = create_attribute((xmlNodePtr)attr, FALSE); 1402 hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMAttribute, (void**)attributeNode); 1403 IUnknown_Release(unk); 1404 } 1405 1406 return hr; 1407 } 1408 1409 static HRESULT WINAPI domelem_setAttributeNode( 1410 IXMLDOMElement *iface, 1411 IXMLDOMAttribute* attribute, 1412 IXMLDOMAttribute** old) 1413 { 1414 domelem *This = impl_from_IXMLDOMElement( iface ); 1415 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0}; 1416 xmlChar *name, *value; 1417 BSTR nameW, prefix; 1418 xmlnode *attr_node; 1419 xmlAttrPtr attr; 1420 VARIANT valueW; 1421 HRESULT hr; 1422 1423 FIXME("(%p)->(%p %p): semi-stub\n", This, attribute, old); 1424 1425 if (!attribute) return E_INVALIDARG; 1426 1427 attr_node = get_node_obj((IXMLDOMNode*)attribute); 1428 if (!attr_node) return E_FAIL; 1429 1430 if (attr_node->parent) 1431 { 1432 WARN("attempt to add already used attribute\n"); 1433 return E_FAIL; 1434 } 1435 1436 hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW); 1437 if (hr != S_OK) return hr; 1438 1439 /* adding xmlns attribute doesn't change a tree or existing namespace definition */ 1440 if (!strcmpW(nameW, xmlnsW)) 1441 { 1442 SysFreeString(nameW); 1443 return DISP_E_UNKNOWNNAME; 1444 } 1445 1446 hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW); 1447 if (hr != S_OK) 1448 { 1449 SysFreeString(nameW); 1450 return hr; 1451 } 1452 1453 if (old) *old = NULL; 1454 1455 TRACE("attribute: %s=%s\n", debugstr_w(nameW), debugstr_w(V_BSTR(&valueW))); 1456 1457 hr = IXMLDOMAttribute_get_prefix(attribute, &prefix); 1458 if (hr == S_OK) 1459 { 1460 FIXME("namespaces not supported: %s\n", debugstr_w(prefix)); 1461 SysFreeString(prefix); 1462 } 1463 1464 name = xmlchar_from_wchar(nameW); 1465 value = xmlchar_from_wchar(V_BSTR(&valueW)); 1466 1467 if (!name || !value) 1468 { 1469 SysFreeString(nameW); 1470 VariantClear(&valueW); 1471 heap_free(name); 1472 heap_free(value); 1473 return E_OUTOFMEMORY; 1474 } 1475 1476 attr = xmlSetNsProp(get_element(This), NULL, name, value); 1477 if (attr) 1478 attr_node->parent = (IXMLDOMNode*)iface; 1479 1480 SysFreeString(nameW); 1481 VariantClear(&valueW); 1482 heap_free(name); 1483 heap_free(value); 1484 1485 return attr ? S_OK : E_FAIL; 1486 } 1487 1488 static HRESULT WINAPI domelem_removeAttributeNode( 1489 IXMLDOMElement *iface, 1490 IXMLDOMAttribute* domAttribute, 1491 IXMLDOMAttribute** attributeNode) 1492 { 1493 domelem *This = impl_from_IXMLDOMElement( iface ); 1494 FIXME("(%p)->(%p %p)\n", This, domAttribute, attributeNode); 1495 return E_NOTIMPL; 1496 } 1497 1498 static HRESULT WINAPI domelem_getElementsByTagName( 1499 IXMLDOMElement *iface, 1500 BSTR tagName, IXMLDOMNodeList** resultList) 1501 { 1502 domelem *This = impl_from_IXMLDOMElement( iface ); 1503 xmlChar *query; 1504 HRESULT hr; 1505 BOOL XPath; 1506 1507 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList); 1508 1509 if (!tagName || !resultList) return E_INVALIDARG; 1510 1511 XPath = is_xpathmode(get_element(This)->doc); 1512 set_xpathmode(get_element(This)->doc, TRUE); 1513 query = tagName_to_XPath(tagName); 1514 hr = create_selection(get_element(This), query, resultList); 1515 xmlFree(query); 1516 set_xpathmode(get_element(This)->doc, XPath); 1517 1518 return hr; 1519 } 1520 1521 static HRESULT WINAPI domelem_normalize( 1522 IXMLDOMElement *iface ) 1523 { 1524 domelem *This = impl_from_IXMLDOMElement( iface ); 1525 FIXME("%p\n", This); 1526 return E_NOTIMPL; 1527 } 1528 1529 static const struct IXMLDOMElementVtbl domelem_vtbl = 1530 { 1531 domelem_QueryInterface, 1532 domelem_AddRef, 1533 domelem_Release, 1534 domelem_GetTypeInfoCount, 1535 domelem_GetTypeInfo, 1536 domelem_GetIDsOfNames, 1537 domelem_Invoke, 1538 domelem_get_nodeName, 1539 domelem_get_nodeValue, 1540 domelem_put_nodeValue, 1541 domelem_get_nodeType, 1542 domelem_get_parentNode, 1543 domelem_get_childNodes, 1544 domelem_get_firstChild, 1545 domelem_get_lastChild, 1546 domelem_get_previousSibling, 1547 domelem_get_nextSibling, 1548 domelem_get_attributes, 1549 domelem_insertBefore, 1550 domelem_replaceChild, 1551 domelem_removeChild, 1552 domelem_appendChild, 1553 domelem_hasChildNodes, 1554 domelem_get_ownerDocument, 1555 domelem_cloneNode, 1556 domelem_get_nodeTypeString, 1557 domelem_get_text, 1558 domelem_put_text, 1559 domelem_get_specified, 1560 domelem_get_definition, 1561 domelem_get_nodeTypedValue, 1562 domelem_put_nodeTypedValue, 1563 domelem_get_dataType, 1564 domelem_put_dataType, 1565 domelem_get_xml, 1566 domelem_transformNode, 1567 domelem_selectNodes, 1568 domelem_selectSingleNode, 1569 domelem_get_parsed, 1570 domelem_get_namespaceURI, 1571 domelem_get_prefix, 1572 domelem_get_baseName, 1573 domelem_transformNodeToObject, 1574 domelem_get_tagName, 1575 domelem_getAttribute, 1576 domelem_setAttribute, 1577 domelem_removeAttribute, 1578 domelem_getAttributeNode, 1579 domelem_setAttributeNode, 1580 domelem_removeAttributeNode, 1581 domelem_getElementsByTagName, 1582 domelem_normalize, 1583 }; 1584 1585 static HRESULT domelem_get_qualified_item(const xmlNodePtr node, BSTR name, BSTR uri, 1586 IXMLDOMNode **item) 1587 { 1588 xmlAttrPtr attr; 1589 xmlChar *nameA; 1590 xmlChar *href; 1591 1592 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item); 1593 1594 if (!name || !item) return E_INVALIDARG; 1595 1596 if (uri && *uri) 1597 { 1598 href = xmlchar_from_wchar(uri); 1599 if (!href) return E_OUTOFMEMORY; 1600 } 1601 else 1602 href = NULL; 1603 1604 nameA = xmlchar_from_wchar(name); 1605 if (!nameA) 1606 { 1607 heap_free(href); 1608 return E_OUTOFMEMORY; 1609 } 1610 1611 attr = xmlHasNsProp(node, nameA, href); 1612 1613 heap_free(nameA); 1614 heap_free(href); 1615 1616 if (!attr) 1617 { 1618 *item = NULL; 1619 return S_FALSE; 1620 } 1621 1622 *item = create_node((xmlNodePtr)attr); 1623 1624 return S_OK; 1625 } 1626 1627 static HRESULT domelem_get_named_item(const xmlNodePtr node, BSTR name, IXMLDOMNode **item) 1628 { 1629 xmlChar *nameA, *local, *prefix; 1630 BSTR uriW, localW; 1631 xmlNsPtr ns; 1632 HRESULT hr; 1633 1634 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item ); 1635 1636 nameA = xmlchar_from_wchar(name); 1637 local = xmlSplitQName2(nameA, &prefix); 1638 heap_free(nameA); 1639 1640 if (!local) 1641 return domelem_get_qualified_item(node, name, NULL, item); 1642 1643 /* try to get namespace uri for supplied qualified name */ 1644 ns = xmlSearchNs(node->doc, node, prefix); 1645 1646 xmlFree(prefix); 1647 1648 if (!ns) 1649 { 1650 xmlFree(local); 1651 if (item) *item = NULL; 1652 return item ? S_FALSE : E_INVALIDARG; 1653 } 1654 1655 uriW = bstr_from_xmlChar(ns->href); 1656 localW = bstr_from_xmlChar(local); 1657 xmlFree(local); 1658 1659 TRACE("got qualified node %s, uri=%s\n", debugstr_w(localW), debugstr_w(uriW)); 1660 1661 hr = domelem_get_qualified_item(node, localW, uriW, item); 1662 1663 SysFreeString(localW); 1664 SysFreeString(uriW); 1665 1666 return hr; 1667 } 1668 1669 static HRESULT domelem_set_named_item(xmlNodePtr node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem) 1670 { 1671 xmlNodePtr nodeNew; 1672 xmlnode *ThisNew; 1673 1674 TRACE("(%p)->(%p %p)\n", node, newItem, namedItem ); 1675 1676 if(!newItem) 1677 return E_INVALIDARG; 1678 1679 if(namedItem) *namedItem = NULL; 1680 1681 /* Must be an Attribute */ 1682 ThisNew = get_node_obj( newItem ); 1683 if(!ThisNew) return E_FAIL; 1684 1685 if(ThisNew->node->type != XML_ATTRIBUTE_NODE) 1686 return E_FAIL; 1687 1688 if(!ThisNew->node->parent) 1689 if(xmldoc_remove_orphan(ThisNew->node->doc, ThisNew->node) != S_OK) 1690 WARN("%p is not an orphan of %p\n", ThisNew->node, ThisNew->node->doc); 1691 1692 nodeNew = xmlAddChild(node, ThisNew->node); 1693 1694 if(namedItem) 1695 *namedItem = create_node( nodeNew ); 1696 return S_OK; 1697 } 1698 1699 static HRESULT domelem_remove_qualified_item(xmlNodePtr node, BSTR name, BSTR uri, IXMLDOMNode **item) 1700 { 1701 xmlChar *nameA, *href; 1702 xmlAttrPtr attr; 1703 1704 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item); 1705 1706 if (!name) return E_INVALIDARG; 1707 1708 if (uri && *uri) 1709 { 1710 href = xmlchar_from_wchar(uri); 1711 if (!href) return E_OUTOFMEMORY; 1712 } 1713 else 1714 href = NULL; 1715 1716 nameA = xmlchar_from_wchar(name); 1717 if (!nameA) 1718 { 1719 heap_free(href); 1720 return E_OUTOFMEMORY; 1721 } 1722 1723 attr = xmlHasNsProp(node, nameA, href); 1724 1725 heap_free(nameA); 1726 heap_free(href); 1727 1728 if (!attr) 1729 { 1730 if (item) *item = NULL; 1731 return S_FALSE; 1732 } 1733 1734 if (item) 1735 { 1736 xmlUnlinkNode( (xmlNodePtr) attr ); 1737 xmldoc_add_orphan( attr->doc, (xmlNodePtr) attr ); 1738 *item = create_node( (xmlNodePtr) attr ); 1739 } 1740 else 1741 { 1742 if (xmlRemoveProp(attr) == -1) 1743 ERR("xmlRemoveProp failed\n"); 1744 } 1745 1746 return S_OK; 1747 } 1748 1749 static HRESULT domelem_remove_named_item(xmlNodePtr node, BSTR name, IXMLDOMNode **item) 1750 { 1751 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item); 1752 return domelem_remove_qualified_item(node, name, NULL, item); 1753 } 1754 1755 static HRESULT domelem_get_item(const xmlNodePtr node, LONG index, IXMLDOMNode **item) 1756 { 1757 xmlNsPtr ns, xmlns; 1758 xmlAttrPtr curr; 1759 LONG attrIndex; 1760 IUnknown *unk; 1761 HRESULT hr; 1762 1763 TRACE("(%p)->(%d %p)\n", node, index, item); 1764 1765 *item = NULL; 1766 1767 if (index < 0) 1768 return S_FALSE; 1769 1770 attrIndex = 0; 1771 curr = node->properties; 1772 if (curr) { 1773 for (; attrIndex < index && curr->next != NULL; attrIndex++) 1774 curr = curr->next; 1775 1776 if (attrIndex == index) { 1777 *item = create_node( (xmlNodePtr) curr ); 1778 return S_OK; 1779 } 1780 } 1781 1782 if (!node->nsDef) 1783 return S_FALSE; 1784 1785 attrIndex++; 1786 ns = node->nsDef; 1787 for (; attrIndex < index && ns->next != NULL; attrIndex++) 1788 ns = ns->next; 1789 1790 if (attrIndex < index) 1791 return S_FALSE; 1792 1793 xmlns = xmlNewNs(NULL, BAD_CAST "http://www.w3.org/2000/xmlns/", BAD_CAST "xmlns"); 1794 if (!xmlns) 1795 return E_OUTOFMEMORY; 1796 1797 curr = xmlNewNsProp(NULL, xmlns, ns->prefix, ns->href); 1798 if (!curr) { 1799 xmlFreeNs(xmlns); 1800 return E_OUTOFMEMORY; 1801 } 1802 curr->doc = node->doc; 1803 1804 unk = create_attribute((xmlNodePtr)curr, TRUE); 1805 if (!unk) { 1806 xmlFreeNs(xmlns); 1807 xmlFreeProp(curr); 1808 return E_OUTOFMEMORY; 1809 } 1810 1811 hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMNode, (void**)item); 1812 IUnknown_Release(unk); 1813 1814 return hr; 1815 } 1816 1817 static HRESULT domelem_get_length(const xmlNodePtr node, LONG *length) 1818 { 1819 xmlAttrPtr curr; 1820 LONG attrCount; 1821 xmlNsPtr ns; 1822 1823 TRACE("(%p)->(%p)\n", node, length); 1824 1825 if( !length ) 1826 return E_INVALIDARG; 1827 1828 attrCount = 0; 1829 curr = node->properties; 1830 while (curr) { 1831 attrCount++; 1832 curr = curr->next; 1833 } 1834 1835 ns = node->nsDef; 1836 while (ns) { 1837 attrCount++; 1838 ns = ns->next; 1839 } 1840 *length = attrCount; 1841 1842 return S_OK; 1843 } 1844 1845 static HRESULT domelem_next_node(const xmlNodePtr node, LONG *iter, IXMLDOMNode **nextNode) 1846 { 1847 xmlAttrPtr curr; 1848 LONG i; 1849 1850 TRACE("(%p)->(%d: %p)\n", node, *iter, nextNode); 1851 1852 *nextNode = NULL; 1853 1854 curr = node->properties; 1855 1856 for (i = 0; i < *iter; i++) { 1857 if (curr->next == NULL) 1858 return S_FALSE; 1859 else 1860 curr = curr->next; 1861 } 1862 1863 (*iter)++; 1864 *nextNode = create_node((xmlNodePtr)curr); 1865 1866 return S_OK; 1867 } 1868 1869 static const struct nodemap_funcs domelem_attr_map = { 1870 domelem_get_named_item, 1871 domelem_set_named_item, 1872 domelem_remove_named_item, 1873 domelem_get_item, 1874 domelem_get_length, 1875 domelem_get_qualified_item, 1876 domelem_remove_qualified_item, 1877 domelem_next_node 1878 }; 1879 1880 static const tid_t domelem_iface_tids[] = { 1881 IXMLDOMElement_tid, 1882 0 1883 }; 1884 1885 static dispex_static_data_t domelem_dispex = { 1886 NULL, 1887 IXMLDOMElement_tid, 1888 NULL, 1889 domelem_iface_tids 1890 }; 1891 1892 IUnknown* create_element( xmlNodePtr element ) 1893 { 1894 domelem *This; 1895 1896 This = heap_alloc( sizeof *This ); 1897 if ( !This ) 1898 return NULL; 1899 1900 This->IXMLDOMElement_iface.lpVtbl = &domelem_vtbl; 1901 This->ref = 1; 1902 1903 init_xmlnode(&This->node, element, (IXMLDOMNode*)&This->IXMLDOMElement_iface, &domelem_dispex); 1904 1905 return (IUnknown*)&This->IXMLDOMElement_iface; 1906 } 1907 1908 #endif 1909