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