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