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