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