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 HRESULT hr = S_FALSE; 1186 1187 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value); 1188 1189 if(!value || !name) 1190 return E_INVALIDARG; 1191 1192 element = get_element( This ); 1193 if ( !element ) 1194 return E_FAIL; 1195 1196 V_BSTR(value) = NULL; 1197 V_VT(value) = VT_NULL; 1198 1199 xml_name = xmlchar_from_wchar( name ); 1200 1201 if(!xmlValidateNameValue(xml_name)) 1202 hr = E_FAIL; 1203 else 1204 xml_value = xmlGetNsProp(element, xml_name, NULL); 1205 1206 heap_free(xml_name); 1207 if(xml_value) 1208 { 1209 V_VT(value) = VT_BSTR; 1210 V_BSTR(value) = bstr_from_xmlChar( xml_value ); 1211 xmlFree(xml_value); 1212 hr = S_OK; 1213 } 1214 1215 return hr; 1216 } 1217 1218 static HRESULT WINAPI domelem_setAttribute( 1219 IXMLDOMElement *iface, 1220 BSTR name, VARIANT value) 1221 { 1222 domelem *This = impl_from_IXMLDOMElement( iface ); 1223 xmlChar *xml_name, *xml_value, *local, *prefix; 1224 xmlNodePtr element; 1225 HRESULT hr = S_OK; 1226 1227 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_variant(&value)); 1228 1229 element = get_element( This ); 1230 if ( !element ) 1231 return E_FAIL; 1232 1233 if (V_VT(&value) != VT_BSTR) 1234 { 1235 VARIANT var; 1236 1237 VariantInit(&var); 1238 hr = VariantChangeType(&var, &value, 0, VT_BSTR); 1239 if (hr != S_OK) 1240 { 1241 FIXME("VariantChangeType failed\n"); 1242 return hr; 1243 } 1244 1245 xml_value = xmlchar_from_wchar(V_BSTR(&var)); 1246 VariantClear(&var); 1247 } 1248 else 1249 xml_value = xmlchar_from_wchar(V_BSTR(&value)); 1250 1251 xml_name = xmlchar_from_wchar( name ); 1252 1253 if ((local = xmlSplitQName2(xml_name, &prefix))) 1254 { 1255 static const xmlChar* xmlnsA = (const xmlChar*)"xmlns"; 1256 xmlNsPtr ns = NULL; 1257 1258 /* it's not allowed to modify existing namespace definition */ 1259 if (xmlStrEqual(prefix, xmlnsA)) 1260 ns = xmlSearchNs(element->doc, element, local); 1261 1262 xmlFree(prefix); 1263 xmlFree(local); 1264 1265 if (ns) 1266 return xmlStrEqual(ns->href, xml_value) ? S_OK : E_INVALIDARG; 1267 } 1268 1269 if (!xmlSetNsProp(element, NULL, xml_name, xml_value)) 1270 hr = E_FAIL; 1271 1272 heap_free(xml_value); 1273 heap_free(xml_name); 1274 1275 return hr; 1276 } 1277 1278 static HRESULT WINAPI domelem_removeAttribute( 1279 IXMLDOMElement *iface, 1280 BSTR p) 1281 { 1282 domelem *This = impl_from_IXMLDOMElement( iface ); 1283 IXMLDOMNamedNodeMap *attr; 1284 HRESULT hr; 1285 1286 TRACE("(%p)->(%s)\n", This, debugstr_w(p)); 1287 1288 hr = IXMLDOMElement_get_attributes(iface, &attr); 1289 if (hr != S_OK) return hr; 1290 1291 hr = IXMLDOMNamedNodeMap_removeNamedItem(attr, p, NULL); 1292 IXMLDOMNamedNodeMap_Release(attr); 1293 1294 return hr; 1295 } 1296 1297 static HRESULT WINAPI domelem_getAttributeNode( 1298 IXMLDOMElement *iface, 1299 BSTR p, IXMLDOMAttribute** attributeNode ) 1300 { 1301 domelem *This = impl_from_IXMLDOMElement( iface ); 1302 xmlChar *local, *prefix, *nameA; 1303 HRESULT hr = S_FALSE; 1304 xmlNodePtr element; 1305 xmlAttrPtr attr; 1306 1307 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), attributeNode); 1308 1309 element = get_element( This ); 1310 if (!element) return E_FAIL; 1311 1312 if (attributeNode) *attributeNode = NULL; 1313 1314 nameA = xmlchar_from_wchar(p); 1315 if (!xmlValidateNameValue(nameA)) 1316 { 1317 heap_free(nameA); 1318 return E_FAIL; 1319 } 1320 1321 if (!attributeNode) 1322 { 1323 heap_free(nameA); 1324 return S_FALSE; 1325 } 1326 1327 *attributeNode = NULL; 1328 1329 local = xmlSplitQName2(nameA, &prefix); 1330 1331 if (local) 1332 { 1333 /* try to get namespace for supplied qualified name */ 1334 xmlNsPtr ns = xmlSearchNs(element->doc, element, prefix); 1335 xmlFree(prefix); 1336 1337 attr = xmlHasNsProp(element, local, ns ? ns->href : NULL); 1338 xmlFree(local); 1339 } 1340 else 1341 { 1342 attr = xmlHasProp(element, nameA); 1343 /* attribute has attached namespace and we requested non-qualified 1344 name - it's a failure case */ 1345 if (attr && attr->ns) attr = NULL; 1346 } 1347 1348 heap_free(nameA); 1349 1350 if (attr) 1351 { 1352 IUnknown *unk = create_attribute((xmlNodePtr)attr); 1353 hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMAttribute, (void**)attributeNode); 1354 IUnknown_Release(unk); 1355 } 1356 1357 return hr; 1358 } 1359 1360 static HRESULT WINAPI domelem_setAttributeNode( 1361 IXMLDOMElement *iface, 1362 IXMLDOMAttribute* attribute, 1363 IXMLDOMAttribute** old) 1364 { 1365 domelem *This = impl_from_IXMLDOMElement( iface ); 1366 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0}; 1367 xmlChar *name, *value; 1368 BSTR nameW, prefix; 1369 xmlnode *attr_node; 1370 xmlAttrPtr attr; 1371 VARIANT valueW; 1372 HRESULT hr; 1373 1374 FIXME("(%p)->(%p %p): semi-stub\n", This, attribute, old); 1375 1376 if (!attribute) return E_INVALIDARG; 1377 1378 attr_node = get_node_obj((IXMLDOMNode*)attribute); 1379 if (!attr_node) return E_FAIL; 1380 1381 if (attr_node->parent) 1382 { 1383 WARN("attempt to add already used attribute\n"); 1384 return E_FAIL; 1385 } 1386 1387 hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW); 1388 if (hr != S_OK) return hr; 1389 1390 /* adding xmlns attribute doesn't change a tree or existing namespace definition */ 1391 if (!strcmpW(nameW, xmlnsW)) 1392 { 1393 SysFreeString(nameW); 1394 return DISP_E_UNKNOWNNAME; 1395 } 1396 1397 hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW); 1398 if (hr != S_OK) 1399 { 1400 SysFreeString(nameW); 1401 return hr; 1402 } 1403 1404 if (old) *old = NULL; 1405 1406 TRACE("attribute: %s=%s\n", debugstr_w(nameW), debugstr_w(V_BSTR(&valueW))); 1407 1408 hr = IXMLDOMAttribute_get_prefix(attribute, &prefix); 1409 if (hr == S_OK) 1410 { 1411 FIXME("namespaces not supported: %s\n", debugstr_w(prefix)); 1412 SysFreeString(prefix); 1413 } 1414 1415 name = xmlchar_from_wchar(nameW); 1416 value = xmlchar_from_wchar(V_BSTR(&valueW)); 1417 1418 if (!name || !value) 1419 { 1420 SysFreeString(nameW); 1421 VariantClear(&valueW); 1422 heap_free(name); 1423 heap_free(value); 1424 return E_OUTOFMEMORY; 1425 } 1426 1427 attr = xmlSetNsProp(get_element(This), NULL, name, value); 1428 if (attr) 1429 attr_node->parent = (IXMLDOMNode*)iface; 1430 1431 SysFreeString(nameW); 1432 VariantClear(&valueW); 1433 heap_free(name); 1434 heap_free(value); 1435 1436 return attr ? S_OK : E_FAIL; 1437 } 1438 1439 static HRESULT WINAPI domelem_removeAttributeNode( 1440 IXMLDOMElement *iface, 1441 IXMLDOMAttribute* domAttribute, 1442 IXMLDOMAttribute** attributeNode) 1443 { 1444 domelem *This = impl_from_IXMLDOMElement( iface ); 1445 FIXME("(%p)->(%p %p)\n", This, domAttribute, attributeNode); 1446 return E_NOTIMPL; 1447 } 1448 1449 static HRESULT WINAPI domelem_getElementsByTagName( 1450 IXMLDOMElement *iface, 1451 BSTR tagName, IXMLDOMNodeList** resultList) 1452 { 1453 domelem *This = impl_from_IXMLDOMElement( iface ); 1454 xmlChar *query; 1455 HRESULT hr; 1456 BOOL XPath; 1457 1458 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList); 1459 1460 if (!tagName || !resultList) return E_INVALIDARG; 1461 1462 XPath = is_xpathmode(get_element(This)->doc); 1463 set_xpathmode(get_element(This)->doc, TRUE); 1464 query = tagName_to_XPath(tagName); 1465 hr = create_selection(get_element(This), query, resultList); 1466 xmlFree(query); 1467 set_xpathmode(get_element(This)->doc, XPath); 1468 1469 return hr; 1470 } 1471 1472 static HRESULT WINAPI domelem_normalize( 1473 IXMLDOMElement *iface ) 1474 { 1475 domelem *This = impl_from_IXMLDOMElement( iface ); 1476 FIXME("%p\n", This); 1477 return E_NOTIMPL; 1478 } 1479 1480 static const struct IXMLDOMElementVtbl domelem_vtbl = 1481 { 1482 domelem_QueryInterface, 1483 domelem_AddRef, 1484 domelem_Release, 1485 domelem_GetTypeInfoCount, 1486 domelem_GetTypeInfo, 1487 domelem_GetIDsOfNames, 1488 domelem_Invoke, 1489 domelem_get_nodeName, 1490 domelem_get_nodeValue, 1491 domelem_put_nodeValue, 1492 domelem_get_nodeType, 1493 domelem_get_parentNode, 1494 domelem_get_childNodes, 1495 domelem_get_firstChild, 1496 domelem_get_lastChild, 1497 domelem_get_previousSibling, 1498 domelem_get_nextSibling, 1499 domelem_get_attributes, 1500 domelem_insertBefore, 1501 domelem_replaceChild, 1502 domelem_removeChild, 1503 domelem_appendChild, 1504 domelem_hasChildNodes, 1505 domelem_get_ownerDocument, 1506 domelem_cloneNode, 1507 domelem_get_nodeTypeString, 1508 domelem_get_text, 1509 domelem_put_text, 1510 domelem_get_specified, 1511 domelem_get_definition, 1512 domelem_get_nodeTypedValue, 1513 domelem_put_nodeTypedValue, 1514 domelem_get_dataType, 1515 domelem_put_dataType, 1516 domelem_get_xml, 1517 domelem_transformNode, 1518 domelem_selectNodes, 1519 domelem_selectSingleNode, 1520 domelem_get_parsed, 1521 domelem_get_namespaceURI, 1522 domelem_get_prefix, 1523 domelem_get_baseName, 1524 domelem_transformNodeToObject, 1525 domelem_get_tagName, 1526 domelem_getAttribute, 1527 domelem_setAttribute, 1528 domelem_removeAttribute, 1529 domelem_getAttributeNode, 1530 domelem_setAttributeNode, 1531 domelem_removeAttributeNode, 1532 domelem_getElementsByTagName, 1533 domelem_normalize, 1534 }; 1535 1536 static HRESULT domelem_get_qualified_item(const xmlNodePtr node, BSTR name, BSTR uri, 1537 IXMLDOMNode **item) 1538 { 1539 xmlAttrPtr attr; 1540 xmlChar *nameA; 1541 xmlChar *href; 1542 1543 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item); 1544 1545 if (!name || !item) return E_INVALIDARG; 1546 1547 if (uri && *uri) 1548 { 1549 href = xmlchar_from_wchar(uri); 1550 if (!href) return E_OUTOFMEMORY; 1551 } 1552 else 1553 href = NULL; 1554 1555 nameA = xmlchar_from_wchar(name); 1556 if (!nameA) 1557 { 1558 heap_free(href); 1559 return E_OUTOFMEMORY; 1560 } 1561 1562 attr = xmlHasNsProp(node, nameA, href); 1563 1564 heap_free(nameA); 1565 heap_free(href); 1566 1567 if (!attr) 1568 { 1569 *item = NULL; 1570 return S_FALSE; 1571 } 1572 1573 *item = create_node((xmlNodePtr)attr); 1574 1575 return S_OK; 1576 } 1577 1578 static HRESULT domelem_get_named_item(const xmlNodePtr node, BSTR name, IXMLDOMNode **item) 1579 { 1580 xmlChar *nameA, *local, *prefix; 1581 BSTR uriW, localW; 1582 xmlNsPtr ns; 1583 HRESULT hr; 1584 1585 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item ); 1586 1587 nameA = xmlchar_from_wchar(name); 1588 local = xmlSplitQName2(nameA, &prefix); 1589 heap_free(nameA); 1590 1591 if (!local) 1592 return domelem_get_qualified_item(node, name, NULL, item); 1593 1594 /* try to get namespace uri for supplied qualified name */ 1595 ns = xmlSearchNs(node->doc, node, prefix); 1596 1597 xmlFree(prefix); 1598 1599 if (!ns) 1600 { 1601 xmlFree(local); 1602 if (item) *item = NULL; 1603 return item ? S_FALSE : E_INVALIDARG; 1604 } 1605 1606 uriW = bstr_from_xmlChar(ns->href); 1607 localW = bstr_from_xmlChar(local); 1608 xmlFree(local); 1609 1610 TRACE("got qualified node %s, uri=%s\n", debugstr_w(localW), debugstr_w(uriW)); 1611 1612 hr = domelem_get_qualified_item(node, localW, uriW, item); 1613 1614 SysFreeString(localW); 1615 SysFreeString(uriW); 1616 1617 return hr; 1618 } 1619 1620 static HRESULT domelem_set_named_item(xmlNodePtr node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem) 1621 { 1622 xmlNodePtr nodeNew; 1623 xmlnode *ThisNew; 1624 1625 TRACE("(%p)->(%p %p)\n", node, newItem, namedItem ); 1626 1627 if(!newItem) 1628 return E_INVALIDARG; 1629 1630 if(namedItem) *namedItem = NULL; 1631 1632 /* Must be an Attribute */ 1633 ThisNew = get_node_obj( newItem ); 1634 if(!ThisNew) return E_FAIL; 1635 1636 if(ThisNew->node->type != XML_ATTRIBUTE_NODE) 1637 return E_FAIL; 1638 1639 if(!ThisNew->node->parent) 1640 if(xmldoc_remove_orphan(ThisNew->node->doc, ThisNew->node) != S_OK) 1641 WARN("%p is not an orphan of %p\n", ThisNew->node, ThisNew->node->doc); 1642 1643 nodeNew = xmlAddChild(node, ThisNew->node); 1644 1645 if(namedItem) 1646 *namedItem = create_node( nodeNew ); 1647 return S_OK; 1648 } 1649 1650 static HRESULT domelem_remove_qualified_item(xmlNodePtr node, BSTR name, BSTR uri, IXMLDOMNode **item) 1651 { 1652 xmlChar *nameA, *href; 1653 xmlAttrPtr attr; 1654 1655 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item); 1656 1657 if (!name) return E_INVALIDARG; 1658 1659 if (uri && *uri) 1660 { 1661 href = xmlchar_from_wchar(uri); 1662 if (!href) return E_OUTOFMEMORY; 1663 } 1664 else 1665 href = NULL; 1666 1667 nameA = xmlchar_from_wchar(name); 1668 if (!nameA) 1669 { 1670 heap_free(href); 1671 return E_OUTOFMEMORY; 1672 } 1673 1674 attr = xmlHasNsProp(node, nameA, href); 1675 1676 heap_free(nameA); 1677 heap_free(href); 1678 1679 if (!attr) 1680 { 1681 if (item) *item = NULL; 1682 return S_FALSE; 1683 } 1684 1685 if (item) 1686 { 1687 xmlUnlinkNode( (xmlNodePtr) attr ); 1688 xmldoc_add_orphan( attr->doc, (xmlNodePtr) attr ); 1689 *item = create_node( (xmlNodePtr) attr ); 1690 } 1691 else 1692 { 1693 if (xmlRemoveProp(attr) == -1) 1694 ERR("xmlRemoveProp failed\n"); 1695 } 1696 1697 return S_OK; 1698 } 1699 1700 static HRESULT domelem_remove_named_item(xmlNodePtr node, BSTR name, IXMLDOMNode **item) 1701 { 1702 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item); 1703 return domelem_remove_qualified_item(node, name, NULL, item); 1704 } 1705 1706 static HRESULT domelem_get_item(const xmlNodePtr node, LONG index, IXMLDOMNode **item) 1707 { 1708 xmlAttrPtr curr; 1709 LONG attrIndex; 1710 1711 TRACE("(%p)->(%d %p)\n", node, index, item); 1712 1713 *item = NULL; 1714 1715 if (index < 0) 1716 return S_FALSE; 1717 1718 curr = node->properties; 1719 1720 for (attrIndex = 0; attrIndex < index; attrIndex++) { 1721 if (curr->next == NULL) 1722 return S_FALSE; 1723 else 1724 curr = curr->next; 1725 } 1726 1727 *item = create_node( (xmlNodePtr) curr ); 1728 1729 return S_OK; 1730 } 1731 1732 static HRESULT domelem_get_length(const xmlNodePtr node, LONG *length) 1733 { 1734 xmlAttrPtr first; 1735 xmlAttrPtr curr; 1736 LONG attrCount; 1737 1738 TRACE("(%p)->(%p)\n", node, length); 1739 1740 if( !length ) 1741 return E_INVALIDARG; 1742 1743 first = node->properties; 1744 if (first == NULL) { 1745 *length = 0; 1746 return S_OK; 1747 } 1748 1749 curr = first; 1750 attrCount = 1; 1751 while (curr->next) { 1752 attrCount++; 1753 curr = curr->next; 1754 } 1755 *length = attrCount; 1756 1757 return S_OK; 1758 } 1759 1760 static HRESULT domelem_next_node(const xmlNodePtr node, LONG *iter, IXMLDOMNode **nextNode) 1761 { 1762 xmlAttrPtr curr; 1763 LONG i; 1764 1765 TRACE("(%p)->(%d: %p)\n", node, *iter, nextNode); 1766 1767 *nextNode = NULL; 1768 1769 curr = node->properties; 1770 1771 for (i = 0; i < *iter; i++) { 1772 if (curr->next == NULL) 1773 return S_FALSE; 1774 else 1775 curr = curr->next; 1776 } 1777 1778 (*iter)++; 1779 *nextNode = create_node((xmlNodePtr)curr); 1780 1781 return S_OK; 1782 } 1783 1784 static const struct nodemap_funcs domelem_attr_map = { 1785 domelem_get_named_item, 1786 domelem_set_named_item, 1787 domelem_remove_named_item, 1788 domelem_get_item, 1789 domelem_get_length, 1790 domelem_get_qualified_item, 1791 domelem_remove_qualified_item, 1792 domelem_next_node 1793 }; 1794 1795 static const tid_t domelem_iface_tids[] = { 1796 IXMLDOMElement_tid, 1797 0 1798 }; 1799 1800 static dispex_static_data_t domelem_dispex = { 1801 NULL, 1802 IXMLDOMElement_tid, 1803 NULL, 1804 domelem_iface_tids 1805 }; 1806 1807 IUnknown* create_element( xmlNodePtr element ) 1808 { 1809 domelem *This; 1810 1811 This = heap_alloc( sizeof *This ); 1812 if ( !This ) 1813 return NULL; 1814 1815 This->IXMLDOMElement_iface.lpVtbl = &domelem_vtbl; 1816 This->ref = 1; 1817 1818 init_xmlnode(&This->node, element, (IXMLDOMNode*)&This->IXMLDOMElement_iface, &domelem_dispex); 1819 1820 return (IUnknown*)&This->IXMLDOMElement_iface; 1821 } 1822 1823 #endif 1824