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