xref: /reactos/dll/win32/msxml3/element.c (revision 84ccccab)
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