hlink: Use ifaces instead of vtbl pointers in ExtensionService.
[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 BSTR EnsureCorrectEOL(BSTR sInput)
877 {
878     int nNum = 0;
879     BSTR sNew;
880     int nLen;
881     int i;
882
883     nLen = SysStringLen(sInput);
884     /* Count line endings */
885     for(i=0; i < nLen; i++)
886     {
887         if(sInput[i] == '\n')
888             nNum++;
889     }
890
891     TRACE("len=%d, num=%d\n", nLen, nNum);
892
893     /* Add linefeed as needed */
894     if(nNum > 0)
895     {
896         int nPlace = 0;
897         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
898         for(i=0; i < nLen; i++)
899         {
900             if(sInput[i] == '\n')
901             {
902                 sNew[i+nPlace] = '\r';
903                 nPlace++;
904             }
905             sNew[i+nPlace] = sInput[i];
906         }
907
908         SysFreeString(sInput);
909     }
910     else
911     {
912         sNew = sInput;
913     }
914
915     TRACE("len %d\n", SysStringLen(sNew));
916
917     return sNew;
918 }
919
920 /* Removes encoding information and last character (nullbyte) */
921 static BSTR EnsureNoEncoding(BSTR sInput)
922 {
923     static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
924     BSTR sNew;
925     WCHAR *pBeg, *pEnd;
926
927     pBeg = sInput;
928     while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
929         pBeg++;
930
931     if(*pBeg == '\n')
932     {
933         SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
934         return sInput;
935     }
936     pBeg--;
937
938     pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
939     while(*pEnd != '\"') pEnd++;
940     pEnd++;
941
942     sNew = SysAllocStringLen(NULL,
943             pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
944     memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
945     memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
946
947     SysFreeString(sInput);
948     return sNew;
949 }
950
951 /*
952  * We are trying to replicate the same behaviour as msxml by converting
953  * line endings to \r\n and using indents as \t. The problem is that msxml
954  * only formats nodes that have a line ending. Using libxml we cannot
955  * reproduce behaviour exactly.
956  *
957  */
958 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
959 {
960     xmlBufferPtr xml_buf;
961     xmlNodePtr xmldecl;
962     int size;
963
964     if(!ret)
965         return E_INVALIDARG;
966
967     *ret = NULL;
968
969     xml_buf = xmlBufferCreate();
970     if(!xml_buf)
971         return E_OUTOFMEMORY;
972
973     xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
974
975     size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
976     if(size > 0) {
977         const xmlChar *buf_content;
978         BSTR content;
979
980         /* Attribute Nodes return a space in front of their name */
981         buf_content = xmlBufferContent(xml_buf);
982
983         content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
984         if(ensure_eol)
985             content = EnsureCorrectEOL(content);
986         if(ensure_no_encoding)
987             content = EnsureNoEncoding(content);
988
989         *ret = content;
990     }else {
991         *ret = SysAllocStringLen(NULL, 0);
992     }
993
994     xmlBufferFree(xml_buf);
995     xmldoc_link_xmldecl( This->node->doc, xmldecl );
996     return *ret ? S_OK : E_OUTOFMEMORY;
997 }
998
999 static HRESULT WINAPI xmlnode_transformNode(
1000     IXMLDOMNode *iface,
1001     IXMLDOMNode* styleSheet,
1002     BSTR* xmlString)
1003 {
1004 #ifdef SONAME_LIBXSLT
1005     xmlnode *This = impl_from_IXMLDOMNode( iface );
1006     xmlnode *pStyleSheet = NULL;
1007     xsltStylesheetPtr xsltSS = NULL;
1008     xmlDocPtr result = NULL;
1009
1010     TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1011
1012     if (!libxslt_handle)
1013         return E_NOTIMPL;
1014     if(!styleSheet || !xmlString)
1015         return E_INVALIDARG;
1016
1017     *xmlString = NULL;
1018
1019     pStyleSheet = get_node_obj(styleSheet);
1020     if(!pStyleSheet) {
1021         FIXME("styleSheet is not our xmlnode implementation\n");
1022         return E_FAIL;
1023     }
1024
1025     xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1026     if(xsltSS)
1027     {
1028         result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1029         if(result)
1030         {
1031             const xmlChar *pContent;
1032
1033             if(result->type == XML_HTML_DOCUMENT_NODE)
1034             {
1035                 xmlOutputBufferPtr      pOutput = xmlAllocOutputBuffer(NULL);
1036                 if(pOutput)
1037                 {
1038                     htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1039                     pContent = xmlBufferContent(pOutput->buffer);
1040                     *xmlString = bstr_from_xmlChar(pContent);
1041                     xmlOutputBufferClose(pOutput);
1042                 }
1043             }
1044             else
1045             {
1046                 xmlBufferPtr pXmlBuf;
1047                 int nSize;
1048
1049                 pXmlBuf = xmlBufferCreate();
1050                 if(pXmlBuf)
1051                 {
1052                     nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1053                     if(nSize > 0)
1054                     {
1055                         pContent = xmlBufferContent(pXmlBuf);
1056                         *xmlString = bstr_from_xmlChar(pContent);
1057                     }
1058                     xmlBufferFree(pXmlBuf);
1059                 }
1060             }
1061             xmlFreeDoc(result);
1062         }
1063         /* libxslt "helpfully" frees the XML document the stylesheet was
1064            generated from, too */
1065         xsltSS->doc = NULL;
1066         pxsltFreeStylesheet(xsltSS);
1067     }
1068
1069     if(*xmlString == NULL)
1070         *xmlString = SysAllocStringLen(NULL, 0);
1071
1072     return S_OK;
1073 #else
1074     FIXME("libxslt headers were not found at compile time\n");
1075     return E_NOTIMPL;
1076 #endif
1077 }
1078
1079 static HRESULT WINAPI xmlnode_selectNodes(
1080     IXMLDOMNode *iface,
1081     BSTR queryString,
1082     IXMLDOMNodeList** resultList)
1083 {
1084     xmlnode *This = impl_from_IXMLDOMNode( iface );
1085     xmlChar* str;
1086     HRESULT hr;
1087
1088     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1089
1090     if (!queryString || !resultList) return E_INVALIDARG;
1091
1092     str = xmlChar_from_wchar(queryString);
1093     hr = queryresult_create(This->node, str, resultList);
1094     heap_free(str);
1095
1096     return hr;
1097 }
1098
1099 static HRESULT WINAPI xmlnode_selectSingleNode(
1100     IXMLDOMNode *iface,
1101     BSTR queryString,
1102     IXMLDOMNode** resultNode)
1103 {
1104     xmlnode *This = impl_from_IXMLDOMNode( iface );
1105     IXMLDOMNodeList *list;
1106     HRESULT r;
1107
1108     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1109
1110     r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1111     if(r == S_OK)
1112     {
1113         r = IXMLDOMNodeList_nextNode(list, resultNode);
1114         IXMLDOMNodeList_Release(list);
1115     }
1116     return r;
1117 }
1118
1119 static HRESULT WINAPI xmlnode_get_namespaceURI(
1120     IXMLDOMNode *iface,
1121     BSTR* namespaceURI)
1122 {
1123     xmlnode *This = impl_from_IXMLDOMNode( iface );
1124     xmlNsPtr *ns;
1125
1126     TRACE("(%p)->(%p)\n", This, namespaceURI );
1127
1128     if(!namespaceURI)
1129         return E_INVALIDARG;
1130
1131     *namespaceURI = NULL;
1132
1133     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1134     {
1135         if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1136         xmlFree(ns);
1137     }
1138
1139     TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1140
1141     return *namespaceURI ? S_OK : S_FALSE;
1142 }
1143
1144 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1145 {
1146     xmlNsPtr *ns;
1147
1148     if (!prefix) return E_INVALIDARG;
1149
1150     *prefix = NULL;
1151
1152     if ((ns = xmlGetNsList(This->node->doc, This->node)))
1153     {
1154         if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1155         xmlFree(ns);
1156     }
1157
1158     TRACE("prefix: %s\n", debugstr_w(*prefix));
1159
1160     return *prefix ? S_OK : S_FALSE;
1161 }
1162
1163 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1164 {
1165     if (!name) return E_INVALIDARG;
1166
1167     *name = bstr_from_xmlChar(This->node->name);
1168     if (!*name) return E_OUTOFMEMORY;
1169
1170     TRACE("returning %s\n", debugstr_w(*name));
1171
1172     return S_OK;
1173 }
1174
1175 static HRESULT WINAPI xmlnode_transformNodeToObject(
1176     IXMLDOMNode *iface,
1177     IXMLDOMNode* stylesheet,
1178     VARIANT outputObject)
1179 {
1180     xmlnode *This = impl_from_IXMLDOMNode( iface );
1181     FIXME("(%p)->(%p)\n", This, stylesheet);
1182     return E_NOTIMPL;
1183 }
1184
1185 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1186 {
1187     NULL,
1188     NULL,
1189     NULL,
1190     NULL,
1191     NULL,
1192     NULL,
1193     NULL,
1194     NULL,
1195     NULL,
1196     NULL,
1197     NULL,
1198     NULL,
1199     NULL,
1200     NULL,
1201     NULL,
1202     NULL,
1203     NULL,
1204     NULL,
1205     NULL,
1206     NULL,
1207     xmlnode_removeChild,
1208     xmlnode_appendChild,
1209     xmlnode_hasChildNodes,
1210     xmlnode_get_ownerDocument,
1211     NULL,
1212     NULL,
1213     xmlnode_get_text,
1214     NULL,
1215     NULL,
1216     NULL,
1217     xmlnode_get_nodeTypedValue,
1218     NULL,
1219     NULL,
1220     NULL,
1221     NULL,
1222     xmlnode_transformNode,
1223     xmlnode_selectNodes,
1224     xmlnode_selectSingleNode,
1225     NULL,
1226     xmlnode_get_namespaceURI,
1227     NULL,
1228     NULL,
1229     xmlnode_transformNodeToObject,
1230 };
1231
1232 void destroy_xmlnode(xmlnode *This)
1233 {
1234     if(This->node)
1235         xmldoc_release(This->node->doc);
1236 }
1237
1238 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1239 {
1240     if(node)
1241         xmldoc_add_ref( node->doc );
1242
1243     This->lpVtbl = &xmlnode_vtbl;
1244     This->node = node;
1245     This->iface = node_iface;
1246
1247     if(dispex_data)
1248         init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1249     else
1250         This->dispex.outer = NULL;
1251 }
1252
1253 typedef struct {
1254     xmlnode node;
1255     const IXMLDOMNodeVtbl *lpVtbl;
1256     LONG ref;
1257 } unknode;
1258
1259 static inline unknode *impl_from_unkIXMLDOMNode(IXMLDOMNode *iface)
1260 {
1261     return (unknode *)((char*)iface - FIELD_OFFSET(unknode, lpVtbl));
1262 }
1263
1264 static HRESULT WINAPI unknode_QueryInterface(
1265     IXMLDOMNode *iface,
1266     REFIID riid,
1267     void** ppvObject )
1268 {
1269     unknode *This = impl_from_unkIXMLDOMNode( iface );
1270
1271     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1272
1273     if (IsEqualGUID(riid, &IID_IUnknown)) {
1274         *ppvObject = iface;
1275     }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1276               IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1277         *ppvObject = &This->lpVtbl;
1278     }else if(node_query_interface(&This->node, riid, ppvObject)) {
1279         return *ppvObject ? S_OK : E_NOINTERFACE;
1280     }else  {
1281         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1282         *ppvObject = NULL;
1283         return E_NOINTERFACE;
1284     }
1285
1286     IUnknown_AddRef((IUnknown*)*ppvObject);
1287     return S_OK;
1288 }
1289
1290 static ULONG WINAPI unknode_AddRef(
1291     IXMLDOMNode *iface )
1292 {
1293     unknode *This = impl_from_unkIXMLDOMNode( iface );
1294
1295     return InterlockedIncrement(&This->ref);
1296 }
1297
1298 static ULONG WINAPI unknode_Release(
1299     IXMLDOMNode *iface )
1300 {
1301     unknode *This = impl_from_unkIXMLDOMNode( iface );
1302     LONG ref;
1303
1304     ref = InterlockedDecrement( &This->ref );
1305     if(!ref) {
1306         destroy_xmlnode(&This->node);
1307         heap_free(This);
1308     }
1309
1310     return ref;
1311 }
1312
1313 static HRESULT WINAPI unknode_GetTypeInfoCount(
1314     IXMLDOMNode *iface,
1315     UINT* pctinfo )
1316 {
1317     unknode *This = impl_from_unkIXMLDOMNode( iface );
1318
1319     TRACE("(%p)->(%p)\n", This, pctinfo);
1320
1321     *pctinfo = 1;
1322
1323     return S_OK;
1324 }
1325
1326 static HRESULT WINAPI unknode_GetTypeInfo(
1327     IXMLDOMNode *iface,
1328     UINT iTInfo,
1329     LCID lcid,
1330     ITypeInfo** ppTInfo )
1331 {
1332     unknode *This = impl_from_unkIXMLDOMNode( iface );
1333     HRESULT hr;
1334
1335     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1336
1337     hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1338
1339     return hr;
1340 }
1341
1342 static HRESULT WINAPI unknode_GetIDsOfNames(
1343     IXMLDOMNode *iface,
1344     REFIID riid,
1345     LPOLESTR* rgszNames,
1346     UINT cNames,
1347     LCID lcid,
1348     DISPID* rgDispId )
1349 {
1350     unknode *This = impl_from_unkIXMLDOMNode( iface );
1351
1352     ITypeInfo *typeinfo;
1353     HRESULT hr;
1354
1355     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1356           lcid, rgDispId);
1357
1358     if(!rgszNames || cNames == 0 || !rgDispId)
1359         return E_INVALIDARG;
1360
1361     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1362     if(SUCCEEDED(hr))
1363     {
1364         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1365         ITypeInfo_Release(typeinfo);
1366     }
1367
1368     return hr;
1369 }
1370
1371 static HRESULT WINAPI unknode_Invoke(
1372     IXMLDOMNode *iface,
1373     DISPID dispIdMember,
1374     REFIID riid,
1375     LCID lcid,
1376     WORD wFlags,
1377     DISPPARAMS* pDispParams,
1378     VARIANT* pVarResult,
1379     EXCEPINFO* pExcepInfo,
1380     UINT* puArgErr )
1381 {
1382     unknode *This = impl_from_unkIXMLDOMNode( iface );
1383     ITypeInfo *typeinfo;
1384     HRESULT hr;
1385
1386     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1387           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1388
1389     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1390     if(SUCCEEDED(hr))
1391     {
1392         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1393                 pVarResult, pExcepInfo, puArgErr);
1394         ITypeInfo_Release(typeinfo);
1395     }
1396
1397     return hr;
1398 }
1399
1400 static HRESULT WINAPI unknode_get_nodeName(
1401     IXMLDOMNode *iface,
1402     BSTR* p )
1403 {
1404     unknode *This = impl_from_unkIXMLDOMNode( iface );
1405
1406     FIXME("(%p)->(%p)\n", This, p);
1407
1408     return node_get_nodeName(&This->node, p);
1409 }
1410
1411 static HRESULT WINAPI unknode_get_nodeValue(
1412     IXMLDOMNode *iface,
1413     VARIANT* value)
1414 {
1415     unknode *This = impl_from_unkIXMLDOMNode( iface );
1416
1417     FIXME("(%p)->(%p)\n", This, value);
1418
1419     if(!value)
1420         return E_INVALIDARG;
1421
1422     V_VT(value) = VT_NULL;
1423     return S_FALSE;
1424 }
1425
1426 static HRESULT WINAPI unknode_put_nodeValue(
1427     IXMLDOMNode *iface,
1428     VARIANT value)
1429 {
1430     unknode *This = impl_from_unkIXMLDOMNode( iface );
1431     FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1432     return E_FAIL;
1433 }
1434
1435 static HRESULT WINAPI unknode_get_nodeType(
1436     IXMLDOMNode *iface,
1437     DOMNodeType* domNodeType )
1438 {
1439     unknode *This = impl_from_unkIXMLDOMNode( iface );
1440
1441     FIXME("(%p)->(%p)\n", This, domNodeType);
1442
1443     *domNodeType = This->node.node->type;
1444     return S_OK;
1445 }
1446
1447 static HRESULT WINAPI unknode_get_parentNode(
1448     IXMLDOMNode *iface,
1449     IXMLDOMNode** parent )
1450 {
1451     unknode *This = impl_from_unkIXMLDOMNode( iface );
1452     FIXME("(%p)->(%p)\n", This, parent);
1453     if (!parent) return E_INVALIDARG;
1454     *parent = NULL;
1455     return S_FALSE;
1456 }
1457
1458 static HRESULT WINAPI unknode_get_childNodes(
1459     IXMLDOMNode *iface,
1460     IXMLDOMNodeList** outList)
1461 {
1462     unknode *This = impl_from_unkIXMLDOMNode( iface );
1463
1464     TRACE("(%p)->(%p)\n", This, outList);
1465
1466     return node_get_child_nodes(&This->node, outList);
1467 }
1468
1469 static HRESULT WINAPI unknode_get_firstChild(
1470     IXMLDOMNode *iface,
1471     IXMLDOMNode** domNode)
1472 {
1473     unknode *This = impl_from_unkIXMLDOMNode( iface );
1474
1475     TRACE("(%p)->(%p)\n", This, domNode);
1476
1477     return node_get_first_child(&This->node, domNode);
1478 }
1479
1480 static HRESULT WINAPI unknode_get_lastChild(
1481     IXMLDOMNode *iface,
1482     IXMLDOMNode** domNode)
1483 {
1484     unknode *This = impl_from_unkIXMLDOMNode( iface );
1485
1486     TRACE("(%p)->(%p)\n", This, domNode);
1487
1488     return node_get_last_child(&This->node, domNode);
1489 }
1490
1491 static HRESULT WINAPI unknode_get_previousSibling(
1492     IXMLDOMNode *iface,
1493     IXMLDOMNode** domNode)
1494 {
1495     unknode *This = impl_from_unkIXMLDOMNode( iface );
1496
1497     TRACE("(%p)->(%p)\n", This, domNode);
1498
1499     return node_get_previous_sibling(&This->node, domNode);
1500 }
1501
1502 static HRESULT WINAPI unknode_get_nextSibling(
1503     IXMLDOMNode *iface,
1504     IXMLDOMNode** domNode)
1505 {
1506     unknode *This = impl_from_unkIXMLDOMNode( iface );
1507
1508     TRACE("(%p)->(%p)\n", This, domNode);
1509
1510     return node_get_next_sibling(&This->node, domNode);
1511 }
1512
1513 static HRESULT WINAPI unknode_get_attributes(
1514     IXMLDOMNode *iface,
1515     IXMLDOMNamedNodeMap** attributeMap)
1516 {
1517     unknode *This = impl_from_unkIXMLDOMNode( iface );
1518
1519     FIXME("(%p)->(%p)\n", This, attributeMap);
1520
1521     return return_null_ptr((void**)attributeMap);
1522 }
1523
1524 static HRESULT WINAPI unknode_insertBefore(
1525     IXMLDOMNode *iface,
1526     IXMLDOMNode* newNode, VARIANT refChild,
1527     IXMLDOMNode** outOldNode)
1528 {
1529     unknode *This = impl_from_unkIXMLDOMNode( iface );
1530
1531     FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1532
1533     return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1534 }
1535
1536 static HRESULT WINAPI unknode_replaceChild(
1537     IXMLDOMNode *iface,
1538     IXMLDOMNode* newNode,
1539     IXMLDOMNode* oldNode,
1540     IXMLDOMNode** outOldNode)
1541 {
1542     unknode *This = impl_from_unkIXMLDOMNode( iface );
1543
1544     FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1545
1546     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1547 }
1548
1549 static HRESULT WINAPI unknode_removeChild(
1550     IXMLDOMNode *iface,
1551     IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1552 {
1553     unknode *This = impl_from_unkIXMLDOMNode( iface );
1554     return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), domNode, oldNode );
1555 }
1556
1557 static HRESULT WINAPI unknode_appendChild(
1558     IXMLDOMNode *iface,
1559     IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1560 {
1561     unknode *This = impl_from_unkIXMLDOMNode( iface );
1562     return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newNode, outNewNode );
1563 }
1564
1565 static HRESULT WINAPI unknode_hasChildNodes(
1566     IXMLDOMNode *iface,
1567     VARIANT_BOOL* pbool)
1568 {
1569     unknode *This = impl_from_unkIXMLDOMNode( iface );
1570     return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), pbool );
1571 }
1572
1573 static HRESULT WINAPI unknode_get_ownerDocument(
1574     IXMLDOMNode *iface,
1575     IXMLDOMDocument** domDocument)
1576 {
1577     unknode *This = impl_from_unkIXMLDOMNode( iface );
1578     return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), domDocument );
1579 }
1580
1581 static HRESULT WINAPI unknode_cloneNode(
1582     IXMLDOMNode *iface,
1583     VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1584 {
1585     unknode *This = impl_from_unkIXMLDOMNode( iface );
1586     return IXMLDOMNode_cloneNode( IXMLDOMNode_from_impl(&This->node), pbool, outNode );
1587 }
1588
1589 static HRESULT WINAPI unknode_get_nodeTypeString(
1590     IXMLDOMNode *iface,
1591     BSTR* p)
1592 {
1593     unknode *This = impl_from_unkIXMLDOMNode( iface );
1594
1595     FIXME("(%p)->(%p)\n", This, p);
1596
1597     return node_get_nodeName(&This->node, p);
1598 }
1599
1600 static HRESULT WINAPI unknode_get_text(
1601     IXMLDOMNode *iface,
1602     BSTR* p)
1603 {
1604     unknode *This = impl_from_unkIXMLDOMNode( iface );
1605     return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), p );
1606 }
1607
1608 static HRESULT WINAPI unknode_put_text(
1609     IXMLDOMNode *iface,
1610     BSTR p)
1611 {
1612     unknode *This = impl_from_unkIXMLDOMNode( iface );
1613     return IXMLDOMNode_put_text( IXMLDOMNode_from_impl(&This->node), p );
1614 }
1615
1616 static HRESULT WINAPI unknode_get_specified(
1617     IXMLDOMNode *iface,
1618     VARIANT_BOOL* isSpecified)
1619 {
1620     unknode *This = impl_from_unkIXMLDOMNode( iface );
1621     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1622     *isSpecified = VARIANT_TRUE;
1623     return S_OK;
1624 }
1625
1626 static HRESULT WINAPI unknode_get_definition(
1627     IXMLDOMNode *iface,
1628     IXMLDOMNode** definitionNode)
1629 {
1630     unknode *This = impl_from_unkIXMLDOMNode( iface );
1631     FIXME("(%p)->(%p)\n", This, definitionNode);
1632     return E_NOTIMPL;
1633 }
1634
1635 static HRESULT WINAPI unknode_get_nodeTypedValue(
1636     IXMLDOMNode *iface,
1637     VARIANT* var1)
1638 {
1639     unknode *This = impl_from_unkIXMLDOMNode( iface );
1640     return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1641 }
1642
1643 static HRESULT WINAPI unknode_put_nodeTypedValue(
1644     IXMLDOMNode *iface,
1645     VARIANT typedValue)
1646 {
1647     unknode *This = impl_from_unkIXMLDOMNode( iface );
1648     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1649     return E_NOTIMPL;
1650 }
1651
1652 static HRESULT WINAPI unknode_get_dataType(
1653     IXMLDOMNode *iface,
1654     VARIANT* var1)
1655 {
1656     unknode *This = impl_from_unkIXMLDOMNode( iface );
1657     return IXMLDOMNode_get_dataType( IXMLDOMNode_from_impl(&This->node), var1 );
1658 }
1659
1660 static HRESULT WINAPI unknode_put_dataType(
1661     IXMLDOMNode *iface,
1662     BSTR p)
1663 {
1664     unknode *This = impl_from_unkIXMLDOMNode( iface );
1665
1666     FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1667
1668     if(!p)
1669         return E_INVALIDARG;
1670
1671     return E_FAIL;
1672 }
1673
1674 static HRESULT WINAPI unknode_get_xml(
1675     IXMLDOMNode *iface,
1676     BSTR* p)
1677 {
1678     unknode *This = impl_from_unkIXMLDOMNode( iface );
1679
1680     FIXME("(%p)->(%p)\n", This, p);
1681
1682     return node_get_xml(&This->node, FALSE, FALSE, p);
1683 }
1684
1685 static HRESULT WINAPI unknode_transformNode(
1686     IXMLDOMNode *iface,
1687     IXMLDOMNode* domNode, BSTR* p)
1688 {
1689     unknode *This = impl_from_unkIXMLDOMNode( iface );
1690     return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), domNode, p );
1691 }
1692
1693 static HRESULT WINAPI unknode_selectNodes(
1694     IXMLDOMNode *iface,
1695     BSTR p, IXMLDOMNodeList** outList)
1696 {
1697     unknode *This = impl_from_unkIXMLDOMNode( iface );
1698     return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), p, outList );
1699 }
1700
1701 static HRESULT WINAPI unknode_selectSingleNode(
1702     IXMLDOMNode *iface,
1703     BSTR p, IXMLDOMNode** outNode)
1704 {
1705     unknode *This = impl_from_unkIXMLDOMNode( iface );
1706     return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), p, outNode );
1707 }
1708
1709 static HRESULT WINAPI unknode_get_parsed(
1710     IXMLDOMNode *iface,
1711     VARIANT_BOOL* isParsed)
1712 {
1713     unknode *This = impl_from_unkIXMLDOMNode( iface );
1714     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1715     *isParsed = VARIANT_TRUE;
1716     return S_OK;
1717 }
1718
1719 static HRESULT WINAPI unknode_get_namespaceURI(
1720     IXMLDOMNode *iface,
1721     BSTR* p)
1722 {
1723     unknode *This = impl_from_unkIXMLDOMNode( iface );
1724     return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), p );
1725 }
1726
1727 static HRESULT WINAPI unknode_get_prefix(
1728     IXMLDOMNode *iface,
1729     BSTR* p)
1730 {
1731     unknode *This = impl_from_unkIXMLDOMNode( iface );
1732     return IXMLDOMNode_get_prefix( IXMLDOMNode_from_impl(&This->node), p );
1733 }
1734
1735 static HRESULT WINAPI unknode_get_baseName(
1736     IXMLDOMNode *iface,
1737     BSTR* p)
1738 {
1739     unknode *This = impl_from_unkIXMLDOMNode( iface );
1740     return IXMLDOMNode_get_baseName( IXMLDOMNode_from_impl(&This->node), p );
1741 }
1742
1743 static HRESULT WINAPI unknode_transformNodeToObject(
1744     IXMLDOMNode *iface,
1745     IXMLDOMNode* domNode, VARIANT var1)
1746 {
1747     unknode *This = impl_from_unkIXMLDOMNode( iface );
1748     return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), domNode, var1 );
1749 }
1750
1751 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1752 {
1753     unknode_QueryInterface,
1754     unknode_AddRef,
1755     unknode_Release,
1756     unknode_GetTypeInfoCount,
1757     unknode_GetTypeInfo,
1758     unknode_GetIDsOfNames,
1759     unknode_Invoke,
1760     unknode_get_nodeName,
1761     unknode_get_nodeValue,
1762     unknode_put_nodeValue,
1763     unknode_get_nodeType,
1764     unknode_get_parentNode,
1765     unknode_get_childNodes,
1766     unknode_get_firstChild,
1767     unknode_get_lastChild,
1768     unknode_get_previousSibling,
1769     unknode_get_nextSibling,
1770     unknode_get_attributes,
1771     unknode_insertBefore,
1772     unknode_replaceChild,
1773     unknode_removeChild,
1774     unknode_appendChild,
1775     unknode_hasChildNodes,
1776     unknode_get_ownerDocument,
1777     unknode_cloneNode,
1778     unknode_get_nodeTypeString,
1779     unknode_get_text,
1780     unknode_put_text,
1781     unknode_get_specified,
1782     unknode_get_definition,
1783     unknode_get_nodeTypedValue,
1784     unknode_put_nodeTypedValue,
1785     unknode_get_dataType,
1786     unknode_put_dataType,
1787     unknode_get_xml,
1788     unknode_transformNode,
1789     unknode_selectNodes,
1790     unknode_selectSingleNode,
1791     unknode_get_parsed,
1792     unknode_get_namespaceURI,
1793     unknode_get_prefix,
1794     unknode_get_baseName,
1795     unknode_transformNodeToObject
1796 };
1797
1798 IXMLDOMNode *create_node( xmlNodePtr node )
1799 {
1800     IUnknown *pUnk;
1801     IXMLDOMNode *ret;
1802     HRESULT hr;
1803
1804     if ( !node )
1805         return NULL;
1806
1807     TRACE("type %d\n", node->type);
1808     switch(node->type)
1809     {
1810     case XML_ELEMENT_NODE:
1811         pUnk = create_element( node );
1812         break;
1813     case XML_ATTRIBUTE_NODE:
1814         pUnk = create_attribute( node );
1815         break;
1816     case XML_TEXT_NODE:
1817         pUnk = create_text( node );
1818         break;
1819     case XML_CDATA_SECTION_NODE:
1820         pUnk = create_cdata( node );
1821         break;
1822     case XML_ENTITY_REF_NODE:
1823         pUnk = create_doc_entity_ref( node );
1824         break;
1825     case XML_PI_NODE:
1826         pUnk = create_pi( node );
1827         break;
1828     case XML_COMMENT_NODE:
1829         pUnk = create_comment( node );
1830         break;
1831     case XML_DOCUMENT_NODE:
1832         pUnk = create_domdoc( node );
1833         break;
1834     case XML_DOCUMENT_FRAG_NODE:
1835         pUnk = create_doc_fragment( node );
1836         break;
1837     case XML_DTD_NODE:
1838         pUnk = create_doc_type( node );
1839         break;
1840     default: {
1841         unknode *new_node;
1842
1843         FIXME("only creating basic node for type %d\n", node->type);
1844
1845         new_node = heap_alloc(sizeof(unknode));
1846         if(!new_node)
1847             return NULL;
1848
1849         new_node->lpVtbl = &unknode_vtbl;
1850         new_node->ref = 1;
1851         init_xmlnode(&new_node->node, node, (IXMLDOMNode*)&new_node->lpVtbl, NULL);
1852         pUnk = (IUnknown*)&new_node->lpVtbl;
1853     }
1854     }
1855
1856     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1857     IUnknown_Release(pUnk);
1858     if(FAILED(hr)) return NULL;
1859     return ret;
1860 }
1861 #endif