ws2_32: name is never NULL as array (Coverity).
[wine] / dlls / msxml3 / node.c
1 /*
2  *    Node implementation
3  *
4  * Copyright 2005 Mike McCormack
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #define COBJMACROS
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 #ifdef HAVE_LIBXML2
36 # include <libxml/HTMLtree.h>
37 #endif
38
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
42
43 #ifdef HAVE_LIBXML2
44
45 /* TODO: get rid of these and use the enum */
46 static const WCHAR szBinBase64[]  = {'b','i','n','.','b','a','s','e','6','4',0};
47 static const WCHAR szString[]     = {'s','t','r','i','n','g',0};
48 static const WCHAR szNumber[]     = {'n','u','m','b','e','r',0};
49 static const WCHAR szInt[]        = {'I','n','t',0};
50 static const WCHAR szFixed[]      = {'F','i','x','e','d','.','1','4','.','4',0};
51 static const WCHAR szBoolean[]    = {'B','o','o','l','e','a','n',0};
52 static const WCHAR szDateTime[]   = {'d','a','t','e','T','i','m','e',0};
53 static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
54 static const WCHAR szDate[]       = {'D','a','t','e',0};
55 static const WCHAR szTime[]       = {'T','i','m','e',0};
56 static const WCHAR szTimeTZ[]     = {'T','i','m','e','.','t','z',0};
57 static const WCHAR szI1[]         = {'i','1',0};
58 static const WCHAR szI2[]         = {'i','2',0};
59 static const WCHAR szI4[]         = {'i','4',0};
60 static const WCHAR szIU1[]        = {'u','i','1',0};
61 static const WCHAR szIU2[]        = {'u','i','2',0};
62 static const WCHAR szIU4[]        = {'u','i','4',0};
63 static const WCHAR szR4[]         = {'r','4',0};
64 static const WCHAR szR8[]         = {'r','8',0};
65 static const WCHAR szFloat[]      = {'f','l','o','a','t',0};
66 static const WCHAR szUUID[]       = {'u','u','i','d',0};
67 static const WCHAR szBinHex[]     = {'b','i','n','.','h','e','x',0};
68
69 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
70
71 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
72 {
73     xmlnode *This;
74
75     if ( !iface )
76         return NULL;
77     This = get_node_obj( iface );
78     if ( !This || !This->node )
79         return NULL;
80     if ( type && This->node->type != type )
81         return NULL;
82     return This->node;
83 }
84
85 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
86 {
87     if(IsEqualGUID(&IID_xmlnode, riid)) {
88         TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
89         *ppv = This;
90         return TRUE;
91     }
92
93     if(This->dispex.outer)
94         return dispex_query_interface(&This->dispex, riid, ppv);
95
96     return FALSE;
97 }
98
99 xmlnode *get_node_obj(IXMLDOMNode *node)
100 {
101     xmlnode *obj;
102     HRESULT hres;
103
104     hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
105     return SUCCEEDED(hres) ? obj : NULL;
106 }
107
108 static inline xmlnode *impl_from_IXMLDOMNode( IXMLDOMNode *iface )
109 {
110     return CONTAINING_RECORD(iface, xmlnode, IXMLDOMNode_iface);
111 }
112
113 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
114 {
115     if (!name)
116         return E_INVALIDARG;
117
118     *name = bstr_from_xmlChar(This->node->name);
119     if (!*name)
120         return S_FALSE;
121
122     return S_OK;
123 }
124
125 HRESULT node_get_content(xmlnode *This, VARIANT *value)
126 {
127     xmlChar *content;
128
129     if(!value)
130         return E_INVALIDARG;
131
132     content = xmlNodeGetContent(This->node);
133     V_VT(value) = VT_BSTR;
134     V_BSTR(value) = bstr_from_xmlChar( content );
135     xmlFree(content);
136
137     TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
138     return S_OK;
139 }
140
141 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
142 {
143     xmlChar *str;
144
145     TRACE("(%p)->(%s)\n", This, debugstr_w(value));
146     str = xmlChar_from_wchar(value);
147     if(!str)
148         return E_OUTOFMEMORY;
149
150     xmlNodeSetContent(This->node, str);
151     heap_free(str);
152     return S_OK;
153 }
154
155 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
156 {
157     xmlChar *str, *escaped;
158
159     TRACE("(%p)->(%s)\n", This, debugstr_w(value));
160     str = xmlChar_from_wchar(value);
161     if(!str)
162         return E_OUTOFMEMORY;
163
164     escaped = xmlEncodeSpecialChars(NULL, str);
165     if(!escaped)
166     {
167         heap_free(str);
168         return E_OUTOFMEMORY;
169     }
170
171     xmlNodeSetContent(This->node, escaped);
172
173     heap_free(str);
174     xmlFree(escaped);
175
176     return S_OK;
177 }
178
179 HRESULT node_put_value(xmlnode *This, VARIANT *value)
180 {
181     VARIANT string_value;
182     HRESULT hr;
183
184     VariantInit(&string_value);
185     hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
186     if(FAILED(hr)) {
187         WARN("Couldn't convert to VT_BSTR\n");
188         return hr;
189     }
190
191     hr = node_set_content(This, V_BSTR(&string_value));
192     VariantClear(&string_value);
193
194     return hr;
195 }
196
197 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
198 {
199     VARIANT string_value;
200     HRESULT hr;
201
202     VariantInit(&string_value);
203     hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
204     if(FAILED(hr)) {
205         WARN("Couldn't convert to VT_BSTR\n");
206         return hr;
207     }
208
209     hr = node_set_content_escaped(This, V_BSTR(&string_value));
210     VariantClear(&string_value);
211
212     return hr;
213 }
214
215 static HRESULT get_node(
216     xmlnode *This,
217     const char *name,
218     xmlNodePtr node,
219     IXMLDOMNode **out )
220 {
221     TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
222
223     if ( !out )
224         return E_INVALIDARG;
225
226     /* if we don't have a doc, use our parent. */
227     if(node && !node->doc && node->parent)
228         node->doc = node->parent->doc;
229
230     *out = create_node( node );
231     if (!*out)
232         return S_FALSE;
233     return S_OK;
234 }
235
236 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
237 {
238     return get_node( This, "parent", This->node->parent, parent );
239 }
240
241 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
242 {
243     if(!ret)
244         return E_INVALIDARG;
245
246     *ret = create_children_nodelist(This->node);
247     if(!*ret)
248         return E_OUTOFMEMORY;
249
250     return S_OK;
251 }
252
253 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
254 {
255     return get_node(This, "firstChild", This->node->children, ret);
256 }
257
258 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
259 {
260     return get_node(This, "lastChild", This->node->last, ret);
261 }
262
263 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
264 {
265     return get_node(This, "previous", This->node->prev, ret);
266 }
267
268 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
269 {
270     return get_node(This, "next", This->node->next, ret);
271 }
272
273 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
274         IXMLDOMNode **ret)
275 {
276     xmlNodePtr before_node, new_child_node;
277     IXMLDOMNode *before = NULL;
278     xmlnode *node_obj;
279     HRESULT hr;
280
281     if(!new_child)
282         return E_INVALIDARG;
283
284     node_obj = get_node_obj(new_child);
285     if(!node_obj) {
286         FIXME("newChild is not our node implementation\n");
287         return E_FAIL;
288     }
289
290     switch(V_VT(ref_child))
291     {
292     case VT_EMPTY:
293     case VT_NULL:
294         break;
295
296     case VT_UNKNOWN:
297     case VT_DISPATCH:
298         hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (LPVOID)&before);
299         if(FAILED(hr)) return hr;
300         break;
301
302     default:
303         FIXME("refChild var type %x\n", V_VT(ref_child));
304         return E_FAIL;
305     }
306
307     new_child_node = node_obj->node;
308     TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
309
310     if(!new_child_node->parent)
311         if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
312             WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
313
314     if(before)
315     {
316         node_obj = get_node_obj(before);
317         IXMLDOMNode_Release(before);
318         if(!node_obj) {
319             FIXME("before node is not our node implementation\n");
320             return E_FAIL;
321         }
322
323         before_node = node_obj->node;
324         xmlAddPrevSibling(before_node, new_child_node);
325     }
326     else
327     {
328         xmlAddChild(This->node, new_child_node);
329     }
330
331     if(ret) {
332         IXMLDOMNode_AddRef(new_child);
333         *ret = new_child;
334     }
335
336     TRACE("ret S_OK\n");
337     return S_OK;
338 }
339
340 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
341         IXMLDOMNode **ret)
342 {
343     xmlnode *old_child, *new_child;
344     xmlDocPtr leaving_doc;
345     xmlNode *my_ancestor;
346
347     /* Do not believe any documentation telling that newChild == NULL
348        means removal. It does certainly *not* apply to msxml3! */
349     if(!newChild || !oldChild)
350         return E_INVALIDARG;
351
352     if(ret)
353         *ret = NULL;
354
355     old_child = get_node_obj(oldChild);
356     if(!old_child) {
357         FIXME("oldChild is not our node implementation\n");
358         return E_FAIL;
359     }
360
361     if(old_child->node->parent != This->node)
362     {
363         WARN("childNode %p is not a child of %p\n", oldChild, This);
364         return E_INVALIDARG;
365     }
366
367     new_child = get_node_obj(newChild);
368     if(!new_child) {
369         FIXME("newChild is not our node implementation\n");
370         return E_FAIL;
371     }
372
373     my_ancestor = This->node;
374     while(my_ancestor)
375     {
376         if(my_ancestor == new_child->node)
377         {
378             WARN("tried to create loop\n");
379             return E_FAIL;
380         }
381         my_ancestor = my_ancestor->parent;
382     }
383
384     if(!new_child->node->parent)
385         if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
386             WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
387
388     leaving_doc = new_child->node->doc;
389     xmldoc_add_ref(old_child->node->doc);
390     xmlReplaceNode(old_child->node, new_child->node);
391     xmldoc_release(leaving_doc);
392
393     xmldoc_add_orphan(old_child->node->doc, old_child->node);
394
395     if(ret)
396     {
397         IXMLDOMNode_AddRef(oldChild);
398         *ret = oldChild;
399     }
400
401     return S_OK;
402 }
403
404 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
405 {
406     xmlnode *child_node;
407
408     if(!child) return E_INVALIDARG;
409
410     if(oldChild)
411         *oldChild = NULL;
412
413     child_node = get_node_obj(child);
414     if(!child_node) {
415         FIXME("childNode is not our node implementation\n");
416         return E_FAIL;
417     }
418
419     if(child_node->node->parent != This->node)
420     {
421         WARN("childNode %p is not a child of %p\n", child, This);
422         return E_INVALIDARG;
423     }
424
425     xmlUnlinkNode(child_node->node);
426
427     if(oldChild)
428     {
429         IXMLDOMNode_AddRef(child);
430         *oldChild = child;
431     }
432
433     return S_OK;
434 }
435
436 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
437 {
438     DOMNodeType type;
439     VARIANT var;
440     HRESULT hr;
441
442     hr = IXMLDOMNode_get_nodeType(child, &type);
443     if(FAILED(hr) || type == NODE_ATTRIBUTE) {
444         if (outChild) *outChild = NULL;
445         return E_FAIL;
446     }
447
448     VariantInit(&var);
449     return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
450 }
451
452 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
453 {
454     if (!ret) return E_INVALIDARG;
455
456     if (!This->node->children)
457     {
458         *ret = VARIANT_FALSE;
459         return S_FALSE;
460     }
461
462     *ret = VARIANT_TRUE;
463     return S_OK;
464 }
465
466 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
467 {
468     return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
469 }
470
471 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
472 {
473     IXMLDOMNode *node;
474     xmlNodePtr clone;
475
476     if(!cloneNode) return E_INVALIDARG;
477
478     clone = xmlCopyNode(This->node, deep ? 1 : 2);
479     if (clone)
480     {
481         clone->doc = This->node->doc;
482         xmldoc_add_orphan(clone->doc, clone);
483
484         node = create_node(clone);
485         if (!node)
486         {
487             ERR("Copy failed\n");
488             return E_FAIL;
489         }
490
491         *cloneNode = node;
492     }
493     else
494     {
495         ERR("Copy failed\n");
496         return E_FAIL;
497     }
498
499     return S_OK;
500 }
501
502 static inline xmlChar* trim_whitespace(xmlChar* str)
503 {
504     xmlChar* ret = str;
505     int len;
506
507     if (!str)
508         return NULL;
509
510     while (*ret && isspace(*ret))
511         ++ret;
512     len = xmlStrlen(ret);
513     if (len)
514         while (isspace(ret[len-1])) --len;
515
516     ret = xmlStrndup(ret, len);
517     xmlFree(str);
518     return ret;
519 }
520
521 static xmlChar* do_get_text(xmlNodePtr node)
522 {
523     xmlNodePtr child;
524     xmlChar* str;
525     BOOL preserving = is_preserving_whitespace(node);
526
527     if (!node->children)
528     {
529         str = xmlNodeGetContent(node);
530     }
531     else
532     {
533         xmlElementType prev_type = XML_TEXT_NODE;
534         xmlChar* tmp;
535         str = xmlStrdup(BAD_CAST "");
536         for (child = node->children; child != NULL; child = child->next)
537         {
538             switch (child->type)
539             {
540             case XML_ELEMENT_NODE:
541                 tmp = do_get_text(child);
542                 break;
543             case XML_TEXT_NODE:
544             case XML_CDATA_SECTION_NODE:
545             case XML_ENTITY_REF_NODE:
546             case XML_ENTITY_NODE:
547                 tmp = xmlNodeGetContent(child);
548                 break;
549             default:
550                 tmp = NULL;
551                 break;
552             }
553
554             if (tmp)
555             {
556                 if (*tmp)
557                 {
558                     if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
559                         str = xmlStrcat(str, BAD_CAST " ");
560                     str = xmlStrcat(str, tmp);
561                     prev_type = child->type;
562                 }
563                 xmlFree(tmp);
564             }
565         }
566     }
567
568     switch (node->type)
569     {
570     case XML_ELEMENT_NODE:
571     case XML_TEXT_NODE:
572     case XML_ENTITY_REF_NODE:
573     case XML_ENTITY_NODE:
574     case XML_DOCUMENT_NODE:
575     case XML_DOCUMENT_FRAG_NODE:
576         if (!preserving)
577             str = trim_whitespace(str);
578         break;
579     default:
580         break;
581     }
582
583     return str;
584 }
585
586 HRESULT node_get_text(const xmlnode *This, BSTR *text)
587 {
588     BSTR str = NULL;
589     xmlChar *content;
590
591     if (!text) return E_INVALIDARG;
592
593     content = do_get_text(This->node);
594     if (content)
595     {
596         str = bstr_from_xmlChar(content);
597         xmlFree(content);
598     }
599
600     /* Always return a string. */
601     if (!str) str = SysAllocStringLen( NULL, 0 );
602
603     TRACE("%p %s\n", This, debugstr_w(str) );
604     *text = str;
605  
606     return S_OK;
607 }
608
609 HRESULT node_put_text(xmlnode *This, BSTR text)
610 {
611     xmlChar *str, *str2;
612
613     TRACE("(%p)->(%s)\n", This, debugstr_w(text));
614
615     str = xmlChar_from_wchar(text);
616
617     /* Escape the string. */
618     str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
619     heap_free(str);
620
621     xmlNodeSetContent(This->node, str2);
622     xmlFree(str2);
623
624     return S_OK;
625 }
626
627 static inline BYTE hex_to_byte(xmlChar c)
628 {
629     if(c <= '9') return c-'0';
630     if(c <= 'F') return c-'A'+10;
631     return c-'a'+10;
632 }
633
634 static inline BYTE base64_to_byte(xmlChar c)
635 {
636     if(c == '+') return 62;
637     if(c == '/') return 63;
638     if(c <= '9') return c-'0'+52;
639     if(c <= 'Z') return c-'A';
640     return c-'a'+26;
641 }
642
643 /* TODO: phasing this version out */
644 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
645 {
646     if(!type || !lstrcmpiW(type, szString) ||
647             !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
648     {
649         V_VT(v) = VT_BSTR;
650         V_BSTR(v) = bstr_from_xmlChar(str);
651
652         if(!V_BSTR(v))
653             return E_OUTOFMEMORY;
654     }
655     else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
656             !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
657             !lstrcmpiW(type, szTimeTZ))
658     {
659         VARIANT src;
660         WCHAR *p, *e;
661         SYSTEMTIME st;
662         DOUBLE date = 0.0;
663
664         st.wYear = 1899;
665         st.wMonth = 12;
666         st.wDay = 30;
667         st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
668
669         V_VT(&src) = VT_BSTR;
670         V_BSTR(&src) = bstr_from_xmlChar(str);
671
672         if(!V_BSTR(&src))
673             return E_OUTOFMEMORY;
674
675         p = V_BSTR(&src);
676         e = p + SysStringLen(V_BSTR(&src));
677
678         if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
679         {
680             st.wYear = atoiW(p);
681             st.wMonth = atoiW(p+5);
682             st.wDay = atoiW(p+8);
683             p += 10;
684
685             if(*p == 'T') p++;
686         }
687
688         if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
689         {
690             st.wHour = atoiW(p);
691             st.wMinute = atoiW(p+3);
692             st.wSecond = atoiW(p+6);
693             p += 8;
694
695             if(*p == '.')
696             {
697                 p++;
698                 while(isdigitW(*p)) p++;
699             }
700         }
701
702         SystemTimeToVariantTime(&st, &date);
703         V_VT(v) = VT_DATE;
704         V_DATE(v) = date;
705
706         if(*p == '+') /* parse timezone offset (+hh:mm) */
707             V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
708         else if(*p == '-') /* parse timezone offset (-hh:mm) */
709             V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
710
711         VariantClear(&src);
712     }
713     else if(!lstrcmpiW(type, szBinHex))
714     {
715         SAFEARRAYBOUND sab;
716         int i, len;
717
718         len = xmlStrlen(str)/2;
719         sab.lLbound = 0;
720         sab.cElements = len;
721
722         V_VT(v) = (VT_ARRAY|VT_UI1);
723         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
724
725         if(!V_ARRAY(v))
726             return E_OUTOFMEMORY;
727
728         for(i=0; i<len; i++)
729             ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
730                 + hex_to_byte(str[2*i+1]);
731     }
732     else if(!lstrcmpiW(type, szBinBase64))
733     {
734         SAFEARRAYBOUND sab;
735         int i, len;
736
737         len  = xmlStrlen(str);
738         if(str[len-2] == '=') i = 2;
739         else if(str[len-1] == '=') i = 1;
740         else i = 0;
741
742         sab.lLbound = 0;
743         sab.cElements = len/4*3-i;
744
745         V_VT(v) = (VT_ARRAY|VT_UI1);
746         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
747
748         if(!V_ARRAY(v))
749             return E_OUTOFMEMORY;
750
751         for(i=0; i<len/4; i++)
752         {
753             ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
754                 + (base64_to_byte(str[4*i+1])>>4);
755             if(3*i+1 < sab.cElements)
756                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
757                     + (base64_to_byte(str[4*i+2])>>2);
758             if(3*i+2 < sab.cElements)
759                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
760                     + base64_to_byte(str[4*i+3]);
761         }
762     }
763     else
764     {
765         VARIANT src;
766         HRESULT hres;
767
768         if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
769             V_VT(v) = VT_I4;
770         else if(!lstrcmpiW(type, szFixed))
771             V_VT(v) = VT_CY;
772         else if(!lstrcmpiW(type, szBoolean))
773             V_VT(v) = VT_BOOL;
774         else if(!lstrcmpiW(type, szI1))
775             V_VT(v) = VT_I1;
776         else if(!lstrcmpiW(type, szI2))
777             V_VT(v) = VT_I2;
778         else if(!lstrcmpiW(type, szIU1))
779             V_VT(v) = VT_UI1;
780         else if(!lstrcmpiW(type, szIU2))
781             V_VT(v) = VT_UI2;
782         else if(!lstrcmpiW(type, szIU4))
783             V_VT(v) = VT_UI4;
784         else if(!lstrcmpiW(type, szR4))
785             V_VT(v) = VT_R4;
786         else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
787             V_VT(v) = VT_R8;
788         else
789         {
790             FIXME("Type handling not yet implemented\n");
791             V_VT(v) = VT_BSTR;
792         }
793
794         V_VT(&src) = VT_BSTR;
795         V_BSTR(&src) = bstr_from_xmlChar(str);
796
797         if(!V_BSTR(&src))
798             return E_OUTOFMEMORY;
799
800         hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
801                         LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
802         VariantClear(&src);
803         return hres;
804     }
805
806     return S_OK;
807 }
808
809 BSTR EnsureCorrectEOL(BSTR sInput)
810 {
811     int nNum = 0;
812     BSTR sNew;
813     int nLen;
814     int i;
815
816     nLen = SysStringLen(sInput);
817     /* Count line endings */
818     for(i=0; i < nLen; i++)
819     {
820         if(sInput[i] == '\n')
821             nNum++;
822     }
823
824     TRACE("len=%d, num=%d\n", nLen, nNum);
825
826     /* Add linefeed as needed */
827     if(nNum > 0)
828     {
829         int nPlace = 0;
830         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
831         for(i=0; i < nLen; i++)
832         {
833             if(sInput[i] == '\n')
834             {
835                 sNew[i+nPlace] = '\r';
836                 nPlace++;
837             }
838             sNew[i+nPlace] = sInput[i];
839         }
840
841         SysFreeString(sInput);
842     }
843     else
844     {
845         sNew = sInput;
846     }
847
848     TRACE("len %d\n", SysStringLen(sNew));
849
850     return sNew;
851 }
852
853 /* Removes encoding information and last character (nullbyte) */
854 static BSTR EnsureNoEncoding(BSTR sInput)
855 {
856     static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
857     BSTR sNew;
858     WCHAR *pBeg, *pEnd;
859
860     pBeg = sInput;
861     while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
862         pBeg++;
863
864     if(*pBeg == '\n')
865     {
866         SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
867         return sInput;
868     }
869     pBeg--;
870
871     pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
872     while(*pEnd != '\"') pEnd++;
873     pEnd++;
874
875     sNew = SysAllocStringLen(NULL,
876             pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
877     memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
878     memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
879
880     SysFreeString(sInput);
881     return sNew;
882 }
883
884 /*
885  * We are trying to replicate the same behaviour as msxml by converting
886  * line endings to \r\n and using indents as \t. The problem is that msxml
887  * only formats nodes that have a line ending. Using libxml we cannot
888  * reproduce behaviour exactly.
889  *
890  */
891 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
892 {
893     xmlBufferPtr xml_buf;
894     xmlNodePtr xmldecl;
895     int size;
896
897     if(!ret)
898         return E_INVALIDARG;
899
900     *ret = NULL;
901
902     xml_buf = xmlBufferCreate();
903     if(!xml_buf)
904         return E_OUTOFMEMORY;
905
906     xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
907
908     size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
909     if(size > 0) {
910         const xmlChar *buf_content;
911         BSTR content;
912
913         /* Attribute Nodes return a space in front of their name */
914         buf_content = xmlBufferContent(xml_buf);
915
916         content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
917         if(ensure_eol)
918             content = EnsureCorrectEOL(content);
919         if(ensure_no_encoding)
920             content = EnsureNoEncoding(content);
921
922         *ret = content;
923     }else {
924         *ret = SysAllocStringLen(NULL, 0);
925     }
926
927     xmlBufferFree(xml_buf);
928     xmldoc_link_xmldecl( This->node->doc, xmldecl );
929     return *ret ? S_OK : E_OUTOFMEMORY;
930 }
931
932 static HRESULT WINAPI xmlnode_transformNode(
933     IXMLDOMNode *iface,
934     IXMLDOMNode* styleSheet,
935     BSTR* xmlString)
936 {
937 #ifdef SONAME_LIBXSLT
938     xmlnode *This = impl_from_IXMLDOMNode( iface );
939     xmlnode *pStyleSheet = NULL;
940     xsltStylesheetPtr xsltSS = NULL;
941     xmlDocPtr result = NULL;
942
943     TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
944
945     if (!libxslt_handle)
946         return E_NOTIMPL;
947     if(!styleSheet || !xmlString)
948         return E_INVALIDARG;
949
950     *xmlString = NULL;
951
952     pStyleSheet = get_node_obj(styleSheet);
953     if(!pStyleSheet) {
954         FIXME("styleSheet is not our xmlnode implementation\n");
955         return E_FAIL;
956     }
957
958     xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
959     if(xsltSS)
960     {
961         result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
962         if(result)
963         {
964             const xmlChar *pContent;
965
966             if(result->type == XML_HTML_DOCUMENT_NODE)
967             {
968                 xmlOutputBufferPtr      pOutput = xmlAllocOutputBuffer(NULL);
969                 if(pOutput)
970                 {
971                     htmlDocContentDumpOutput(pOutput, result->doc, NULL);
972                     pContent = xmlBufferContent(pOutput->buffer);
973                     *xmlString = bstr_from_xmlChar(pContent);
974                     xmlOutputBufferClose(pOutput);
975                 }
976             }
977             else
978             {
979                 xmlBufferPtr pXmlBuf;
980                 int nSize;
981
982                 pXmlBuf = xmlBufferCreate();
983                 if(pXmlBuf)
984                 {
985                     nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
986                     if(nSize > 0)
987                     {
988                         pContent = xmlBufferContent(pXmlBuf);
989                         *xmlString = bstr_from_xmlChar(pContent);
990                     }
991                     xmlBufferFree(pXmlBuf);
992                 }
993             }
994             xmlFreeDoc(result);
995         }
996         /* libxslt "helpfully" frees the XML document the stylesheet was
997            generated from, too */
998         xsltSS->doc = NULL;
999         pxsltFreeStylesheet(xsltSS);
1000     }
1001
1002     if(*xmlString == NULL)
1003         *xmlString = SysAllocStringLen(NULL, 0);
1004
1005     return S_OK;
1006 #else
1007     FIXME("libxslt headers were not found at compile time\n");
1008     return E_NOTIMPL;
1009 #endif
1010 }
1011
1012 static HRESULT WINAPI xmlnode_selectNodes(
1013     IXMLDOMNode *iface,
1014     BSTR queryString,
1015     IXMLDOMNodeList** resultList)
1016 {
1017     xmlnode *This = impl_from_IXMLDOMNode( iface );
1018     xmlChar* str;
1019     HRESULT hr;
1020
1021     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1022
1023     if (!queryString || !resultList) return E_INVALIDARG;
1024
1025     str = xmlChar_from_wchar(queryString);
1026     hr = queryresult_create(This->node, str, resultList);
1027     heap_free(str);
1028
1029     return hr;
1030 }
1031
1032 static HRESULT WINAPI xmlnode_selectSingleNode(
1033     IXMLDOMNode *iface,
1034     BSTR queryString,
1035     IXMLDOMNode** resultNode)
1036 {
1037     xmlnode *This = impl_from_IXMLDOMNode( iface );
1038     IXMLDOMNodeList *list;
1039     HRESULT r;
1040
1041     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1042
1043     r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1044     if(r == S_OK)
1045     {
1046         r = IXMLDOMNodeList_nextNode(list, resultNode);
1047         IXMLDOMNodeList_Release(list);
1048     }
1049     return r;
1050 }
1051
1052 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1053 {
1054     xmlNsPtr *ns;
1055
1056     if(!namespaceURI)
1057         return E_INVALIDARG;
1058
1059     *namespaceURI = NULL;
1060
1061     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1062     {
1063         if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1064         xmlFree(ns);
1065     }
1066
1067     TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1068
1069     return *namespaceURI ? S_OK : S_FALSE;
1070 }
1071
1072 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1073 {
1074     xmlNsPtr *ns;
1075
1076     if (!prefix) return E_INVALIDARG;
1077
1078     *prefix = NULL;
1079
1080     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1081     {
1082         if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1083         xmlFree(ns);
1084     }
1085
1086     TRACE("prefix: %s\n", debugstr_w(*prefix));
1087
1088     return *prefix ? S_OK : S_FALSE;
1089 }
1090
1091 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1092 {
1093     if (!name) return E_INVALIDARG;
1094
1095     *name = bstr_from_xmlChar(This->node->name);
1096     if (!*name) return E_OUTOFMEMORY;
1097
1098     TRACE("returning %s\n", debugstr_w(*name));
1099
1100     return S_OK;
1101 }
1102
1103 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1104 {
1105     NULL,
1106     NULL,
1107     NULL,
1108     NULL,
1109     NULL,
1110     NULL,
1111     NULL,
1112     NULL,
1113     NULL,
1114     NULL,
1115     NULL,
1116     NULL,
1117     NULL,
1118     NULL,
1119     NULL,
1120     NULL,
1121     NULL,
1122     NULL,
1123     NULL,
1124     NULL,
1125     NULL,
1126     NULL,
1127     NULL,
1128     NULL,
1129     NULL,
1130     NULL,
1131     NULL,
1132     NULL,
1133     NULL,
1134     NULL,
1135     NULL,
1136     NULL,
1137     NULL,
1138     NULL,
1139     NULL,
1140     xmlnode_transformNode,
1141     xmlnode_selectNodes,
1142     xmlnode_selectSingleNode
1143 };
1144
1145 void destroy_xmlnode(xmlnode *This)
1146 {
1147     if(This->node)
1148         xmldoc_release(This->node->doc);
1149 }
1150
1151 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1152 {
1153     if(node)
1154         xmldoc_add_ref( node->doc );
1155
1156     This->IXMLDOMNode_iface.lpVtbl = &xmlnode_vtbl;
1157     This->node = node;
1158     This->iface = node_iface;
1159
1160     if(dispex_data)
1161         init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1162     else
1163         This->dispex.outer = NULL;
1164 }
1165
1166 typedef struct {
1167     xmlnode node;
1168     IXMLDOMNode IXMLDOMNode_iface;
1169     LONG ref;
1170 } unknode;
1171
1172 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1173 {
1174     return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1175 }
1176
1177 static HRESULT WINAPI unknode_QueryInterface(
1178     IXMLDOMNode *iface,
1179     REFIID riid,
1180     void** ppvObject )
1181 {
1182     unknode *This = unknode_from_IXMLDOMNode( iface );
1183
1184     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1185
1186     if (IsEqualGUID(riid, &IID_IUnknown)) {
1187         *ppvObject = iface;
1188     }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1189               IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1190         *ppvObject = &This->IXMLDOMNode_iface;
1191     }else if(node_query_interface(&This->node, riid, ppvObject)) {
1192         return *ppvObject ? S_OK : E_NOINTERFACE;
1193     }else  {
1194         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1195         *ppvObject = NULL;
1196         return E_NOINTERFACE;
1197     }
1198
1199     IUnknown_AddRef((IUnknown*)*ppvObject);
1200     return S_OK;
1201 }
1202
1203 static ULONG WINAPI unknode_AddRef(
1204     IXMLDOMNode *iface )
1205 {
1206     unknode *This = unknode_from_IXMLDOMNode( iface );
1207
1208     return InterlockedIncrement(&This->ref);
1209 }
1210
1211 static ULONG WINAPI unknode_Release(
1212     IXMLDOMNode *iface )
1213 {
1214     unknode *This = unknode_from_IXMLDOMNode( iface );
1215     LONG ref;
1216
1217     ref = InterlockedDecrement( &This->ref );
1218     if(!ref) {
1219         destroy_xmlnode(&This->node);
1220         heap_free(This);
1221     }
1222
1223     return ref;
1224 }
1225
1226 static HRESULT WINAPI unknode_GetTypeInfoCount(
1227     IXMLDOMNode *iface,
1228     UINT* pctinfo )
1229 {
1230     unknode *This = unknode_from_IXMLDOMNode( iface );
1231
1232     TRACE("(%p)->(%p)\n", This, pctinfo);
1233
1234     *pctinfo = 1;
1235
1236     return S_OK;
1237 }
1238
1239 static HRESULT WINAPI unknode_GetTypeInfo(
1240     IXMLDOMNode *iface,
1241     UINT iTInfo,
1242     LCID lcid,
1243     ITypeInfo** ppTInfo )
1244 {
1245     unknode *This = unknode_from_IXMLDOMNode( iface );
1246     HRESULT hr;
1247
1248     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1249
1250     hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1251
1252     return hr;
1253 }
1254
1255 static HRESULT WINAPI unknode_GetIDsOfNames(
1256     IXMLDOMNode *iface,
1257     REFIID riid,
1258     LPOLESTR* rgszNames,
1259     UINT cNames,
1260     LCID lcid,
1261     DISPID* rgDispId )
1262 {
1263     unknode *This = unknode_from_IXMLDOMNode( iface );
1264
1265     ITypeInfo *typeinfo;
1266     HRESULT hr;
1267
1268     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1269           lcid, rgDispId);
1270
1271     if(!rgszNames || cNames == 0 || !rgDispId)
1272         return E_INVALIDARG;
1273
1274     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1275     if(SUCCEEDED(hr))
1276     {
1277         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1278         ITypeInfo_Release(typeinfo);
1279     }
1280
1281     return hr;
1282 }
1283
1284 static HRESULT WINAPI unknode_Invoke(
1285     IXMLDOMNode *iface,
1286     DISPID dispIdMember,
1287     REFIID riid,
1288     LCID lcid,
1289     WORD wFlags,
1290     DISPPARAMS* pDispParams,
1291     VARIANT* pVarResult,
1292     EXCEPINFO* pExcepInfo,
1293     UINT* puArgErr )
1294 {
1295     unknode *This = unknode_from_IXMLDOMNode( iface );
1296     ITypeInfo *typeinfo;
1297     HRESULT hr;
1298
1299     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1300           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1301
1302     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1303     if(SUCCEEDED(hr))
1304     {
1305         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1306                 pVarResult, pExcepInfo, puArgErr);
1307         ITypeInfo_Release(typeinfo);
1308     }
1309
1310     return hr;
1311 }
1312
1313 static HRESULT WINAPI unknode_get_nodeName(
1314     IXMLDOMNode *iface,
1315     BSTR* p )
1316 {
1317     unknode *This = unknode_from_IXMLDOMNode( iface );
1318
1319     FIXME("(%p)->(%p)\n", This, p);
1320
1321     return node_get_nodeName(&This->node, p);
1322 }
1323
1324 static HRESULT WINAPI unknode_get_nodeValue(
1325     IXMLDOMNode *iface,
1326     VARIANT* value)
1327 {
1328     unknode *This = unknode_from_IXMLDOMNode( iface );
1329
1330     FIXME("(%p)->(%p)\n", This, value);
1331
1332     if(!value)
1333         return E_INVALIDARG;
1334
1335     V_VT(value) = VT_NULL;
1336     return S_FALSE;
1337 }
1338
1339 static HRESULT WINAPI unknode_put_nodeValue(
1340     IXMLDOMNode *iface,
1341     VARIANT value)
1342 {
1343     unknode *This = unknode_from_IXMLDOMNode( iface );
1344     FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1345     return E_FAIL;
1346 }
1347
1348 static HRESULT WINAPI unknode_get_nodeType(
1349     IXMLDOMNode *iface,
1350     DOMNodeType* domNodeType )
1351 {
1352     unknode *This = unknode_from_IXMLDOMNode( iface );
1353
1354     FIXME("(%p)->(%p)\n", This, domNodeType);
1355
1356     *domNodeType = This->node.node->type;
1357     return S_OK;
1358 }
1359
1360 static HRESULT WINAPI unknode_get_parentNode(
1361     IXMLDOMNode *iface,
1362     IXMLDOMNode** parent )
1363 {
1364     unknode *This = unknode_from_IXMLDOMNode( iface );
1365     FIXME("(%p)->(%p)\n", This, parent);
1366     if (!parent) return E_INVALIDARG;
1367     *parent = NULL;
1368     return S_FALSE;
1369 }
1370
1371 static HRESULT WINAPI unknode_get_childNodes(
1372     IXMLDOMNode *iface,
1373     IXMLDOMNodeList** outList)
1374 {
1375     unknode *This = unknode_from_IXMLDOMNode( iface );
1376
1377     TRACE("(%p)->(%p)\n", This, outList);
1378
1379     return node_get_child_nodes(&This->node, outList);
1380 }
1381
1382 static HRESULT WINAPI unknode_get_firstChild(
1383     IXMLDOMNode *iface,
1384     IXMLDOMNode** domNode)
1385 {
1386     unknode *This = unknode_from_IXMLDOMNode( iface );
1387
1388     TRACE("(%p)->(%p)\n", This, domNode);
1389
1390     return node_get_first_child(&This->node, domNode);
1391 }
1392
1393 static HRESULT WINAPI unknode_get_lastChild(
1394     IXMLDOMNode *iface,
1395     IXMLDOMNode** domNode)
1396 {
1397     unknode *This = unknode_from_IXMLDOMNode( iface );
1398
1399     TRACE("(%p)->(%p)\n", This, domNode);
1400
1401     return node_get_last_child(&This->node, domNode);
1402 }
1403
1404 static HRESULT WINAPI unknode_get_previousSibling(
1405     IXMLDOMNode *iface,
1406     IXMLDOMNode** domNode)
1407 {
1408     unknode *This = unknode_from_IXMLDOMNode( iface );
1409
1410     TRACE("(%p)->(%p)\n", This, domNode);
1411
1412     return node_get_previous_sibling(&This->node, domNode);
1413 }
1414
1415 static HRESULT WINAPI unknode_get_nextSibling(
1416     IXMLDOMNode *iface,
1417     IXMLDOMNode** domNode)
1418 {
1419     unknode *This = unknode_from_IXMLDOMNode( iface );
1420
1421     TRACE("(%p)->(%p)\n", This, domNode);
1422
1423     return node_get_next_sibling(&This->node, domNode);
1424 }
1425
1426 static HRESULT WINAPI unknode_get_attributes(
1427     IXMLDOMNode *iface,
1428     IXMLDOMNamedNodeMap** attributeMap)
1429 {
1430     unknode *This = unknode_from_IXMLDOMNode( iface );
1431
1432     FIXME("(%p)->(%p)\n", This, attributeMap);
1433
1434     return return_null_ptr((void**)attributeMap);
1435 }
1436
1437 static HRESULT WINAPI unknode_insertBefore(
1438     IXMLDOMNode *iface,
1439     IXMLDOMNode* newNode, VARIANT refChild,
1440     IXMLDOMNode** outOldNode)
1441 {
1442     unknode *This = unknode_from_IXMLDOMNode( iface );
1443
1444     FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1445
1446     return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1447 }
1448
1449 static HRESULT WINAPI unknode_replaceChild(
1450     IXMLDOMNode *iface,
1451     IXMLDOMNode* newNode,
1452     IXMLDOMNode* oldNode,
1453     IXMLDOMNode** outOldNode)
1454 {
1455     unknode *This = unknode_from_IXMLDOMNode( iface );
1456
1457     FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1458
1459     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1460 }
1461
1462 static HRESULT WINAPI unknode_removeChild(
1463     IXMLDOMNode *iface,
1464     IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1465 {
1466     unknode *This = unknode_from_IXMLDOMNode( iface );
1467     return node_remove_child(&This->node, domNode, oldNode);
1468 }
1469
1470 static HRESULT WINAPI unknode_appendChild(
1471     IXMLDOMNode *iface,
1472     IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1473 {
1474     unknode *This = unknode_from_IXMLDOMNode( iface );
1475     return node_append_child(&This->node, newNode, outNewNode);
1476 }
1477
1478 static HRESULT WINAPI unknode_hasChildNodes(
1479     IXMLDOMNode *iface,
1480     VARIANT_BOOL* pbool)
1481 {
1482     unknode *This = unknode_from_IXMLDOMNode( iface );
1483     return node_has_childnodes(&This->node, pbool);
1484 }
1485
1486 static HRESULT WINAPI unknode_get_ownerDocument(
1487     IXMLDOMNode *iface,
1488     IXMLDOMDocument** domDocument)
1489 {
1490     unknode *This = unknode_from_IXMLDOMNode( iface );
1491     return node_get_owner_doc(&This->node, domDocument);
1492 }
1493
1494 static HRESULT WINAPI unknode_cloneNode(
1495     IXMLDOMNode *iface,
1496     VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1497 {
1498     unknode *This = unknode_from_IXMLDOMNode( iface );
1499     return IXMLDOMNode_cloneNode( &This->node.IXMLDOMNode_iface, pbool, outNode );
1500 }
1501
1502 static HRESULT WINAPI unknode_get_nodeTypeString(
1503     IXMLDOMNode *iface,
1504     BSTR* p)
1505 {
1506     unknode *This = unknode_from_IXMLDOMNode( iface );
1507
1508     FIXME("(%p)->(%p)\n", This, p);
1509
1510     return node_get_nodeName(&This->node, p);
1511 }
1512
1513 static HRESULT WINAPI unknode_get_text(
1514     IXMLDOMNode *iface,
1515     BSTR* p)
1516 {
1517     unknode *This = unknode_from_IXMLDOMNode( iface );
1518     return node_get_text(&This->node, p);
1519 }
1520
1521 static HRESULT WINAPI unknode_put_text(
1522     IXMLDOMNode *iface,
1523     BSTR p)
1524 {
1525     unknode *This = unknode_from_IXMLDOMNode( iface );
1526     return IXMLDOMNode_put_text( &This->node.IXMLDOMNode_iface, p );
1527 }
1528
1529 static HRESULT WINAPI unknode_get_specified(
1530     IXMLDOMNode *iface,
1531     VARIANT_BOOL* isSpecified)
1532 {
1533     unknode *This = unknode_from_IXMLDOMNode( iface );
1534     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1535     *isSpecified = VARIANT_TRUE;
1536     return S_OK;
1537 }
1538
1539 static HRESULT WINAPI unknode_get_definition(
1540     IXMLDOMNode *iface,
1541     IXMLDOMNode** definitionNode)
1542 {
1543     unknode *This = unknode_from_IXMLDOMNode( iface );
1544     FIXME("(%p)->(%p)\n", This, definitionNode);
1545     return E_NOTIMPL;
1546 }
1547
1548 static HRESULT WINAPI unknode_get_nodeTypedValue(
1549     IXMLDOMNode *iface,
1550     VARIANT* var1)
1551 {
1552     unknode *This = unknode_from_IXMLDOMNode( iface );
1553     FIXME("(%p)->(%p)\n", This, var1);
1554     return return_null_var(var1);
1555 }
1556
1557 static HRESULT WINAPI unknode_put_nodeTypedValue(
1558     IXMLDOMNode *iface,
1559     VARIANT typedValue)
1560 {
1561     unknode *This = unknode_from_IXMLDOMNode( iface );
1562     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1563     return E_NOTIMPL;
1564 }
1565
1566 static HRESULT WINAPI unknode_get_dataType(
1567     IXMLDOMNode *iface,
1568     VARIANT* var1)
1569 {
1570     unknode *This = unknode_from_IXMLDOMNode( iface );
1571     return IXMLDOMNode_get_dataType( &This->node.IXMLDOMNode_iface, var1 );
1572 }
1573
1574 static HRESULT WINAPI unknode_put_dataType(
1575     IXMLDOMNode *iface,
1576     BSTR p)
1577 {
1578     unknode *This = unknode_from_IXMLDOMNode( iface );
1579
1580     FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1581
1582     if(!p)
1583         return E_INVALIDARG;
1584
1585     return E_FAIL;
1586 }
1587
1588 static HRESULT WINAPI unknode_get_xml(
1589     IXMLDOMNode *iface,
1590     BSTR* p)
1591 {
1592     unknode *This = unknode_from_IXMLDOMNode( iface );
1593
1594     FIXME("(%p)->(%p)\n", This, p);
1595
1596     return node_get_xml(&This->node, FALSE, FALSE, p);
1597 }
1598
1599 static HRESULT WINAPI unknode_transformNode(
1600     IXMLDOMNode *iface,
1601     IXMLDOMNode* domNode, BSTR* p)
1602 {
1603     unknode *This = unknode_from_IXMLDOMNode( iface );
1604     return IXMLDOMNode_transformNode( &This->node.IXMLDOMNode_iface, domNode, p );
1605 }
1606
1607 static HRESULT WINAPI unknode_selectNodes(
1608     IXMLDOMNode *iface,
1609     BSTR p, IXMLDOMNodeList** outList)
1610 {
1611     unknode *This = unknode_from_IXMLDOMNode( iface );
1612     return IXMLDOMNode_selectNodes( &This->node.IXMLDOMNode_iface, p, outList );
1613 }
1614
1615 static HRESULT WINAPI unknode_selectSingleNode(
1616     IXMLDOMNode *iface,
1617     BSTR p, IXMLDOMNode** outNode)
1618 {
1619     unknode *This = unknode_from_IXMLDOMNode( iface );
1620     return IXMLDOMNode_selectSingleNode( &This->node.IXMLDOMNode_iface, p, outNode );
1621 }
1622
1623 static HRESULT WINAPI unknode_get_parsed(
1624     IXMLDOMNode *iface,
1625     VARIANT_BOOL* isParsed)
1626 {
1627     unknode *This = unknode_from_IXMLDOMNode( iface );
1628     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1629     *isParsed = VARIANT_TRUE;
1630     return S_OK;
1631 }
1632
1633 static HRESULT WINAPI unknode_get_namespaceURI(
1634     IXMLDOMNode *iface,
1635     BSTR* p)
1636 {
1637     unknode *This = unknode_from_IXMLDOMNode( iface );
1638     TRACE("(%p)->(%p)\n", This, p);
1639     return node_get_namespaceURI(&This->node, p);
1640 }
1641
1642 static HRESULT WINAPI unknode_get_prefix(
1643     IXMLDOMNode *iface,
1644     BSTR* p)
1645 {
1646     unknode *This = unknode_from_IXMLDOMNode( iface );
1647     return IXMLDOMNode_get_prefix( &This->node.IXMLDOMNode_iface, p );
1648 }
1649
1650 static HRESULT WINAPI unknode_get_baseName(
1651     IXMLDOMNode *iface,
1652     BSTR* p)
1653 {
1654     unknode *This = unknode_from_IXMLDOMNode( iface );
1655     return IXMLDOMNode_get_baseName( &This->node.IXMLDOMNode_iface, p );
1656 }
1657
1658 static HRESULT WINAPI unknode_transformNodeToObject(
1659     IXMLDOMNode *iface,
1660     IXMLDOMNode* domNode, VARIANT var1)
1661 {
1662     unknode *This = unknode_from_IXMLDOMNode( iface );
1663     FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1664     return E_NOTIMPL;
1665 }
1666
1667 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1668 {
1669     unknode_QueryInterface,
1670     unknode_AddRef,
1671     unknode_Release,
1672     unknode_GetTypeInfoCount,
1673     unknode_GetTypeInfo,
1674     unknode_GetIDsOfNames,
1675     unknode_Invoke,
1676     unknode_get_nodeName,
1677     unknode_get_nodeValue,
1678     unknode_put_nodeValue,
1679     unknode_get_nodeType,
1680     unknode_get_parentNode,
1681     unknode_get_childNodes,
1682     unknode_get_firstChild,
1683     unknode_get_lastChild,
1684     unknode_get_previousSibling,
1685     unknode_get_nextSibling,
1686     unknode_get_attributes,
1687     unknode_insertBefore,
1688     unknode_replaceChild,
1689     unknode_removeChild,
1690     unknode_appendChild,
1691     unknode_hasChildNodes,
1692     unknode_get_ownerDocument,
1693     unknode_cloneNode,
1694     unknode_get_nodeTypeString,
1695     unknode_get_text,
1696     unknode_put_text,
1697     unknode_get_specified,
1698     unknode_get_definition,
1699     unknode_get_nodeTypedValue,
1700     unknode_put_nodeTypedValue,
1701     unknode_get_dataType,
1702     unknode_put_dataType,
1703     unknode_get_xml,
1704     unknode_transformNode,
1705     unknode_selectNodes,
1706     unknode_selectSingleNode,
1707     unknode_get_parsed,
1708     unknode_get_namespaceURI,
1709     unknode_get_prefix,
1710     unknode_get_baseName,
1711     unknode_transformNodeToObject
1712 };
1713
1714 IXMLDOMNode *create_node( xmlNodePtr node )
1715 {
1716     IUnknown *pUnk;
1717     IXMLDOMNode *ret;
1718     HRESULT hr;
1719
1720     if ( !node )
1721         return NULL;
1722
1723     TRACE("type %d\n", node->type);
1724     switch(node->type)
1725     {
1726     case XML_ELEMENT_NODE:
1727         pUnk = create_element( node );
1728         break;
1729     case XML_ATTRIBUTE_NODE:
1730         pUnk = create_attribute( node );
1731         break;
1732     case XML_TEXT_NODE:
1733         pUnk = create_text( node );
1734         break;
1735     case XML_CDATA_SECTION_NODE:
1736         pUnk = create_cdata( node );
1737         break;
1738     case XML_ENTITY_REF_NODE:
1739         pUnk = create_doc_entity_ref( node );
1740         break;
1741     case XML_PI_NODE:
1742         pUnk = create_pi( node );
1743         break;
1744     case XML_COMMENT_NODE:
1745         pUnk = create_comment( node );
1746         break;
1747     case XML_DOCUMENT_NODE:
1748         pUnk = create_domdoc( node );
1749         break;
1750     case XML_DOCUMENT_FRAG_NODE:
1751         pUnk = create_doc_fragment( node );
1752         break;
1753     case XML_DTD_NODE:
1754         pUnk = create_doc_type( node );
1755         break;
1756     default: {
1757         unknode *new_node;
1758
1759         FIXME("only creating basic node for type %d\n", node->type);
1760
1761         new_node = heap_alloc(sizeof(unknode));
1762         if(!new_node)
1763             return NULL;
1764
1765         new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1766         new_node->ref = 1;
1767         init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1768         pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1769     }
1770     }
1771
1772     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1773     IUnknown_Release(pUnk);
1774     if(FAILED(hr)) return NULL;
1775     return ret;
1776 }
1777 #endif