msi/tests: Test a return value (clang).
[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 static HRESULT WINAPI xmlnode_removeChild(
405     IXMLDOMNode *iface,
406     IXMLDOMNode* childNode,
407     IXMLDOMNode** oldChild)
408 {
409     xmlnode *This = impl_from_IXMLDOMNode( iface );
410     xmlnode *child_node;
411
412     TRACE("(%p)->(%p %p)\n", This, childNode, oldChild);
413
414     if(!childNode) return E_INVALIDARG;
415
416     if(oldChild)
417         *oldChild = NULL;
418
419     child_node = get_node_obj(childNode);
420     if(!child_node) {
421         FIXME("childNode is not our node implementation\n");
422         return E_FAIL;
423     }
424
425     if(child_node->node->parent != This->node)
426     {
427         WARN("childNode %p is not a child of %p\n", childNode, iface);
428         return E_INVALIDARG;
429     }
430
431     xmlUnlinkNode(child_node->node);
432
433     if(oldChild)
434     {
435         IXMLDOMNode_AddRef(childNode);
436         *oldChild = childNode;
437     }
438
439     return S_OK;
440 }
441
442 static HRESULT WINAPI xmlnode_appendChild(
443     IXMLDOMNode *iface,
444     IXMLDOMNode* newChild,
445     IXMLDOMNode** outNewChild)
446 {
447     xmlnode *This = impl_from_IXMLDOMNode( iface );
448     DOMNodeType type;
449     VARIANT var;
450     HRESULT hr;
451
452     TRACE("(%p)->(%p %p)\n", This, newChild, outNewChild);
453
454     hr = IXMLDOMNode_get_nodeType(newChild, &type);
455     if(FAILED(hr) || type == NODE_ATTRIBUTE) {
456         if(outNewChild) *outNewChild = NULL;
457         return E_FAIL;
458     }
459
460     VariantInit(&var);
461     return IXMLDOMNode_insertBefore(This->iface, newChild, var, outNewChild);
462 }
463
464 static HRESULT WINAPI xmlnode_hasChildNodes(
465     IXMLDOMNode *iface,
466     VARIANT_BOOL* hasChild)
467 {
468     xmlnode *This = impl_from_IXMLDOMNode( iface );
469
470     TRACE("(%p)->(%p)\n", This, hasChild);
471
472     if (!hasChild)
473         return E_INVALIDARG;
474     if (!This->node->children)
475     {
476         *hasChild = VARIANT_FALSE;
477         return S_FALSE;
478     }
479
480     *hasChild = VARIANT_TRUE;
481     return S_OK;
482 }
483
484 static HRESULT WINAPI xmlnode_get_ownerDocument(
485     IXMLDOMNode *iface,
486     IXMLDOMDocument** DOMDocument)
487 {
488     xmlnode *This = impl_from_IXMLDOMNode( iface );
489
490     TRACE("(%p)->(%p)\n", This, DOMDocument);
491
492     return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)DOMDocument);
493 }
494
495 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
496 {
497     IXMLDOMNode *node;
498     xmlNodePtr clone;
499
500     if(!cloneNode) return E_INVALIDARG;
501
502     clone = xmlCopyNode(This->node, deep ? 1 : 2);
503     if (clone)
504     {
505         clone->doc = This->node->doc;
506         xmldoc_add_orphan(clone->doc, clone);
507
508         node = create_node(clone);
509         if (!node)
510         {
511             ERR("Copy failed\n");
512             return E_FAIL;
513         }
514
515         *cloneNode = node;
516     }
517     else
518     {
519         ERR("Copy failed\n");
520         return E_FAIL;
521     }
522
523     return S_OK;
524 }
525
526 static inline xmlChar* trim_whitespace(xmlChar* str)
527 {
528     xmlChar* ret = str;
529     int len;
530
531     if (!str)
532         return NULL;
533
534     while (*ret && isspace(*ret))
535         ++ret;
536     len = xmlStrlen(ret);
537     if (len)
538         while (isspace(ret[len-1])) --len;
539
540     ret = xmlStrndup(ret, len);
541     xmlFree(str);
542     return ret;
543 }
544
545 static xmlChar* do_get_text(xmlNodePtr node)
546 {
547     xmlNodePtr child;
548     xmlChar* str;
549     BOOL preserving = is_preserving_whitespace(node);
550
551     if (!node->children)
552     {
553         str = xmlNodeGetContent(node);
554     }
555     else
556     {
557         xmlElementType prev_type = XML_TEXT_NODE;
558         xmlChar* tmp;
559         str = xmlStrdup(BAD_CAST "");
560         for (child = node->children; child != NULL; child = child->next)
561         {
562             switch (child->type)
563             {
564             case XML_ELEMENT_NODE:
565                 tmp = do_get_text(child);
566                 break;
567             case XML_TEXT_NODE:
568             case XML_CDATA_SECTION_NODE:
569             case XML_ENTITY_REF_NODE:
570             case XML_ENTITY_NODE:
571                 tmp = xmlNodeGetContent(child);
572                 break;
573             default:
574                 tmp = NULL;
575                 break;
576             }
577
578             if (tmp)
579             {
580                 if (*tmp)
581                 {
582                     if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
583                         str = xmlStrcat(str, BAD_CAST " ");
584                     str = xmlStrcat(str, tmp);
585                     prev_type = child->type;
586                 }
587                 xmlFree(tmp);
588             }
589         }
590     }
591
592     switch (node->type)
593     {
594     case XML_ELEMENT_NODE:
595     case XML_TEXT_NODE:
596     case XML_ENTITY_REF_NODE:
597     case XML_ENTITY_NODE:
598     case XML_DOCUMENT_NODE:
599     case XML_DOCUMENT_FRAG_NODE:
600         if (!preserving)
601             str = trim_whitespace(str);
602         break;
603     default:
604         break;
605     }
606
607     return str;
608 }
609
610 static HRESULT WINAPI xmlnode_get_text(
611     IXMLDOMNode *iface,
612     BSTR* text)
613 {
614     xmlnode *This = impl_from_IXMLDOMNode( iface );
615     BSTR str = NULL;
616     xmlChar *pContent;
617
618     TRACE("(%p, type %d)->(%p)\n", This, This->node->type, text);
619
620     if ( !text )
621         return E_INVALIDARG;
622
623     pContent = do_get_text((xmlNodePtr)This->node);
624     if(pContent)
625     {
626         str = bstr_from_xmlChar(pContent);
627         xmlFree(pContent);
628     }
629
630     /* Always return a string. */
631     if (!str) str = SysAllocStringLen( NULL, 0 );
632
633     TRACE("%p %s\n", This, debugstr_w(str) );
634     *text = str;
635  
636     return S_OK;
637 }
638
639 HRESULT node_put_text(xmlnode *This, BSTR text)
640 {
641     xmlChar *str, *str2;
642
643     TRACE("(%p)->(%s)\n", This, debugstr_w(text));
644
645     str = xmlChar_from_wchar(text);
646
647     /* Escape the string. */
648     str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
649     heap_free(str);
650
651     xmlNodeSetContent(This->node, str2);
652     xmlFree(str2);
653
654     return S_OK;
655 }
656
657 static inline BYTE hex_to_byte(xmlChar c)
658 {
659     if(c <= '9') return c-'0';
660     if(c <= 'F') return c-'A'+10;
661     return c-'a'+10;
662 }
663
664 static inline BYTE base64_to_byte(xmlChar c)
665 {
666     if(c == '+') return 62;
667     if(c == '/') return 63;
668     if(c <= '9') return c-'0'+52;
669     if(c <= 'Z') return c-'A';
670     return c-'a'+26;
671 }
672
673 /* TODO: phasing this version out */
674 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
675 {
676     if(!type || !lstrcmpiW(type, szString) ||
677             !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
678     {
679         V_VT(v) = VT_BSTR;
680         V_BSTR(v) = bstr_from_xmlChar(str);
681
682         if(!V_BSTR(v))
683             return E_OUTOFMEMORY;
684     }
685     else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
686             !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
687             !lstrcmpiW(type, szTimeTZ))
688     {
689         VARIANT src;
690         WCHAR *p, *e;
691         SYSTEMTIME st;
692         DOUBLE date = 0.0;
693
694         st.wYear = 1899;
695         st.wMonth = 12;
696         st.wDay = 30;
697         st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
698
699         V_VT(&src) = VT_BSTR;
700         V_BSTR(&src) = bstr_from_xmlChar(str);
701
702         if(!V_BSTR(&src))
703             return E_OUTOFMEMORY;
704
705         p = V_BSTR(&src);
706         e = p + SysStringLen(V_BSTR(&src));
707
708         if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
709         {
710             st.wYear = atoiW(p);
711             st.wMonth = atoiW(p+5);
712             st.wDay = atoiW(p+8);
713             p += 10;
714
715             if(*p == 'T') p++;
716         }
717
718         if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
719         {
720             st.wHour = atoiW(p);
721             st.wMinute = atoiW(p+3);
722             st.wSecond = atoiW(p+6);
723             p += 8;
724
725             if(*p == '.')
726             {
727                 p++;
728                 while(isdigitW(*p)) p++;
729             }
730         }
731
732         SystemTimeToVariantTime(&st, &date);
733         V_VT(v) = VT_DATE;
734         V_DATE(v) = date;
735
736         if(*p == '+') /* parse timezone offset (+hh:mm) */
737             V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
738         else if(*p == '-') /* parse timezone offset (-hh:mm) */
739             V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
740
741         VariantClear(&src);
742     }
743     else if(!lstrcmpiW(type, szBinHex))
744     {
745         SAFEARRAYBOUND sab;
746         int i, len;
747
748         len = xmlStrlen(str)/2;
749         sab.lLbound = 0;
750         sab.cElements = len;
751
752         V_VT(v) = (VT_ARRAY|VT_UI1);
753         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
754
755         if(!V_ARRAY(v))
756             return E_OUTOFMEMORY;
757
758         for(i=0; i<len; i++)
759             ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
760                 + hex_to_byte(str[2*i+1]);
761     }
762     else if(!lstrcmpiW(type, szBinBase64))
763     {
764         SAFEARRAYBOUND sab;
765         int i, len;
766
767         len  = xmlStrlen(str);
768         if(str[len-2] == '=') i = 2;
769         else if(str[len-1] == '=') i = 1;
770         else i = 0;
771
772         sab.lLbound = 0;
773         sab.cElements = len/4*3-i;
774
775         V_VT(v) = (VT_ARRAY|VT_UI1);
776         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
777
778         if(!V_ARRAY(v))
779             return E_OUTOFMEMORY;
780
781         for(i=0; i<len/4; i++)
782         {
783             ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
784                 + (base64_to_byte(str[4*i+1])>>4);
785             if(3*i+1 < sab.cElements)
786                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
787                     + (base64_to_byte(str[4*i+2])>>2);
788             if(3*i+2 < sab.cElements)
789                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
790                     + base64_to_byte(str[4*i+3]);
791         }
792     }
793     else
794     {
795         VARIANT src;
796         HRESULT hres;
797
798         if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
799             V_VT(v) = VT_I4;
800         else if(!lstrcmpiW(type, szFixed))
801             V_VT(v) = VT_CY;
802         else if(!lstrcmpiW(type, szBoolean))
803             V_VT(v) = VT_BOOL;
804         else if(!lstrcmpiW(type, szI1))
805             V_VT(v) = VT_I1;
806         else if(!lstrcmpiW(type, szI2))
807             V_VT(v) = VT_I2;
808         else if(!lstrcmpiW(type, szIU1))
809             V_VT(v) = VT_UI1;
810         else if(!lstrcmpiW(type, szIU2))
811             V_VT(v) = VT_UI2;
812         else if(!lstrcmpiW(type, szIU4))
813             V_VT(v) = VT_UI4;
814         else if(!lstrcmpiW(type, szR4))
815             V_VT(v) = VT_R4;
816         else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
817             V_VT(v) = VT_R8;
818         else
819         {
820             FIXME("Type handling not yet implemented\n");
821             V_VT(v) = VT_BSTR;
822         }
823
824         V_VT(&src) = VT_BSTR;
825         V_BSTR(&src) = bstr_from_xmlChar(str);
826
827         if(!V_BSTR(&src))
828             return E_OUTOFMEMORY;
829
830         hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
831                         LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
832         VariantClear(&src);
833         return hres;
834     }
835
836     return S_OK;
837 }
838
839 BSTR EnsureCorrectEOL(BSTR sInput)
840 {
841     int nNum = 0;
842     BSTR sNew;
843     int nLen;
844     int i;
845
846     nLen = SysStringLen(sInput);
847     /* Count line endings */
848     for(i=0; i < nLen; i++)
849     {
850         if(sInput[i] == '\n')
851             nNum++;
852     }
853
854     TRACE("len=%d, num=%d\n", nLen, nNum);
855
856     /* Add linefeed as needed */
857     if(nNum > 0)
858     {
859         int nPlace = 0;
860         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
861         for(i=0; i < nLen; i++)
862         {
863             if(sInput[i] == '\n')
864             {
865                 sNew[i+nPlace] = '\r';
866                 nPlace++;
867             }
868             sNew[i+nPlace] = sInput[i];
869         }
870
871         SysFreeString(sInput);
872     }
873     else
874     {
875         sNew = sInput;
876     }
877
878     TRACE("len %d\n", SysStringLen(sNew));
879
880     return sNew;
881 }
882
883 /* Removes encoding information and last character (nullbyte) */
884 static BSTR EnsureNoEncoding(BSTR sInput)
885 {
886     static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
887     BSTR sNew;
888     WCHAR *pBeg, *pEnd;
889
890     pBeg = sInput;
891     while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
892         pBeg++;
893
894     if(*pBeg == '\n')
895     {
896         SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
897         return sInput;
898     }
899     pBeg--;
900
901     pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
902     while(*pEnd != '\"') pEnd++;
903     pEnd++;
904
905     sNew = SysAllocStringLen(NULL,
906             pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
907     memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
908     memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
909
910     SysFreeString(sInput);
911     return sNew;
912 }
913
914 /*
915  * We are trying to replicate the same behaviour as msxml by converting
916  * line endings to \r\n and using indents as \t. The problem is that msxml
917  * only formats nodes that have a line ending. Using libxml we cannot
918  * reproduce behaviour exactly.
919  *
920  */
921 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
922 {
923     xmlBufferPtr xml_buf;
924     xmlNodePtr xmldecl;
925     int size;
926
927     if(!ret)
928         return E_INVALIDARG;
929
930     *ret = NULL;
931
932     xml_buf = xmlBufferCreate();
933     if(!xml_buf)
934         return E_OUTOFMEMORY;
935
936     xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
937
938     size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
939     if(size > 0) {
940         const xmlChar *buf_content;
941         BSTR content;
942
943         /* Attribute Nodes return a space in front of their name */
944         buf_content = xmlBufferContent(xml_buf);
945
946         content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
947         if(ensure_eol)
948             content = EnsureCorrectEOL(content);
949         if(ensure_no_encoding)
950             content = EnsureNoEncoding(content);
951
952         *ret = content;
953     }else {
954         *ret = SysAllocStringLen(NULL, 0);
955     }
956
957     xmlBufferFree(xml_buf);
958     xmldoc_link_xmldecl( This->node->doc, xmldecl );
959     return *ret ? S_OK : E_OUTOFMEMORY;
960 }
961
962 static HRESULT WINAPI xmlnode_transformNode(
963     IXMLDOMNode *iface,
964     IXMLDOMNode* styleSheet,
965     BSTR* xmlString)
966 {
967 #ifdef SONAME_LIBXSLT
968     xmlnode *This = impl_from_IXMLDOMNode( iface );
969     xmlnode *pStyleSheet = NULL;
970     xsltStylesheetPtr xsltSS = NULL;
971     xmlDocPtr result = NULL;
972
973     TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
974
975     if (!libxslt_handle)
976         return E_NOTIMPL;
977     if(!styleSheet || !xmlString)
978         return E_INVALIDARG;
979
980     *xmlString = NULL;
981
982     pStyleSheet = get_node_obj(styleSheet);
983     if(!pStyleSheet) {
984         FIXME("styleSheet is not our xmlnode implementation\n");
985         return E_FAIL;
986     }
987
988     xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
989     if(xsltSS)
990     {
991         result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
992         if(result)
993         {
994             const xmlChar *pContent;
995
996             if(result->type == XML_HTML_DOCUMENT_NODE)
997             {
998                 xmlOutputBufferPtr      pOutput = xmlAllocOutputBuffer(NULL);
999                 if(pOutput)
1000                 {
1001                     htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1002                     pContent = xmlBufferContent(pOutput->buffer);
1003                     *xmlString = bstr_from_xmlChar(pContent);
1004                     xmlOutputBufferClose(pOutput);
1005                 }
1006             }
1007             else
1008             {
1009                 xmlBufferPtr pXmlBuf;
1010                 int nSize;
1011
1012                 pXmlBuf = xmlBufferCreate();
1013                 if(pXmlBuf)
1014                 {
1015                     nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1016                     if(nSize > 0)
1017                     {
1018                         pContent = xmlBufferContent(pXmlBuf);
1019                         *xmlString = bstr_from_xmlChar(pContent);
1020                     }
1021                     xmlBufferFree(pXmlBuf);
1022                 }
1023             }
1024             xmlFreeDoc(result);
1025         }
1026         /* libxslt "helpfully" frees the XML document the stylesheet was
1027            generated from, too */
1028         xsltSS->doc = NULL;
1029         pxsltFreeStylesheet(xsltSS);
1030     }
1031
1032     if(*xmlString == NULL)
1033         *xmlString = SysAllocStringLen(NULL, 0);
1034
1035     return S_OK;
1036 #else
1037     FIXME("libxslt headers were not found at compile time\n");
1038     return E_NOTIMPL;
1039 #endif
1040 }
1041
1042 static HRESULT WINAPI xmlnode_selectNodes(
1043     IXMLDOMNode *iface,
1044     BSTR queryString,
1045     IXMLDOMNodeList** resultList)
1046 {
1047     xmlnode *This = impl_from_IXMLDOMNode( iface );
1048     xmlChar* str;
1049     HRESULT hr;
1050
1051     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1052
1053     if (!queryString || !resultList) return E_INVALIDARG;
1054
1055     str = xmlChar_from_wchar(queryString);
1056     hr = queryresult_create(This->node, str, resultList);
1057     heap_free(str);
1058
1059     return hr;
1060 }
1061
1062 static HRESULT WINAPI xmlnode_selectSingleNode(
1063     IXMLDOMNode *iface,
1064     BSTR queryString,
1065     IXMLDOMNode** resultNode)
1066 {
1067     xmlnode *This = impl_from_IXMLDOMNode( iface );
1068     IXMLDOMNodeList *list;
1069     HRESULT r;
1070
1071     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1072
1073     r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1074     if(r == S_OK)
1075     {
1076         r = IXMLDOMNodeList_nextNode(list, resultNode);
1077         IXMLDOMNodeList_Release(list);
1078     }
1079     return r;
1080 }
1081
1082 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1083 {
1084     xmlNsPtr *ns;
1085
1086     if(!namespaceURI)
1087         return E_INVALIDARG;
1088
1089     *namespaceURI = NULL;
1090
1091     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1092     {
1093         if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1094         xmlFree(ns);
1095     }
1096
1097     TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1098
1099     return *namespaceURI ? S_OK : S_FALSE;
1100 }
1101
1102 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1103 {
1104     xmlNsPtr *ns;
1105
1106     if (!prefix) return E_INVALIDARG;
1107
1108     *prefix = NULL;
1109
1110     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1111     {
1112         if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1113         xmlFree(ns);
1114     }
1115
1116     TRACE("prefix: %s\n", debugstr_w(*prefix));
1117
1118     return *prefix ? S_OK : S_FALSE;
1119 }
1120
1121 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1122 {
1123     if (!name) return E_INVALIDARG;
1124
1125     *name = bstr_from_xmlChar(This->node->name);
1126     if (!*name) return E_OUTOFMEMORY;
1127
1128     TRACE("returning %s\n", debugstr_w(*name));
1129
1130     return S_OK;
1131 }
1132
1133 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1134 {
1135     NULL,
1136     NULL,
1137     NULL,
1138     NULL,
1139     NULL,
1140     NULL,
1141     NULL,
1142     NULL,
1143     NULL,
1144     NULL,
1145     NULL,
1146     NULL,
1147     NULL,
1148     NULL,
1149     NULL,
1150     NULL,
1151     NULL,
1152     NULL,
1153     NULL,
1154     NULL,
1155     xmlnode_removeChild,
1156     xmlnode_appendChild,
1157     xmlnode_hasChildNodes,
1158     xmlnode_get_ownerDocument,
1159     NULL,
1160     NULL,
1161     xmlnode_get_text,
1162     NULL,
1163     NULL,
1164     NULL,
1165     NULL,
1166     NULL,
1167     NULL,
1168     NULL,
1169     NULL,
1170     xmlnode_transformNode,
1171     xmlnode_selectNodes,
1172     xmlnode_selectSingleNode
1173 };
1174
1175 void destroy_xmlnode(xmlnode *This)
1176 {
1177     if(This->node)
1178         xmldoc_release(This->node->doc);
1179 }
1180
1181 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1182 {
1183     if(node)
1184         xmldoc_add_ref( node->doc );
1185
1186     This->IXMLDOMNode_iface.lpVtbl = &xmlnode_vtbl;
1187     This->node = node;
1188     This->iface = node_iface;
1189
1190     if(dispex_data)
1191         init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1192     else
1193         This->dispex.outer = NULL;
1194 }
1195
1196 typedef struct {
1197     xmlnode node;
1198     IXMLDOMNode IXMLDOMNode_iface;
1199     LONG ref;
1200 } unknode;
1201
1202 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1203 {
1204     return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1205 }
1206
1207 static HRESULT WINAPI unknode_QueryInterface(
1208     IXMLDOMNode *iface,
1209     REFIID riid,
1210     void** ppvObject )
1211 {
1212     unknode *This = unknode_from_IXMLDOMNode( iface );
1213
1214     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1215
1216     if (IsEqualGUID(riid, &IID_IUnknown)) {
1217         *ppvObject = iface;
1218     }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1219               IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1220         *ppvObject = &This->IXMLDOMNode_iface;
1221     }else if(node_query_interface(&This->node, riid, ppvObject)) {
1222         return *ppvObject ? S_OK : E_NOINTERFACE;
1223     }else  {
1224         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1225         *ppvObject = NULL;
1226         return E_NOINTERFACE;
1227     }
1228
1229     IUnknown_AddRef((IUnknown*)*ppvObject);
1230     return S_OK;
1231 }
1232
1233 static ULONG WINAPI unknode_AddRef(
1234     IXMLDOMNode *iface )
1235 {
1236     unknode *This = unknode_from_IXMLDOMNode( iface );
1237
1238     return InterlockedIncrement(&This->ref);
1239 }
1240
1241 static ULONG WINAPI unknode_Release(
1242     IXMLDOMNode *iface )
1243 {
1244     unknode *This = unknode_from_IXMLDOMNode( iface );
1245     LONG ref;
1246
1247     ref = InterlockedDecrement( &This->ref );
1248     if(!ref) {
1249         destroy_xmlnode(&This->node);
1250         heap_free(This);
1251     }
1252
1253     return ref;
1254 }
1255
1256 static HRESULT WINAPI unknode_GetTypeInfoCount(
1257     IXMLDOMNode *iface,
1258     UINT* pctinfo )
1259 {
1260     unknode *This = unknode_from_IXMLDOMNode( iface );
1261
1262     TRACE("(%p)->(%p)\n", This, pctinfo);
1263
1264     *pctinfo = 1;
1265
1266     return S_OK;
1267 }
1268
1269 static HRESULT WINAPI unknode_GetTypeInfo(
1270     IXMLDOMNode *iface,
1271     UINT iTInfo,
1272     LCID lcid,
1273     ITypeInfo** ppTInfo )
1274 {
1275     unknode *This = unknode_from_IXMLDOMNode( iface );
1276     HRESULT hr;
1277
1278     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1279
1280     hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1281
1282     return hr;
1283 }
1284
1285 static HRESULT WINAPI unknode_GetIDsOfNames(
1286     IXMLDOMNode *iface,
1287     REFIID riid,
1288     LPOLESTR* rgszNames,
1289     UINT cNames,
1290     LCID lcid,
1291     DISPID* rgDispId )
1292 {
1293     unknode *This = unknode_from_IXMLDOMNode( iface );
1294
1295     ITypeInfo *typeinfo;
1296     HRESULT hr;
1297
1298     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1299           lcid, rgDispId);
1300
1301     if(!rgszNames || cNames == 0 || !rgDispId)
1302         return E_INVALIDARG;
1303
1304     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1305     if(SUCCEEDED(hr))
1306     {
1307         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1308         ITypeInfo_Release(typeinfo);
1309     }
1310
1311     return hr;
1312 }
1313
1314 static HRESULT WINAPI unknode_Invoke(
1315     IXMLDOMNode *iface,
1316     DISPID dispIdMember,
1317     REFIID riid,
1318     LCID lcid,
1319     WORD wFlags,
1320     DISPPARAMS* pDispParams,
1321     VARIANT* pVarResult,
1322     EXCEPINFO* pExcepInfo,
1323     UINT* puArgErr )
1324 {
1325     unknode *This = unknode_from_IXMLDOMNode( iface );
1326     ITypeInfo *typeinfo;
1327     HRESULT hr;
1328
1329     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1330           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1331
1332     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1333     if(SUCCEEDED(hr))
1334     {
1335         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1336                 pVarResult, pExcepInfo, puArgErr);
1337         ITypeInfo_Release(typeinfo);
1338     }
1339
1340     return hr;
1341 }
1342
1343 static HRESULT WINAPI unknode_get_nodeName(
1344     IXMLDOMNode *iface,
1345     BSTR* p )
1346 {
1347     unknode *This = unknode_from_IXMLDOMNode( iface );
1348
1349     FIXME("(%p)->(%p)\n", This, p);
1350
1351     return node_get_nodeName(&This->node, p);
1352 }
1353
1354 static HRESULT WINAPI unknode_get_nodeValue(
1355     IXMLDOMNode *iface,
1356     VARIANT* value)
1357 {
1358     unknode *This = unknode_from_IXMLDOMNode( iface );
1359
1360     FIXME("(%p)->(%p)\n", This, value);
1361
1362     if(!value)
1363         return E_INVALIDARG;
1364
1365     V_VT(value) = VT_NULL;
1366     return S_FALSE;
1367 }
1368
1369 static HRESULT WINAPI unknode_put_nodeValue(
1370     IXMLDOMNode *iface,
1371     VARIANT value)
1372 {
1373     unknode *This = unknode_from_IXMLDOMNode( iface );
1374     FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1375     return E_FAIL;
1376 }
1377
1378 static HRESULT WINAPI unknode_get_nodeType(
1379     IXMLDOMNode *iface,
1380     DOMNodeType* domNodeType )
1381 {
1382     unknode *This = unknode_from_IXMLDOMNode( iface );
1383
1384     FIXME("(%p)->(%p)\n", This, domNodeType);
1385
1386     *domNodeType = This->node.node->type;
1387     return S_OK;
1388 }
1389
1390 static HRESULT WINAPI unknode_get_parentNode(
1391     IXMLDOMNode *iface,
1392     IXMLDOMNode** parent )
1393 {
1394     unknode *This = unknode_from_IXMLDOMNode( iface );
1395     FIXME("(%p)->(%p)\n", This, parent);
1396     if (!parent) return E_INVALIDARG;
1397     *parent = NULL;
1398     return S_FALSE;
1399 }
1400
1401 static HRESULT WINAPI unknode_get_childNodes(
1402     IXMLDOMNode *iface,
1403     IXMLDOMNodeList** outList)
1404 {
1405     unknode *This = unknode_from_IXMLDOMNode( iface );
1406
1407     TRACE("(%p)->(%p)\n", This, outList);
1408
1409     return node_get_child_nodes(&This->node, outList);
1410 }
1411
1412 static HRESULT WINAPI unknode_get_firstChild(
1413     IXMLDOMNode *iface,
1414     IXMLDOMNode** domNode)
1415 {
1416     unknode *This = unknode_from_IXMLDOMNode( iface );
1417
1418     TRACE("(%p)->(%p)\n", This, domNode);
1419
1420     return node_get_first_child(&This->node, domNode);
1421 }
1422
1423 static HRESULT WINAPI unknode_get_lastChild(
1424     IXMLDOMNode *iface,
1425     IXMLDOMNode** domNode)
1426 {
1427     unknode *This = unknode_from_IXMLDOMNode( iface );
1428
1429     TRACE("(%p)->(%p)\n", This, domNode);
1430
1431     return node_get_last_child(&This->node, domNode);
1432 }
1433
1434 static HRESULT WINAPI unknode_get_previousSibling(
1435     IXMLDOMNode *iface,
1436     IXMLDOMNode** domNode)
1437 {
1438     unknode *This = unknode_from_IXMLDOMNode( iface );
1439
1440     TRACE("(%p)->(%p)\n", This, domNode);
1441
1442     return node_get_previous_sibling(&This->node, domNode);
1443 }
1444
1445 static HRESULT WINAPI unknode_get_nextSibling(
1446     IXMLDOMNode *iface,
1447     IXMLDOMNode** domNode)
1448 {
1449     unknode *This = unknode_from_IXMLDOMNode( iface );
1450
1451     TRACE("(%p)->(%p)\n", This, domNode);
1452
1453     return node_get_next_sibling(&This->node, domNode);
1454 }
1455
1456 static HRESULT WINAPI unknode_get_attributes(
1457     IXMLDOMNode *iface,
1458     IXMLDOMNamedNodeMap** attributeMap)
1459 {
1460     unknode *This = unknode_from_IXMLDOMNode( iface );
1461
1462     FIXME("(%p)->(%p)\n", This, attributeMap);
1463
1464     return return_null_ptr((void**)attributeMap);
1465 }
1466
1467 static HRESULT WINAPI unknode_insertBefore(
1468     IXMLDOMNode *iface,
1469     IXMLDOMNode* newNode, VARIANT refChild,
1470     IXMLDOMNode** outOldNode)
1471 {
1472     unknode *This = unknode_from_IXMLDOMNode( iface );
1473
1474     FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1475
1476     return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1477 }
1478
1479 static HRESULT WINAPI unknode_replaceChild(
1480     IXMLDOMNode *iface,
1481     IXMLDOMNode* newNode,
1482     IXMLDOMNode* oldNode,
1483     IXMLDOMNode** outOldNode)
1484 {
1485     unknode *This = unknode_from_IXMLDOMNode( iface );
1486
1487     FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1488
1489     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1490 }
1491
1492 static HRESULT WINAPI unknode_removeChild(
1493     IXMLDOMNode *iface,
1494     IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1495 {
1496     unknode *This = unknode_from_IXMLDOMNode( iface );
1497     return IXMLDOMNode_removeChild( &This->node.IXMLDOMNode_iface, domNode, oldNode );
1498 }
1499
1500 static HRESULT WINAPI unknode_appendChild(
1501     IXMLDOMNode *iface,
1502     IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1503 {
1504     unknode *This = unknode_from_IXMLDOMNode( iface );
1505     return IXMLDOMNode_appendChild( &This->node.IXMLDOMNode_iface, newNode, outNewNode );
1506 }
1507
1508 static HRESULT WINAPI unknode_hasChildNodes(
1509     IXMLDOMNode *iface,
1510     VARIANT_BOOL* pbool)
1511 {
1512     unknode *This = unknode_from_IXMLDOMNode( iface );
1513     return IXMLDOMNode_hasChildNodes( &This->node.IXMLDOMNode_iface, pbool );
1514 }
1515
1516 static HRESULT WINAPI unknode_get_ownerDocument(
1517     IXMLDOMNode *iface,
1518     IXMLDOMDocument** domDocument)
1519 {
1520     unknode *This = unknode_from_IXMLDOMNode( iface );
1521     return IXMLDOMNode_get_ownerDocument( &This->node.IXMLDOMNode_iface, domDocument );
1522 }
1523
1524 static HRESULT WINAPI unknode_cloneNode(
1525     IXMLDOMNode *iface,
1526     VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1527 {
1528     unknode *This = unknode_from_IXMLDOMNode( iface );
1529     return IXMLDOMNode_cloneNode( &This->node.IXMLDOMNode_iface, pbool, outNode );
1530 }
1531
1532 static HRESULT WINAPI unknode_get_nodeTypeString(
1533     IXMLDOMNode *iface,
1534     BSTR* p)
1535 {
1536     unknode *This = unknode_from_IXMLDOMNode( iface );
1537
1538     FIXME("(%p)->(%p)\n", This, p);
1539
1540     return node_get_nodeName(&This->node, p);
1541 }
1542
1543 static HRESULT WINAPI unknode_get_text(
1544     IXMLDOMNode *iface,
1545     BSTR* p)
1546 {
1547     unknode *This = unknode_from_IXMLDOMNode( iface );
1548     return IXMLDOMNode_get_text( &This->node.IXMLDOMNode_iface, p );
1549 }
1550
1551 static HRESULT WINAPI unknode_put_text(
1552     IXMLDOMNode *iface,
1553     BSTR p)
1554 {
1555     unknode *This = unknode_from_IXMLDOMNode( iface );
1556     return IXMLDOMNode_put_text( &This->node.IXMLDOMNode_iface, p );
1557 }
1558
1559 static HRESULT WINAPI unknode_get_specified(
1560     IXMLDOMNode *iface,
1561     VARIANT_BOOL* isSpecified)
1562 {
1563     unknode *This = unknode_from_IXMLDOMNode( iface );
1564     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1565     *isSpecified = VARIANT_TRUE;
1566     return S_OK;
1567 }
1568
1569 static HRESULT WINAPI unknode_get_definition(
1570     IXMLDOMNode *iface,
1571     IXMLDOMNode** definitionNode)
1572 {
1573     unknode *This = unknode_from_IXMLDOMNode( iface );
1574     FIXME("(%p)->(%p)\n", This, definitionNode);
1575     return E_NOTIMPL;
1576 }
1577
1578 static HRESULT WINAPI unknode_get_nodeTypedValue(
1579     IXMLDOMNode *iface,
1580     VARIANT* var1)
1581 {
1582     unknode *This = unknode_from_IXMLDOMNode( iface );
1583     FIXME("(%p)->(%p)\n", This, var1);
1584     return return_null_var(var1);
1585 }
1586
1587 static HRESULT WINAPI unknode_put_nodeTypedValue(
1588     IXMLDOMNode *iface,
1589     VARIANT typedValue)
1590 {
1591     unknode *This = unknode_from_IXMLDOMNode( iface );
1592     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1593     return E_NOTIMPL;
1594 }
1595
1596 static HRESULT WINAPI unknode_get_dataType(
1597     IXMLDOMNode *iface,
1598     VARIANT* var1)
1599 {
1600     unknode *This = unknode_from_IXMLDOMNode( iface );
1601     return IXMLDOMNode_get_dataType( &This->node.IXMLDOMNode_iface, var1 );
1602 }
1603
1604 static HRESULT WINAPI unknode_put_dataType(
1605     IXMLDOMNode *iface,
1606     BSTR p)
1607 {
1608     unknode *This = unknode_from_IXMLDOMNode( iface );
1609
1610     FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1611
1612     if(!p)
1613         return E_INVALIDARG;
1614
1615     return E_FAIL;
1616 }
1617
1618 static HRESULT WINAPI unknode_get_xml(
1619     IXMLDOMNode *iface,
1620     BSTR* p)
1621 {
1622     unknode *This = unknode_from_IXMLDOMNode( iface );
1623
1624     FIXME("(%p)->(%p)\n", This, p);
1625
1626     return node_get_xml(&This->node, FALSE, FALSE, p);
1627 }
1628
1629 static HRESULT WINAPI unknode_transformNode(
1630     IXMLDOMNode *iface,
1631     IXMLDOMNode* domNode, BSTR* p)
1632 {
1633     unknode *This = unknode_from_IXMLDOMNode( iface );
1634     return IXMLDOMNode_transformNode( &This->node.IXMLDOMNode_iface, domNode, p );
1635 }
1636
1637 static HRESULT WINAPI unknode_selectNodes(
1638     IXMLDOMNode *iface,
1639     BSTR p, IXMLDOMNodeList** outList)
1640 {
1641     unknode *This = unknode_from_IXMLDOMNode( iface );
1642     return IXMLDOMNode_selectNodes( &This->node.IXMLDOMNode_iface, p, outList );
1643 }
1644
1645 static HRESULT WINAPI unknode_selectSingleNode(
1646     IXMLDOMNode *iface,
1647     BSTR p, IXMLDOMNode** outNode)
1648 {
1649     unknode *This = unknode_from_IXMLDOMNode( iface );
1650     return IXMLDOMNode_selectSingleNode( &This->node.IXMLDOMNode_iface, p, outNode );
1651 }
1652
1653 static HRESULT WINAPI unknode_get_parsed(
1654     IXMLDOMNode *iface,
1655     VARIANT_BOOL* isParsed)
1656 {
1657     unknode *This = unknode_from_IXMLDOMNode( iface );
1658     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1659     *isParsed = VARIANT_TRUE;
1660     return S_OK;
1661 }
1662
1663 static HRESULT WINAPI unknode_get_namespaceURI(
1664     IXMLDOMNode *iface,
1665     BSTR* p)
1666 {
1667     unknode *This = unknode_from_IXMLDOMNode( iface );
1668     TRACE("(%p)->(%p)\n", This, p);
1669     return node_get_namespaceURI(&This->node, p);
1670 }
1671
1672 static HRESULT WINAPI unknode_get_prefix(
1673     IXMLDOMNode *iface,
1674     BSTR* p)
1675 {
1676     unknode *This = unknode_from_IXMLDOMNode( iface );
1677     return IXMLDOMNode_get_prefix( &This->node.IXMLDOMNode_iface, p );
1678 }
1679
1680 static HRESULT WINAPI unknode_get_baseName(
1681     IXMLDOMNode *iface,
1682     BSTR* p)
1683 {
1684     unknode *This = unknode_from_IXMLDOMNode( iface );
1685     return IXMLDOMNode_get_baseName( &This->node.IXMLDOMNode_iface, p );
1686 }
1687
1688 static HRESULT WINAPI unknode_transformNodeToObject(
1689     IXMLDOMNode *iface,
1690     IXMLDOMNode* domNode, VARIANT var1)
1691 {
1692     unknode *This = unknode_from_IXMLDOMNode( iface );
1693     FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1694     return E_NOTIMPL;
1695 }
1696
1697 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1698 {
1699     unknode_QueryInterface,
1700     unknode_AddRef,
1701     unknode_Release,
1702     unknode_GetTypeInfoCount,
1703     unknode_GetTypeInfo,
1704     unknode_GetIDsOfNames,
1705     unknode_Invoke,
1706     unknode_get_nodeName,
1707     unknode_get_nodeValue,
1708     unknode_put_nodeValue,
1709     unknode_get_nodeType,
1710     unknode_get_parentNode,
1711     unknode_get_childNodes,
1712     unknode_get_firstChild,
1713     unknode_get_lastChild,
1714     unknode_get_previousSibling,
1715     unknode_get_nextSibling,
1716     unknode_get_attributes,
1717     unknode_insertBefore,
1718     unknode_replaceChild,
1719     unknode_removeChild,
1720     unknode_appendChild,
1721     unknode_hasChildNodes,
1722     unknode_get_ownerDocument,
1723     unknode_cloneNode,
1724     unknode_get_nodeTypeString,
1725     unknode_get_text,
1726     unknode_put_text,
1727     unknode_get_specified,
1728     unknode_get_definition,
1729     unknode_get_nodeTypedValue,
1730     unknode_put_nodeTypedValue,
1731     unknode_get_dataType,
1732     unknode_put_dataType,
1733     unknode_get_xml,
1734     unknode_transformNode,
1735     unknode_selectNodes,
1736     unknode_selectSingleNode,
1737     unknode_get_parsed,
1738     unknode_get_namespaceURI,
1739     unknode_get_prefix,
1740     unknode_get_baseName,
1741     unknode_transformNodeToObject
1742 };
1743
1744 IXMLDOMNode *create_node( xmlNodePtr node )
1745 {
1746     IUnknown *pUnk;
1747     IXMLDOMNode *ret;
1748     HRESULT hr;
1749
1750     if ( !node )
1751         return NULL;
1752
1753     TRACE("type %d\n", node->type);
1754     switch(node->type)
1755     {
1756     case XML_ELEMENT_NODE:
1757         pUnk = create_element( node );
1758         break;
1759     case XML_ATTRIBUTE_NODE:
1760         pUnk = create_attribute( node );
1761         break;
1762     case XML_TEXT_NODE:
1763         pUnk = create_text( node );
1764         break;
1765     case XML_CDATA_SECTION_NODE:
1766         pUnk = create_cdata( node );
1767         break;
1768     case XML_ENTITY_REF_NODE:
1769         pUnk = create_doc_entity_ref( node );
1770         break;
1771     case XML_PI_NODE:
1772         pUnk = create_pi( node );
1773         break;
1774     case XML_COMMENT_NODE:
1775         pUnk = create_comment( node );
1776         break;
1777     case XML_DOCUMENT_NODE:
1778         pUnk = create_domdoc( node );
1779         break;
1780     case XML_DOCUMENT_FRAG_NODE:
1781         pUnk = create_doc_fragment( node );
1782         break;
1783     case XML_DTD_NODE:
1784         pUnk = create_doc_type( node );
1785         break;
1786     default: {
1787         unknode *new_node;
1788
1789         FIXME("only creating basic node for type %d\n", node->type);
1790
1791         new_node = heap_alloc(sizeof(unknode));
1792         if(!new_node)
1793             return NULL;
1794
1795         new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1796         new_node->ref = 1;
1797         init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1798         pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1799     }
1800     }
1801
1802     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1803     IUnknown_Release(pUnk);
1804     if(FAILED(hr)) return NULL;
1805     return ret;
1806 }
1807 #endif