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