storage.dll16: COM cleanup in storage.c.
[wine] / dlls / msxml3 / element.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31 #include "msxml6.h"
32
33 #include "msxml_private.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
38
39 #ifdef HAVE_LIBXML2
40
41 static const xmlChar DT_prefix[] = "dt";
42 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
43
44 typedef struct _domelem
45 {
46     xmlnode node;
47     IXMLDOMElement IXMLDOMElement_iface;
48     LONG ref;
49 } domelem;
50
51 static inline domelem *impl_from_IXMLDOMElement( IXMLDOMElement *iface )
52 {
53     return CONTAINING_RECORD(iface, domelem, IXMLDOMElement_iface);
54 }
55
56 static inline xmlNodePtr get_element( const domelem *This )
57 {
58     return This->node.node;
59 }
60
61 static HRESULT WINAPI domelem_QueryInterface(
62     IXMLDOMElement *iface,
63     REFIID riid,
64     void** ppvObject )
65 {
66     domelem *This = impl_from_IXMLDOMElement( iface );
67
68     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
69
70     if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) ||
71          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
72          IsEqualGUID( riid, &IID_IDispatch ) ||
73          IsEqualGUID( riid, &IID_IUnknown ) )
74     {
75         *ppvObject = &This->IXMLDOMElement_iface;
76     }
77     else if(node_query_interface(&This->node, riid, ppvObject))
78     {
79         return *ppvObject ? S_OK : E_NOINTERFACE;
80     }
81     else
82     {
83         FIXME("interface %s not implemented\n", debugstr_guid(riid));
84         return E_NOINTERFACE;
85     }
86
87     IUnknown_AddRef( (IUnknown*)*ppvObject );
88     return S_OK;
89 }
90
91 static ULONG WINAPI domelem_AddRef(
92     IXMLDOMElement *iface )
93 {
94     domelem *This = impl_from_IXMLDOMElement( iface );
95     LONG ref = InterlockedIncrement(&This->ref);
96
97     TRACE("(%p) ref=%d\n", This, ref);
98
99     return ref;
100 }
101
102 static ULONG WINAPI domelem_Release(
103     IXMLDOMElement *iface )
104 {
105     domelem *This = impl_from_IXMLDOMElement( iface );
106     ULONG ref = InterlockedDecrement(&This->ref);
107
108     TRACE("(%p) ref=%d\n", This, ref);
109
110     if(!ref) {
111         destroy_xmlnode(&This->node);
112         heap_free(This);
113     }
114
115     return ref;
116 }
117
118 static HRESULT WINAPI domelem_GetTypeInfoCount(
119     IXMLDOMElement *iface,
120     UINT* pctinfo )
121 {
122     domelem *This = impl_from_IXMLDOMElement( iface );
123
124     TRACE("(%p)->(%p)\n", This, pctinfo);
125
126     *pctinfo = 1;
127
128     return S_OK;
129 }
130
131 static HRESULT WINAPI domelem_GetTypeInfo(
132     IXMLDOMElement *iface,
133     UINT iTInfo, LCID lcid,
134     ITypeInfo** ppTInfo )
135 {
136     domelem *This = impl_from_IXMLDOMElement( iface );
137     HRESULT hr;
138
139     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
140
141     hr = get_typeinfo(IXMLDOMElement_tid, ppTInfo);
142
143     return hr;
144 }
145
146 static HRESULT WINAPI domelem_GetIDsOfNames(
147     IXMLDOMElement *iface,
148     REFIID riid, LPOLESTR* rgszNames,
149     UINT cNames, LCID lcid, DISPID* rgDispId )
150 {
151     domelem *This = impl_from_IXMLDOMElement( iface );
152     ITypeInfo *typeinfo;
153     HRESULT hr;
154
155     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
156           lcid, rgDispId);
157
158     if(!rgszNames || cNames == 0 || !rgDispId)
159         return E_INVALIDARG;
160
161     hr = get_typeinfo(IXMLDOMElement_tid, &typeinfo);
162     if(SUCCEEDED(hr))
163     {
164         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
165         ITypeInfo_Release(typeinfo);
166     }
167
168     return hr;
169 }
170
171 static HRESULT WINAPI domelem_Invoke(
172     IXMLDOMElement *iface,
173     DISPID dispIdMember, REFIID riid, LCID lcid,
174     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
175     EXCEPINFO* pExcepInfo, UINT* puArgErr )
176 {
177     domelem *This = impl_from_IXMLDOMElement( iface );
178     ITypeInfo *typeinfo;
179     HRESULT hr;
180
181     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
182           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
183
184     hr = get_typeinfo(IXMLDOMElement_tid, &typeinfo);
185     if(SUCCEEDED(hr))
186     {
187         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMElement_iface, dispIdMember, wFlags,
188                 pDispParams, pVarResult, pExcepInfo, puArgErr);
189         ITypeInfo_Release(typeinfo);
190     }
191
192     return hr;
193 }
194
195 static HRESULT WINAPI domelem_get_nodeName(
196     IXMLDOMElement *iface,
197     BSTR* p )
198 {
199     domelem *This = impl_from_IXMLDOMElement( iface );
200
201     TRACE("(%p)->(%p)\n", This, p);
202
203     return node_get_nodeName(&This->node, p);
204 }
205
206 static HRESULT WINAPI domelem_get_nodeValue(
207     IXMLDOMElement *iface,
208     VARIANT* value)
209 {
210     domelem *This = impl_from_IXMLDOMElement( iface );
211
212     TRACE("(%p)->(%p)\n", This, value);
213
214     if(!value)
215         return E_INVALIDARG;
216
217     V_VT(value) = VT_NULL;
218     V_BSTR(value) = NULL; /* tests show that we should do this */
219     return S_FALSE;
220 }
221
222 static HRESULT WINAPI domelem_put_nodeValue(
223     IXMLDOMElement *iface,
224     VARIANT value)
225 {
226     domelem *This = impl_from_IXMLDOMElement( iface );
227     TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
228     return E_FAIL;
229 }
230
231 static HRESULT WINAPI domelem_get_nodeType(
232     IXMLDOMElement *iface,
233     DOMNodeType* domNodeType )
234 {
235     domelem *This = impl_from_IXMLDOMElement( iface );
236
237     TRACE("(%p)->(%p)\n", This, domNodeType);
238
239     *domNodeType = NODE_ELEMENT;
240     return S_OK;
241 }
242
243 static HRESULT WINAPI domelem_get_parentNode(
244     IXMLDOMElement *iface,
245     IXMLDOMNode** parent )
246 {
247     domelem *This = impl_from_IXMLDOMElement( iface );
248
249     TRACE("(%p)->(%p)\n", This, parent);
250
251     return node_get_parent(&This->node, parent);
252 }
253
254 static HRESULT WINAPI domelem_get_childNodes(
255     IXMLDOMElement *iface,
256     IXMLDOMNodeList** outList)
257 {
258     domelem *This = impl_from_IXMLDOMElement( iface );
259
260     TRACE("(%p)->(%p)\n", This, outList);
261
262     return node_get_child_nodes(&This->node, outList);
263 }
264
265 static HRESULT WINAPI domelem_get_firstChild(
266     IXMLDOMElement *iface,
267     IXMLDOMNode** domNode)
268 {
269     domelem *This = impl_from_IXMLDOMElement( iface );
270
271     TRACE("(%p)->(%p)\n", This, domNode);
272
273     return node_get_first_child(&This->node, domNode);
274 }
275
276 static HRESULT WINAPI domelem_get_lastChild(
277     IXMLDOMElement *iface,
278     IXMLDOMNode** domNode)
279 {
280     domelem *This = impl_from_IXMLDOMElement( iface );
281
282     TRACE("(%p)->(%p)\n", This, domNode);
283
284     return node_get_last_child(&This->node, domNode);
285 }
286
287 static HRESULT WINAPI domelem_get_previousSibling(
288     IXMLDOMElement *iface,
289     IXMLDOMNode** domNode)
290 {
291     domelem *This = impl_from_IXMLDOMElement( iface );
292
293     TRACE("(%p)->(%p)\n", This, domNode);
294
295     return node_get_previous_sibling(&This->node, domNode);
296 }
297
298 static HRESULT WINAPI domelem_get_nextSibling(
299     IXMLDOMElement *iface,
300     IXMLDOMNode** domNode)
301 {
302     domelem *This = impl_from_IXMLDOMElement( iface );
303
304     TRACE("(%p)->(%p)\n", This, domNode);
305
306     return node_get_next_sibling(&This->node, domNode);
307 }
308
309 static HRESULT WINAPI domelem_get_attributes(
310     IXMLDOMElement *iface,
311     IXMLDOMNamedNodeMap** attributeMap)
312 {
313     domelem *This = impl_from_IXMLDOMElement( iface );
314
315     TRACE("(%p)->(%p)\n", This, attributeMap);
316
317     *attributeMap = create_nodemap((IXMLDOMNode*)&This->IXMLDOMElement_iface);
318     return S_OK;
319 }
320
321 static HRESULT WINAPI domelem_insertBefore(
322     IXMLDOMElement *iface,
323     IXMLDOMNode* newNode, VARIANT refChild,
324     IXMLDOMNode** outOldNode)
325 {
326     domelem *This = impl_from_IXMLDOMElement( iface );
327
328     TRACE("(%p)->(%p %s %p)\n", This, newNode, debugstr_variant(&refChild), outOldNode);
329
330     return node_insert_before(&This->node, newNode, &refChild, outOldNode);
331 }
332
333 static HRESULT WINAPI domelem_replaceChild(
334     IXMLDOMElement *iface,
335     IXMLDOMNode* newNode,
336     IXMLDOMNode* oldNode,
337     IXMLDOMNode** outOldNode)
338 {
339     domelem *This = impl_from_IXMLDOMElement( iface );
340
341     TRACE("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
342
343     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
344 }
345
346 static HRESULT WINAPI domelem_removeChild(
347     IXMLDOMElement *iface,
348     IXMLDOMNode *child, IXMLDOMNode **oldChild)
349 {
350     domelem *This = impl_from_IXMLDOMElement( iface );
351     TRACE("(%p)->(%p %p)\n", This, child, oldChild);
352     return node_remove_child(&This->node, child, oldChild);
353 }
354
355 static HRESULT WINAPI domelem_appendChild(
356     IXMLDOMElement *iface,
357     IXMLDOMNode *child, IXMLDOMNode **outChild)
358 {
359     domelem *This = impl_from_IXMLDOMElement( iface );
360     TRACE("(%p)->(%p %p)\n", This, child, outChild);
361     return node_append_child(&This->node, child, outChild);
362 }
363
364 static HRESULT WINAPI domelem_hasChildNodes(
365     IXMLDOMElement *iface,
366     VARIANT_BOOL *ret)
367 {
368     domelem *This = impl_from_IXMLDOMElement( iface );
369     TRACE("(%p)->(%p)\n", This, ret);
370     return node_has_childnodes(&This->node, ret);
371 }
372
373 static HRESULT WINAPI domelem_get_ownerDocument(
374     IXMLDOMElement   *iface,
375     IXMLDOMDocument **doc)
376 {
377     domelem *This = impl_from_IXMLDOMElement( iface );
378     TRACE("(%p)->(%p)\n", This, doc);
379     return node_get_owner_doc(&This->node, doc);
380 }
381
382 static HRESULT WINAPI domelem_cloneNode(
383     IXMLDOMElement *iface,
384     VARIANT_BOOL deep, IXMLDOMNode** outNode)
385 {
386     domelem *This = impl_from_IXMLDOMElement( iface );
387     TRACE("(%p)->(%d %p)\n", This, deep, outNode);
388     return node_clone( &This->node, deep, outNode );
389 }
390
391 static HRESULT WINAPI domelem_get_nodeTypeString(
392     IXMLDOMElement *iface,
393     BSTR* p)
394 {
395     domelem *This = impl_from_IXMLDOMElement( iface );
396     static const WCHAR elementW[] = {'e','l','e','m','e','n','t',0};
397
398     TRACE("(%p)->(%p)\n", This, p);
399
400     return return_bstr(elementW, p);
401 }
402
403 static HRESULT WINAPI domelem_get_text(
404     IXMLDOMElement *iface,
405     BSTR* p)
406 {
407     domelem *This = impl_from_IXMLDOMElement( iface );
408     TRACE("(%p)->(%p)\n", This, p);
409     return node_get_text(&This->node, p);
410 }
411
412 static HRESULT WINAPI domelem_put_text(
413     IXMLDOMElement *iface,
414     BSTR p)
415 {
416     domelem *This = impl_from_IXMLDOMElement( iface );
417     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
418     return node_put_text( &This->node, p );
419 }
420
421 static HRESULT WINAPI domelem_get_specified(
422     IXMLDOMElement *iface,
423     VARIANT_BOOL* isSpecified)
424 {
425     domelem *This = impl_from_IXMLDOMElement( iface );
426     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
427     *isSpecified = VARIANT_TRUE;
428     return S_OK;
429 }
430
431 static HRESULT WINAPI domelem_get_definition(
432     IXMLDOMElement *iface,
433     IXMLDOMNode** definitionNode)
434 {
435     domelem *This = impl_from_IXMLDOMElement( iface );
436     FIXME("(%p)->(%p)\n", This, definitionNode);
437     return E_NOTIMPL;
438 }
439
440 static inline BYTE hex_to_byte(xmlChar c)
441 {
442     if(c <= '9') return c-'0';
443     if(c <= 'F') return c-'A'+10;
444     return c-'a'+10;
445 }
446
447 static inline BYTE base64_to_byte(xmlChar c)
448 {
449     if(c == '+') return 62;
450     if(c == '/') return 63;
451     if(c <= '9') return c-'0'+52;
452     if(c <= 'Z') return c-'A';
453     return c-'a'+26;
454 }
455
456 static inline HRESULT VARIANT_from_DT(XDR_DT dt, xmlChar* str, VARIANT* v)
457 {
458     VARIANT src;
459     HRESULT hr = S_OK;
460     BOOL handled = FALSE;
461
462     VariantInit(&src);
463
464     switch (dt)
465     {
466     case DT_INVALID:
467     case DT_STRING:
468     case DT_NMTOKEN:
469     case DT_NMTOKENS:
470     case DT_NUMBER:
471     case DT_URI:
472     case DT_UUID:
473         {
474             V_VT(v) = VT_BSTR;
475             V_BSTR(v) = bstr_from_xmlChar(str);
476
477             if(!V_BSTR(v))
478                 return E_OUTOFMEMORY;
479             handled = TRUE;
480         }
481         break;
482     case DT_DATE:
483     case DT_DATE_TZ:
484     case DT_DATETIME:
485     case DT_DATETIME_TZ:
486     case DT_TIME:
487     case DT_TIME_TZ:
488         {
489             WCHAR *p, *e;
490             SYSTEMTIME st;
491             DOUBLE date = 0.0;
492
493             st.wYear = 1899;
494             st.wMonth = 12;
495             st.wDay = 30;
496             st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
497
498             V_VT(&src) = VT_BSTR;
499             V_BSTR(&src) = bstr_from_xmlChar(str);
500
501             if(!V_BSTR(&src))
502                 return E_OUTOFMEMORY;
503
504             p = V_BSTR(&src);
505             e = p + SysStringLen(V_BSTR(&src));
506
507             if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
508             {
509                 st.wYear = atoiW(p);
510                 st.wMonth = atoiW(p+5);
511                 st.wDay = atoiW(p+8);
512                 p += 10;
513
514                 if(*p == 'T') p++;
515             }
516
517             if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
518             {
519                 st.wHour = atoiW(p);
520                 st.wMinute = atoiW(p+3);
521                 st.wSecond = atoiW(p+6);
522                 p += 8;
523
524                 if(*p == '.')
525                 {
526                     p++;
527                     while(isdigitW(*p)) p++;
528                 }
529             }
530
531             SystemTimeToVariantTime(&st, &date);
532             V_VT(v) = VT_DATE;
533             V_DATE(v) = date;
534
535             if(*p == '+') /* parse timezone offset (+hh:mm) */
536                 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
537             else if(*p == '-') /* parse timezone offset (-hh:mm) */
538                 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
539
540             VariantClear(&src);
541             handled = TRUE;
542         }
543         break;
544     case DT_BIN_HEX:
545         {
546             SAFEARRAYBOUND sab;
547             int i, len;
548
549             len = xmlStrlen(str)/2;
550             sab.lLbound = 0;
551             sab.cElements = len;
552
553             V_VT(v) = (VT_ARRAY|VT_UI1);
554             V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
555
556             if(!V_ARRAY(v))
557                 return E_OUTOFMEMORY;
558
559             for(i=0; i<len; i++)
560                 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
561                     + hex_to_byte(str[2*i+1]);
562             handled = TRUE;
563         }
564         break;
565     case DT_BIN_BASE64:
566         {
567             SAFEARRAYBOUND sab;
568             int i, len;
569
570             len  = xmlStrlen(str);
571             if(str[len-2] == '=') i = 2;
572             else if(str[len-1] == '=') i = 1;
573             else i = 0;
574
575             sab.lLbound = 0;
576             sab.cElements = len/4*3-i;
577
578             V_VT(v) = (VT_ARRAY|VT_UI1);
579             V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
580
581             if(!V_ARRAY(v))
582                 return E_OUTOFMEMORY;
583
584             for(i=0; i<len/4; i++)
585             {
586                 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
587                     + (base64_to_byte(str[4*i+1])>>4);
588                 if(3*i+1 < sab.cElements)
589                     ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
590                         + (base64_to_byte(str[4*i+2])>>2);
591                 if(3*i+2 < sab.cElements)
592                     ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
593                         + base64_to_byte(str[4*i+3]);
594             }
595             handled = TRUE;
596         }
597         break;
598     case DT_BOOLEAN:
599         V_VT(v) = VT_BOOL;
600         break;
601     case DT_FIXED_14_4:
602         V_VT(v) = VT_CY;
603         break;
604     case DT_I1:
605         V_VT(v) = VT_I1;
606         break;
607     case DT_I2:
608         V_VT(v) = VT_I2;
609         break;
610     case DT_I4:
611     case DT_INT:
612         V_VT(v) = VT_I4;
613         break;
614     case DT_I8:
615         V_VT(v) = VT_I8;
616         break;
617     case DT_R4:
618         V_VT(v) = VT_R4;
619         break;
620     case DT_FLOAT:
621     case DT_R8:
622         V_VT(v) = VT_R8;
623         break;
624     case DT_UI1:
625         V_VT(v) = VT_UI1;
626         break;
627     case DT_UI2:
628         V_VT(v) = VT_UI2;
629         break;
630     case DT_UI4:
631         V_VT(v) = VT_UI4;
632         break;
633     case DT_UI8:
634         V_VT(v) = VT_UI8;
635         break;
636     case DT_CHAR:
637     case DT_ENTITY:
638     case DT_ENTITIES:
639     case DT_ENUMERATION:
640     case DT_ID:
641     case DT_IDREF:
642     case DT_IDREFS:
643     case DT_NOTATION:
644         FIXME("need to handle dt:%s\n", dt_to_str(dt));
645         V_VT(v) = VT_BSTR;
646         V_BSTR(v) = bstr_from_xmlChar(str);
647         if (!V_BSTR(v))
648             return E_OUTOFMEMORY;
649         handled = TRUE;
650         break;
651     }
652
653     if (!handled)
654     {
655         V_VT(&src) = VT_BSTR;
656         V_BSTR(&src) = bstr_from_xmlChar(str);
657
658         if(!V_BSTR(&src))
659             return E_OUTOFMEMORY;
660
661         hr = VariantChangeTypeEx(v, &src,
662                 MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
663         VariantClear(&src);
664     }
665     return hr;
666 }
667
668 static HRESULT WINAPI domelem_get_nodeTypedValue(
669     IXMLDOMElement *iface,
670     VARIANT* var1)
671 {
672     domelem *This = impl_from_IXMLDOMElement( iface );
673     XDR_DT dt;
674     xmlChar* content;
675     HRESULT hr;
676
677     TRACE("(%p)->(%p)\n", This, var1);
678
679     if(!var1)
680         return E_INVALIDARG;
681
682     V_VT(var1) = VT_NULL;
683
684     dt = element_get_dt(get_element(This));
685     content = xmlNodeGetContent(get_element(This));
686     hr = VARIANT_from_DT(dt, content, var1);
687     xmlFree(content);
688
689     return hr;
690 }
691
692 static HRESULT WINAPI domelem_put_nodeTypedValue(
693     IXMLDOMElement *iface,
694     VARIANT value)
695 {
696     domelem *This = impl_from_IXMLDOMElement( iface );
697     VARIANT type;
698     HRESULT hr;
699
700     TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
701
702     /* for untyped node coerce to BSTR and set */
703     if (IXMLDOMElement_get_dataType(iface, &type) == S_FALSE)
704     {
705         if (V_VT(&value) != VT_BSTR)
706         {
707             hr = VariantChangeType(&value, &value, 0, VT_BSTR);
708             if (hr == S_OK)
709             {
710                 hr = node_set_content(&This->node, V_BSTR(&value));
711                 VariantClear(&value);
712             }
713         }
714         else
715             hr = node_set_content(&This->node, V_BSTR(&value));
716     }
717     else
718     {
719         FIXME("not implemented for typed nodes. type %s\n", debugstr_w(V_BSTR(&value)));
720         VariantClear(&type);
721         return E_NOTIMPL;
722     }
723
724     return hr;
725 }
726
727 XDR_DT element_get_dt(xmlNodePtr node)
728 {
729     XDR_DT dt = DT_INVALID;
730
731     TRACE("(%p)\n", node);
732     if(node->type != XML_ELEMENT_NODE)
733     {
734         FIXME("invalid element node\n");
735         return dt;
736     }
737
738     if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
739     {
740         dt = str_to_dt(node->name, -1);
741     }
742     else
743     {
744         xmlChar* pVal = xmlGetNsProp(node, BAD_CAST "dt", DT_nsURI);
745         if (pVal)
746         {
747             dt = str_to_dt(pVal, -1);
748             xmlFree(pVal);
749         }
750         else if (node->doc)
751         {
752             IXMLDOMDocument3* doc = (IXMLDOMDocument3*)create_domdoc((xmlNodePtr)node->doc);
753             if (doc)
754             {
755                 VARIANT v;
756                 VariantInit(&v);
757
758                 if (IXMLDOMDocument3_get_schemas(doc, &v) == S_OK &&
759                     V_VT(&v) == VT_DISPATCH)
760                 {
761                     dt = SchemaCache_get_node_dt((IXMLDOMSchemaCollection2*)V_DISPATCH(&v), node);
762                 }
763                 VariantClear(&v);
764                 IXMLDOMDocument3_Release(doc);
765             }
766         }
767     }
768
769     TRACE("=> dt:%s\n", dt_to_str(dt));
770     return dt;
771 }
772
773 static HRESULT WINAPI domelem_get_dataType(
774     IXMLDOMElement *iface,
775     VARIANT* typename)
776 {
777     domelem *This = impl_from_IXMLDOMElement( iface );
778     XDR_DT dt;
779
780     TRACE("(%p)->(%p)\n", This, typename);
781
782     if (!typename)
783         return E_INVALIDARG;
784
785     dt = element_get_dt(get_element(This));
786     switch (dt)
787     {
788         case DT_BIN_BASE64:
789         case DT_BIN_HEX:
790         case DT_BOOLEAN:
791         case DT_CHAR:
792         case DT_DATE:
793         case DT_DATE_TZ:
794         case DT_DATETIME:
795         case DT_DATETIME_TZ:
796         case DT_FIXED_14_4:
797         case DT_FLOAT:
798         case DT_I1:
799         case DT_I2:
800         case DT_I4:
801         case DT_I8:
802         case DT_INT:
803         case DT_NUMBER:
804         case DT_R4:
805         case DT_R8:
806         case DT_TIME:
807         case DT_TIME_TZ:
808         case DT_UI1:
809         case DT_UI2:
810         case DT_UI4:
811         case DT_UI8:
812         case DT_URI:
813         case DT_UUID:
814             V_VT(typename) = VT_BSTR;
815             V_BSTR(typename) = SysAllocString(dt_to_bstr(dt));
816
817             if (!V_BSTR(typename))
818                 return E_OUTOFMEMORY;
819             break;
820         default:
821             /* Other types (DTD equivalents) do not return anything here,
822              * but the pointer part of the VARIANT is set to NULL */
823             V_VT(typename) = VT_NULL;
824             V_BSTR(typename) = NULL;
825             break;
826     }
827     return (V_VT(typename) != VT_NULL) ? S_OK : S_FALSE;
828 }
829
830 static HRESULT WINAPI domelem_put_dataType(
831     IXMLDOMElement *iface,
832     BSTR dtName)
833 {
834     domelem *This = impl_from_IXMLDOMElement( iface );
835     HRESULT hr = E_FAIL;
836     xmlChar *str;
837     XDR_DT dt;
838
839     TRACE("(%p)->(%s)\n", This, debugstr_w(dtName));
840
841     if(dtName == NULL)
842         return E_INVALIDARG;
843
844     dt = bstr_to_dt(dtName, -1);
845
846     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
847        This applies to changing types (string->bool) or setting a new one
848      */
849     str = xmlNodeGetContent(get_element(This));
850     hr = dt_validate(dt, str);
851     xmlFree(str);
852
853     /* Check all supported types. */
854     if (hr == S_OK)
855     {
856         switch (dt)
857         {
858         case DT_BIN_BASE64:
859         case DT_BIN_HEX:
860         case DT_BOOLEAN:
861         case DT_CHAR:
862         case DT_DATE:
863         case DT_DATE_TZ:
864         case DT_DATETIME:
865         case DT_DATETIME_TZ:
866         case DT_FIXED_14_4:
867         case DT_FLOAT:
868         case DT_I1:
869         case DT_I2:
870         case DT_I4:
871         case DT_I8:
872         case DT_INT:
873         case DT_NMTOKEN:
874         case DT_NMTOKENS:
875         case DT_NUMBER:
876         case DT_R4:
877         case DT_R8:
878         case DT_STRING:
879         case DT_TIME:
880         case DT_TIME_TZ:
881         case DT_UI1:
882         case DT_UI2:
883         case DT_UI4:
884         case DT_UI8:
885         case DT_URI:
886         case DT_UUID:
887             {
888                 xmlAttrPtr attr = xmlHasNsProp(get_element(This), DT_prefix, DT_nsURI);
889                 if (attr)
890                 {
891                     attr = xmlSetNsProp(get_element(This), attr->ns, DT_prefix, dt_to_str(dt));
892                     hr = S_OK;
893                 }
894                 else
895                 {
896                     xmlNsPtr ns = xmlNewNs(get_element(This), DT_nsURI, DT_prefix);
897                     if (ns)
898                     {
899                         attr = xmlNewNsProp(get_element(This), ns, DT_prefix, dt_to_str(dt));
900                         if (attr)
901                         {
902                             xmlAddChild(get_element(This), (xmlNodePtr)attr);
903                             hr = S_OK;
904                         }
905                         else
906                             ERR("Failed to create Attribute\n");
907                     }
908                     else
909                         ERR("Failed to create Namespace\n");
910                 }
911             }
912             break;
913         default:
914             FIXME("need to handle dt:%s\n", dt_to_str(dt));
915             break;
916         }
917     }
918
919     return hr;
920 }
921
922 static HRESULT WINAPI domelem_get_xml(
923     IXMLDOMElement *iface,
924     BSTR* p)
925 {
926     domelem *This = impl_from_IXMLDOMElement( iface );
927
928     TRACE("(%p)->(%p)\n", This, p);
929
930     return node_get_xml(&This->node, TRUE, FALSE, p);
931 }
932
933 static HRESULT WINAPI domelem_transformNode(
934     IXMLDOMElement *iface,
935     IXMLDOMNode* domNode, BSTR* p)
936 {
937     domelem *This = impl_from_IXMLDOMElement( iface );
938     return IXMLDOMNode_transformNode( &This->node.IXMLDOMNode_iface, domNode, p );
939 }
940
941 static HRESULT WINAPI domelem_selectNodes(
942     IXMLDOMElement *iface,
943     BSTR p, IXMLDOMNodeList** outList)
944 {
945     domelem *This = impl_from_IXMLDOMElement( iface );
946     return IXMLDOMNode_selectNodes( &This->node.IXMLDOMNode_iface, p, outList );
947 }
948
949 static HRESULT WINAPI domelem_selectSingleNode(
950     IXMLDOMElement *iface,
951     BSTR p, IXMLDOMNode** outNode)
952 {
953     domelem *This = impl_from_IXMLDOMElement( iface );
954     return IXMLDOMNode_selectSingleNode( &This->node.IXMLDOMNode_iface, p, outNode );
955 }
956
957 static HRESULT WINAPI domelem_get_parsed(
958     IXMLDOMElement *iface,
959     VARIANT_BOOL* isParsed)
960 {
961     domelem *This = impl_from_IXMLDOMElement( iface );
962     FIXME("(%p)->(%p) stub!\n", This, isParsed);
963     *isParsed = VARIANT_TRUE;
964     return S_OK;
965 }
966
967 static HRESULT WINAPI domelem_get_namespaceURI(
968     IXMLDOMElement *iface,
969     BSTR* p)
970 {
971     domelem *This = impl_from_IXMLDOMElement( iface );
972     TRACE("(%p)->(%p)\n", This, p);
973     return node_get_namespaceURI(&This->node, p);
974 }
975
976 static HRESULT WINAPI domelem_get_prefix(
977     IXMLDOMElement *iface,
978     BSTR* prefix)
979 {
980     domelem *This = impl_from_IXMLDOMElement( iface );
981     TRACE("(%p)->(%p)\n", This, prefix);
982     return node_get_prefix( &This->node, prefix );
983 }
984
985 static HRESULT WINAPI domelem_get_baseName(
986     IXMLDOMElement *iface,
987     BSTR* name)
988 {
989     domelem *This = impl_from_IXMLDOMElement( iface );
990     TRACE("(%p)->(%p)\n", This, name);
991     return node_get_base_name( &This->node, name );
992 }
993
994 static HRESULT WINAPI domelem_transformNodeToObject(
995     IXMLDOMElement *iface,
996     IXMLDOMNode* domNode, VARIANT var1)
997 {
998     domelem *This = impl_from_IXMLDOMElement( iface );
999     FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1000     return E_NOTIMPL;
1001 }
1002
1003 static HRESULT WINAPI domelem_get_tagName(
1004     IXMLDOMElement *iface,
1005     BSTR* p)
1006 {
1007     domelem *This = impl_from_IXMLDOMElement( iface );
1008     xmlNodePtr element;
1009     const xmlChar *prefix;
1010     xmlChar *qname;
1011
1012     TRACE("(%p)->(%p)\n", This, p );
1013
1014     if (!p) return E_INVALIDARG;
1015
1016     element = get_element( This );
1017     if ( !element )
1018         return E_FAIL;
1019
1020     prefix = element->ns ? element->ns->prefix : NULL;
1021     qname = xmlBuildQName(element->name, prefix, NULL, 0);
1022
1023     *p = bstr_from_xmlChar(qname);
1024     if (qname != element->name) xmlFree(qname);
1025
1026     return *p ? S_OK : E_OUTOFMEMORY;
1027 }
1028
1029 static HRESULT WINAPI domelem_getAttribute(
1030     IXMLDOMElement *iface,
1031     BSTR name, VARIANT* value)
1032 {
1033     domelem *This = impl_from_IXMLDOMElement( iface );
1034     xmlNodePtr element;
1035     xmlChar *xml_name, *xml_value = NULL;
1036     HRESULT hr = S_FALSE;
1037
1038     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
1039
1040     if(!value || !name)
1041         return E_INVALIDARG;
1042
1043     element = get_element( This );
1044     if ( !element )
1045         return E_FAIL;
1046
1047     V_BSTR(value) = NULL;
1048     V_VT(value) = VT_NULL;
1049
1050     xml_name = xmlChar_from_wchar( name );
1051
1052     if(!xmlValidateNameValue(xml_name))
1053         hr = E_FAIL;
1054     else
1055         xml_value = xmlGetNsProp(element, xml_name, NULL);
1056
1057     heap_free(xml_name);
1058     if(xml_value)
1059     {
1060         V_VT(value) = VT_BSTR;
1061         V_BSTR(value) = bstr_from_xmlChar( xml_value );
1062         xmlFree(xml_value);
1063         hr = S_OK;
1064     }
1065
1066     return hr;
1067 }
1068
1069 static HRESULT WINAPI domelem_setAttribute(
1070     IXMLDOMElement *iface,
1071     BSTR name, VARIANT value)
1072 {
1073     domelem *This = impl_from_IXMLDOMElement( iface );
1074     xmlNodePtr element;
1075     xmlChar *xml_name, *xml_value;
1076     HRESULT hr;
1077     VARIANT var;
1078
1079     TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_variant(&value));
1080
1081     element = get_element( This );
1082     if ( !element )
1083         return E_FAIL;
1084
1085     VariantInit(&var);
1086     hr = VariantChangeType(&var, &value, 0, VT_BSTR);
1087     if(hr != S_OK)
1088     {
1089         FIXME("VariantChangeType failed\n");
1090         return hr;
1091     }
1092
1093     xml_name = xmlChar_from_wchar( name );
1094     xml_value = xmlChar_from_wchar( V_BSTR(&var) );
1095
1096     if(!xmlSetNsProp(element, NULL,  xml_name, xml_value))
1097         hr = E_FAIL;
1098
1099     heap_free(xml_value);
1100     heap_free(xml_name);
1101     VariantClear(&var);
1102
1103     return hr;
1104 }
1105
1106 static HRESULT WINAPI domelem_removeAttribute(
1107     IXMLDOMElement *iface,
1108     BSTR p)
1109 {
1110     domelem *This = impl_from_IXMLDOMElement( iface );
1111     IXMLDOMNamedNodeMap *attr;
1112     HRESULT hr;
1113
1114     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
1115
1116     hr = IXMLDOMElement_get_attributes(iface, &attr);
1117     if (hr != S_OK) return hr;
1118
1119     hr = IXMLDOMNamedNodeMap_removeNamedItem(attr, p, NULL);
1120     IXMLDOMNamedNodeMap_Release(attr);
1121
1122     return hr;
1123 }
1124
1125 static HRESULT WINAPI domelem_getAttributeNode(
1126     IXMLDOMElement *iface,
1127     BSTR p, IXMLDOMAttribute** attributeNode )
1128 {
1129     domelem *This = impl_from_IXMLDOMElement( iface );
1130     xmlChar *xml_name;
1131     xmlNodePtr element;
1132     xmlAttrPtr attr;
1133     IUnknown *unk;
1134     HRESULT hr = S_FALSE;
1135
1136     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), attributeNode);
1137
1138     if(!attributeNode)
1139         return E_FAIL;
1140
1141     *attributeNode = NULL;
1142
1143     element = get_element( This );
1144     if ( !element )
1145         return E_FAIL;
1146
1147     xml_name = xmlChar_from_wchar(p);
1148
1149     if(!xmlValidateNameValue(xml_name))
1150     {
1151         heap_free(xml_name);
1152         return E_FAIL;
1153     }
1154
1155     attr = xmlHasProp(element, xml_name);
1156     if(attr) {
1157         unk = create_attribute((xmlNodePtr)attr);
1158         hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMAttribute, (void**)attributeNode);
1159         IUnknown_Release(unk);
1160     }
1161
1162     heap_free(xml_name);
1163
1164     return hr;
1165 }
1166
1167 static HRESULT WINAPI domelem_setAttributeNode(
1168     IXMLDOMElement *iface,
1169     IXMLDOMAttribute* attribute,
1170     IXMLDOMAttribute** old)
1171 {
1172     domelem *This = impl_from_IXMLDOMElement( iface );
1173     xmlChar *name, *value;
1174     BSTR nameW, prefix;
1175     xmlAttrPtr attr;
1176     VARIANT valueW;
1177     HRESULT hr;
1178
1179     FIXME("(%p)->(%p %p): semi-stub\n", This, attribute, old);
1180
1181     if (!attribute) return E_INVALIDARG;
1182
1183     if (old) *old = NULL;
1184
1185     hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW);
1186     if (hr != S_OK) return hr;
1187
1188     hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW);
1189     if (hr != S_OK)
1190     {
1191         SysFreeString(nameW);
1192         return hr;
1193     }
1194
1195     TRACE("attribute: %s=%s\n", debugstr_w(nameW), debugstr_w(V_BSTR(&valueW)));
1196
1197     hr = IXMLDOMAttribute_get_prefix(attribute, &prefix);
1198     if (hr == S_OK)
1199     {
1200         FIXME("namespaces not supported: %s\n", debugstr_w(prefix));
1201         SysFreeString(prefix);
1202     }
1203
1204     name = xmlChar_from_wchar(nameW);
1205     value = xmlChar_from_wchar(V_BSTR(&valueW));
1206
1207     if (!name || !value)
1208     {
1209         SysFreeString(nameW);
1210         VariantClear(&valueW);
1211         heap_free(name);
1212         heap_free(value);
1213         return E_OUTOFMEMORY;
1214     }
1215
1216     attr = xmlSetNsProp(get_element(This), NULL, name, value);
1217
1218     SysFreeString(nameW);
1219     VariantClear(&valueW);
1220     heap_free(name);
1221     heap_free(value);
1222
1223     return attr ? S_OK : E_FAIL;
1224 }
1225
1226 static HRESULT WINAPI domelem_removeAttributeNode(
1227     IXMLDOMElement *iface,
1228     IXMLDOMAttribute* domAttribute,
1229     IXMLDOMAttribute** attributeNode)
1230 {
1231     domelem *This = impl_from_IXMLDOMElement( iface );
1232     FIXME("(%p)->(%p %p)\n", This, domAttribute, attributeNode);
1233     return E_NOTIMPL;
1234 }
1235
1236 static HRESULT WINAPI domelem_getElementsByTagName(
1237     IXMLDOMElement *iface,
1238     BSTR tagName, IXMLDOMNodeList** resultList)
1239 {
1240     domelem *This = impl_from_IXMLDOMElement( iface );
1241     xmlChar *query;
1242     HRESULT hr;
1243     BOOL XPath;
1244
1245     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1246
1247     if (!tagName || !resultList) return E_INVALIDARG;
1248
1249     XPath = is_xpathmode(get_element(This)->doc);
1250     set_xpathmode(get_element(This)->doc, TRUE);
1251     query = tagName_to_XPath(tagName);
1252     hr = queryresult_create(get_element(This), query, resultList);
1253     xmlFree(query);
1254     set_xpathmode(get_element(This)->doc, XPath);
1255
1256     return hr;
1257 }
1258
1259 static HRESULT WINAPI domelem_normalize(
1260     IXMLDOMElement *iface )
1261 {
1262     domelem *This = impl_from_IXMLDOMElement( iface );
1263     FIXME("%p\n", This);
1264     return E_NOTIMPL;
1265 }
1266
1267 static const struct IXMLDOMElementVtbl domelem_vtbl =
1268 {
1269     domelem_QueryInterface,
1270     domelem_AddRef,
1271     domelem_Release,
1272     domelem_GetTypeInfoCount,
1273     domelem_GetTypeInfo,
1274     domelem_GetIDsOfNames,
1275     domelem_Invoke,
1276     domelem_get_nodeName,
1277     domelem_get_nodeValue,
1278     domelem_put_nodeValue,
1279     domelem_get_nodeType,
1280     domelem_get_parentNode,
1281     domelem_get_childNodes,
1282     domelem_get_firstChild,
1283     domelem_get_lastChild,
1284     domelem_get_previousSibling,
1285     domelem_get_nextSibling,
1286     domelem_get_attributes,
1287     domelem_insertBefore,
1288     domelem_replaceChild,
1289     domelem_removeChild,
1290     domelem_appendChild,
1291     domelem_hasChildNodes,
1292     domelem_get_ownerDocument,
1293     domelem_cloneNode,
1294     domelem_get_nodeTypeString,
1295     domelem_get_text,
1296     domelem_put_text,
1297     domelem_get_specified,
1298     domelem_get_definition,
1299     domelem_get_nodeTypedValue,
1300     domelem_put_nodeTypedValue,
1301     domelem_get_dataType,
1302     domelem_put_dataType,
1303     domelem_get_xml,
1304     domelem_transformNode,
1305     domelem_selectNodes,
1306     domelem_selectSingleNode,
1307     domelem_get_parsed,
1308     domelem_get_namespaceURI,
1309     domelem_get_prefix,
1310     domelem_get_baseName,
1311     domelem_transformNodeToObject,
1312     domelem_get_tagName,
1313     domelem_getAttribute,
1314     domelem_setAttribute,
1315     domelem_removeAttribute,
1316     domelem_getAttributeNode,
1317     domelem_setAttributeNode,
1318     domelem_removeAttributeNode,
1319     domelem_getElementsByTagName,
1320     domelem_normalize,
1321 };
1322
1323 static const tid_t domelem_iface_tids[] = {
1324     IXMLDOMElement_tid,
1325     0
1326 };
1327
1328 static dispex_static_data_t domelem_dispex = {
1329     NULL,
1330     IXMLDOMElement_tid,
1331     NULL,
1332     domelem_iface_tids
1333 };
1334
1335 IUnknown* create_element( xmlNodePtr element )
1336 {
1337     domelem *This;
1338
1339     This = heap_alloc( sizeof *This );
1340     if ( !This )
1341         return NULL;
1342
1343     This->IXMLDOMElement_iface.lpVtbl = &domelem_vtbl;
1344     This->ref = 1;
1345
1346     init_xmlnode(&This->node, element, (IXMLDOMNode*)&This->IXMLDOMElement_iface, &domelem_dispex);
1347
1348     return (IUnknown*)&This->IXMLDOMElement_iface;
1349 }
1350
1351 #endif