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