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