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