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