msxml3: Optimize bstr_from_xmlChar implementation.
[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 "msxml2.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 inline xmlnode *impl_from_InternalUnknown( IUnknown *iface )
70 {
71     return (xmlnode *)((char*)iface - FIELD_OFFSET(xmlnode, lpInternalUnkVtbl));
72 }
73
74 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
75 {
76     xmlnode *This;
77
78     if ( !iface )
79         return NULL;
80     This = impl_from_IXMLDOMNode( iface );
81     if ( !This->node )
82         return NULL;
83     if ( type && This->node->type != type )
84         return NULL;
85     return This->node;
86 }
87
88 static HRESULT WINAPI xmlnode_QueryInterface(
89     IXMLDOMNode *iface,
90     REFIID riid,
91     void** ppvObject )
92 {
93     xmlnode *This = impl_from_IXMLDOMNode( iface );
94     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
95
96     return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
97 }
98
99 static ULONG WINAPI xmlnode_AddRef(
100     IXMLDOMNode *iface )
101 {
102     xmlnode *This = impl_from_IXMLDOMNode( iface );
103     return IUnknown_AddRef(This->pUnkOuter);
104 }
105
106 static ULONG WINAPI xmlnode_Release(
107     IXMLDOMNode *iface )
108 {
109     xmlnode *This = impl_from_IXMLDOMNode( iface );
110     return IUnknown_Release(This->pUnkOuter);
111 }
112
113 static HRESULT WINAPI xmlnode_GetTypeInfoCount(
114     IXMLDOMNode *iface,
115     UINT* pctinfo )
116 {
117     xmlnode *This = impl_from_IXMLDOMNode( iface );
118
119     TRACE("(%p)->(%p)\n", This, pctinfo);
120
121     *pctinfo = 1;
122
123     return S_OK;
124 }
125
126 static HRESULT WINAPI xmlnode_GetTypeInfo(
127     IXMLDOMNode *iface,
128     UINT iTInfo,
129     LCID lcid,
130     ITypeInfo** ppTInfo )
131 {
132     xmlnode *This = impl_from_IXMLDOMNode( iface );
133     HRESULT hr;
134
135     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
136
137     hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
138
139     return hr;
140 }
141
142 static HRESULT WINAPI xmlnode_GetIDsOfNames(
143     IXMLDOMNode *iface,
144     REFIID riid,
145     LPOLESTR* rgszNames,
146     UINT cNames,
147     LCID lcid,
148     DISPID* rgDispId )
149 {
150     xmlnode *This = impl_from_IXMLDOMNode( iface );
151
152     ITypeInfo *typeinfo;
153     HRESULT hr;
154
155     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
156           lcid, rgDispId);
157
158     if(!rgszNames || cNames == 0 || !rgDispId)
159         return E_INVALIDARG;
160
161     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
162     if(SUCCEEDED(hr))
163     {
164         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
165         ITypeInfo_Release(typeinfo);
166     }
167
168     return hr;
169 }
170
171 static HRESULT WINAPI xmlnode_Invoke(
172     IXMLDOMNode *iface,
173     DISPID dispIdMember,
174     REFIID riid,
175     LCID lcid,
176     WORD wFlags,
177     DISPPARAMS* pDispParams,
178     VARIANT* pVarResult,
179     EXCEPINFO* pExcepInfo,
180     UINT* puArgErr )
181 {
182     xmlnode *This = impl_from_IXMLDOMNode( iface );
183     ITypeInfo *typeinfo;
184     HRESULT hr;
185
186     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
187           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
188
189     hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
190     if(SUCCEEDED(hr))
191     {
192         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
193                 pVarResult, pExcepInfo, puArgErr);
194         ITypeInfo_Release(typeinfo);
195     }
196
197     return hr;
198 }
199
200 static HRESULT WINAPI xmlnode_get_nodeName(
201     IXMLDOMNode *iface,
202     BSTR* name)
203 {
204     xmlnode *This = impl_from_IXMLDOMNode( iface );
205     const xmlChar *str;
206
207     TRACE("%p\n", This );
208
209     if (!name)
210         return E_INVALIDARG;
211
212     if ( !This->node )
213         return E_FAIL;
214
215     switch( This->node->type )
216     {
217     case XML_CDATA_SECTION_NODE:
218         str = (const xmlChar*) "#cdata-section";
219         break;
220     case XML_COMMENT_NODE:
221         str = (const xmlChar*) "#comment";
222         break;
223     case XML_DOCUMENT_FRAG_NODE:
224         str = (const xmlChar*) "#document-fragment";
225         break;
226     case XML_TEXT_NODE:
227          str = (const xmlChar*) "#text";
228          break;
229     case XML_DOCUMENT_NODE:
230          str = (const xmlChar*) "#document";
231             break;
232         case XML_ATTRIBUTE_NODE:
233         case XML_ELEMENT_NODE:
234         case XML_PI_NODE:
235         str = This->node->name;
236             break;
237     default:
238         FIXME("nodeName not mapped correctly (%d)\n", This->node->type);
239         str = This->node->name;
240         break;
241     }
242
243     *name = bstr_from_xmlChar( str );
244     if (!*name)
245         return S_FALSE;
246
247     return S_OK;
248 }
249
250 static HRESULT WINAPI xmlnode_get_nodeValue(
251     IXMLDOMNode *iface,
252     VARIANT* value)
253 {
254     xmlnode *This = impl_from_IXMLDOMNode( iface );
255     HRESULT r = S_FALSE;
256
257     TRACE("%p %p\n", This, value);
258
259     if(!value)
260         return E_INVALIDARG;
261
262     V_BSTR(value) = NULL;
263     V_VT(value) = VT_NULL;
264
265     switch ( This->node->type )
266     {
267     case XML_CDATA_SECTION_NODE:
268     case XML_COMMENT_NODE:
269     case XML_PI_NODE:
270     case XML_ATTRIBUTE_NODE:
271       {
272         xmlChar *content = xmlNodeGetContent(This->node);
273         V_VT(value) = VT_BSTR;
274         V_BSTR(value) = bstr_from_xmlChar( content );
275         xmlFree(content);
276         r = S_OK;
277         break;
278       }
279     case XML_TEXT_NODE:
280         V_VT(value) = VT_BSTR;
281         V_BSTR(value) = bstr_from_xmlChar( This->node->content );
282         r = S_OK;
283         break;
284     case XML_ELEMENT_NODE:
285     case XML_DOCUMENT_NODE:
286         /* these seem to return NULL */
287         break;
288
289     default:
290         FIXME("node %p type %d\n", This, This->node->type);
291     }
292  
293     TRACE("%p returned %s\n", This, debugstr_w( V_BSTR(value) ) );
294
295     return r;
296 }
297
298 static HRESULT WINAPI xmlnode_put_nodeValue(
299     IXMLDOMNode *iface,
300     VARIANT value)
301 {
302     xmlnode *This = impl_from_IXMLDOMNode( iface );
303     HRESULT hr;
304     xmlChar *str = NULL;
305     VARIANT string_value;
306
307     TRACE("%p type(%d)\n", This, This->node->type);
308
309     VariantInit(&string_value);
310     hr = VariantChangeType(&string_value, &value, 0, VT_BSTR);
311     if(FAILED(hr))
312     {
313         VariantClear(&string_value);
314         WARN("Couldn't convert to VT_BSTR\n");
315         return hr;
316     }
317
318     hr = S_FALSE;
319     /* Document, Document Fragment, Document Type, Element,
320         Entity, Entity Reference, Notation aren't supported. */
321     switch ( This->node->type )
322     {
323     case XML_ATTRIBUTE_NODE:
324     case XML_CDATA_SECTION_NODE:
325     case XML_COMMENT_NODE:
326     case XML_PI_NODE:
327     case XML_TEXT_NODE:
328       {
329         str = xmlChar_from_wchar(V_BSTR(&string_value));
330         xmlNodeSetContent(This->node, str);
331         HeapFree(GetProcessHeap(),0,str);
332         hr = S_OK;
333         break;
334       }
335     default:
336         /* Do nothing for unsupported types. */
337         break;
338     }
339
340     VariantClear(&string_value);
341
342     return hr;
343 }
344
345 static HRESULT WINAPI xmlnode_get_nodeType(
346     IXMLDOMNode *iface,
347     DOMNodeType* type)
348 {
349     xmlnode *This = impl_from_IXMLDOMNode( iface );
350
351     TRACE("%p %p\n", This, type);
352
353     assert( (int)NODE_ELEMENT  == (int)XML_ELEMENT_NODE );
354     assert( (int)NODE_NOTATION == (int)XML_NOTATION_NODE );
355
356     *type = This->node->type;
357
358     return S_OK;
359 }
360
361 static HRESULT get_node(
362     xmlnode *This,
363     const char *name,
364     xmlNodePtr node,
365     IXMLDOMNode **out )
366 {
367     TRACE("%p->%s %p\n", This, name, node );
368
369     if ( !out )
370         return E_INVALIDARG;
371
372     /* if we don't have a doc, use our parent. */
373     if(node && !node->doc && node->parent)
374         node->doc = node->parent->doc;
375
376     *out = create_node( node );
377     if (!*out)
378         return S_FALSE;
379     return S_OK;
380 }
381
382 static HRESULT WINAPI xmlnode_get_parentNode(
383     IXMLDOMNode *iface,
384     IXMLDOMNode** parent)
385 {
386     xmlnode *This = impl_from_IXMLDOMNode( iface );
387     return get_node( This, "parent", This->node->parent, parent );
388 }
389
390 static HRESULT WINAPI xmlnode_get_childNodes(
391     IXMLDOMNode *iface,
392     IXMLDOMNodeList** childList)
393 {
394     xmlnode *This = impl_from_IXMLDOMNode( iface );
395
396     TRACE("%p %p\n", This, childList );
397
398     if ( !childList )
399         return E_INVALIDARG;
400
401     *childList = create_children_nodelist(This->node);
402     if (*childList == NULL)
403         return E_OUTOFMEMORY;
404
405     return S_OK;
406 }
407
408 static HRESULT WINAPI xmlnode_get_firstChild(
409     IXMLDOMNode *iface,
410     IXMLDOMNode** firstChild)
411 {
412     xmlnode *This = impl_from_IXMLDOMNode( iface );
413     return get_node( This, "firstChild", This->node->children, firstChild );
414 }
415
416 static HRESULT WINAPI xmlnode_get_lastChild(
417     IXMLDOMNode *iface,
418     IXMLDOMNode** lastChild)
419 {
420     xmlnode *This = impl_from_IXMLDOMNode( iface );
421
422     TRACE("%p\n", This );
423
424     if (!lastChild)
425         return E_INVALIDARG;
426
427     switch( This->node->type )
428     {
429     /* CDATASection, Comment, PI and Text Nodes do not support lastChild */
430     case XML_TEXT_NODE:
431     case XML_CDATA_SECTION_NODE:
432     case XML_PI_NODE:
433     case XML_COMMENT_NODE:
434         *lastChild = NULL;
435         return S_FALSE;
436     default:
437         return get_node( This, "lastChild", This->node->last, lastChild );
438     }
439 }
440
441 static HRESULT WINAPI xmlnode_get_previousSibling(
442     IXMLDOMNode *iface,
443     IXMLDOMNode** previousSibling)
444 {
445     xmlnode *This = impl_from_IXMLDOMNode( iface );
446
447     TRACE("%p\n", This );
448
449     if (!previousSibling)
450         return E_INVALIDARG;
451
452     switch( This->node->type )
453     {
454     /* Attribute, Document and Document Fragment Nodes do not support previousSibling */
455     case XML_DOCUMENT_NODE:
456     case XML_DOCUMENT_FRAG_NODE:
457     case XML_ATTRIBUTE_NODE:
458         *previousSibling = NULL;
459         return S_FALSE;
460     default:
461         return get_node( This, "previous", This->node->prev, previousSibling );
462     }
463 }
464
465 static HRESULT WINAPI xmlnode_get_nextSibling(
466     IXMLDOMNode *iface,
467     IXMLDOMNode** nextSibling)
468 {
469     xmlnode *This = impl_from_IXMLDOMNode( iface );
470
471     TRACE("%p\n", This );
472
473     if (!nextSibling)
474         return E_INVALIDARG;
475
476     switch( This->node->type )
477     {
478     /* Attribute, Document and Document Fragment Nodes do not support nextSibling */
479     case XML_DOCUMENT_NODE:
480     case XML_DOCUMENT_FRAG_NODE:
481     case XML_ATTRIBUTE_NODE:
482         *nextSibling = NULL;
483         return S_FALSE;
484     default:
485         return get_node( This, "next", This->node->next, nextSibling );
486     }
487 }
488
489 static HRESULT WINAPI xmlnode_get_attributes(
490     IXMLDOMNode *iface,
491     IXMLDOMNamedNodeMap** attributeMap)
492 {
493     xmlnode *This = impl_from_IXMLDOMNode( iface );
494     TRACE("%p\n", This);
495
496     if (!attributeMap)
497         return E_INVALIDARG;
498
499     switch( This->node->type )
500     {
501     /* Attribute, CDataSection, Comment, Documents, Documents Fragments,
502        Entity and Text Nodes does not support get_attributes */
503     case XML_ATTRIBUTE_NODE:
504     case XML_CDATA_SECTION_NODE:
505     case XML_COMMENT_NODE:
506     case XML_DOCUMENT_NODE:
507     case XML_DOCUMENT_FRAG_NODE:
508     case XML_ENTITY_NODE:
509     case XML_ENTITY_REF_NODE:
510     case XML_TEXT_NODE:
511         *attributeMap = NULL;
512         return S_FALSE;
513     default:
514         *attributeMap = create_nodemap( iface );
515         return S_OK;
516     }
517 }
518
519 static HRESULT WINAPI xmlnode_insertBefore(
520     IXMLDOMNode *iface,
521     IXMLDOMNode* newChild,
522     VARIANT refChild,
523     IXMLDOMNode** outNewChild)
524 {
525     xmlnode *This = impl_from_IXMLDOMNode( iface );
526     xmlNodePtr before_node, new_child_node;
527     IXMLDOMNode *before = NULL, *new;
528     HRESULT hr;
529
530     TRACE("(%p)->(%p,var,%p)\n",This,newChild,outNewChild);
531
532     if (!newChild)
533         return E_INVALIDARG;
534
535     switch(V_VT(&refChild))
536     {
537     case VT_EMPTY:
538     case VT_NULL:
539         break;
540
541     case VT_UNKNOWN:
542         hr = IUnknown_QueryInterface(V_UNKNOWN(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
543         if(FAILED(hr)) return hr;
544         break;
545
546     case VT_DISPATCH:
547         hr = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
548         if(FAILED(hr)) return hr;
549         break;
550
551     default:
552         FIXME("refChild var type %x\n", V_VT(&refChild));
553         return E_FAIL;
554     }
555
556     IXMLDOMNode_QueryInterface(newChild, &IID_IXMLDOMNode, (LPVOID)&new);
557     new_child_node = impl_from_IXMLDOMNode(new)->node;
558     TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
559
560     if(!new_child_node->parent)
561         if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
562             WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
563
564     if(before)
565     {
566         before_node = impl_from_IXMLDOMNode(before)->node;
567         xmlAddPrevSibling(before_node, new_child_node);
568         IXMLDOMNode_Release(before);
569     }
570     else
571     {
572         xmlAddChild(This->node, new_child_node);
573     }
574
575     IXMLDOMNode_Release(new);
576     IXMLDOMNode_AddRef(newChild);
577     if(outNewChild)
578         *outNewChild = newChild;
579
580     TRACE("ret S_OK\n");
581     return S_OK;
582 }
583
584 static HRESULT WINAPI xmlnode_replaceChild(
585     IXMLDOMNode *iface,
586     IXMLDOMNode* newChild,
587     IXMLDOMNode* oldChild,
588     IXMLDOMNode** outOldChild)
589 {
590     xmlnode *This = impl_from_IXMLDOMNode( iface );
591     xmlNode *old_child_ptr, *new_child_ptr;
592     xmlDocPtr leaving_doc;
593     xmlNode *my_ancestor;
594     IXMLDOMNode *realOldChild;
595     HRESULT hr;
596
597     TRACE("%p->(%p,%p,%p)\n",This,newChild,oldChild,outOldChild);
598
599     /* Do not believe any documentation telling that newChild == NULL
600        means removal. It does certainly *not* apply to msxml3! */
601     if(!newChild || !oldChild)
602         return E_INVALIDARG;
603
604     if(outOldChild)
605         *outOldChild = NULL;
606
607     hr = IXMLDOMNode_QueryInterface(oldChild,&IID_IXMLDOMNode,(LPVOID*)&realOldChild);
608     if(FAILED(hr))
609         return hr;
610
611     old_child_ptr = impl_from_IXMLDOMNode(realOldChild)->node;
612     IXMLDOMNode_Release(realOldChild);
613     if(old_child_ptr->parent != This->node)
614     {
615         WARN("childNode %p is not a child of %p\n", oldChild, iface);
616         return E_INVALIDARG;
617     }
618
619     new_child_ptr = impl_from_IXMLDOMNode(newChild)->node;
620     my_ancestor = This->node;
621     while(my_ancestor)
622     {
623         if(my_ancestor == new_child_ptr)
624         {
625             WARN("tried to create loop\n");
626             return E_FAIL;
627         }
628         my_ancestor = my_ancestor->parent;
629     }
630
631     if(!new_child_ptr->parent)
632         if(xmldoc_remove_orphan(new_child_ptr->doc, new_child_ptr) != S_OK)
633             WARN("%p is not an orphan of %p\n", new_child_ptr, new_child_ptr->doc);
634
635     leaving_doc = new_child_ptr->doc;
636     xmldoc_add_ref(old_child_ptr->doc);
637     xmlReplaceNode(old_child_ptr, new_child_ptr);
638     xmldoc_release(leaving_doc);
639
640     xmldoc_add_orphan(old_child_ptr->doc, old_child_ptr);
641
642     if(outOldChild)
643     {
644         IXMLDOMNode_AddRef(oldChild);
645         *outOldChild = oldChild;
646     }
647
648     return S_OK;
649 }
650
651 static HRESULT WINAPI xmlnode_removeChild(
652     IXMLDOMNode *iface,
653     IXMLDOMNode* childNode,
654     IXMLDOMNode** oldChild)
655 {
656     xmlnode *This = impl_from_IXMLDOMNode( iface );
657     xmlNode *child_node_ptr;
658     HRESULT hr;
659     IXMLDOMNode *child;
660
661     TRACE("%p->(%p, %p)\n", This, childNode, oldChild);
662
663     if(!childNode) return E_INVALIDARG;
664
665     if(oldChild)
666         *oldChild = NULL;
667
668     hr = IXMLDOMNode_QueryInterface(childNode, &IID_IXMLDOMNode, (LPVOID)&child);
669     if(FAILED(hr))
670         return hr;
671
672     child_node_ptr = impl_from_IXMLDOMNode(child)->node;
673     if(child_node_ptr->parent != This->node)
674     {
675         WARN("childNode %p is not a child of %p\n", childNode, iface);
676         IXMLDOMNode_Release(child);
677         return E_INVALIDARG;
678     }
679
680     xmlUnlinkNode(child_node_ptr);
681
682     IXMLDOMNode_Release(child);
683
684     if(oldChild)
685     {
686         IXMLDOMNode_AddRef(childNode);
687         *oldChild = childNode;
688     }
689
690     return S_OK;
691 }
692
693 static HRESULT WINAPI xmlnode_appendChild(
694     IXMLDOMNode *iface,
695     IXMLDOMNode* newChild,
696     IXMLDOMNode** outNewChild)
697 {
698     xmlnode *This = impl_from_IXMLDOMNode( iface );
699     DOMNodeType type;
700     VARIANT var;
701     HRESULT hr;
702
703     TRACE("(%p)->(%p,%p)\n", This, newChild, outNewChild);
704
705     hr = IXMLDOMNode_get_nodeType(newChild, &type);
706     if(FAILED(hr) || type == NODE_ATTRIBUTE) {
707         if(outNewChild) *outNewChild = NULL;
708         return E_FAIL;
709     }
710
711     VariantInit(&var);
712     return IXMLDOMNode_insertBefore(iface, newChild, var, outNewChild);
713 }
714
715 static HRESULT WINAPI xmlnode_hasChildNodes(
716     IXMLDOMNode *iface,
717     VARIANT_BOOL* hasChild)
718 {
719     xmlnode *This = impl_from_IXMLDOMNode( iface );
720
721     TRACE("%p\n", This);
722
723     if (!hasChild)
724         return E_INVALIDARG;
725     if (!This->node->children)
726     {
727         *hasChild = VARIANT_FALSE;
728         return S_FALSE;
729     }
730
731     *hasChild = VARIANT_TRUE;
732     return S_OK;
733 }
734
735 static HRESULT WINAPI xmlnode_get_ownerDocument(
736     IXMLDOMNode *iface,
737     IXMLDOMDocument** DOMDocument)
738 {
739     xmlnode *This = impl_from_IXMLDOMNode( iface );
740
741     TRACE("%p (%p)\n", This, DOMDocument);
742
743     return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument2**)DOMDocument);
744 }
745
746 static HRESULT WINAPI xmlnode_cloneNode(
747     IXMLDOMNode *iface,
748     VARIANT_BOOL deep,
749     IXMLDOMNode** cloneRoot)
750 {
751     xmlnode *This = impl_from_IXMLDOMNode( iface );
752     xmlNodePtr pClone = NULL;
753     IXMLDOMNode *pNode = NULL;
754
755     TRACE("%p (%d)\n", This, deep);
756
757     if(!cloneRoot)
758         return E_INVALIDARG;
759
760     pClone = xmlCopyNode(This->node, deep ? 1 : 2);
761     if(pClone)
762     {
763         pClone->doc = This->node->doc;
764         xmldoc_add_orphan(pClone->doc, pClone);
765
766         pNode = create_node(pClone);
767         if(!pNode)
768         {
769             ERR("Copy failed\n");
770             return E_FAIL;
771         }
772
773         *cloneRoot = pNode;
774     }
775     else
776     {
777         ERR("Copy failed\n");
778         return E_FAIL;
779     }
780
781     return S_OK;
782 }
783
784 static HRESULT WINAPI xmlnode_get_nodeTypeString(
785     IXMLDOMNode *iface,
786     BSTR* xmlnodeType)
787 {
788     xmlnode *This = impl_from_IXMLDOMNode( iface );
789     const xmlChar *str;
790
791     TRACE("%p\n", This );
792
793     if (!xmlnodeType)
794         return E_INVALIDARG;
795
796     if ( !This->node )
797         return E_FAIL;
798
799     switch( This->node->type )
800     {
801     case XML_ATTRIBUTE_NODE:
802         str = (const xmlChar*) "attribute";
803         break;
804     case XML_CDATA_SECTION_NODE:
805         str = (const xmlChar*) "cdatasection";
806         break;
807     case XML_COMMENT_NODE:
808         str = (const xmlChar*) "comment";
809         break;
810     case XML_DOCUMENT_NODE:
811         str = (const xmlChar*) "document";
812         break;
813     case XML_DOCUMENT_FRAG_NODE:
814         str = (const xmlChar*) "documentfragment";
815         break;
816     case XML_ELEMENT_NODE:
817         str = (const xmlChar*) "element";
818         break;
819     case XML_ENTITY_NODE:
820         str = (const xmlChar*) "entity";
821         break;
822     case XML_ENTITY_REF_NODE:
823         str = (const xmlChar*) "entityreference";
824         break;
825     case XML_NOTATION_NODE:
826         str = (const xmlChar*) "notation";
827         break;
828     case XML_PI_NODE:
829         str = (const xmlChar*) "processinginstruction";
830         break;
831     case XML_TEXT_NODE:
832         str = (const xmlChar*) "text";
833         break;
834     default:
835         FIXME("Unknown node type (%d)\n", This->node->type);
836         str = This->node->name;
837         break;
838     }
839
840     *xmlnodeType = bstr_from_xmlChar( str );
841     if (!*xmlnodeType)
842         return S_FALSE;
843
844     return S_OK;
845 }
846
847 static HRESULT WINAPI xmlnode_get_text(
848     IXMLDOMNode *iface,
849     BSTR* text)
850 {
851     xmlnode *This = impl_from_IXMLDOMNode( iface );
852     BSTR str = NULL;
853     xmlChar *pContent;
854
855     TRACE("%p type %d\n", This, This->node->type);
856
857     if ( !text )
858         return E_INVALIDARG;
859
860     pContent = xmlNodeGetContent((xmlNodePtr)This->node);
861     if(pContent)
862     {
863         str = bstr_from_xmlChar(pContent);
864         xmlFree(pContent);
865     }
866
867     /* Always return a string. */
868     if (!str) str = SysAllocStringLen( NULL, 0 );
869
870     TRACE("%p %s\n", This, debugstr_w(str) );
871     *text = str;
872  
873     return S_OK;
874 }
875
876 static HRESULT WINAPI xmlnode_put_text(
877     IXMLDOMNode *iface,
878     BSTR text)
879 {
880     xmlnode *This = impl_from_IXMLDOMNode( iface );
881     xmlChar *str, *str2;
882
883     TRACE("%p\n", This);
884
885     switch(This->node->type)
886     {
887     case XML_DOCUMENT_NODE:
888         return E_FAIL;
889     default:
890         break;
891     }
892
893     str = xmlChar_from_wchar(text);
894
895     /* Escape the string. */
896     str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
897     HeapFree(GetProcessHeap(), 0, str);
898
899     xmlNodeSetContent(This->node, str2);
900     xmlFree(str2);
901
902     return S_OK;
903 }
904
905 static HRESULT WINAPI xmlnode_get_specified(
906     IXMLDOMNode *iface,
907     VARIANT_BOOL* isSpecified)
908 {
909     FIXME("\n");
910     return E_NOTIMPL;
911 }
912
913 static HRESULT WINAPI xmlnode_get_definition(
914     IXMLDOMNode *iface,
915     IXMLDOMNode** definitionNode)
916 {
917     FIXME("\n");
918     return E_NOTIMPL;
919 }
920
921 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
922     IXMLDOMNode *iface,
923     VARIANT* typedValue)
924 {
925     xmlnode *This = impl_from_IXMLDOMNode( iface );
926     HRESULT r = S_FALSE;
927
928     FIXME("ignoring data type %p %p\n", This, typedValue);
929
930     if(!typedValue)
931         return E_INVALIDARG;
932
933     V_VT(typedValue) = VT_NULL;
934
935     switch ( This->node->type )
936     {
937     case XML_ELEMENT_NODE:
938     {
939         xmlChar *content = xmlNodeGetContent(This->node);
940         V_VT(typedValue) = VT_BSTR;
941         V_BSTR(typedValue) = bstr_from_xmlChar( content );
942         xmlFree(content);
943         r = S_OK;
944         break;
945     }
946     default:
947         r = xmlnode_get_nodeValue(iface, typedValue);
948     }
949
950     return r;
951 }
952
953 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
954     IXMLDOMNode *iface,
955     VARIANT typedValue)
956 {
957     FIXME("\n");
958     return E_NOTIMPL;
959 }
960
961 static HRESULT WINAPI xmlnode_get_dataType(
962     IXMLDOMNode *iface,
963     VARIANT* dataTypeName)
964 {
965     xmlnode *This = impl_from_IXMLDOMNode( iface );
966     xmlChar *pVal;
967
968     TRACE("iface %p\n", iface);
969
970     if(!dataTypeName)
971         return E_INVALIDARG;
972
973     /* Attribute, CDATA Section, Comment, Document, Document Fragment,
974         Entity, Notation, PI, and Text Node are non-typed. */
975     V_BSTR(dataTypeName) = NULL;
976     V_VT(dataTypeName) = VT_NULL;
977
978     switch ( This->node->type )
979     {
980     case XML_ELEMENT_NODE:
981         pVal = xmlGetNsProp(This->node, (xmlChar*)"dt",
982                             (xmlChar*)"urn:schemas-microsoft-com:datatypes");
983         if (pVal)
984         {
985             V_VT(dataTypeName) = VT_BSTR;
986             V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
987             xmlFree(pVal);
988         }
989         break;
990     case XML_ENTITY_REF_NODE:
991         FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
992         break;
993     default:
994         TRACE("Type %d returning NULL\n", This->node->type);
995     }
996
997     /* non-typed nodes return S_FALSE */
998     if(V_VT(dataTypeName) == VT_NULL)
999     {
1000         return S_FALSE;
1001     }
1002
1003     return S_OK;
1004 }
1005
1006 static HRESULT WINAPI xmlnode_put_dataType(
1007     IXMLDOMNode *iface,
1008     BSTR dataTypeName)
1009 {
1010     xmlnode *This = impl_from_IXMLDOMNode( iface );
1011     HRESULT hr = E_FAIL;
1012
1013     TRACE("iface %p\n", iface);
1014
1015     if(dataTypeName == NULL)
1016         return E_INVALIDARG;
1017
1018     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1019        This applies to changing types (string->bool) or setting a new one
1020      */
1021     FIXME("Need to Validate the data before allowing a type to be set.\n");
1022
1023     /* Check all supported types. */
1024     if(lstrcmpiW(dataTypeName,szString) == 0  ||
1025        lstrcmpiW(dataTypeName,szNumber) == 0  ||
1026        lstrcmpiW(dataTypeName,szUUID) == 0    ||
1027        lstrcmpiW(dataTypeName,szInt) == 0     ||
1028        lstrcmpiW(dataTypeName,szI4) == 0      ||
1029        lstrcmpiW(dataTypeName,szFixed) == 0   ||
1030        lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1031        lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1032        lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1033        lstrcmpiW(dataTypeName,szDate) == 0    ||
1034        lstrcmpiW(dataTypeName,szTime) == 0    ||
1035        lstrcmpiW(dataTypeName,szTimeTZ) == 0  ||
1036        lstrcmpiW(dataTypeName,szI1) == 0      ||
1037        lstrcmpiW(dataTypeName,szI2) == 0      ||
1038        lstrcmpiW(dataTypeName,szIU1) == 0     ||
1039        lstrcmpiW(dataTypeName,szIU2) == 0     ||
1040        lstrcmpiW(dataTypeName,szIU4) == 0     ||
1041        lstrcmpiW(dataTypeName,szR4) == 0      ||
1042        lstrcmpiW(dataTypeName,szR8) == 0      ||
1043        lstrcmpiW(dataTypeName,szFloat) == 0   ||
1044        lstrcmpiW(dataTypeName,szBinHex) == 0  ||
1045        lstrcmpiW(dataTypeName,szBinBase64) == 0)
1046     {
1047         xmlNsPtr pNS = NULL;
1048         xmlAttrPtr pAttr = NULL;
1049         xmlChar* str = xmlChar_from_wchar(dataTypeName);
1050
1051         pAttr = xmlHasNsProp(This->node, (xmlChar*)"dt",
1052                             (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1053         if (pAttr)
1054         {
1055             pAttr = xmlSetNsProp(This->node, pAttr->ns, (xmlChar*)"dt", str);
1056
1057             hr = S_OK;
1058         }
1059         else
1060         {
1061             pNS = xmlNewNs(This->node, (xmlChar*)"urn:schemas-microsoft-com:datatypes", (xmlChar*)"dt");
1062             if(pNS)
1063             {
1064                 pAttr = xmlNewNsProp(This->node, pNS, (xmlChar*)"dt", str);
1065                 if(pAttr)
1066                 {
1067                     xmlAddChild(This->node, (xmlNodePtr)pAttr);
1068
1069                     hr = S_OK;
1070                 }
1071                 else
1072                     ERR("Failed to create Attribute\n");
1073             }
1074             else
1075                 ERR("Failed to Create Namepsace\n");
1076         }
1077         HeapFree( GetProcessHeap(), 0, str );
1078     }
1079
1080     return hr;
1081 }
1082
1083 static BSTR EnsureCorrectEOL(BSTR sInput)
1084 {
1085     static const WCHAR SZ_RETURN[] = {'\n',0};
1086     static const WCHAR SZ_LINEFEED[] = {'\r',0};
1087     int nNum = 0;
1088     BSTR sNew;
1089     int nLen;
1090     int i;
1091
1092     nLen = lstrlenW(sInput);
1093     /* Count line endings */
1094     for(i=0; i < nLen; i++)
1095     {
1096         if(sInput[i] == SZ_RETURN[0])
1097             nNum++;
1098     }
1099
1100     TRACE("len=%d, num=%d\n", nLen, nNum);
1101
1102     /* Add linefeed as needed */
1103     if(nNum > 0)
1104     {
1105         int nPlace = 0;
1106         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1107         for(i=0; i < nLen; i++)
1108         {
1109             if(sInput[i] == SZ_RETURN[0])
1110             {
1111                 sNew[i+nPlace] = SZ_LINEFEED[0];
1112                 nPlace++;
1113             }
1114             sNew[i+nPlace] = sInput[i];
1115         }
1116
1117         SysFreeString(sInput);
1118     }
1119     else
1120     {
1121         sNew = sInput;
1122     }
1123
1124     TRACE("len %d\n", lstrlenW(sNew));
1125
1126     return sNew;
1127 }
1128
1129 /* Removes encoding information and last character (nullbyte) */
1130 static BSTR EnsureNoEncoding(BSTR sInput)
1131 {
1132     static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1133     BSTR sNew;
1134     WCHAR *pBeg, *pEnd;
1135
1136     pBeg = sInput;
1137     while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1138         pBeg++;
1139
1140     if(*pBeg == '\n')
1141     {
1142         SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1143         return sInput;
1144     }
1145     pBeg--;
1146
1147     pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1148     while(*pEnd != '\"') pEnd++;
1149     pEnd++;
1150
1151     sNew = SysAllocStringLen(NULL,
1152             pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1153     memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1154     memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1155
1156     SysFreeString(sInput);
1157     return sNew;
1158 }
1159
1160 /*
1161  * We are trying to replicate the same behaviour as msxml by converting
1162  * line endings to \r\n and using idents as \t. The problem is that msxml
1163  * only formats nodes that have a line ending. Using libxml we cannot
1164  * reproduce behaviour exactly.
1165  *
1166  */
1167 static HRESULT WINAPI xmlnode_get_xml(
1168     IXMLDOMNode *iface,
1169     BSTR* xmlString)
1170 {
1171     xmlnode *This = impl_from_IXMLDOMNode( iface );
1172     xmlBufferPtr pXmlBuf;
1173     int nSize;
1174
1175     TRACE("iface %p %d\n", iface, This->node->type);
1176
1177     if(!xmlString)
1178         return E_INVALIDARG;
1179
1180     *xmlString = NULL;
1181
1182     pXmlBuf = xmlBufferCreate();
1183     if(pXmlBuf)
1184     {
1185         nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1186         if(nSize > 0)
1187         {
1188             const xmlChar *pContent;
1189             BSTR bstrContent;
1190
1191             /* Attribute Nodes return a space in front of their name */
1192             pContent = xmlBufferContent(pXmlBuf);
1193             if( ((char*)pContent)[0] == ' ')
1194                 bstrContent = bstr_from_xmlChar(pContent+1);
1195             else
1196                 bstrContent = bstr_from_xmlChar(pContent);
1197
1198             switch(This->node->type)
1199             {
1200                 case XML_ELEMENT_NODE:
1201                     *xmlString = EnsureCorrectEOL(bstrContent);
1202                     break;
1203                 case XML_DOCUMENT_NODE:
1204                     *xmlString = EnsureCorrectEOL(bstrContent);
1205                     *xmlString = EnsureNoEncoding(*xmlString);
1206                     break;
1207                 default:
1208                     *xmlString = bstrContent;
1209             }
1210         }
1211
1212         xmlBufferFree(pXmlBuf);
1213     }
1214
1215     /* Always returns a string. */
1216     if(*xmlString == NULL)  *xmlString = SysAllocStringLen( NULL, 0 );
1217
1218     return S_OK;
1219 }
1220
1221 static HRESULT WINAPI xmlnode_transformNode(
1222     IXMLDOMNode *iface,
1223     IXMLDOMNode* styleSheet,
1224     BSTR* xmlString)
1225 {
1226 #ifdef SONAME_LIBXSLT
1227     xmlnode *This = impl_from_IXMLDOMNode( iface );
1228     xmlnode *pStyleSheet = NULL;
1229     xsltStylesheetPtr xsltSS = NULL;
1230     xmlDocPtr result = NULL;
1231     IXMLDOMNode *ssNew;
1232
1233     TRACE("%p %p %p\n", This, styleSheet, xmlString);
1234
1235     if (!libxslt_handle)
1236         return E_NOTIMPL;
1237     if(!styleSheet || !xmlString)
1238         return E_INVALIDARG;
1239
1240     *xmlString = NULL;
1241
1242     if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1243     {
1244         pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1245
1246         xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1247         if(xsltSS)
1248         {
1249             result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1250             if(result)
1251             {
1252                 const xmlChar *pContent;
1253
1254                 if(result->type == XML_HTML_DOCUMENT_NODE)
1255                 {
1256                     xmlOutputBufferPtr  pOutput = xmlAllocOutputBuffer(NULL);
1257                     if(pOutput)
1258                     {
1259                         htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1260                         pContent = xmlBufferContent(pOutput->buffer);
1261                         *xmlString = bstr_from_xmlChar(pContent);
1262                         xmlOutputBufferClose(pOutput);
1263                     }
1264                 }
1265                 else
1266                 {
1267                     xmlBufferPtr pXmlBuf;
1268                     int nSize;
1269
1270                     pXmlBuf = xmlBufferCreate();
1271                     if(pXmlBuf)
1272                     {
1273                         nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1274                         if(nSize > 0)
1275                         {
1276                             pContent = xmlBufferContent(pXmlBuf);
1277                             *xmlString = bstr_from_xmlChar(pContent);
1278                         }
1279                         xmlBufferFree(pXmlBuf);
1280                     }
1281                 }
1282                 xmlFreeDoc(result);
1283             }
1284             /* libxslt "helpfully" frees the XML document the stylesheet was
1285                generated from, too */
1286             xsltSS->doc = NULL;
1287             pxsltFreeStylesheet(xsltSS);
1288         }
1289
1290         IXMLDOMNode_Release(ssNew);
1291     }
1292
1293     if(*xmlString == NULL)
1294         *xmlString = SysAllocStringLen(NULL, 0);
1295
1296     return S_OK;
1297 #else
1298     FIXME("libxslt headers were not found at compile time\n");
1299     return E_NOTIMPL;
1300 #endif
1301 }
1302
1303 static HRESULT WINAPI xmlnode_selectNodes(
1304     IXMLDOMNode *iface,
1305     BSTR queryString,
1306     IXMLDOMNodeList** resultList)
1307 {
1308     xmlnode *This = impl_from_IXMLDOMNode( iface );
1309
1310     TRACE("%p %s %p\n", This, debugstr_w(queryString), resultList );
1311
1312     return queryresult_create( This->node, queryString, resultList );
1313 }
1314
1315 static HRESULT WINAPI xmlnode_selectSingleNode(
1316     IXMLDOMNode *iface,
1317     BSTR queryString,
1318     IXMLDOMNode** resultNode)
1319 {
1320     xmlnode *This = impl_from_IXMLDOMNode( iface );
1321     IXMLDOMNodeList *list;
1322     HRESULT r;
1323
1324     TRACE("%p %s %p\n", This, debugstr_w(queryString), resultNode );
1325
1326     *resultNode = NULL;
1327     r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1328     if(r == S_OK)
1329     {
1330         r = IXMLDOMNodeList_nextNode(list, resultNode);
1331         IXMLDOMNodeList_Release(list);
1332     }
1333     return r;
1334 }
1335
1336 static HRESULT WINAPI xmlnode_get_parsed(
1337     IXMLDOMNode *iface,
1338     VARIANT_BOOL* isParsed)
1339 {
1340     FIXME("\n");
1341     return E_NOTIMPL;
1342 }
1343
1344 static HRESULT WINAPI xmlnode_get_namespaceURI(
1345     IXMLDOMNode *iface,
1346     BSTR* namespaceURI)
1347 {
1348     xmlnode *This = impl_from_IXMLDOMNode( iface );
1349     HRESULT hr = S_FALSE;
1350     xmlNsPtr *pNSList;
1351
1352     TRACE("%p %p\n", This, namespaceURI );
1353
1354     if(!namespaceURI)
1355         return E_INVALIDARG;
1356
1357     *namespaceURI = NULL;
1358
1359     pNSList = xmlGetNsList(This->node->doc, This->node);
1360     if(pNSList)
1361     {
1362         *namespaceURI = bstr_from_xmlChar( pNSList[0]->href );
1363
1364         xmlFree( pNSList );
1365         hr = S_OK;
1366     }
1367
1368     return hr;
1369 }
1370
1371 static HRESULT WINAPI xmlnode_get_prefix(
1372     IXMLDOMNode *iface,
1373     BSTR* prefixString)
1374 {
1375     xmlnode *This = impl_from_IXMLDOMNode( iface );
1376     HRESULT hr = S_FALSE;
1377     xmlNsPtr *pNSList;
1378
1379     TRACE("%p %p\n", This, prefixString );
1380
1381     if(!prefixString)
1382         return E_INVALIDARG;
1383
1384     *prefixString = NULL;
1385
1386     pNSList = xmlGetNsList(This->node->doc, This->node);
1387     if(pNSList)
1388     {
1389         *prefixString = bstr_from_xmlChar( pNSList[0]->prefix );
1390
1391         xmlFree(pNSList);
1392         hr = S_OK;
1393     }
1394
1395     return hr;
1396 }
1397
1398 static HRESULT WINAPI xmlnode_get_baseName(
1399     IXMLDOMNode *iface,
1400     BSTR* nameString)
1401 {
1402     xmlnode *This = impl_from_IXMLDOMNode( iface );
1403     BSTR str = NULL;
1404     HRESULT r = S_FALSE;
1405
1406     TRACE("%p %p\n", This, nameString );
1407
1408     if ( !nameString )
1409         return E_INVALIDARG;
1410
1411     switch ( This->node->type )
1412     {
1413     case XML_ELEMENT_NODE:
1414     case XML_ATTRIBUTE_NODE:
1415         str = bstr_from_xmlChar( This->node->name );
1416         r = S_OK;
1417         break;
1418     case XML_TEXT_NODE:
1419         break;
1420     default:
1421         ERR("Unhandled type %d\n", This->node->type );
1422         break;
1423     }
1424
1425     TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1426
1427     *nameString = str;
1428     return r;
1429 }
1430
1431 static HRESULT WINAPI xmlnode_transformNodeToObject(
1432     IXMLDOMNode *iface,
1433     IXMLDOMNode* stylesheet,
1434     VARIANT outputObject)
1435 {
1436     FIXME("\n");
1437     return E_NOTIMPL;
1438 }
1439
1440 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1441 {
1442     xmlnode_QueryInterface,
1443     xmlnode_AddRef,
1444     xmlnode_Release,
1445     xmlnode_GetTypeInfoCount,
1446     xmlnode_GetTypeInfo,
1447     xmlnode_GetIDsOfNames,
1448     xmlnode_Invoke,
1449     xmlnode_get_nodeName,
1450     xmlnode_get_nodeValue,
1451     xmlnode_put_nodeValue,
1452     xmlnode_get_nodeType,
1453     xmlnode_get_parentNode,
1454     xmlnode_get_childNodes,
1455     xmlnode_get_firstChild,
1456     xmlnode_get_lastChild,
1457     xmlnode_get_previousSibling,
1458     xmlnode_get_nextSibling,
1459     xmlnode_get_attributes,
1460     xmlnode_insertBefore,
1461     xmlnode_replaceChild,
1462     xmlnode_removeChild,
1463     xmlnode_appendChild,
1464     xmlnode_hasChildNodes,
1465     xmlnode_get_ownerDocument,
1466     xmlnode_cloneNode,
1467     xmlnode_get_nodeTypeString,
1468     xmlnode_get_text,
1469     xmlnode_put_text,
1470     xmlnode_get_specified,
1471     xmlnode_get_definition,
1472     xmlnode_get_nodeTypedValue,
1473     xmlnode_put_nodeTypedValue,
1474     xmlnode_get_dataType,
1475     xmlnode_put_dataType,
1476     xmlnode_get_xml,
1477     xmlnode_transformNode,
1478     xmlnode_selectNodes,
1479     xmlnode_selectSingleNode,
1480     xmlnode_get_parsed,
1481     xmlnode_get_namespaceURI,
1482     xmlnode_get_prefix,
1483     xmlnode_get_baseName,
1484     xmlnode_transformNodeToObject,
1485 };
1486
1487 static HRESULT WINAPI Internal_QueryInterface(
1488     IUnknown *iface,
1489     REFIID riid,
1490     void** ppvObject )
1491 {
1492     xmlnode *This = impl_from_InternalUnknown( iface );
1493
1494     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
1495
1496
1497     if ( IsEqualGUID( riid, &IID_IUnknown ))
1498         *ppvObject = iface;
1499     else if ( IsEqualGUID( riid, &IID_IDispatch ) ||
1500               IsEqualGUID( riid, &IID_IXMLDOMNode ) )
1501         *ppvObject = &This->lpVtbl;
1502     else
1503     {
1504         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1505         *ppvObject = NULL;
1506         return E_NOINTERFACE;
1507     }
1508
1509     IUnknown_AddRef( (IUnknown*)*ppvObject );
1510
1511     return S_OK;
1512 }
1513
1514 static ULONG WINAPI Internal_AddRef(
1515                  IUnknown *iface )
1516 {
1517     xmlnode *This = impl_from_InternalUnknown( iface );
1518     return InterlockedIncrement( &This->ref );
1519 }
1520
1521 static ULONG WINAPI Internal_Release(
1522     IUnknown *iface )
1523 {
1524     xmlnode *This = impl_from_InternalUnknown( iface );
1525     ULONG ref;
1526
1527     ref = InterlockedDecrement( &This->ref );
1528     if ( ref == 0 )
1529     {
1530         if( This->node )
1531             xmldoc_release( This->node->doc );
1532         HeapFree( GetProcessHeap(), 0, This );
1533     }
1534
1535     return ref;
1536 }
1537
1538 static const struct IUnknownVtbl internal_unk_vtbl =
1539 {
1540     Internal_QueryInterface,
1541     Internal_AddRef,
1542     Internal_Release
1543 };
1544
1545 IUnknown *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter )
1546 {
1547     xmlnode *This;
1548
1549     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1550     if ( !This )
1551         return NULL;
1552
1553     if(node)
1554         xmldoc_add_ref( node->doc );
1555
1556     This->lpVtbl = &xmlnode_vtbl;
1557     This->lpInternalUnkVtbl = &internal_unk_vtbl;
1558
1559     if(pUnkOuter)
1560         This->pUnkOuter = pUnkOuter; /* Don't take a ref on outer Unknown */
1561     else
1562         This->pUnkOuter = (IUnknown *)&This->lpInternalUnkVtbl;
1563
1564     This->ref = 1;
1565     This->node = node;
1566
1567     return (IUnknown*)&This->lpInternalUnkVtbl;
1568 }
1569
1570 IXMLDOMNode *create_node( xmlNodePtr node )
1571 {
1572     IUnknown *pUnk;
1573     IXMLDOMNode *ret;
1574     HRESULT hr;
1575
1576     if ( !node )
1577         return NULL;
1578
1579     TRACE("type %d\n", node->type);
1580     switch(node->type)
1581     {
1582     case XML_ELEMENT_NODE:
1583         pUnk = create_element( node, NULL );
1584         break;
1585     case XML_ATTRIBUTE_NODE:
1586         pUnk = create_attribute( node );
1587         break;
1588     case XML_TEXT_NODE:
1589         pUnk = create_text( node );
1590         break;
1591     case XML_CDATA_SECTION_NODE:
1592         pUnk = create_cdata( node );
1593         break;
1594     case XML_COMMENT_NODE:
1595         pUnk = create_comment( node );
1596         break;
1597     case XML_DOCUMENT_NODE:
1598         pUnk = create_domdoc( node );
1599         break;
1600     default:
1601         FIXME("only creating basic node for type %d\n", node->type);
1602         pUnk = create_basic_node( node, NULL );
1603     }
1604
1605     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1606     IUnknown_Release(pUnk);
1607     if(FAILED(hr)) return NULL;
1608     return ret;
1609 }
1610 #endif