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