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