shell32: Update the Polish translation.
[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) stub!\n", This, isSpecified);
938     *isSpecified = VARIANT_TRUE;
939     return S_OK;
940 }
941
942 static HRESULT WINAPI xmlnode_get_definition(
943     IXMLDOMNode *iface,
944     IXMLDOMNode** definitionNode)
945 {
946     xmlnode *This = impl_from_IXMLDOMNode( iface );
947     FIXME("(%p)->(%p)\n", This, definitionNode);
948     return E_NOTIMPL;
949 }
950
951 static inline BYTE hex_to_byte(xmlChar c)
952 {
953     if(c <= '9') return c-'0';
954     if(c <= 'F') return c-'A'+10;
955     return c-'a'+10;
956 }
957
958 static inline BYTE base64_to_byte(xmlChar c)
959 {
960     if(c == '+') return 62;
961     if(c == '/') return 63;
962     if(c <= '9') return c-'0'+52;
963     if(c <= 'Z') return c-'A';
964     return c-'a'+26;
965 }
966
967 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
968 {
969     if(!type || !lstrcmpiW(type, szString) ||
970             !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
971     {
972         V_VT(v) = VT_BSTR;
973         V_BSTR(v) = bstr_from_xmlChar(str);
974
975         if(!V_BSTR(v))
976             return E_OUTOFMEMORY;
977     }
978     else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
979             !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
980             !lstrcmpiW(type, szTimeTZ))
981     {
982         VARIANT src;
983         WCHAR *p, *e;
984         SYSTEMTIME st;
985         DOUBLE date = 0.0;
986
987         st.wYear = 1899;
988         st.wMonth = 12;
989         st.wDay = 30;
990         st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
991
992         V_VT(&src) = VT_BSTR;
993         V_BSTR(&src) = bstr_from_xmlChar(str);
994
995         if(!V_BSTR(&src))
996             return E_OUTOFMEMORY;
997
998         p = V_BSTR(&src);
999         e = p + SysStringLen(V_BSTR(&src));
1000
1001         if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
1002         {
1003             st.wYear = atoiW(p);
1004             st.wMonth = atoiW(p+5);
1005             st.wDay = atoiW(p+8);
1006             p += 10;
1007
1008             if(*p == 'T') p++;
1009         }
1010
1011         if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
1012         {
1013             st.wHour = atoiW(p);
1014             st.wMinute = atoiW(p+3);
1015             st.wSecond = atoiW(p+6);
1016             p += 8;
1017
1018             if(*p == '.')
1019             {
1020                 p++;
1021                 while(isdigitW(*p)) p++;
1022             }
1023         }
1024
1025         SystemTimeToVariantTime(&st, &date);
1026         V_VT(v) = VT_DATE;
1027         V_DATE(v) = date;
1028
1029         if(*p == '+') /* parse timezone offset (+hh:mm) */
1030             V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1031         else if(*p == '-') /* parse timezone offset (-hh:mm) */
1032             V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1033
1034         VariantClear(&src);
1035     }
1036     else if(!lstrcmpiW(type, szBinHex))
1037     {
1038         SAFEARRAYBOUND sab;
1039         int i, len;
1040
1041         len = xmlStrlen(str)/2;
1042         sab.lLbound = 0;
1043         sab.cElements = len;
1044
1045         V_VT(v) = (VT_ARRAY|VT_UI1);
1046         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1047
1048         if(!V_ARRAY(v))
1049             return E_OUTOFMEMORY;
1050
1051         for(i=0; i<len; i++)
1052             ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
1053                 + hex_to_byte(str[2*i+1]);
1054     }
1055     else if(!lstrcmpiW(type, szBinBase64))
1056     {
1057         SAFEARRAYBOUND sab;
1058         int i, len;
1059
1060         len  = xmlStrlen(str);
1061         if(str[len-2] == '=') i = 2;
1062         else if(str[len-1] == '=') i = 1;
1063         else i = 0;
1064
1065         sab.lLbound = 0;
1066         sab.cElements = len/4*3-i;
1067
1068         V_VT(v) = (VT_ARRAY|VT_UI1);
1069         V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1070
1071         if(!V_ARRAY(v))
1072             return E_OUTOFMEMORY;
1073
1074         for(i=0; i<len/4; i++)
1075         {
1076             ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
1077                 + (base64_to_byte(str[4*i+1])>>4);
1078             if(3*i+1 < sab.cElements)
1079                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
1080                     + (base64_to_byte(str[4*i+2])>>2);
1081             if(3*i+2 < sab.cElements)
1082                 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
1083                     + base64_to_byte(str[4*i+3]);
1084         }
1085     }
1086     else
1087     {
1088         VARIANT src;
1089         HRESULT hres;
1090
1091         if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
1092             V_VT(v) = VT_I4;
1093         else if(!lstrcmpiW(type, szFixed))
1094             V_VT(v) = VT_CY;
1095         else if(!lstrcmpiW(type, szBoolean))
1096             V_VT(v) = VT_BOOL;
1097         else if(!lstrcmpiW(type, szI1))
1098             V_VT(v) = VT_I1;
1099         else if(!lstrcmpiW(type, szI2))
1100             V_VT(v) = VT_I2;
1101         else if(!lstrcmpiW(type, szIU1))
1102             V_VT(v) = VT_UI1;
1103         else if(!lstrcmpiW(type, szIU2))
1104             V_VT(v) = VT_UI2;
1105         else if(!lstrcmpiW(type, szIU4))
1106             V_VT(v) = VT_UI4;
1107         else if(!lstrcmpiW(type, szR4))
1108             V_VT(v) = VT_R4;
1109         else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
1110             V_VT(v) = VT_R8;
1111         else
1112         {
1113             FIXME("Type handling not yet implemented\n");
1114             V_VT(v) = VT_BSTR;
1115         }
1116
1117         V_VT(&src) = VT_BSTR;
1118         V_BSTR(&src) = bstr_from_xmlChar(str);
1119
1120         if(!V_BSTR(&src))
1121             return E_OUTOFMEMORY;
1122
1123         hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
1124                         LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
1125         VariantClear(&src);
1126         return hres;
1127     }
1128
1129     return S_OK;
1130 }
1131
1132 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
1133     IXMLDOMNode *iface,
1134     VARIANT* typedValue)
1135 {
1136     xmlnode *This = impl_from_IXMLDOMNode( iface );
1137     VARIANT type;
1138     xmlChar *content;
1139     HRESULT hres = S_FALSE;
1140
1141     TRACE("(%p)->(%p)\n", This, typedValue);
1142
1143     if(!typedValue)
1144         return E_INVALIDARG;
1145
1146     V_VT(typedValue) = VT_NULL;
1147
1148     if(This->node->type == XML_ELEMENT_NODE ||
1149             This->node->type == XML_TEXT_NODE ||
1150             This->node->type == XML_ENTITY_REF_NODE)
1151         hres = IXMLDOMNode_get_dataType(iface, &type);
1152
1153     if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
1154         return IXMLDOMNode_get_nodeValue(iface, typedValue);
1155
1156     content = xmlNodeGetContent(This->node);
1157     hres = VARIANT_from_xmlChar(content, typedValue,
1158             hres==S_OK ? V_BSTR(&type) : NULL);
1159     xmlFree(content);
1160     VariantClear(&type);
1161
1162     return hres;
1163 }
1164
1165 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
1166     IXMLDOMNode *iface,
1167     VARIANT typedValue)
1168 {
1169     xmlnode *This = impl_from_IXMLDOMNode( iface );
1170     FIXME("%p\n", This);
1171     return E_NOTIMPL;
1172 }
1173
1174 static HRESULT WINAPI xmlnode_get_dataType(
1175     IXMLDOMNode *iface,
1176     VARIANT* dataTypeName)
1177 {
1178     xmlnode *This = impl_from_IXMLDOMNode( iface );
1179     xmlChar *pVal;
1180
1181     TRACE("(%p)->(%p)\n", This, dataTypeName);
1182
1183     if(!dataTypeName)
1184         return E_INVALIDARG;
1185
1186     /* Attribute, CDATA Section, Comment, Document, Document Fragment,
1187         Entity, Notation, PI, and Text Node are non-typed. */
1188     V_BSTR(dataTypeName) = NULL;
1189     V_VT(dataTypeName) = VT_NULL;
1190
1191     switch ( This->node->type )
1192     {
1193     case XML_ELEMENT_NODE:
1194         pVal = xmlGetNsProp(This->node, (const xmlChar*)"dt",
1195                             (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
1196         if (pVal)
1197         {
1198             V_VT(dataTypeName) = VT_BSTR;
1199             V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
1200             xmlFree(pVal);
1201         }
1202         break;
1203     case XML_ENTITY_REF_NODE:
1204         FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
1205         break;
1206     default:
1207         TRACE("Type %d returning NULL\n", This->node->type);
1208     }
1209
1210     /* non-typed nodes return S_FALSE */
1211     if(V_VT(dataTypeName) == VT_NULL)
1212     {
1213         return S_FALSE;
1214     }
1215
1216     return S_OK;
1217 }
1218
1219 static HRESULT WINAPI xmlnode_put_dataType(
1220     IXMLDOMNode *iface,
1221     BSTR dataTypeName)
1222 {
1223     xmlnode *This = impl_from_IXMLDOMNode( iface );
1224     HRESULT hr = E_FAIL;
1225
1226     TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1227
1228     if(dataTypeName == NULL)
1229         return E_INVALIDARG;
1230
1231     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1232        This applies to changing types (string->bool) or setting a new one
1233      */
1234     FIXME("Need to Validate the data before allowing a type to be set.\n");
1235
1236     /* Check all supported types. */
1237     if(lstrcmpiW(dataTypeName,szString) == 0  ||
1238        lstrcmpiW(dataTypeName,szNumber) == 0  ||
1239        lstrcmpiW(dataTypeName,szUUID) == 0    ||
1240        lstrcmpiW(dataTypeName,szInt) == 0     ||
1241        lstrcmpiW(dataTypeName,szI4) == 0      ||
1242        lstrcmpiW(dataTypeName,szFixed) == 0   ||
1243        lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1244        lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1245        lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1246        lstrcmpiW(dataTypeName,szDate) == 0    ||
1247        lstrcmpiW(dataTypeName,szTime) == 0    ||
1248        lstrcmpiW(dataTypeName,szTimeTZ) == 0  ||
1249        lstrcmpiW(dataTypeName,szI1) == 0      ||
1250        lstrcmpiW(dataTypeName,szI2) == 0      ||
1251        lstrcmpiW(dataTypeName,szIU1) == 0     ||
1252        lstrcmpiW(dataTypeName,szIU2) == 0     ||
1253        lstrcmpiW(dataTypeName,szIU4) == 0     ||
1254        lstrcmpiW(dataTypeName,szR4) == 0      ||
1255        lstrcmpiW(dataTypeName,szR8) == 0      ||
1256        lstrcmpiW(dataTypeName,szFloat) == 0   ||
1257        lstrcmpiW(dataTypeName,szBinHex) == 0  ||
1258        lstrcmpiW(dataTypeName,szBinBase64) == 0)
1259     {
1260         xmlNsPtr pNS = NULL;
1261         xmlAttrPtr pAttr = NULL;
1262         xmlChar* str = xmlChar_from_wchar(dataTypeName);
1263
1264         pAttr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
1265                             (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
1266         if (pAttr)
1267         {
1268             pAttr = xmlSetNsProp(This->node, pAttr->ns, (const xmlChar*)"dt", str);
1269
1270             hr = S_OK;
1271         }
1272         else
1273         {
1274             pNS = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
1275             if(pNS)
1276             {
1277                 pAttr = xmlNewNsProp(This->node, pNS, (const xmlChar*)"dt", str);
1278                 if(pAttr)
1279                 {
1280                     xmlAddChild(This->node, (xmlNodePtr)pAttr);
1281
1282                     hr = S_OK;
1283                 }
1284                 else
1285                     ERR("Failed to create Attribute\n");
1286             }
1287             else
1288                 ERR("Failed to Create Namepsace\n");
1289         }
1290         heap_free( str );
1291     }
1292
1293     return hr;
1294 }
1295
1296 static BSTR EnsureCorrectEOL(BSTR sInput)
1297 {
1298     int nNum = 0;
1299     BSTR sNew;
1300     int nLen;
1301     int i;
1302
1303     nLen = lstrlenW(sInput);
1304     /* Count line endings */
1305     for(i=0; i < nLen; i++)
1306     {
1307         if(sInput[i] == '\n')
1308             nNum++;
1309     }
1310
1311     TRACE("len=%d, num=%d\n", nLen, nNum);
1312
1313     /* Add linefeed as needed */
1314     if(nNum > 0)
1315     {
1316         int nPlace = 0;
1317         sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1318         for(i=0; i < nLen; i++)
1319         {
1320             if(sInput[i] == '\n')
1321             {
1322                 sNew[i+nPlace] = '\r';
1323                 nPlace++;
1324             }
1325             sNew[i+nPlace] = sInput[i];
1326         }
1327
1328         SysFreeString(sInput);
1329     }
1330     else
1331     {
1332         sNew = sInput;
1333     }
1334
1335     TRACE("len %d\n", lstrlenW(sNew));
1336
1337     return sNew;
1338 }
1339
1340 /* Removes encoding information and last character (nullbyte) */
1341 static BSTR EnsureNoEncoding(BSTR sInput)
1342 {
1343     static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1344     BSTR sNew;
1345     WCHAR *pBeg, *pEnd;
1346
1347     pBeg = sInput;
1348     while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1349         pBeg++;
1350
1351     if(*pBeg == '\n')
1352     {
1353         SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1354         return sInput;
1355     }
1356     pBeg--;
1357
1358     pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1359     while(*pEnd != '\"') pEnd++;
1360     pEnd++;
1361
1362     sNew = SysAllocStringLen(NULL,
1363             pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1364     memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1365     memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1366
1367     SysFreeString(sInput);
1368     return sNew;
1369 }
1370
1371 /*
1372  * We are trying to replicate the same behaviour as msxml by converting
1373  * line endings to \r\n and using indents as \t. The problem is that msxml
1374  * only formats nodes that have a line ending. Using libxml we cannot
1375  * reproduce behaviour exactly.
1376  *
1377  */
1378 static HRESULT WINAPI xmlnode_get_xml(
1379     IXMLDOMNode *iface,
1380     BSTR* xmlString)
1381 {
1382     xmlnode *This = impl_from_IXMLDOMNode( iface );
1383     xmlBufferPtr pXmlBuf;
1384     int nSize;
1385
1386     TRACE("(%p %d)->(%p)\n", This, This->node->type, xmlString);
1387
1388     if(!xmlString)
1389         return E_INVALIDARG;
1390
1391     *xmlString = NULL;
1392
1393     pXmlBuf = xmlBufferCreate();
1394     if(pXmlBuf)
1395     {
1396         nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1397         if(nSize > 0)
1398         {
1399             const xmlChar *pContent;
1400             BSTR bstrContent;
1401
1402             /* Attribute Nodes return a space in front of their name */
1403             pContent = xmlBufferContent(pXmlBuf);
1404             if( ((const char*)pContent)[0] == ' ')
1405                 bstrContent = bstr_from_xmlChar(pContent+1);
1406             else
1407                 bstrContent = bstr_from_xmlChar(pContent);
1408
1409             switch(This->node->type)
1410             {
1411                 case XML_ELEMENT_NODE:
1412                     *xmlString = EnsureCorrectEOL(bstrContent);
1413                     break;
1414                 case XML_DOCUMENT_NODE:
1415                     *xmlString = EnsureCorrectEOL(bstrContent);
1416                     *xmlString = EnsureNoEncoding(*xmlString);
1417                     break;
1418                 default:
1419                     *xmlString = bstrContent;
1420             }
1421         }
1422
1423         xmlBufferFree(pXmlBuf);
1424     }
1425
1426     /* Always returns a string. */
1427     if(*xmlString == NULL)  *xmlString = SysAllocStringLen( NULL, 0 );
1428
1429     return S_OK;
1430 }
1431
1432 static HRESULT WINAPI xmlnode_transformNode(
1433     IXMLDOMNode *iface,
1434     IXMLDOMNode* styleSheet,
1435     BSTR* xmlString)
1436 {
1437 #ifdef SONAME_LIBXSLT
1438     xmlnode *This = impl_from_IXMLDOMNode( iface );
1439     xmlnode *pStyleSheet = NULL;
1440     xsltStylesheetPtr xsltSS = NULL;
1441     xmlDocPtr result = NULL;
1442     IXMLDOMNode *ssNew;
1443
1444     TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1445
1446     if (!libxslt_handle)
1447         return E_NOTIMPL;
1448     if(!styleSheet || !xmlString)
1449         return E_INVALIDARG;
1450
1451     *xmlString = NULL;
1452
1453     if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1454     {
1455         pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1456
1457         xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1458         if(xsltSS)
1459         {
1460             result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1461             if(result)
1462             {
1463                 const xmlChar *pContent;
1464
1465                 if(result->type == XML_HTML_DOCUMENT_NODE)
1466                 {
1467                     xmlOutputBufferPtr  pOutput = xmlAllocOutputBuffer(NULL);
1468                     if(pOutput)
1469                     {
1470                         htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1471                         pContent = xmlBufferContent(pOutput->buffer);
1472                         *xmlString = bstr_from_xmlChar(pContent);
1473                         xmlOutputBufferClose(pOutput);
1474                     }
1475                 }
1476                 else
1477                 {
1478                     xmlBufferPtr pXmlBuf;
1479                     int nSize;
1480
1481                     pXmlBuf = xmlBufferCreate();
1482                     if(pXmlBuf)
1483                     {
1484                         nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1485                         if(nSize > 0)
1486                         {
1487                             pContent = xmlBufferContent(pXmlBuf);
1488                             *xmlString = bstr_from_xmlChar(pContent);
1489                         }
1490                         xmlBufferFree(pXmlBuf);
1491                     }
1492                 }
1493                 xmlFreeDoc(result);
1494             }
1495             /* libxslt "helpfully" frees the XML document the stylesheet was
1496                generated from, too */
1497             xsltSS->doc = NULL;
1498             pxsltFreeStylesheet(xsltSS);
1499         }
1500
1501         IXMLDOMNode_Release(ssNew);
1502     }
1503
1504     if(*xmlString == NULL)
1505         *xmlString = SysAllocStringLen(NULL, 0);
1506
1507     return S_OK;
1508 #else
1509     FIXME("libxslt headers were not found at compile time\n");
1510     return E_NOTIMPL;
1511 #endif
1512 }
1513
1514 static HRESULT WINAPI xmlnode_selectNodes(
1515     IXMLDOMNode *iface,
1516     BSTR queryString,
1517     IXMLDOMNodeList** resultList)
1518 {
1519     xmlnode *This = impl_from_IXMLDOMNode( iface );
1520
1521     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1522
1523     return queryresult_create( This->node, queryString, resultList );
1524 }
1525
1526 static HRESULT WINAPI xmlnode_selectSingleNode(
1527     IXMLDOMNode *iface,
1528     BSTR queryString,
1529     IXMLDOMNode** resultNode)
1530 {
1531     xmlnode *This = impl_from_IXMLDOMNode( iface );
1532     IXMLDOMNodeList *list;
1533     HRESULT r;
1534
1535     TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1536
1537     *resultNode = NULL;
1538     r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1539     if(r == S_OK)
1540     {
1541         r = IXMLDOMNodeList_nextNode(list, resultNode);
1542         IXMLDOMNodeList_Release(list);
1543     }
1544     return r;
1545 }
1546
1547 static HRESULT WINAPI xmlnode_get_parsed(
1548     IXMLDOMNode *iface,
1549     VARIANT_BOOL* isParsed)
1550 {
1551     xmlnode *This = impl_from_IXMLDOMNode( iface );
1552     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1553     *isParsed = VARIANT_TRUE;
1554     return S_OK;
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