msxml3: Remove Byte since it's not a valid datatype.
[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 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
39
40 #ifdef HAVE_LIBXML2
41
42 static const WCHAR szBinBase64[]  = {'b','i','n','.','b','a','s','e','6','4',0};
43 static const WCHAR szString[]     = {'s','t','r','i','n','g',0};
44 static const WCHAR szNumber[]     = {'n','u','m','b','e','r',0};
45 static const WCHAR szInt[]        = {'I','n','t',0};
46 static const WCHAR szFixed[]      = {'F','i','x','e','d','.','1','4','.','4',0};
47 static const WCHAR szBoolean[]    = {'B','o','o','l','e','a','n',0};
48 static const WCHAR szDateTime[]   = {'d','a','t','e','T','i','m','e',0};
49 static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
50 static const WCHAR szDate[]       = {'D','a','t','e',0};
51 static const WCHAR szTime[]       = {'T','i','m','e',0};
52 static const WCHAR szTimeTZ[]     = {'T','i','m','e','.','t','z',0};
53 static const WCHAR szI1[]         = {'i','1',0};
54 static const WCHAR szI2[]         = {'i','2',0};
55 static const WCHAR szI4[]         = {'i','4',0};
56 static const WCHAR szIU1[]        = {'u','i','1',0};
57 static const WCHAR szIU2[]        = {'u','i','2',0};
58 static const WCHAR szIU4[]        = {'u','i','4',0};
59 static const WCHAR szR4[]         = {'r','4',0};
60 static const WCHAR szR8[]         = {'r','8',0};
61 static const WCHAR szFloat[]      = {'f','l','o','a','t',0};
62 static const WCHAR szUUID[]       = {'u','u','i','d',0};
63 static const WCHAR szBinHex[]     = {'b','i','n','.','h','e','x',0};
64
65 static inline xmlnode *impl_from_InternalUnknown( IUnknown *iface )
66 {
67     return (xmlnode *)((char*)iface - FIELD_OFFSET(xmlnode, lpInternalUnkVtbl));
68 }
69
70 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
71 {
72     xmlnode *This;
73
74     if ( !iface )
75         return NULL;
76     This = impl_from_IXMLDOMNode( iface );
77     if ( !This->node )
78         return NULL;
79     if ( type && This->node->type != type )
80         return NULL;
81     return This->node;
82 }
83
84 void attach_xmlnode( IXMLDOMNode *node, xmlNodePtr xml )
85 {
86     xmlnode *This = impl_from_IXMLDOMNode( node );
87
88     if(This->node)
89         xmldoc_release(This->node->doc);
90
91     This->node = xml;
92     if(This->node)
93         xmldoc_add_ref(This->node->doc);
94
95     return;
96 }
97
98 static HRESULT WINAPI xmlnode_QueryInterface(
99     IXMLDOMNode *iface,
100     REFIID riid,
101     void** ppvObject )
102 {
103     xmlnode *This = impl_from_IXMLDOMNode( iface );
104     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
105
106     return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
107 }
108
109 static ULONG WINAPI xmlnode_AddRef(
110     IXMLDOMNode *iface )
111 {
112     xmlnode *This = impl_from_IXMLDOMNode( iface );
113     return IUnknown_AddRef(This->pUnkOuter);
114 }
115
116 static ULONG WINAPI xmlnode_Release(
117     IXMLDOMNode *iface )
118 {
119     xmlnode *This = impl_from_IXMLDOMNode( iface );
120     return IUnknown_Release(This->pUnkOuter);
121 }
122
123 static HRESULT WINAPI xmlnode_GetTypeInfoCount(
124     IXMLDOMNode *iface,
125     UINT* pctinfo )
126 {
127     FIXME("\n");
128     return E_NOTIMPL;
129 }
130
131 static HRESULT WINAPI xmlnode_GetTypeInfo(
132     IXMLDOMNode *iface,
133     UINT iTInfo,
134     LCID lcid,
135     ITypeInfo** ppTInfo )
136 {
137     FIXME("\n");
138     return E_NOTIMPL;
139 }
140
141 static HRESULT WINAPI xmlnode_GetIDsOfNames(
142     IXMLDOMNode *iface,
143     REFIID riid,
144     LPOLESTR* rgszNames,
145     UINT cNames,
146     LCID lcid,
147     DISPID* rgDispId )
148 {
149     FIXME("\n");
150     return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI xmlnode_Invoke(
154     IXMLDOMNode *iface,
155     DISPID dispIdMember,
156     REFIID riid,
157     LCID lcid,
158     WORD wFlags,
159     DISPPARAMS* pDispParams,
160     VARIANT* pVarResult,
161     EXCEPINFO* pExcepInfo,
162     UINT* puArgErr )
163 {
164     FIXME("\n");
165     return E_NOTIMPL;
166 }
167
168 static HRESULT WINAPI xmlnode_get_nodeName(
169     IXMLDOMNode *iface,
170     BSTR* name)
171 {
172     xmlnode *This = impl_from_IXMLDOMNode( iface );
173     const xmlChar *str;
174
175     TRACE("%p\n", This );
176
177     if (!name)
178         return E_INVALIDARG;
179
180     if ( !This->node )
181         return E_FAIL;
182
183     switch( This->node->type )
184     {
185     case XML_CDATA_SECTION_NODE:
186         str = (const xmlChar*) "#cdata-section";
187         break;
188     case XML_COMMENT_NODE:
189         str = (const xmlChar*) "#comment";
190         break;
191     case XML_DOCUMENT_FRAG_NODE:
192         str = (const xmlChar*) "#document-fragment";
193         break;
194     case XML_TEXT_NODE:
195          str = (const xmlChar*) "#text";
196          break;
197     case XML_DOCUMENT_NODE:
198          str = (const xmlChar*) "#document";
199             break;
200         case XML_ATTRIBUTE_NODE:
201         case XML_ELEMENT_NODE:
202         case XML_PI_NODE:
203         str = This->node->name;
204             break;
205     default:
206         FIXME("nodeName not mapped correctly (%d)\n", This->node->type);
207         str = This->node->name;
208         break;
209     }
210
211     *name = bstr_from_xmlChar( str );
212     if (!*name)
213         return S_FALSE;
214
215     return S_OK;
216 }
217
218 BSTR bstr_from_xmlChar( const xmlChar *buf )
219 {
220     DWORD len;
221     LPWSTR str;
222     BSTR bstr;
223
224     if ( !buf )
225         return NULL;
226
227     len = MultiByteToWideChar( CP_UTF8, 0, (LPCSTR) buf, -1, NULL, 0 );
228     str = (LPWSTR) HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
229     if ( !str )
230         return NULL;
231     MultiByteToWideChar( CP_UTF8, 0, (LPCSTR) buf, -1, str, len );
232     bstr = SysAllocString( str );
233     HeapFree( GetProcessHeap(), 0, str );
234     return bstr;
235 }
236
237 static HRESULT WINAPI xmlnode_get_nodeValue(
238     IXMLDOMNode *iface,
239     VARIANT* value)
240 {
241     xmlnode *This = impl_from_IXMLDOMNode( iface );
242     HRESULT r = S_FALSE;
243
244     TRACE("%p %p\n", This, value);
245
246     if(!value)
247         return E_INVALIDARG;
248
249     V_BSTR(value) = NULL;
250     V_VT(value) = VT_NULL;
251
252     switch ( This->node->type )
253     {
254     case XML_CDATA_SECTION_NODE:
255     case XML_COMMENT_NODE:
256     case XML_PI_NODE:
257     case XML_ATTRIBUTE_NODE:
258       {
259         xmlChar *content = xmlNodeGetContent(This->node);
260         V_VT(value) = VT_BSTR;
261         V_BSTR(value) = bstr_from_xmlChar( content );
262         xmlFree(content);
263         r = S_OK;
264         break;
265       }
266     case XML_TEXT_NODE:
267         V_VT(value) = VT_BSTR;
268         V_BSTR(value) = bstr_from_xmlChar( This->node->content );
269         r = S_OK;
270         break;
271     case XML_ELEMENT_NODE:
272     case XML_DOCUMENT_NODE:
273         /* these seem to return NULL */
274         break;
275
276     default:
277         FIXME("node %p type %d\n", This, This->node->type);
278     }
279  
280     TRACE("%p returned %s\n", This, debugstr_w( V_BSTR(value) ) );
281
282     return r;
283 }
284
285 static HRESULT WINAPI xmlnode_put_nodeValue(
286     IXMLDOMNode *iface,
287     VARIANT value)
288 {
289     xmlnode *This = impl_from_IXMLDOMNode( iface );
290     HRESULT hr = S_FALSE;
291     xmlChar *str = NULL;
292
293     TRACE("%p type(%d)\n", This, This->node->type);
294
295     /* Document, Document Fragment, Document Type, Element,
296         Entity, Entity Reference, Notation arent supported. */
297     switch ( This->node->type )
298     {
299     case XML_ATTRIBUTE_NODE:
300     case XML_CDATA_SECTION_NODE:
301     case XML_COMMENT_NODE:
302     case XML_PI_NODE:
303     case XML_TEXT_NODE:
304       {
305         str = xmlChar_from_wchar((WCHAR*)V_BSTR(&value));
306
307         xmlNodeSetContent(This->node, str);
308         hr = S_OK;
309         break;
310       }
311     default:
312         /* Do nothing for unsupported types. */
313         break;
314     }
315
316     return hr;
317 }
318
319 static HRESULT WINAPI xmlnode_get_nodeType(
320     IXMLDOMNode *iface,
321     DOMNodeType* type)
322 {
323     xmlnode *This = impl_from_IXMLDOMNode( iface );
324
325     TRACE("%p %p\n", This, type);
326
327     assert( NODE_ELEMENT == XML_ELEMENT_NODE );
328     assert( NODE_NOTATION == XML_NOTATION_NODE );
329
330     *type = This->node->type;
331
332     return S_OK;
333 }
334
335 static HRESULT get_node(
336     xmlnode *This,
337     const char *name,
338     xmlNodePtr node,
339     IXMLDOMNode **out )
340 {
341     TRACE("%p->%s %p\n", This, name, node );
342
343     if ( !out )
344         return E_INVALIDARG;
345     *out = create_node( node );
346     if (!*out)
347         return S_FALSE;
348     return S_OK;
349 }
350
351 static HRESULT WINAPI xmlnode_get_parentNode(
352     IXMLDOMNode *iface,
353     IXMLDOMNode** parent)
354 {
355     xmlnode *This = impl_from_IXMLDOMNode( iface );
356     return get_node( This, "parent", This->node->parent, parent );
357 }
358
359 static HRESULT WINAPI xmlnode_get_childNodes(
360     IXMLDOMNode *iface,
361     IXMLDOMNodeList** childList)
362 {
363     xmlnode *This = impl_from_IXMLDOMNode( iface );
364
365     TRACE("%p %p\n", This, childList );
366
367     if ( !childList )
368         return E_INVALIDARG;
369
370     *childList = create_children_nodelist(This->node);
371     if (*childList == NULL)
372         return E_OUTOFMEMORY;
373
374     return S_OK;
375 }
376
377 static HRESULT WINAPI xmlnode_get_firstChild(
378     IXMLDOMNode *iface,
379     IXMLDOMNode** firstChild)
380 {
381     xmlnode *This = impl_from_IXMLDOMNode( iface );
382     return get_node( This, "firstChild", This->node->children, firstChild );
383 }
384
385 static HRESULT WINAPI xmlnode_get_lastChild(
386     IXMLDOMNode *iface,
387     IXMLDOMNode** lastChild)
388 {
389     xmlnode *This = impl_from_IXMLDOMNode( iface );
390
391     TRACE("%p\n", This );
392
393     if (!lastChild)
394         return E_INVALIDARG;
395
396     switch( This->node->type )
397     {
398     /* CDATASection, Comment, PI and Text Nodes do not support lastChild */
399     case XML_TEXT_NODE:
400     case XML_CDATA_SECTION_NODE:
401     case XML_PI_NODE:
402     case XML_COMMENT_NODE:
403         *lastChild = NULL;
404         return S_FALSE;
405     default:
406         return get_node( This, "lastChild", This->node->last, lastChild );
407     }
408 }
409
410 static HRESULT WINAPI xmlnode_get_previousSibling(
411     IXMLDOMNode *iface,
412     IXMLDOMNode** previousSibling)
413 {
414     xmlnode *This = impl_from_IXMLDOMNode( iface );
415
416     TRACE("%p\n", This );
417
418     if (!previousSibling)
419         return E_INVALIDARG;
420
421     switch( This->node->type )
422     {
423     /* Attribute, Document and Document Fragment Nodes do not support previousSibling */
424     case XML_DOCUMENT_NODE:
425     case XML_DOCUMENT_FRAG_NODE:
426     case XML_ATTRIBUTE_NODE:
427         *previousSibling = NULL;
428         return S_FALSE;
429     default:
430         return get_node( This, "previous", This->node->prev, previousSibling );
431     }
432 }
433
434 static HRESULT WINAPI xmlnode_get_nextSibling(
435     IXMLDOMNode *iface,
436     IXMLDOMNode** nextSibling)
437 {
438     xmlnode *This = impl_from_IXMLDOMNode( iface );
439
440     TRACE("%p\n", This );
441
442     if (!nextSibling)
443         return E_INVALIDARG;
444
445     switch( This->node->type )
446     {
447     /* Attribute, Document and Document Fragment Nodes do not support nextSibling */
448     case XML_DOCUMENT_NODE:
449     case XML_DOCUMENT_FRAG_NODE:
450     case XML_ATTRIBUTE_NODE:
451         *nextSibling = NULL;
452         return S_FALSE;
453     default:
454         return get_node( This, "next", This->node->next, nextSibling );
455     }
456 }
457
458 static HRESULT WINAPI xmlnode_get_attributes(
459     IXMLDOMNode *iface,
460     IXMLDOMNamedNodeMap** attributeMap)
461 {
462     xmlnode *This = impl_from_IXMLDOMNode( iface );
463     TRACE("%p\n", This);
464
465     if (!attributeMap)
466         return E_INVALIDARG;
467
468     switch( This->node->type )
469     {
470     /* Attribute, CDataSection, Comment, Documents, Documents Fragments,
471        Entity and Text Nodes does not support get_attributes */
472     case XML_ATTRIBUTE_NODE:
473     case XML_CDATA_SECTION_NODE:
474     case XML_COMMENT_NODE:
475     case XML_DOCUMENT_NODE:
476     case XML_DOCUMENT_FRAG_NODE:
477     case XML_ENTITY_NODE:
478     case XML_ENTITY_REF_NODE:
479     case XML_TEXT_NODE:
480         *attributeMap = NULL;
481         return S_FALSE;
482     default:
483         *attributeMap = create_nodemap( iface );
484         return S_OK;
485     }
486 }
487
488 static HRESULT WINAPI xmlnode_insertBefore(
489     IXMLDOMNode *iface,
490     IXMLDOMNode* newChild,
491     VARIANT refChild,
492     IXMLDOMNode** outNewChild)
493 {
494     xmlnode *This = impl_from_IXMLDOMNode( iface );
495     xmlNodePtr before_node, new_child_node;
496     IXMLDOMNode *before = NULL, *new;
497     HRESULT hr;
498
499     TRACE("(%p)->(%p,var,%p)\n",This,newChild,outNewChild);
500
501     if (!newChild)
502         return E_INVALIDARG;
503
504     switch(V_VT(&refChild))
505     {
506     case VT_EMPTY:
507     case VT_NULL:
508         break;
509
510     case VT_UNKNOWN:
511         hr = IUnknown_QueryInterface(V_UNKNOWN(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
512         if(FAILED(hr)) return hr;
513         break;
514
515     case VT_DISPATCH:
516         hr = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
517         if(FAILED(hr)) return hr;
518         break;
519
520     default:
521         FIXME("refChild var type %x\n", V_VT(&refChild));
522         return E_FAIL;
523     }
524
525     IXMLDOMNode_QueryInterface(newChild, &IID_IXMLDOMNode, (LPVOID)&new);
526     new_child_node = impl_from_IXMLDOMNode(new)->node;
527     TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
528
529     if(before)
530     {
531         before_node = impl_from_IXMLDOMNode(before)->node;
532         xmlAddPrevSibling(before_node, new_child_node);
533         IXMLDOMNode_Release(before);
534     }
535     else
536     {
537         xmlAddChild(This->node, new_child_node);
538     }
539
540     IXMLDOMNode_Release(new);
541     IXMLDOMNode_AddRef(newChild);
542     if(outNewChild)
543         *outNewChild = newChild;
544
545     TRACE("ret S_OK\n");
546     return S_OK;
547 }
548
549 static HRESULT WINAPI xmlnode_replaceChild(
550     IXMLDOMNode *iface,
551     IXMLDOMNode* newChild,
552     IXMLDOMNode* oldChild,
553     IXMLDOMNode** outOldChild)
554 {
555     FIXME("\n");
556     return E_NOTIMPL;
557 }
558
559 static HRESULT WINAPI xmlnode_removeChild(
560     IXMLDOMNode *iface,
561     IXMLDOMNode* childNode,
562     IXMLDOMNode** oldChild)
563 {
564     xmlnode *This = impl_from_IXMLDOMNode( iface );
565     xmlNode *ancestor, *child_node_ptr;
566     HRESULT hr;
567     IXMLDOMNode *child;
568
569     TRACE("%p->(%p, %p)\n", This, childNode, oldChild);
570
571     *oldChild = NULL;
572
573     if(!childNode) return E_INVALIDARG;
574
575     hr = IXMLDOMNode_QueryInterface(childNode, &IID_IXMLDOMNode, (LPVOID)&child);
576     if(FAILED(hr))
577         return hr;
578
579     child_node_ptr = ancestor = impl_from_IXMLDOMNode(child)->node;
580     while(ancestor->parent)
581     {
582         if(ancestor->parent == This->node)
583             break;
584         ancestor = ancestor->parent;
585     }
586     if(!ancestor->parent)
587     {
588         WARN("childNode %p is not a child of %p\n", childNode, iface);
589         IXMLDOMNode_Release(child);
590         return E_INVALIDARG;
591     }
592
593     xmlUnlinkNode(child_node_ptr);
594
595     IXMLDOMNode_Release(child);
596     IXMLDOMNode_AddRef(childNode);
597     *oldChild = childNode;
598     return S_OK;
599 }
600
601 static HRESULT WINAPI xmlnode_appendChild(
602     IXMLDOMNode *iface,
603     IXMLDOMNode* newChild,
604     IXMLDOMNode** outNewChild)
605 {
606     xmlnode *This = impl_from_IXMLDOMNode( iface );
607     IXMLDOMNode *pAttr = NULL;
608     VARIANT var;
609
610     TRACE("(%p)->(%p,%p)\n", This, newChild, outNewChild);
611
612     /* Cannot Append an Attribute node. */
613     IUnknown_QueryInterface(newChild, &IID_IXMLDOMNode, (LPVOID*)&pAttr);
614     if(pAttr)
615     {
616         xmlnode *ThisNew = impl_from_IXMLDOMNode( pAttr );
617
618         if(ThisNew->node->type == XML_ATTRIBUTE_NODE)
619         {
620             if(outNewChild) *outNewChild = NULL;
621
622             IUnknown_Release(pAttr);
623
624             return E_FAIL;
625         }
626
627         IUnknown_Release(pAttr);
628     }
629
630     VariantInit(&var);
631     return IXMLDOMNode_insertBefore(iface, newChild, var, outNewChild);
632 }
633
634 static HRESULT WINAPI xmlnode_hasChildNodes(
635     IXMLDOMNode *iface,
636     VARIANT_BOOL* hasChild)
637 {
638     xmlnode *This = impl_from_IXMLDOMNode( iface );
639
640     TRACE("%p\n", This);
641
642     if (!hasChild)
643         return E_INVALIDARG;
644     if (!This->node->children)
645     {
646         *hasChild = VARIANT_FALSE;
647         return S_FALSE;
648     }
649
650     *hasChild = VARIANT_TRUE;
651     return S_OK;
652 }
653
654 static HRESULT WINAPI xmlnode_get_ownerDocument(
655     IXMLDOMNode *iface,
656     IXMLDOMDocument** DOMDocument)
657 {
658     FIXME("\n");
659     return E_NOTIMPL;
660 }
661
662 static HRESULT WINAPI xmlnode_cloneNode(
663     IXMLDOMNode *iface,
664     VARIANT_BOOL deep,
665     IXMLDOMNode** cloneRoot)
666 {
667     xmlnode *This = impl_from_IXMLDOMNode( iface );
668     xmlNodePtr pClone = NULL;
669     IXMLDOMNode *pNode = NULL;
670
671     TRACE("%p (%d)\n", This, deep);
672
673     if(!cloneRoot)
674         return E_INVALIDARG;
675
676     pClone = xmlCopyNode(This->node, deep ? 1 : 2);
677     if(pClone)
678     {
679         pClone->doc = This->node->doc;
680
681         pNode = create_node(pClone);
682         if(!pNode)
683         {
684             ERR("Copy failed\n");
685             return E_FAIL;
686         }
687
688         *cloneRoot = pNode;
689     }
690     else
691     {
692         ERR("Copy failed\n");
693         return E_FAIL;
694     }
695
696     return S_OK;
697 }
698
699 static HRESULT WINAPI xmlnode_get_nodeTypeString(
700     IXMLDOMNode *iface,
701     BSTR* xmlnodeType)
702 {
703     xmlnode *This = impl_from_IXMLDOMNode( iface );
704     const xmlChar *str;
705
706     TRACE("%p\n", This );
707
708     if (!xmlnodeType)
709         return E_INVALIDARG;
710
711     if ( !This->node )
712         return E_FAIL;
713
714     switch( This->node->type )
715     {
716     case XML_ATTRIBUTE_NODE:
717         str = (const xmlChar*) "attribute";
718         break;
719     case XML_CDATA_SECTION_NODE:
720         str = (const xmlChar*) "cdatasection";
721         break;
722     case XML_COMMENT_NODE:
723         str = (const xmlChar*) "comment";
724         break;
725     case XML_DOCUMENT_NODE:
726         str = (const xmlChar*) "document";
727         break;
728     case XML_DOCUMENT_FRAG_NODE:
729         str = (const xmlChar*) "documentfragment";
730         break;
731     case XML_ELEMENT_NODE:
732         str = (const xmlChar*) "element";
733         break;
734     case XML_ENTITY_NODE:
735         str = (const xmlChar*) "entity";
736         break;
737     case XML_ENTITY_REF_NODE:
738         str = (const xmlChar*) "entityreference";
739         break;
740     case XML_NOTATION_NODE:
741         str = (const xmlChar*) "notation";
742         break;
743     case XML_PI_NODE:
744         str = (const xmlChar*) "processinginstruction";
745         break;
746     case XML_TEXT_NODE:
747         str = (const xmlChar*) "text";
748         break;
749     default:
750         FIXME("nodeName not mapped correctly (%d)\n", This->node->type);
751         str = This->node->name;
752         break;
753     }
754
755     *xmlnodeType = bstr_from_xmlChar( str );
756     if (!*xmlnodeType)
757         return S_FALSE;
758
759     return S_OK;
760 }
761
762 static HRESULT WINAPI xmlnode_get_text(
763     IXMLDOMNode *iface,
764     BSTR* text)
765 {
766     xmlnode *This = impl_from_IXMLDOMNode( iface );
767     BSTR str = NULL;
768
769     TRACE("%p\n", This);
770
771     if ( !text )
772         return E_INVALIDARG;
773
774     switch(This->node->type)
775     {
776     case XML_ELEMENT_NODE:
777     case XML_ATTRIBUTE_NODE:
778     {
779         xmlNodePtr child = This->node->children;
780         if ( child && child->type == XML_TEXT_NODE )
781             str = bstr_from_xmlChar( child->content );
782         break;
783     }
784
785     case XML_TEXT_NODE:
786     case XML_CDATA_SECTION_NODE:
787     case XML_PI_NODE:
788     case XML_COMMENT_NODE:
789         str = bstr_from_xmlChar( This->node->content );
790         break;
791
792     default:
793         FIXME("Unhandled node type %d\n", This->node->type);
794     }
795
796     /* Always return a string. */
797     if (!str) str = SysAllocStringLen( NULL, 0 );
798
799     TRACE("%p %s\n", This, debugstr_w(str) );
800     *text = str;
801  
802     return S_OK;
803 }
804
805 static HRESULT WINAPI xmlnode_put_text(
806     IXMLDOMNode *iface,
807     BSTR text)
808 {
809     xmlnode *This = impl_from_IXMLDOMNode( iface );
810     xmlChar *str = NULL;
811
812     TRACE("%p\n", This);
813
814     switch(This->node->type)
815     {
816     case XML_DOCUMENT_NODE:
817         return E_FAIL;
818     default:
819         break;
820     }
821
822     str = xmlChar_from_wchar((WCHAR*)text);
823
824     /* Escape the string. */
825     str = xmlEncodeEntitiesReentrant(This->node->doc, str);
826     str = xmlEncodeSpecialChars(This->node->doc, str);
827
828     xmlNodeSetContent(This->node, str);
829     xmlFree(str);
830
831     return S_OK;
832 }
833
834 static HRESULT WINAPI xmlnode_get_specified(
835     IXMLDOMNode *iface,
836     VARIANT_BOOL* isSpecified)
837 {
838     FIXME("\n");
839     return E_NOTIMPL;
840 }
841
842 static HRESULT WINAPI xmlnode_get_definition(
843     IXMLDOMNode *iface,
844     IXMLDOMNode** definitionNode)
845 {
846     FIXME("\n");
847     return E_NOTIMPL;
848 }
849
850 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
851     IXMLDOMNode *iface,
852     VARIANT* typedValue)
853 {
854     FIXME("ignoring data type\n");
855     return xmlnode_get_nodeValue(iface, typedValue);
856 }
857
858 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
859     IXMLDOMNode *iface,
860     VARIANT typedValue)
861 {
862     FIXME("\n");
863     return E_NOTIMPL;
864 }
865
866 static HRESULT WINAPI xmlnode_get_dataType(
867     IXMLDOMNode *iface,
868     VARIANT* dataTypeName)
869 {
870     xmlnode *This = impl_from_IXMLDOMNode( iface );
871     xmlChar *pVal;
872
873     TRACE("iface %p\n", iface);
874
875     if(!dataTypeName)
876         return E_INVALIDARG;
877
878     /* Attribute, CDATA Section, Comment, Document, Document Fragment,
879         Entity, Notation, PI, and Text Node are non-typed. */
880     V_BSTR(dataTypeName) = NULL;
881     V_VT(dataTypeName) = VT_NULL;
882
883     switch ( This->node->type )
884     {
885     case XML_ELEMENT_NODE:
886         pVal = xmlGetNsProp(This->node, (xmlChar*)"dt",
887                             (xmlChar*)"urn:schemas-microsoft-com:datatypes");
888         if (pVal)
889         {
890             V_VT(dataTypeName) = VT_BSTR;
891             V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
892             xmlFree(pVal);
893         }
894         break;
895     case XML_ENTITY_REF_NODE:
896         FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
897         break;
898     default:
899         TRACE("Type %d returning NULL\n", This->node->type);
900     }
901
902     /* non-typed nodes return S_FALSE */
903     if(V_VT(dataTypeName) == VT_NULL)
904     {
905         return S_FALSE;
906     }
907
908     return S_OK;
909 }
910
911 static HRESULT WINAPI xmlnode_put_dataType(
912     IXMLDOMNode *iface,
913     BSTR dataTypeName)
914 {
915     xmlnode *This = impl_from_IXMLDOMNode( iface );
916     HRESULT hr = E_FAIL;
917
918     TRACE("iface %p\n", iface);
919
920     if(dataTypeName == NULL)
921         return E_INVALIDARG;
922
923     /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
924        This applies to changing types (string->bool) or setting a new one
925      */
926     FIXME("Need to Validate the data before allowing a type to be set.\n");
927
928     /* Check all supported types. */
929     if(lstrcmpiW(dataTypeName,szString) == 0  ||
930        lstrcmpiW(dataTypeName,szNumber) == 0  ||
931        lstrcmpiW(dataTypeName,szUUID) == 0    ||
932        lstrcmpiW(dataTypeName,szInt) == 0     ||
933        lstrcmpiW(dataTypeName,szI4) == 0      ||
934        lstrcmpiW(dataTypeName,szFixed) == 0   ||
935        lstrcmpiW(dataTypeName,szBoolean) == 0 ||
936        lstrcmpiW(dataTypeName,szDateTime) == 0 ||
937        lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
938        lstrcmpiW(dataTypeName,szDate) == 0    ||
939        lstrcmpiW(dataTypeName,szTime) == 0    ||
940        lstrcmpiW(dataTypeName,szTimeTZ) == 0  ||
941        lstrcmpiW(dataTypeName,szI1) == 0      ||
942        lstrcmpiW(dataTypeName,szI2) == 0      ||
943        lstrcmpiW(dataTypeName,szIU1) == 0     ||
944        lstrcmpiW(dataTypeName,szIU2) == 0     ||
945        lstrcmpiW(dataTypeName,szIU4) == 0     ||
946        lstrcmpiW(dataTypeName,szR4) == 0      ||
947        lstrcmpiW(dataTypeName,szR8) == 0      ||
948        lstrcmpiW(dataTypeName,szFloat) == 0   ||
949        lstrcmpiW(dataTypeName,szBinHex) == 0  ||
950        lstrcmpiW(dataTypeName,szBinBase64) == 0)
951     {
952         xmlNsPtr pNS = NULL;
953         xmlAttrPtr pAttr = NULL;
954         xmlChar* str = xmlChar_from_wchar((WCHAR*)dataTypeName);
955
956         pAttr = xmlHasNsProp(This->node, (xmlChar*)"dt",
957                             (xmlChar*)"urn:schemas-microsoft-com:datatypes");
958         if (pAttr)
959         {
960             pAttr = xmlSetNsProp(This->node, pAttr->ns, (xmlChar*)"dt", str);
961
962             hr = S_OK;
963         }
964         else
965         {
966             pNS = xmlNewNs(This->node, (xmlChar*)"urn:schemas-microsoft-com:datatypes", (xmlChar*)"dt");
967             if(pNS)
968             {
969                 pAttr = xmlNewNsProp(This->node, pNS, (xmlChar*)"dt", str);
970                 if(pAttr)
971                 {
972                     xmlAddChild(This->node, (xmlNodePtr)pAttr);
973
974                     hr = S_OK;
975                 }
976                 else
977                     ERR("Failed to create Attribute\n");
978             }
979             else
980                 ERR("Failed to Create Namepsace\n");
981         }
982     }
983
984     return hr;
985 }
986
987 static HRESULT WINAPI xmlnode_get_xml(
988     IXMLDOMNode *iface,
989     BSTR* xmlString)
990 {
991     xmlnode *This = impl_from_IXMLDOMNode( iface );
992     xmlBufferPtr pXmlBuf;
993     int nSize;
994
995     TRACE("iface %p\n", iface);
996
997     if(!xmlString)
998         return E_INVALIDARG;
999
1000     *xmlString = NULL;
1001
1002     pXmlBuf = xmlBufferCreate();
1003     if(pXmlBuf)
1004     {
1005         nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 0);
1006         if(nSize > 0)
1007         {
1008             const xmlChar *pContent;
1009
1010             /* Attribute Nodes return a space infront of their name */
1011             pContent = xmlBufferContent(pXmlBuf);
1012             if( ((char*)pContent)[0] == ' ')
1013                 *xmlString = bstr_from_xmlChar(pContent+1);
1014             else
1015                 *xmlString = bstr_from_xmlChar(pContent);
1016
1017
1018             xmlBufferFree(pXmlBuf);
1019         }
1020     }
1021
1022     /* Always returns a string. */
1023     if(*xmlString == NULL)  *xmlString = SysAllocStringLen( NULL, 0 );
1024
1025     return S_OK;
1026 }
1027
1028 static HRESULT WINAPI xmlnode_transformNode(
1029     IXMLDOMNode *iface,
1030     IXMLDOMNode* styleSheet,
1031     BSTR* xmlString)
1032 {
1033     FIXME("\n");
1034     return E_NOTIMPL;
1035 }
1036
1037 static HRESULT WINAPI xmlnode_selectNodes(
1038     IXMLDOMNode *iface,
1039     BSTR queryString,
1040     IXMLDOMNodeList** resultList)
1041 {
1042     xmlnode *This = impl_from_IXMLDOMNode( iface );
1043
1044     TRACE("%p %s %p\n", This, debugstr_w(queryString), resultList );
1045
1046     return queryresult_create( This->node, queryString, resultList );
1047 }
1048
1049 static HRESULT WINAPI xmlnode_selectSingleNode(
1050     IXMLDOMNode *iface,
1051     BSTR queryString,
1052     IXMLDOMNode** resultNode)
1053 {
1054     xmlnode *This = impl_from_IXMLDOMNode( iface );
1055     IXMLDOMNodeList *list;
1056     HRESULT r;
1057
1058     TRACE("%p %s %p\n", This, debugstr_w(queryString), resultNode );
1059
1060     *resultNode = NULL;
1061     r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1062     if(r == S_OK)
1063     {
1064         r = IXMLDOMNodeList_nextNode(list, resultNode);
1065         IXMLDOMNodeList_Release(list);
1066     }
1067     return r;
1068 }
1069
1070 static HRESULT WINAPI xmlnode_get_parsed(
1071     IXMLDOMNode *iface,
1072     VARIANT_BOOL* isParsed)
1073 {
1074     FIXME("\n");
1075     return E_NOTIMPL;
1076 }
1077
1078 static HRESULT WINAPI xmlnode_get_namespaceURI(
1079     IXMLDOMNode *iface,
1080     BSTR* namespaceURI)
1081 {
1082     FIXME("\n");
1083     return E_NOTIMPL;
1084 }
1085
1086 static HRESULT WINAPI xmlnode_get_prefix(
1087     IXMLDOMNode *iface,
1088     BSTR* prefixString)
1089 {
1090     FIXME("\n");
1091     return E_NOTIMPL;
1092 }
1093
1094 static HRESULT WINAPI xmlnode_get_baseName(
1095     IXMLDOMNode *iface,
1096     BSTR* nameString)
1097 {
1098     xmlnode *This = impl_from_IXMLDOMNode( iface );
1099     BSTR str = NULL;
1100     HRESULT r = S_FALSE;
1101
1102     TRACE("%p %p\n", This, nameString );
1103
1104     if ( !nameString )
1105         return E_INVALIDARG;
1106
1107     switch ( This->node->type )
1108     {
1109     case XML_ELEMENT_NODE:
1110     case XML_ATTRIBUTE_NODE:
1111         str = bstr_from_xmlChar( This->node->name );
1112         r = S_OK;
1113         break;
1114     case XML_TEXT_NODE:
1115         break;
1116     default:
1117         ERR("Unhandled type %d\n", This->node->type );
1118         break;
1119     }
1120
1121     TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1122
1123     *nameString = str;
1124     return r;
1125 }
1126
1127 static HRESULT WINAPI xmlnode_transformNodeToObject(
1128     IXMLDOMNode *iface,
1129     IXMLDOMNode* stylesheet,
1130     VARIANT outputObject)
1131 {
1132     FIXME("\n");
1133     return E_NOTIMPL;
1134 }
1135
1136 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1137 {
1138     xmlnode_QueryInterface,
1139     xmlnode_AddRef,
1140     xmlnode_Release,
1141     xmlnode_GetTypeInfoCount,
1142     xmlnode_GetTypeInfo,
1143     xmlnode_GetIDsOfNames,
1144     xmlnode_Invoke,
1145     xmlnode_get_nodeName,
1146     xmlnode_get_nodeValue,
1147     xmlnode_put_nodeValue,
1148     xmlnode_get_nodeType,
1149     xmlnode_get_parentNode,
1150     xmlnode_get_childNodes,
1151     xmlnode_get_firstChild,
1152     xmlnode_get_lastChild,
1153     xmlnode_get_previousSibling,
1154     xmlnode_get_nextSibling,
1155     xmlnode_get_attributes,
1156     xmlnode_insertBefore,
1157     xmlnode_replaceChild,
1158     xmlnode_removeChild,
1159     xmlnode_appendChild,
1160     xmlnode_hasChildNodes,
1161     xmlnode_get_ownerDocument,
1162     xmlnode_cloneNode,
1163     xmlnode_get_nodeTypeString,
1164     xmlnode_get_text,
1165     xmlnode_put_text,
1166     xmlnode_get_specified,
1167     xmlnode_get_definition,
1168     xmlnode_get_nodeTypedValue,
1169     xmlnode_put_nodeTypedValue,
1170     xmlnode_get_dataType,
1171     xmlnode_put_dataType,
1172     xmlnode_get_xml,
1173     xmlnode_transformNode,
1174     xmlnode_selectNodes,
1175     xmlnode_selectSingleNode,
1176     xmlnode_get_parsed,
1177     xmlnode_get_namespaceURI,
1178     xmlnode_get_prefix,
1179     xmlnode_get_baseName,
1180     xmlnode_transformNodeToObject,
1181 };
1182
1183 static HRESULT WINAPI Internal_QueryInterface(
1184     IUnknown *iface,
1185     REFIID riid,
1186     void** ppvObject )
1187 {
1188     xmlnode *This = impl_from_InternalUnknown( iface );
1189
1190     TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
1191
1192
1193     if ( IsEqualGUID( riid, &IID_IUnknown ))
1194         *ppvObject = iface;
1195     else if ( IsEqualGUID( riid, &IID_IDispatch ) ||
1196               IsEqualGUID( riid, &IID_IXMLDOMNode ) )
1197         *ppvObject = &This->lpVtbl;
1198     else
1199     {
1200         FIXME("interface %s not implemented\n", debugstr_guid(riid));
1201         *ppvObject = NULL;
1202         return E_NOINTERFACE;
1203     }
1204
1205     IUnknown_AddRef( (IUnknown*)*ppvObject );
1206
1207     return S_OK;
1208 }
1209
1210 static ULONG WINAPI Internal_AddRef(
1211                  IUnknown *iface )
1212 {
1213     xmlnode *This = impl_from_InternalUnknown( iface );
1214     return InterlockedIncrement( &This->ref );
1215 }
1216
1217 static ULONG WINAPI Internal_Release(
1218     IUnknown *iface )
1219 {
1220     xmlnode *This = impl_from_InternalUnknown( iface );
1221     ULONG ref;
1222
1223     ref = InterlockedDecrement( &This->ref );
1224     if ( ref == 0 )
1225     {
1226         if( This->node )
1227             xmldoc_release( This->node->doc );
1228         HeapFree( GetProcessHeap(), 0, This );
1229     }
1230
1231     return ref;
1232 }
1233
1234 static const struct IUnknownVtbl internal_unk_vtbl =
1235 {
1236     Internal_QueryInterface,
1237     Internal_AddRef,
1238     Internal_Release
1239 };
1240
1241 IUnknown *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter )
1242 {
1243     xmlnode *This;
1244
1245     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
1246     if ( !This )
1247         return NULL;
1248
1249     if(node)
1250         xmldoc_add_ref( node->doc );
1251
1252     This->lpVtbl = &xmlnode_vtbl;
1253     This->lpInternalUnkVtbl = &internal_unk_vtbl;
1254
1255     if(pUnkOuter)
1256         This->pUnkOuter = pUnkOuter; /* Don't take a ref on outer Unknown */
1257     else
1258         This->pUnkOuter = (IUnknown *)&This->lpInternalUnkVtbl;
1259
1260     This->ref = 1;
1261     This->node = node;
1262
1263     return (IUnknown*)&This->lpInternalUnkVtbl;
1264 }
1265
1266 IXMLDOMNode *create_node( xmlNodePtr node )
1267 {
1268     IUnknown *pUnk;
1269     IXMLDOMNode *ret;
1270     HRESULT hr;
1271
1272     if ( !node )
1273         return NULL;
1274
1275     TRACE("type %d\n", node->type);
1276     switch(node->type)
1277     {
1278     case XML_ELEMENT_NODE:
1279         pUnk = create_element( node, NULL );
1280         break;
1281     case XML_ATTRIBUTE_NODE:
1282         pUnk = create_attribute( node );
1283         break;
1284     case XML_TEXT_NODE:
1285         pUnk = create_text( node );
1286         break;
1287     case XML_COMMENT_NODE:
1288         pUnk = create_comment( node );
1289         break;
1290     case XML_DOCUMENT_NODE:
1291         ERR("shouldn't be here!\n");
1292         return NULL;
1293     default:
1294         FIXME("only creating basic node for type %d\n", node->type);
1295         pUnk = create_basic_node( node, NULL );
1296     }
1297
1298     hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1299     IUnknown_Release(pUnk);
1300     if(FAILED(hr)) return NULL;
1301     return ret;
1302 }
1303 #endif