xref: /reactos/dll/win32/msxml3/node.c (revision c0fa4859)
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     FIXME("\n");
613     return E_NOTIMPL;
614 }
615 
616 static HRESULT WINAPI xmlnode_removeChild(
617     IXMLDOMNode *iface,
618     IXMLDOMNode* childNode,
619     IXMLDOMNode** oldChild)
620 {
621     xmlnode *This = impl_from_IXMLDOMNode( iface );
622     xmlNode *ancestor, *child_node_ptr;
623     HRESULT hr;
624     IXMLDOMNode *child;
625 
626     TRACE("%p->(%p, %p)\n", This, childNode, oldChild);
627 
628     if(oldChild)
629         *oldChild = NULL;
630 
631     if(!childNode) return E_INVALIDARG;
632 
633     hr = IXMLDOMNode_QueryInterface(childNode, &IID_IXMLDOMNode, (LPVOID)&child);
634     if(FAILED(hr))
635         return hr;
636 
637     child_node_ptr = ancestor = impl_from_IXMLDOMNode(child)->node;
638     while(ancestor->parent)
639     {
640         if(ancestor->parent == This->node)
641             break;
642         ancestor = ancestor->parent;
643     }
644     if(!ancestor->parent)
645     {
646         WARN("childNode %p is not a child of %p\n", childNode, iface);
647         IXMLDOMNode_Release(child);
648         return E_INVALIDARG;
649     }
650 
651     xmlUnlinkNode(child_node_ptr);
652 
653     IXMLDOMNode_Release(child);
654 
655     if(oldChild)
656     {
657         IXMLDOMNode_AddRef(childNode);
658         *oldChild = childNode;
659     }
660 
661     return S_OK;
662 }
663 
664 static HRESULT WINAPI xmlnode_appendChild(
665     IXMLDOMNode *iface,
666     IXMLDOMNode* newChild,
667     IXMLDOMNode** outNewChild)
668 {
669     xmlnode *This = impl_from_IXMLDOMNode( iface );
670     DOMNodeType type;
671     VARIANT var;
672     HRESULT hr;
673 
674     TRACE("(%p)->(%p,%p)\n", This, newChild, outNewChild);
675 
676     hr = IXMLDOMNode_get_nodeType(newChild, &type);
677     if(FAILED(hr) || type == NODE_ATTRIBUTE) {
678         if(outNewChild) *outNewChild = NULL;
679         return E_FAIL;
680     }
681 
682     VariantInit(&var);
683     return IXMLDOMNode_insertBefore(iface, newChild, var, outNewChild);
684 }
685 
686 static HRESULT WINAPI xmlnode_hasChildNodes(
687     IXMLDOMNode *iface,
688     VARIANT_BOOL* hasChild)
689 {
690     xmlnode *This = impl_from_IXMLDOMNode( iface );
691 
692     TRACE("%p\n", This);
693 
694     if (!hasChild)
695         return E_INVALIDARG;
696     if (!This->node->children)
697     {
698         *hasChild = VARIANT_FALSE;
699         return S_FALSE;
700     }
701 
702     *hasChild = VARIANT_TRUE;
703     return S_OK;
704 }
705 
706 static HRESULT WINAPI xmlnode_get_ownerDocument(
707     IXMLDOMNode *iface,
708     IXMLDOMDocument** DOMDocument)
709 {
710     xmlnode *This = impl_from_IXMLDOMNode( iface );
711 
712     TRACE("%p (%p)\n", This, DOMDocument);
713 
714     return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument2**)DOMDocument);
715 }
716 
717 static HRESULT WINAPI xmlnode_cloneNode(
718     IXMLDOMNode *iface,
719     VARIANT_BOOL deep,
720     IXMLDOMNode** cloneRoot)
721 {
722     xmlnode *This = impl_from_IXMLDOMNode( iface );
723     xmlNodePtr pClone = NULL;
724     IXMLDOMNode *pNode = NULL;
725 
726     TRACE("%p (%d)\n", This, deep);
727 
728     if(!cloneRoot)
729         return E_INVALIDARG;
730 
731     pClone = xmlCopyNode(This->node, deep ? 1 : 2);
732     if(pClone)
733     {
734         pClone->doc = This->node->doc;
735 
736         pNode = create_node(pClone);
737         if(!pNode)
738         {
739             ERR("Copy failed\n");
740             return E_FAIL;
741         }
742 
743         *cloneRoot = pNode;
744     }
745     else
746     {
747         ERR("Copy failed\n");
748         return E_FAIL;
749     }
750 
751     return S_OK;
752 }
753 
754 static HRESULT WINAPI xmlnode_get_nodeTypeString(
755     IXMLDOMNode *iface,
756     BSTR* xmlnodeType)
757 {
758     xmlnode *This = impl_from_IXMLDOMNode( iface );
759     const xmlChar *str;
760 
761     TRACE("%p\n", This );
762 
763     if (!xmlnodeType)
764         return E_INVALIDARG;
765 
766     if ( !This->node )
767         return E_FAIL;
768 
769     switch( This->node->type )
770     {
771     case XML_ATTRIBUTE_NODE:
772         str = (const xmlChar*) "attribute";
773         break;
774     case XML_CDATA_SECTION_NODE:
775         str = (const xmlChar*) "cdatasection";
776         break;
777     case XML_COMMENT_NODE:
778         str = (const xmlChar*) "comment";
779         break;
780     case XML_DOCUMENT_NODE:
781         str = (const xmlChar*) "document";
782         break;
783     case XML_DOCUMENT_FRAG_NODE:
784         str = (const xmlChar*) "documentfragment";
785         break;
786     case XML_ELEMENT_NODE:
787         str = (const xmlChar*) "element";
788         break;
789     case XML_ENTITY_NODE:
790         str = (const xmlChar*) "entity";
791         break;
792     case XML_ENTITY_REF_NODE:
793         str = (const xmlChar*) "entityreference";
794         break;
795     case XML_NOTATION_NODE:
796         str = (const xmlChar*) "notation";
797         break;
798     case XML_PI_NODE:
799         str = (const xmlChar*) "processinginstruction";
800         break;
801     case XML_TEXT_NODE:
802         str = (const xmlChar*) "text";
803         break;
804     default:
805         FIXME("Unknown node type (%d)\n", This->node->type);
806         str = This->node->name;
807         break;
808     }
809 
810     *xmlnodeType = bstr_from_xmlChar( str );
811     if (!*xmlnodeType)
812         return S_FALSE;
813 
814     return S_OK;
815 }
816 
817 static HRESULT WINAPI xmlnode_get_text(
818     IXMLDOMNode *iface,
819     BSTR* text)
820 {
821     xmlnode *This = impl_from_IXMLDOMNode( iface );
822     BSTR str = NULL;
823 
824     TRACE("%p\n", This);
825 
826     if ( !text )
827         return E_INVALIDARG;
828 
829     switch(This->node->type)
830     {
831     case XML_ELEMENT_NODE:
832     case XML_ATTRIBUTE_NODE:
833     {
834         xmlNodePtr child = This->node->children;
835         if ( child && child->type == XML_TEXT_NODE )
836             str = bstr_from_xmlChar( child->content );
837         break;
838     }
839 
840     case XML_TEXT_NODE:
841     case XML_CDATA_SECTION_NODE:
842     case XML_PI_NODE:
843     case XML_COMMENT_NODE:
844         str = bstr_from_xmlChar( This->node->content );
845         break;
846 
847     default:
848         FIXME("Unhandled node type %d\n", This->node->type);
849     }
850 
851     /* Always return a string. */
852     if (!str) str = SysAllocStringLen( NULL, 0 );
853 
854     TRACE("%p %s\n", This, debugstr_w(str) );
855     *text = str;
856 
857     return S_OK;
858 }
859 
860 static HRESULT WINAPI xmlnode_put_text(
861     IXMLDOMNode *iface,
862     BSTR text)
863 {
864     xmlnode *This = impl_from_IXMLDOMNode( iface );
865     xmlChar *str = NULL;
866 
867     TRACE("%p\n", This);
868 
869     switch(This->node->type)
870     {
871     case XML_DOCUMENT_NODE:
872         return E_FAIL;
873     default:
874         break;
875     }
876 
877     str = xmlChar_from_wchar((WCHAR*)text);
878 
879     /* Escape the string. */
880     str = xmlEncodeEntitiesReentrant(This->node->doc, str);
881     str = xmlEncodeSpecialChars(This->node->doc, str);
882 
883     xmlNodeSetContent(This->node, str);
884     xmlFree(str);
885 
886     return S_OK;
887 }
888 
889 static HRESULT WINAPI xmlnode_get_specified(
890     IXMLDOMNode *iface,
891     VARIANT_BOOL* isSpecified)
892 {
893     FIXME("\n");
894     return E_NOTIMPL;
895 }
896 
897 static HRESULT WINAPI xmlnode_get_definition(
898     IXMLDOMNode *iface,
899     IXMLDOMNode** definitionNode)
900 {
901     FIXME("\n");
902     return E_NOTIMPL;
903 }
904 
905 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
906     IXMLDOMNode *iface,
907     VARIANT* typedValue)
908 {
909     FIXME("ignoring data type\n");
910     return xmlnode_get_nodeValue(iface, typedValue);
911 }
912 
913 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
914     IXMLDOMNode *iface,
915     VARIANT typedValue)
916 {
917     FIXME("\n");
918     return E_NOTIMPL;
919 }
920 
921 static HRESULT WINAPI xmlnode_get_dataType(
922     IXMLDOMNode *iface,
923     VARIANT* dataTypeName)
924 {
925     xmlnode *This = impl_from_IXMLDOMNode( iface );
926     xmlChar *pVal;
927 
928     TRACE("iface %p\n", iface);
929 
930     if(!dataTypeName)
931         return E_INVALIDARG;
932 
933     /* Attribute, CDATA Section, Comment, Document, Document Fragment,
934         Entity, Notation, PI, and Text Node are non-typed. */
935     V_BSTR(dataTypeName) = NULL;
936     V_VT(dataTypeName) = VT_NULL;
937 
938     switch ( This->node->type )
939     {
940     case XML_ELEMENT_NODE:
941         pVal = xmlGetNsProp(This->node, (xmlChar*)"dt",
942                             (xmlChar*)"urn:schemas-microsoft-com:datatypes");
943         if (pVal)
944         {
945             V_VT(dataTypeName) = VT_BSTR;
946             V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
947             xmlFree(pVal);
948         }
949         break;
950     case XML_ENTITY_REF_NODE:
951         FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
952         break;
953     default:
954         TRACE("Type %d returning NULL\n", This->node->type);
955     }
956 
957     /* non-typed nodes return S_FALSE */
958     if(V_VT(dataTypeName) == VT_NULL)
959     {
960         return S_FALSE;
961     }
962 
963     return S_OK;
964 }
965 
966 static HRESULT WINAPI xmlnode_put_dataType(
967     IXMLDOMNode *iface,
968     BSTR dataTypeName)
969 {
970     xmlnode *This = impl_from_IXMLDOMNode( iface );
971     HRESULT hr = E_FAIL;
972 
973     TRACE("iface %p\n", iface);
974 
975     if(dataTypeName == NULL)
976         return E_INVALIDARG;
977 
978     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
979        This applies to changing types (string->bool) or setting a new one
980      */
981     FIXME("Need to Validate the data before allowing a type to be set.\n");
982 
983     /* Check all supported types. */
984     if(lstrcmpiW(dataTypeName,szString) == 0  ||
985        lstrcmpiW(dataTypeName,szNumber) == 0  ||
986        lstrcmpiW(dataTypeName,szUUID) == 0    ||
987        lstrcmpiW(dataTypeName,szInt) == 0     ||
988        lstrcmpiW(dataTypeName,szI4) == 0      ||
989        lstrcmpiW(dataTypeName,szFixed) == 0   ||
990        lstrcmpiW(dataTypeName,szBoolean) == 0 ||
991        lstrcmpiW(dataTypeName,szDateTime) == 0 ||
992        lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
993        lstrcmpiW(dataTypeName,szDate) == 0    ||
994        lstrcmpiW(dataTypeName,szTime) == 0    ||
995        lstrcmpiW(dataTypeName,szTimeTZ) == 0  ||
996        lstrcmpiW(dataTypeName,szI1) == 0      ||
997        lstrcmpiW(dataTypeName,szI2) == 0      ||
998        lstrcmpiW(dataTypeName,szIU1) == 0     ||
999        lstrcmpiW(dataTypeName,szIU2) == 0     ||
1000        lstrcmpiW(dataTypeName,szIU4) == 0     ||
1001        lstrcmpiW(dataTypeName,szR4) == 0      ||
1002        lstrcmpiW(dataTypeName,szR8) == 0      ||
1003        lstrcmpiW(dataTypeName,szFloat) == 0   ||
1004        lstrcmpiW(dataTypeName,szBinHex) == 0  ||
1005        lstrcmpiW(dataTypeName,szBinBase64) == 0)
1006     {
1007         xmlNsPtr pNS = NULL;
1008         xmlAttrPtr pAttr = NULL;
1009         xmlChar* str = xmlChar_from_wchar((WCHAR*)dataTypeName);
1010 
1011         pAttr = xmlHasNsProp(This->node, (xmlChar*)"dt",
1012                             (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1013         if (pAttr)
1014         {
1015             pAttr = xmlSetNsProp(This->node, pAttr->ns, (xmlChar*)"dt", str);
1016 
1017             hr = S_OK;
1018         }
1019         else
1020         {
1021             pNS = xmlNewNs(This->node, (xmlChar*)"urn:schemas-microsoft-com:datatypes", (xmlChar*)"dt");
1022             if(pNS)
1023             {
1024                 pAttr = xmlNewNsProp(This->node, pNS, (xmlChar*)"dt", str);
1025                 if(pAttr)
1026                 {
1027                     xmlAddChild(This->node, (xmlNodePtr)pAttr);
1028 
1029                     hr = S_OK;
1030                 }
1031                 else
1032                     ERR("Failed to create Attribute\n");
1033             }
1034             else
1035                 ERR("Failed to Create Namepsace\n");
1036         }
1037     }
1038 
1039     return hr;
1040 }
1041 
1042 static BSTR EnsureCorrectEOL(BSTR sInput)
1043 {
1044     static const WCHAR SZ_RETURN[] = {'\n',0};
1045     static const WCHAR SZ_LINEFEED[] = {'\r',0};
1046     int nNum = 0;
1047     BSTR sNew;
1048     int nLen;
1049     int i;
1050 
1051     nLen = lstrlenW(sInput);
1052     /* Count line endings */
1053     for(i=0; i < nLen; i++)
1054     {
1055         if(sInput[i] == SZ_RETURN[0])
1056             nNum++;
1057     }
1058 
1059     TRACE("len=%d, num=%d\n", nLen, nNum);
1060 
1061     /* Add linefeed as needed */
1062     if(nNum > 0)
1063     {
1064         int nPlace = 0;
1065         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1066         for(i=0; i < nLen; i++)
1067         {
1068             if(sInput[i] == SZ_RETURN[0])
1069             {
1070                 sNew[i+nPlace] = SZ_LINEFEED[0];
1071                 nPlace++;
1072             }
1073             sNew[i+nPlace] = sInput[i];
1074         }
1075 
1076         SysFreeString(sInput);
1077     }
1078     else
1079     {
1080         sNew = sInput;
1081     }
1082 
1083     TRACE("len %d\n", lstrlenW(sNew));
1084 
1085     return sNew;
1086 }
1087 
1088 /*
1089  * We are trying to replicate the same behaviour as msxml by converting
1090  * line endings to \r\n and using idents as \t. The problem is that msxml
1091  * only formats nodes that have a line ending. Using libxml we cannot
1092  * reproduce behaviour exactly.
1093  *
1094  */
1095 static HRESULT WINAPI xmlnode_get_xml(
1096     IXMLDOMNode *iface,
1097     BSTR* xmlString)
1098 {
1099     xmlnode *This = impl_from_IXMLDOMNode( iface );
1100     xmlBufferPtr pXmlBuf;
1101     int nSize;
1102 
1103     TRACE("iface %p %d\n", iface, This->node->type);
1104 
1105     if(!xmlString)
1106         return E_INVALIDARG;
1107 
1108     *xmlString = NULL;
1109 
1110     pXmlBuf = xmlBufferCreate();
1111     if(pXmlBuf)
1112     {
1113         nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1114         if(nSize > 0)
1115         {
1116             const xmlChar *pContent;
1117             BSTR bstrContent;
1118 
1119             /* Attribute Nodes return a space in front of their name */
1120             pContent = xmlBufferContent(pXmlBuf);
1121             if( ((char*)pContent)[0] == ' ')
1122                 bstrContent = bstr_from_xmlChar(pContent+1);
1123             else
1124                 bstrContent = bstr_from_xmlChar(pContent);
1125 
1126             *xmlString = This->node->type == XML_ELEMENT_NODE ? EnsureCorrectEOL(bstrContent) : bstrContent;
1127         }
1128 
1129         xmlBufferFree(pXmlBuf);
1130     }
1131 
1132     /* Always returns a string. */
1133     if(*xmlString == NULL)  *xmlString = SysAllocStringLen( NULL, 0 );
1134 
1135     return S_OK;
1136 }
1137 
1138 static HRESULT WINAPI xmlnode_transformNode(
1139     IXMLDOMNode *iface,
1140     IXMLDOMNode* styleSheet,
1141     BSTR* xmlString)
1142 {
1143 #ifdef HAVE_LIBXSLT
1144     xmlnode *This = impl_from_IXMLDOMNode( iface );
1145     xmlnode *pStyleSheet = NULL;
1146     xsltStylesheetPtr xsltSS = NULL;
1147     xmlDocPtr result = NULL;
1148     IXMLDOMNode *ssNew;
1149 
1150     TRACE("%p %p %p\n", This, styleSheet, xmlString);
1151 
1152     if(!styleSheet || !xmlString)
1153         return E_INVALIDARG;
1154 
1155     *xmlString = NULL;
1156 
1157     if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1158     {
1159         pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1160 
1161         xsltSS = xsltParseStylesheetDoc( pStyleSheet->node->doc);
1162         if(xsltSS)
1163         {
1164             result = xsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1165             if(result)
1166             {
1167                 const xmlChar *pContent;
1168 
1169                 if(result->type == XML_HTML_DOCUMENT_NODE)
1170                 {
1171                     xmlOutputBufferPtr	pOutput = xmlAllocOutputBuffer(NULL);
1172                     if(pOutput)
1173                     {
1174                         htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1175                         if(pOutput)
1176                         {
1177                             pContent = xmlBufferContent(pOutput->buffer);
1178                             *xmlString = bstr_from_xmlChar(pContent);
1179                         }
1180 
1181                         xmlOutputBufferClose(pOutput);
1182                     }
1183                 }
1184                 else
1185                 {
1186                     xmlBufferPtr pXmlBuf;
1187                     int nSize;
1188 
1189                     pXmlBuf = xmlBufferCreate();
1190                     if(pXmlBuf)
1191                     {
1192                         nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1193                         if(nSize > 0)
1194                         {
1195                             pContent = xmlBufferContent(pXmlBuf);
1196                             *xmlString = bstr_from_xmlChar(pContent);
1197 
1198                             xmlBufferFree(pXmlBuf);
1199                         }
1200                     }
1201                 }
1202             }
1203         }
1204 
1205         IXMLDOMNode_Release(ssNew);
1206     }
1207 
1208     if(*xmlString == NULL)
1209         *xmlString = SysAllocStringLen(NULL, 0);
1210 
1211     return S_OK;
1212 #else
1213     FIXME("libxslt headers were not found at compile time\n");
1214     return E_NOTIMPL;
1215 #endif
1216 }
1217 
1218 static HRESULT WINAPI xmlnode_selectNodes(
1219     IXMLDOMNode *iface,
1220     BSTR queryString,
1221     IXMLDOMNodeList** resultList)
1222 {
1223     xmlnode *This = impl_from_IXMLDOMNode( iface );
1224 
1225     TRACE("%p %s %p\n", This, debugstr_w(queryString), resultList );
1226 
1227     return queryresult_create( This->node, queryString, resultList );
1228 }
1229 
1230 static HRESULT WINAPI xmlnode_selectSingleNode(
1231     IXMLDOMNode *iface,
1232     BSTR queryString,
1233     IXMLDOMNode** resultNode)
1234 {
1235     xmlnode *This = impl_from_IXMLDOMNode( iface );
1236     IXMLDOMNodeList *list;
1237     HRESULT r;
1238 
1239     TRACE("%p %s %p\n", This, debugstr_w(queryString), resultNode );
1240 
1241     *resultNode = NULL;
1242     r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1243     if(r == S_OK)
1244     {
1245         r = IXMLDOMNodeList_nextNode(list, resultNode);
1246         IXMLDOMNodeList_Release(list);
1247     }
1248     return r;
1249 }
1250 
1251 static HRESULT WINAPI xmlnode_get_parsed(
1252     IXMLDOMNode *iface,
1253     VARIANT_BOOL* isParsed)
1254 {
1255     FIXME("\n");
1256     return E_NOTIMPL;
1257 }
1258 
1259 static HRESULT WINAPI xmlnode_get_namespaceURI(
1260     IXMLDOMNode *iface,
1261     BSTR* namespaceURI)
1262 {
1263     xmlnode *This = impl_from_IXMLDOMNode( iface );
1264     HRESULT hr = S_FALSE;
1265     xmlNsPtr *pNSList;
1266 
1267     TRACE("%p %p\n", This, namespaceURI );
1268 
1269     if(!namespaceURI)
1270         return E_INVALIDARG;
1271 
1272     *namespaceURI = NULL;
1273 
1274     pNSList = xmlGetNsList(This->node->doc, This->node);
1275     if(pNSList)
1276     {
1277         *namespaceURI = bstr_from_xmlChar( pNSList[0]->href );
1278 
1279         hr = S_OK;
1280     }
1281 
1282     return hr;
1283 }
1284 
1285 static HRESULT WINAPI xmlnode_get_prefix(
1286     IXMLDOMNode *iface,
1287     BSTR* prefixString)
1288 {
1289     xmlnode *This = impl_from_IXMLDOMNode( iface );
1290     HRESULT hr = S_FALSE;
1291     xmlNsPtr *pNSList;
1292 
1293     TRACE("%p %p\n", This, prefixString );
1294 
1295     if(!prefixString)
1296         return E_INVALIDARG;
1297 
1298     *prefixString = NULL;
1299 
1300     pNSList = xmlGetNsList(This->node->doc, This->node);
1301     if(pNSList)
1302     {
1303         *prefixString = bstr_from_xmlChar( pNSList[0]->prefix );
1304 
1305         hr = S_OK;
1306     }
1307 
1308     return hr;
1309 }
1310 
1311 static HRESULT WINAPI xmlnode_get_baseName(
1312     IXMLDOMNode *iface,
1313     BSTR* nameString)
1314 {
1315     xmlnode *This = impl_from_IXMLDOMNode( iface );
1316     BSTR str = NULL;
1317     HRESULT r = S_FALSE;
1318 
1319     TRACE("%p %p\n", This, nameString );
1320 
1321     if ( !nameString )
1322         return E_INVALIDARG;
1323 
1324     switch ( This->node->type )
1325     {
1326     case XML_ELEMENT_NODE:
1327     case XML_ATTRIBUTE_NODE:
1328         str = bstr_from_xmlChar( This->node->name );
1329         r = S_OK;
1330         break;
1331     case XML_TEXT_NODE:
1332         break;
1333     default:
1334         ERR("Unhandled type %d\n", This->node->type );
1335         break;
1336     }
1337 
1338     TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1339 
1340     *nameString = str;
1341     return r;
1342 }
1343 
1344 static HRESULT WINAPI xmlnode_transformNodeToObject(
1345     IXMLDOMNode *iface,
1346     IXMLDOMNode* stylesheet,
1347     VARIANT outputObject)
1348 {
1349     FIXME("\n");
1350     return E_NOTIMPL;
1351 }
1352 
1353 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1354 {
1355     xmlnode_QueryInterface,
1356     xmlnode_AddRef,
1357     xmlnode_Release,
1358     xmlnode_GetTypeInfoCount,
1359     xmlnode_GetTypeInfo,
1360     xmlnode_GetIDsOfNames,
1361     xmlnode_Invoke,
1362     xmlnode_get_nodeName,
1363     xmlnode_get_nodeValue,
1364     xmlnode_put_nodeValue,
1365     xmlnode_get_nodeType,
1366     xmlnode_get_parentNode,
1367     xmlnode_get_childNodes,
1368     xmlnode_get_firstChild,
1369     xmlnode_get_lastChild,
1370     xmlnode_get_previousSibling,
1371     xmlnode_get_nextSibling,
1372     xmlnode_get_attributes,
1373     xmlnode_insertBefore,
1374     xmlnode_replaceChild,
1375     xmlnode_removeChild,
1376     xmlnode_appendChild,
1377     xmlnode_hasChildNodes,
1378     xmlnode_get_ownerDocument,
1379     xmlnode_cloneNode,
1380     xmlnode_get_nodeTypeString,
1381     xmlnode_get_text,
1382     xmlnode_put_text,
1383     xmlnode_get_specified,
1384     xmlnode_get_definition,
1385     xmlnode_get_nodeTypedValue,
1386     xmlnode_put_nodeTypedValue,
1387     xmlnode_get_dataType,
1388     xmlnode_put_dataType,
1389     xmlnode_get_xml,
1390     xmlnode_transformNode,
1391     xmlnode_selectNodes,
1392     xmlnode_selectSingleNode,
1393     xmlnode_get_parsed,
1394     xmlnode_get_namespaceURI,
1395     xmlnode_get_prefix,
1396     xmlnode_get_baseName,
1397     xmlnode_transformNodeToObject,
1398 };
1399 
1400 static HRESULT WINAPI Internal_QueryInterface(
1401     IUnknown *iface,
1402     REFIID riid,
1403     void** ppvObject )
1404 {
1405     xmlnode *This = impl_from_InternalUnknown( iface );
1406 
1407     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
1408 
1409 
1410     if ( IsEqualGUID( riid, &IID_IUnknown ))
1411         *ppvObject = iface;
1412     else if ( IsEqualGUID( riid, &IID_IDispatch ) ||
1413               IsEqualGUID( riid, &IID_IXMLDOMNode ) )
1414         *ppvObject = &This->lpVtbl;
1415     else
1416     {
1417         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1418         *ppvObject = NULL;
1419         return E_NOINTERFACE;
1420     }
1421 
1422     IUnknown_AddRef( (IUnknown*)*ppvObject );
1423 
1424     return S_OK;
1425 }
1426 
1427 static ULONG WINAPI Internal_AddRef(
1428                  IUnknown *iface )
1429 {
1430     xmlnode *This = impl_from_InternalUnknown( iface );
1431     return InterlockedIncrement( &This->ref );
1432 }
1433 
1434 static ULONG WINAPI Internal_Release(
1435     IUnknown *iface )
1436 {
1437     xmlnode *This = impl_from_InternalUnknown( iface );
1438     ULONG ref;
1439 
1440     ref = InterlockedDecrement( &This->ref );
1441     if ( ref == 0 )
1442     {
1443         if( This->node )
1444 	    xmldoc_release( This->node->doc );
1445         HeapFree( GetProcessHeap(), 0, This );
1446     }
1447 
1448     return ref;
1449 }
1450 
1451 static const struct IUnknownVtbl internal_unk_vtbl =
1452 {
1453     Internal_QueryInterface,
1454     Internal_AddRef,
1455     Internal_Release
1456 };
1457 
1458 IUnknown *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter )
1459 {
1460     xmlnode *This;
1461 
1462     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1463     if ( !This )
1464         return NULL;
1465 
1466     if(node)
1467         xmldoc_add_ref( node->doc );
1468 
1469     This->lpVtbl = &xmlnode_vtbl;
1470     This->lpInternalUnkVtbl = &internal_unk_vtbl;
1471 
1472     if(pUnkOuter)
1473         This->pUnkOuter = pUnkOuter; /* Don't take a ref on outer Unknown */
1474     else
1475         This->pUnkOuter = (IUnknown *)&This->lpInternalUnkVtbl;
1476 
1477     This->ref = 1;
1478     This->node = node;
1479 
1480     return (IUnknown*)&This->lpInternalUnkVtbl;
1481 }
1482 
1483 IXMLDOMNode *create_node( xmlNodePtr node )
1484 {
1485     IUnknown *pUnk;
1486     IXMLDOMNode *ret;
1487     HRESULT hr;
1488 
1489     if ( !node )
1490         return NULL;
1491 
1492     TRACE("type %d\n", node->type);
1493     switch(node->type)
1494     {
1495     case XML_ELEMENT_NODE:
1496         pUnk = create_element( node, NULL );
1497         break;
1498     case XML_ATTRIBUTE_NODE:
1499         pUnk = create_attribute( node );
1500         break;
1501     case XML_TEXT_NODE:
1502         pUnk = create_text( node );
1503         break;
1504     case XML_CDATA_SECTION_NODE:
1505         pUnk = create_cdata( node );
1506         break;
1507     case XML_COMMENT_NODE:
1508         pUnk = create_comment( node );
1509         break;
1510     case XML_DOCUMENT_NODE:
1511         pUnk = create_domdoc( node );
1512         break;
1513     default:
1514         FIXME("only creating basic node for type %d\n", node->type);
1515         pUnk = create_basic_node( node, NULL );
1516     }
1517 
1518     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1519     IUnknown_Release(pUnk);
1520     if(FAILED(hr)) return NULL;
1521     return ret;
1522 }
1523 #endif
1524