msxml3: Don't include assert.h where it's not used.
[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 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
673 {
674     if(!type || !lstrcmpiW(type, szString) ||
675             !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
676     {
677         V_VT(v) = VT_BSTR;
678         V_BSTR(v) = bstr_from_xmlChar(str);
679
680         if(!V_BSTR(v))
681             return E_OUTOFMEMORY;
682     }
683     else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
684             !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
685             !lstrcmpiW(type, szTimeTZ))
686     {
687         VARIANT src;
688         WCHAR *p, *e;
689         SYSTEMTIME st;
690         DOUBLE date = 0.0;
691
692         st.wYear = 1899;
693         st.wMonth = 12;
694         st.wDay = 30;
695         st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
696
697         V_VT(&src) = VT_BSTR;
698         V_BSTR(&src) = bstr_from_xmlChar(str);
699
700         if(!V_BSTR(&src))
701             return E_OUTOFMEMORY;
702
703         p = V_BSTR(&src);
704         e = p + SysStringLen(V_BSTR(&src));
705
706         if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
707         {
708             st.wYear = atoiW(p);
709             st.wMonth = atoiW(p+5);
710             st.wDay = atoiW(p+8);
711             p += 10;
712
713             if(*p == 'T') p++;
714         }
715
716         if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
717         {
718             st.wHour = atoiW(p);
719             st.wMinute = atoiW(p+3);
720             st.wSecond = atoiW(p+6);
721             p += 8;
722
723             if(*p == '.')
724             {
725                 p++;
726                 while(isdigitW(*p)) p++;
727             }
728         }
729
730         SystemTimeToVariantTime(&st, &date);
731         V_VT(v) = VT_DATE;
732         V_DATE(v) = date;
733
734         if(*p == '+') /* parse timezone offset (+hh:mm) */
735             V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
736         else if(*p == '-') /* parse timezone offset (-hh:mm) */
737             V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
738
739         VariantClear(&src);
740     }
741     else if(!lstrcmpiW(type, szBinHex))
742     {
743         SAFEARRAYBOUND sab;
744         int i, len;
745
746         len = xmlStrlen(str)/2;
747         sab.lLbound = 0;
748         sab.cElements = len;
749
750         V_VT(v) = (VT_ARRAY|VT_UI1);
751         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
752
753         if(!V_ARRAY(v))
754             return E_OUTOFMEMORY;
755
756         for(i=0; i<len; i++)
757             ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
758                 + hex_to_byte(str[2*i+1]);
759     }
760     else if(!lstrcmpiW(type, szBinBase64))
761     {
762         SAFEARRAYBOUND sab;
763         int i, len;
764
765         len  = xmlStrlen(str);
766         if(str[len-2] == '=') i = 2;
767         else if(str[len-1] == '=') i = 1;
768         else i = 0;
769
770         sab.lLbound = 0;
771         sab.cElements = len/4*3-i;
772
773         V_VT(v) = (VT_ARRAY|VT_UI1);
774         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
775
776         if(!V_ARRAY(v))
777             return E_OUTOFMEMORY;
778
779         for(i=0; i<len/4; i++)
780         {
781             ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
782                 + (base64_to_byte(str[4*i+1])>>4);
783             if(3*i+1 < sab.cElements)
784                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
785                     + (base64_to_byte(str[4*i+2])>>2);
786             if(3*i+2 < sab.cElements)
787                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
788                     + base64_to_byte(str[4*i+3]);
789         }
790     }
791     else
792     {
793         VARIANT src;
794         HRESULT hres;
795
796         if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
797             V_VT(v) = VT_I4;
798         else if(!lstrcmpiW(type, szFixed))
799             V_VT(v) = VT_CY;
800         else if(!lstrcmpiW(type, szBoolean))
801             V_VT(v) = VT_BOOL;
802         else if(!lstrcmpiW(type, szI1))
803             V_VT(v) = VT_I1;
804         else if(!lstrcmpiW(type, szI2))
805             V_VT(v) = VT_I2;
806         else if(!lstrcmpiW(type, szIU1))
807             V_VT(v) = VT_UI1;
808         else if(!lstrcmpiW(type, szIU2))
809             V_VT(v) = VT_UI2;
810         else if(!lstrcmpiW(type, szIU4))
811             V_VT(v) = VT_UI4;
812         else if(!lstrcmpiW(type, szR4))
813             V_VT(v) = VT_R4;
814         else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
815             V_VT(v) = VT_R8;
816         else
817         {
818             FIXME("Type handling not yet implemented\n");
819             V_VT(v) = VT_BSTR;
820         }
821
822         V_VT(&src) = VT_BSTR;
823         V_BSTR(&src) = bstr_from_xmlChar(str);
824
825         if(!V_BSTR(&src))
826             return E_OUTOFMEMORY;
827
828         hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
829                         LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
830         VariantClear(&src);
831         return hres;
832     }
833
834     return S_OK;
835 }
836
837 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
838     IXMLDOMNode *iface,
839     VARIANT* typedValue)
840 {
841     xmlnode *This = impl_from_IXMLDOMNode( iface );
842     VARIANT type;
843     xmlChar *content;
844     HRESULT hres = S_FALSE;
845
846     TRACE("(%p)->(%p)\n", This, typedValue);
847
848     if(!typedValue)
849         return E_INVALIDARG;
850
851     V_VT(typedValue) = VT_NULL;
852
853     if(This->node->type == XML_ELEMENT_NODE ||
854             This->node->type == XML_TEXT_NODE ||
855             This->node->type == XML_ENTITY_REF_NODE)
856         hres = IXMLDOMNode_get_dataType(This->iface, &type);
857
858     if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
859         return IXMLDOMNode_get_nodeValue(This->iface, typedValue);
860
861     content = xmlNodeGetContent(This->node);
862     hres = VARIANT_from_xmlChar(content, typedValue,
863             hres==S_OK ? V_BSTR(&type) : NULL);
864     xmlFree(content);
865     VariantClear(&type);
866
867     return hres;
868 }
869
870 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
871     IXMLDOMNode *iface,
872     VARIANT typedValue)
873 {
874     xmlnode *This = impl_from_IXMLDOMNode( iface );
875     FIXME("%p\n", This);
876     return E_NOTIMPL;
877 }
878
879 static HRESULT WINAPI xmlnode_put_dataType(
880     IXMLDOMNode *iface,
881     BSTR dataTypeName)
882 {
883     xmlnode *This = impl_from_IXMLDOMNode( iface );
884     HRESULT hr = E_FAIL;
885
886     TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
887
888     if(dataTypeName == NULL)
889         return E_INVALIDARG;
890
891     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
892        This applies to changing types (string->bool) or setting a new one
893      */
894     FIXME("Need to Validate the data before allowing a type to be set.\n");
895
896     /* Check all supported types. */
897     if(lstrcmpiW(dataTypeName,szString) == 0  ||
898        lstrcmpiW(dataTypeName,szNumber) == 0  ||
899        lstrcmpiW(dataTypeName,szUUID) == 0    ||
900        lstrcmpiW(dataTypeName,szInt) == 0     ||
901        lstrcmpiW(dataTypeName,szI4) == 0      ||
902        lstrcmpiW(dataTypeName,szFixed) == 0   ||
903        lstrcmpiW(dataTypeName,szBoolean) == 0 ||
904        lstrcmpiW(dataTypeName,szDateTime) == 0 ||
905        lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
906        lstrcmpiW(dataTypeName,szDate) == 0    ||
907        lstrcmpiW(dataTypeName,szTime) == 0    ||
908        lstrcmpiW(dataTypeName,szTimeTZ) == 0  ||
909        lstrcmpiW(dataTypeName,szI1) == 0      ||
910        lstrcmpiW(dataTypeName,szI2) == 0      ||
911        lstrcmpiW(dataTypeName,szIU1) == 0     ||
912        lstrcmpiW(dataTypeName,szIU2) == 0     ||
913        lstrcmpiW(dataTypeName,szIU4) == 0     ||
914        lstrcmpiW(dataTypeName,szR4) == 0      ||
915        lstrcmpiW(dataTypeName,szR8) == 0      ||
916        lstrcmpiW(dataTypeName,szFloat) == 0   ||
917        lstrcmpiW(dataTypeName,szBinHex) == 0  ||
918        lstrcmpiW(dataTypeName,szBinBase64) == 0)
919     {
920         xmlChar* str = xmlChar_from_wchar(dataTypeName);
921         xmlAttrPtr attr;
922
923         if (!str) return E_OUTOFMEMORY;
924
925         attr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
926                             (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
927         if (attr)
928         {
929             attr = xmlSetNsProp(This->node, attr->ns, (const xmlChar*)"dt", str);
930             hr = S_OK;
931         }
932         else
933         {
934             xmlNsPtr ns = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
935             if (ns)
936             {
937                 attr = xmlNewNsProp(This->node, ns, (const xmlChar*)"dt", str);
938                 if (attr)
939                 {
940                     xmlAddChild(This->node, (xmlNodePtr)attr);
941                     hr = S_OK;
942                 }
943                 else
944                     ERR("Failed to create Attribute\n");
945             }
946             else
947                 ERR("Failed to create Namespace\n");
948         }
949         heap_free( str );
950     }
951
952     return hr;
953 }
954
955 BSTR EnsureCorrectEOL(BSTR sInput)
956 {
957     int nNum = 0;
958     BSTR sNew;
959     int nLen;
960     int i;
961
962     nLen = SysStringLen(sInput);
963     /* Count line endings */
964     for(i=0; i < nLen; i++)
965     {
966         if(sInput[i] == '\n')
967             nNum++;
968     }
969
970     TRACE("len=%d, num=%d\n", nLen, nNum);
971
972     /* Add linefeed as needed */
973     if(nNum > 0)
974     {
975         int nPlace = 0;
976         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
977         for(i=0; i < nLen; i++)
978         {
979             if(sInput[i] == '\n')
980             {
981                 sNew[i+nPlace] = '\r';
982                 nPlace++;
983             }
984             sNew[i+nPlace] = sInput[i];
985         }
986
987         SysFreeString(sInput);
988     }
989     else
990     {
991         sNew = sInput;
992     }
993
994     TRACE("len %d\n", SysStringLen(sNew));
995
996     return sNew;
997 }
998
999 /* Removes encoding information and last character (nullbyte) */
1000 static BSTR EnsureNoEncoding(BSTR sInput)
1001 {
1002     static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1003     BSTR sNew;
1004     WCHAR *pBeg, *pEnd;
1005
1006     pBeg = sInput;
1007     while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1008         pBeg++;
1009
1010     if(*pBeg == '\n')
1011     {
1012         SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1013         return sInput;
1014     }
1015     pBeg--;
1016
1017     pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1018     while(*pEnd != '\"') pEnd++;
1019     pEnd++;
1020
1021     sNew = SysAllocStringLen(NULL,
1022             pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1023     memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1024     memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1025
1026     SysFreeString(sInput);
1027     return sNew;
1028 }
1029
1030 /*
1031  * We are trying to replicate the same behaviour as msxml by converting
1032  * line endings to \r\n and using indents as \t. The problem is that msxml
1033  * only formats nodes that have a line ending. Using libxml we cannot
1034  * reproduce behaviour exactly.
1035  *
1036  */
1037 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
1038 {
1039     xmlBufferPtr xml_buf;
1040     xmlNodePtr xmldecl;
1041     int size;
1042
1043     if(!ret)
1044         return E_INVALIDARG;
1045
1046     *ret = NULL;
1047
1048     xml_buf = xmlBufferCreate();
1049     if(!xml_buf)
1050         return E_OUTOFMEMORY;
1051
1052     xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
1053
1054     size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
1055     if(size > 0) {
1056         const xmlChar *buf_content;
1057         BSTR content;
1058
1059         /* Attribute Nodes return a space in front of their name */
1060         buf_content = xmlBufferContent(xml_buf);
1061
1062         content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
1063         if(ensure_eol)
1064             content = EnsureCorrectEOL(content);
1065         if(ensure_no_encoding)
1066             content = EnsureNoEncoding(content);
1067
1068         *ret = content;
1069     }else {
1070         *ret = SysAllocStringLen(NULL, 0);
1071     }
1072
1073     xmlBufferFree(xml_buf);
1074     xmldoc_link_xmldecl( This->node->doc, xmldecl );
1075     return *ret ? S_OK : E_OUTOFMEMORY;
1076 }
1077
1078 static HRESULT WINAPI xmlnode_transformNode(
1079     IXMLDOMNode *iface,
1080     IXMLDOMNode* styleSheet,
1081     BSTR* xmlString)
1082 {
1083 #ifdef SONAME_LIBXSLT
1084     xmlnode *This = impl_from_IXMLDOMNode( iface );
1085     xmlnode *pStyleSheet = NULL;
1086     xsltStylesheetPtr xsltSS = NULL;
1087     xmlDocPtr result = NULL;
1088
1089     TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1090
1091     if (!libxslt_handle)
1092         return E_NOTIMPL;
1093     if(!styleSheet || !xmlString)
1094         return E_INVALIDARG;
1095
1096     *xmlString = NULL;
1097
1098     pStyleSheet = get_node_obj(styleSheet);
1099     if(!pStyleSheet) {
1100         FIXME("styleSheet is not our xmlnode implementation\n");
1101         return E_FAIL;
1102     }
1103
1104     xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1105     if(xsltSS)
1106     {
1107         result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1108         if(result)
1109         {
1110             const xmlChar *pContent;
1111
1112             if(result->type == XML_HTML_DOCUMENT_NODE)
1113             {
1114                 xmlOutputBufferPtr      pOutput = xmlAllocOutputBuffer(NULL);
1115                 if(pOutput)
1116                 {
1117                     htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1118                     pContent = xmlBufferContent(pOutput->buffer);
1119                     *xmlString = bstr_from_xmlChar(pContent);
1120                     xmlOutputBufferClose(pOutput);
1121                 }
1122             }
1123             else
1124             {
1125                 xmlBufferPtr pXmlBuf;
1126                 int nSize;
1127
1128                 pXmlBuf = xmlBufferCreate();
1129                 if(pXmlBuf)
1130                 {
1131                     nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1132                     if(nSize > 0)
1133                     {
1134                         pContent = xmlBufferContent(pXmlBuf);
1135                         *xmlString = bstr_from_xmlChar(pContent);
1136                     }
1137                     xmlBufferFree(pXmlBuf);
1138                 }
1139             }
1140             xmlFreeDoc(result);
1141         }
1142         /* libxslt "helpfully" frees the XML document the stylesheet was
1143            generated from, too */
1144         xsltSS->doc = NULL;
1145         pxsltFreeStylesheet(xsltSS);
1146     }
1147
1148     if(*xmlString == NULL)
1149         *xmlString = SysAllocStringLen(NULL, 0);
1150
1151     return S_OK;
1152 #else
1153     FIXME("libxslt headers were not found at compile time\n");
1154     return E_NOTIMPL;
1155 #endif
1156 }
1157
1158 static HRESULT WINAPI xmlnode_selectNodes(
1159     IXMLDOMNode *iface,
1160     BSTR queryString,
1161     IXMLDOMNodeList** resultList)
1162 {
1163     xmlnode *This = impl_from_IXMLDOMNode( iface );
1164
1165     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1166
1167     if (!queryString || !resultList) return E_INVALIDARG;
1168
1169     return queryresult_create( This->node, queryString, resultList );
1170 }
1171
1172 static HRESULT WINAPI xmlnode_selectSingleNode(
1173     IXMLDOMNode *iface,
1174     BSTR queryString,
1175     IXMLDOMNode** resultNode)
1176 {
1177     xmlnode *This = impl_from_IXMLDOMNode( iface );
1178     IXMLDOMNodeList *list;
1179     HRESULT r;
1180
1181     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1182
1183     r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1184     if(r == S_OK)
1185     {
1186         r = IXMLDOMNodeList_nextNode(list, resultNode);
1187         IXMLDOMNodeList_Release(list);
1188     }
1189     return r;
1190 }
1191
1192 static HRESULT WINAPI xmlnode_get_namespaceURI(
1193     IXMLDOMNode *iface,
1194     BSTR* namespaceURI)
1195 {
1196     xmlnode *This = impl_from_IXMLDOMNode( iface );
1197     xmlNsPtr *ns;
1198
1199     TRACE("(%p)->(%p)\n", This, namespaceURI );
1200
1201     if(!namespaceURI)
1202         return E_INVALIDARG;
1203
1204     *namespaceURI = NULL;
1205
1206     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1207     {
1208         if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1209         xmlFree(ns);
1210     }
1211
1212     TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1213
1214     return *namespaceURI ? S_OK : S_FALSE;
1215 }
1216
1217 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1218 {
1219     xmlNsPtr *ns;
1220
1221     if (!prefix) return E_INVALIDARG;
1222
1223     *prefix = NULL;
1224
1225     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1226     {
1227         if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1228         xmlFree(ns);
1229     }
1230
1231     TRACE("prefix: %s\n", debugstr_w(*prefix));
1232
1233     return *prefix ? S_OK : S_FALSE;
1234 }
1235
1236 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1237 {
1238     if (!name) return E_INVALIDARG;
1239
1240     *name = bstr_from_xmlChar(This->node->name);
1241     if (!*name) return E_OUTOFMEMORY;
1242
1243     TRACE("returning %s\n", debugstr_w(*name));
1244
1245     return S_OK;
1246 }
1247
1248 static HRESULT WINAPI xmlnode_transformNodeToObject(
1249     IXMLDOMNode *iface,
1250     IXMLDOMNode* stylesheet,
1251     VARIANT outputObject)
1252 {
1253     xmlnode *This = impl_from_IXMLDOMNode( iface );
1254     FIXME("(%p)->(%p)\n", This, stylesheet);
1255     return E_NOTIMPL;
1256 }
1257
1258 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1259 {
1260     NULL,
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     xmlnode_removeChild,
1281     xmlnode_appendChild,
1282     xmlnode_hasChildNodes,
1283     xmlnode_get_ownerDocument,
1284     NULL,
1285     NULL,
1286     xmlnode_get_text,
1287     NULL,
1288     NULL,
1289     NULL,
1290     xmlnode_get_nodeTypedValue,
1291     xmlnode_put_nodeTypedValue,
1292     NULL,
1293     xmlnode_put_dataType,
1294     NULL,
1295     xmlnode_transformNode,
1296     xmlnode_selectNodes,
1297     xmlnode_selectSingleNode,
1298     NULL,
1299     xmlnode_get_namespaceURI,
1300     NULL,
1301     NULL,
1302     xmlnode_transformNodeToObject,
1303 };
1304
1305 void destroy_xmlnode(xmlnode *This)
1306 {
1307     if(This->node)
1308         xmldoc_release(This->node->doc);
1309 }
1310
1311 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1312 {
1313     if(node)
1314         xmldoc_add_ref( node->doc );
1315
1316     This->lpVtbl = &xmlnode_vtbl;
1317     This->node = node;
1318     This->iface = node_iface;
1319
1320     if(dispex_data)
1321         init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1322     else
1323         This->dispex.outer = NULL;
1324 }
1325
1326 typedef struct {
1327     xmlnode node;
1328     const IXMLDOMNodeVtbl *lpVtbl;
1329     LONG ref;
1330 } unknode;
1331
1332 static inline unknode *impl_from_unkIXMLDOMNode(IXMLDOMNode *iface)
1333 {
1334     return (unknode *)((char*)iface - FIELD_OFFSET(unknode, lpVtbl));
1335 }
1336
1337 static HRESULT WINAPI unknode_QueryInterface(
1338     IXMLDOMNode *iface,
1339     REFIID riid,
1340     void** ppvObject )
1341 {
1342     unknode *This = impl_from_unkIXMLDOMNode( iface );
1343
1344     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1345
1346     if (IsEqualGUID(riid, &IID_IUnknown)) {
1347         *ppvObject = iface;
1348     }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1349               IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1350         *ppvObject = &This->lpVtbl;
1351     }else if(node_query_interface(&This->node, riid, ppvObject)) {
1352         return *ppvObject ? S_OK : E_NOINTERFACE;
1353     }else  {
1354         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1355         *ppvObject = NULL;
1356         return E_NOINTERFACE;
1357     }
1358
1359     IUnknown_AddRef((IUnknown*)*ppvObject);
1360     return S_OK;
1361 }
1362
1363 static ULONG WINAPI unknode_AddRef(
1364     IXMLDOMNode *iface )
1365 {
1366     unknode *This = impl_from_unkIXMLDOMNode( iface );
1367
1368     return InterlockedIncrement(&This->ref);
1369 }
1370
1371 static ULONG WINAPI unknode_Release(
1372     IXMLDOMNode *iface )
1373 {
1374     unknode *This = impl_from_unkIXMLDOMNode( iface );
1375     LONG ref;
1376
1377     ref = InterlockedDecrement( &This->ref );
1378     if(!ref) {
1379         destroy_xmlnode(&This->node);
1380         heap_free(This);
1381     }
1382
1383     return ref;
1384 }
1385
1386 static HRESULT WINAPI unknode_GetTypeInfoCount(
1387     IXMLDOMNode *iface,
1388     UINT* pctinfo )
1389 {
1390     unknode *This = impl_from_unkIXMLDOMNode( iface );
1391
1392     TRACE("(%p)->(%p)\n", This, pctinfo);
1393
1394     *pctinfo = 1;
1395
1396     return S_OK;
1397 }
1398
1399 static HRESULT WINAPI unknode_GetTypeInfo(
1400     IXMLDOMNode *iface,
1401     UINT iTInfo,
1402     LCID lcid,
1403     ITypeInfo** ppTInfo )
1404 {
1405     unknode *This = impl_from_unkIXMLDOMNode( iface );
1406     HRESULT hr;
1407
1408     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1409
1410     hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1411
1412     return hr;
1413 }
1414
1415 static HRESULT WINAPI unknode_GetIDsOfNames(
1416     IXMLDOMNode *iface,
1417     REFIID riid,
1418     LPOLESTR* rgszNames,
1419     UINT cNames,
1420     LCID lcid,
1421     DISPID* rgDispId )
1422 {
1423     unknode *This = impl_from_unkIXMLDOMNode( iface );
1424
1425     ITypeInfo *typeinfo;
1426     HRESULT hr;
1427
1428     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1429           lcid, rgDispId);
1430
1431     if(!rgszNames || cNames == 0 || !rgDispId)
1432         return E_INVALIDARG;
1433
1434     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1435     if(SUCCEEDED(hr))
1436     {
1437         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1438         ITypeInfo_Release(typeinfo);
1439     }
1440
1441     return hr;
1442 }
1443
1444 static HRESULT WINAPI unknode_Invoke(
1445     IXMLDOMNode *iface,
1446     DISPID dispIdMember,
1447     REFIID riid,
1448     LCID lcid,
1449     WORD wFlags,
1450     DISPPARAMS* pDispParams,
1451     VARIANT* pVarResult,
1452     EXCEPINFO* pExcepInfo,
1453     UINT* puArgErr )
1454 {
1455     unknode *This = impl_from_unkIXMLDOMNode( iface );
1456     ITypeInfo *typeinfo;
1457     HRESULT hr;
1458
1459     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1460           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1461
1462     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1463     if(SUCCEEDED(hr))
1464     {
1465         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1466                 pVarResult, pExcepInfo, puArgErr);
1467         ITypeInfo_Release(typeinfo);
1468     }
1469
1470     return hr;
1471 }
1472
1473 static HRESULT WINAPI unknode_get_nodeName(
1474     IXMLDOMNode *iface,
1475     BSTR* p )
1476 {
1477     unknode *This = impl_from_unkIXMLDOMNode( iface );
1478
1479     FIXME("(%p)->(%p)\n", This, p);
1480
1481     return node_get_nodeName(&This->node, p);
1482 }
1483
1484 static HRESULT WINAPI unknode_get_nodeValue(
1485     IXMLDOMNode *iface,
1486     VARIANT* value)
1487 {
1488     unknode *This = impl_from_unkIXMLDOMNode( iface );
1489
1490     FIXME("(%p)->(%p)\n", This, value);
1491
1492     if(!value)
1493         return E_INVALIDARG;
1494
1495     V_VT(value) = VT_NULL;
1496     return S_FALSE;
1497 }
1498
1499 static HRESULT WINAPI unknode_put_nodeValue(
1500     IXMLDOMNode *iface,
1501     VARIANT value)
1502 {
1503     unknode *This = impl_from_unkIXMLDOMNode( iface );
1504     FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1505     return E_FAIL;
1506 }
1507
1508 static HRESULT WINAPI unknode_get_nodeType(
1509     IXMLDOMNode *iface,
1510     DOMNodeType* domNodeType )
1511 {
1512     unknode *This = impl_from_unkIXMLDOMNode( iface );
1513
1514     FIXME("(%p)->(%p)\n", This, domNodeType);
1515
1516     *domNodeType = This->node.node->type;
1517     return S_OK;
1518 }
1519
1520 static HRESULT WINAPI unknode_get_parentNode(
1521     IXMLDOMNode *iface,
1522     IXMLDOMNode** parent )
1523 {
1524     unknode *This = impl_from_unkIXMLDOMNode( iface );
1525     FIXME("(%p)->(%p)\n", This, parent);
1526     if (!parent) return E_INVALIDARG;
1527     *parent = NULL;
1528     return S_FALSE;
1529 }
1530
1531 static HRESULT WINAPI unknode_get_childNodes(
1532     IXMLDOMNode *iface,
1533     IXMLDOMNodeList** outList)
1534 {
1535     unknode *This = impl_from_unkIXMLDOMNode( iface );
1536
1537     TRACE("(%p)->(%p)\n", This, outList);
1538
1539     return node_get_child_nodes(&This->node, outList);
1540 }
1541
1542 static HRESULT WINAPI unknode_get_firstChild(
1543     IXMLDOMNode *iface,
1544     IXMLDOMNode** domNode)
1545 {
1546     unknode *This = impl_from_unkIXMLDOMNode( iface );
1547
1548     TRACE("(%p)->(%p)\n", This, domNode);
1549
1550     return node_get_first_child(&This->node, domNode);
1551 }
1552
1553 static HRESULT WINAPI unknode_get_lastChild(
1554     IXMLDOMNode *iface,
1555     IXMLDOMNode** domNode)
1556 {
1557     unknode *This = impl_from_unkIXMLDOMNode( iface );
1558
1559     TRACE("(%p)->(%p)\n", This, domNode);
1560
1561     return node_get_last_child(&This->node, domNode);
1562 }
1563
1564 static HRESULT WINAPI unknode_get_previousSibling(
1565     IXMLDOMNode *iface,
1566     IXMLDOMNode** domNode)
1567 {
1568     unknode *This = impl_from_unkIXMLDOMNode( iface );
1569
1570     TRACE("(%p)->(%p)\n", This, domNode);
1571
1572     return node_get_previous_sibling(&This->node, domNode);
1573 }
1574
1575 static HRESULT WINAPI unknode_get_nextSibling(
1576     IXMLDOMNode *iface,
1577     IXMLDOMNode** domNode)
1578 {
1579     unknode *This = impl_from_unkIXMLDOMNode( iface );
1580
1581     TRACE("(%p)->(%p)\n", This, domNode);
1582
1583     return node_get_next_sibling(&This->node, domNode);
1584 }
1585
1586 static HRESULT WINAPI unknode_get_attributes(
1587     IXMLDOMNode *iface,
1588     IXMLDOMNamedNodeMap** attributeMap)
1589 {
1590     unknode *This = impl_from_unkIXMLDOMNode( iface );
1591
1592     FIXME("(%p)->(%p)\n", This, attributeMap);
1593
1594     return return_null_ptr((void**)attributeMap);
1595 }
1596
1597 static HRESULT WINAPI unknode_insertBefore(
1598     IXMLDOMNode *iface,
1599     IXMLDOMNode* newNode, VARIANT refChild,
1600     IXMLDOMNode** outOldNode)
1601 {
1602     unknode *This = impl_from_unkIXMLDOMNode( iface );
1603
1604     FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1605
1606     return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1607 }
1608
1609 static HRESULT WINAPI unknode_replaceChild(
1610     IXMLDOMNode *iface,
1611     IXMLDOMNode* newNode,
1612     IXMLDOMNode* oldNode,
1613     IXMLDOMNode** outOldNode)
1614 {
1615     unknode *This = impl_from_unkIXMLDOMNode( iface );
1616
1617     FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1618
1619     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1620 }
1621
1622 static HRESULT WINAPI unknode_removeChild(
1623     IXMLDOMNode *iface,
1624     IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1625 {
1626     unknode *This = impl_from_unkIXMLDOMNode( iface );
1627     return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), domNode, oldNode );
1628 }
1629
1630 static HRESULT WINAPI unknode_appendChild(
1631     IXMLDOMNode *iface,
1632     IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1633 {
1634     unknode *This = impl_from_unkIXMLDOMNode( iface );
1635     return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newNode, outNewNode );
1636 }
1637
1638 static HRESULT WINAPI unknode_hasChildNodes(
1639     IXMLDOMNode *iface,
1640     VARIANT_BOOL* pbool)
1641 {
1642     unknode *This = impl_from_unkIXMLDOMNode( iface );
1643     return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), pbool );
1644 }
1645
1646 static HRESULT WINAPI unknode_get_ownerDocument(
1647     IXMLDOMNode *iface,
1648     IXMLDOMDocument** domDocument)
1649 {
1650     unknode *This = impl_from_unkIXMLDOMNode( iface );
1651     return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), domDocument );
1652 }
1653
1654 static HRESULT WINAPI unknode_cloneNode(
1655     IXMLDOMNode *iface,
1656     VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1657 {
1658     unknode *This = impl_from_unkIXMLDOMNode( iface );
1659     return IXMLDOMNode_cloneNode( IXMLDOMNode_from_impl(&This->node), pbool, outNode );
1660 }
1661
1662 static HRESULT WINAPI unknode_get_nodeTypeString(
1663     IXMLDOMNode *iface,
1664     BSTR* p)
1665 {
1666     unknode *This = impl_from_unkIXMLDOMNode( iface );
1667
1668     FIXME("(%p)->(%p)\n", This, p);
1669
1670     return node_get_nodeName(&This->node, p);
1671 }
1672
1673 static HRESULT WINAPI unknode_get_text(
1674     IXMLDOMNode *iface,
1675     BSTR* p)
1676 {
1677     unknode *This = impl_from_unkIXMLDOMNode( iface );
1678     return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), p );
1679 }
1680
1681 static HRESULT WINAPI unknode_put_text(
1682     IXMLDOMNode *iface,
1683     BSTR p)
1684 {
1685     unknode *This = impl_from_unkIXMLDOMNode( iface );
1686     return IXMLDOMNode_put_text( IXMLDOMNode_from_impl(&This->node), p );
1687 }
1688
1689 static HRESULT WINAPI unknode_get_specified(
1690     IXMLDOMNode *iface,
1691     VARIANT_BOOL* isSpecified)
1692 {
1693     unknode *This = impl_from_unkIXMLDOMNode( iface );
1694     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1695     *isSpecified = VARIANT_TRUE;
1696     return S_OK;
1697 }
1698
1699 static HRESULT WINAPI unknode_get_definition(
1700     IXMLDOMNode *iface,
1701     IXMLDOMNode** definitionNode)
1702 {
1703     unknode *This = impl_from_unkIXMLDOMNode( iface );
1704     FIXME("(%p)->(%p)\n", This, definitionNode);
1705     return E_NOTIMPL;
1706 }
1707
1708 static HRESULT WINAPI unknode_get_nodeTypedValue(
1709     IXMLDOMNode *iface,
1710     VARIANT* var1)
1711 {
1712     unknode *This = impl_from_unkIXMLDOMNode( iface );
1713     return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1714 }
1715
1716 static HRESULT WINAPI unknode_put_nodeTypedValue(
1717     IXMLDOMNode *iface,
1718     VARIANT var1)
1719 {
1720     unknode *This = impl_from_unkIXMLDOMNode( iface );
1721     return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1722 }
1723
1724 static HRESULT WINAPI unknode_get_dataType(
1725     IXMLDOMNode *iface,
1726     VARIANT* var1)
1727 {
1728     unknode *This = impl_from_unkIXMLDOMNode( iface );
1729     return IXMLDOMNode_get_dataType( IXMLDOMNode_from_impl(&This->node), var1 );
1730 }
1731
1732 static HRESULT WINAPI unknode_put_dataType(
1733     IXMLDOMNode *iface,
1734     BSTR p)
1735 {
1736     unknode *This = impl_from_unkIXMLDOMNode( iface );
1737     return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), p );
1738 }
1739
1740 static HRESULT WINAPI unknode_get_xml(
1741     IXMLDOMNode *iface,
1742     BSTR* p)
1743 {
1744     unknode *This = impl_from_unkIXMLDOMNode( iface );
1745
1746     FIXME("(%p)->(%p)\n", This, p);
1747
1748     return node_get_xml(&This->node, FALSE, FALSE, p);
1749 }
1750
1751 static HRESULT WINAPI unknode_transformNode(
1752     IXMLDOMNode *iface,
1753     IXMLDOMNode* domNode, BSTR* p)
1754 {
1755     unknode *This = impl_from_unkIXMLDOMNode( iface );
1756     return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), domNode, p );
1757 }
1758
1759 static HRESULT WINAPI unknode_selectNodes(
1760     IXMLDOMNode *iface,
1761     BSTR p, IXMLDOMNodeList** outList)
1762 {
1763     unknode *This = impl_from_unkIXMLDOMNode( iface );
1764     return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), p, outList );
1765 }
1766
1767 static HRESULT WINAPI unknode_selectSingleNode(
1768     IXMLDOMNode *iface,
1769     BSTR p, IXMLDOMNode** outNode)
1770 {
1771     unknode *This = impl_from_unkIXMLDOMNode( iface );
1772     return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), p, outNode );
1773 }
1774
1775 static HRESULT WINAPI unknode_get_parsed(
1776     IXMLDOMNode *iface,
1777     VARIANT_BOOL* isParsed)
1778 {
1779     unknode *This = impl_from_unkIXMLDOMNode( iface );
1780     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1781     *isParsed = VARIANT_TRUE;
1782     return S_OK;
1783 }
1784
1785 static HRESULT WINAPI unknode_get_namespaceURI(
1786     IXMLDOMNode *iface,
1787     BSTR* p)
1788 {
1789     unknode *This = impl_from_unkIXMLDOMNode( iface );
1790     return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), p );
1791 }
1792
1793 static HRESULT WINAPI unknode_get_prefix(
1794     IXMLDOMNode *iface,
1795     BSTR* p)
1796 {
1797     unknode *This = impl_from_unkIXMLDOMNode( iface );
1798     return IXMLDOMNode_get_prefix( IXMLDOMNode_from_impl(&This->node), p );
1799 }
1800
1801 static HRESULT WINAPI unknode_get_baseName(
1802     IXMLDOMNode *iface,
1803     BSTR* p)
1804 {
1805     unknode *This = impl_from_unkIXMLDOMNode( iface );
1806     return IXMLDOMNode_get_baseName( IXMLDOMNode_from_impl(&This->node), p );
1807 }
1808
1809 static HRESULT WINAPI unknode_transformNodeToObject(
1810     IXMLDOMNode *iface,
1811     IXMLDOMNode* domNode, VARIANT var1)
1812 {
1813     unknode *This = impl_from_unkIXMLDOMNode( iface );
1814     return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), domNode, var1 );
1815 }
1816
1817 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1818 {
1819     unknode_QueryInterface,
1820     unknode_AddRef,
1821     unknode_Release,
1822     unknode_GetTypeInfoCount,
1823     unknode_GetTypeInfo,
1824     unknode_GetIDsOfNames,
1825     unknode_Invoke,
1826     unknode_get_nodeName,
1827     unknode_get_nodeValue,
1828     unknode_put_nodeValue,
1829     unknode_get_nodeType,
1830     unknode_get_parentNode,
1831     unknode_get_childNodes,
1832     unknode_get_firstChild,
1833     unknode_get_lastChild,
1834     unknode_get_previousSibling,
1835     unknode_get_nextSibling,
1836     unknode_get_attributes,
1837     unknode_insertBefore,
1838     unknode_replaceChild,
1839     unknode_removeChild,
1840     unknode_appendChild,
1841     unknode_hasChildNodes,
1842     unknode_get_ownerDocument,
1843     unknode_cloneNode,
1844     unknode_get_nodeTypeString,
1845     unknode_get_text,
1846     unknode_put_text,
1847     unknode_get_specified,
1848     unknode_get_definition,
1849     unknode_get_nodeTypedValue,
1850     unknode_put_nodeTypedValue,
1851     unknode_get_dataType,
1852     unknode_put_dataType,
1853     unknode_get_xml,
1854     unknode_transformNode,
1855     unknode_selectNodes,
1856     unknode_selectSingleNode,
1857     unknode_get_parsed,
1858     unknode_get_namespaceURI,
1859     unknode_get_prefix,
1860     unknode_get_baseName,
1861     unknode_transformNodeToObject
1862 };
1863
1864 IXMLDOMNode *create_node( xmlNodePtr node )
1865 {
1866     IUnknown *pUnk;
1867     IXMLDOMNode *ret;
1868     HRESULT hr;
1869
1870     if ( !node )
1871         return NULL;
1872
1873     TRACE("type %d\n", node->type);
1874     switch(node->type)
1875     {
1876     case XML_ELEMENT_NODE:
1877         pUnk = create_element( node );
1878         break;
1879     case XML_ATTRIBUTE_NODE:
1880         pUnk = create_attribute( node );
1881         break;
1882     case XML_TEXT_NODE:
1883         pUnk = create_text( node );
1884         break;
1885     case XML_CDATA_SECTION_NODE:
1886         pUnk = create_cdata( node );
1887         break;
1888     case XML_ENTITY_REF_NODE:
1889         pUnk = create_doc_entity_ref( node );
1890         break;
1891     case XML_PI_NODE:
1892         pUnk = create_pi( node );
1893         break;
1894     case XML_COMMENT_NODE:
1895         pUnk = create_comment( node );
1896         break;
1897     case XML_DOCUMENT_NODE:
1898         pUnk = create_domdoc( node );
1899         break;
1900     case XML_DOCUMENT_FRAG_NODE:
1901         pUnk = create_doc_fragment( node );
1902         break;
1903     case XML_DTD_NODE:
1904         pUnk = create_doc_type( node );
1905         break;
1906     default: {
1907         unknode *new_node;
1908
1909         FIXME("only creating basic node for type %d\n", node->type);
1910
1911         new_node = heap_alloc(sizeof(unknode));
1912         if(!new_node)
1913             return NULL;
1914
1915         new_node->lpVtbl = &unknode_vtbl;
1916         new_node->ref = 1;
1917         init_xmlnode(&new_node->node, node, (IXMLDOMNode*)&new_node->lpVtbl, NULL);
1918         pUnk = (IUnknown*)&new_node->lpVtbl;
1919     }
1920     }
1921
1922     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1923     IUnknown_Release(pUnk);
1924     if(FAILED(hr)) return NULL;
1925     return ret;
1926 }
1927 #endif