4 * Copyright 2005 Mike McCormack
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.
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.
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
34 #include "msxml_private.h"
37 # include <libxml/HTMLtree.h>
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
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};
69 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
75 This = impl_from_IXMLDOMNode( iface );
78 if ( type && This->node->type != type )
83 static HRESULT WINAPI xmlnode_QueryInterface(
88 xmlnode *This = impl_from_IXMLDOMNode( iface );
90 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
93 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
95 if (IsEqualGUID(riid, &IID_IUnknown)) {
97 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
98 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
99 *ppvObject = &This->lpVtbl;
101 FIXME("interface %s not implemented\n", debugstr_guid(riid));
103 return E_NOINTERFACE;
106 IUnknown_AddRef( (IUnknown*)*ppvObject );
110 static ULONG WINAPI xmlnode_AddRef(
113 xmlnode *This = impl_from_IXMLDOMNode( iface );
116 return IUnknown_AddRef(This->pUnkOuter);
118 return InterlockedIncrement(&This->ref);
121 static ULONG WINAPI xmlnode_Release(
124 xmlnode *This = impl_from_IXMLDOMNode( iface );
128 return IUnknown_Release(This->pUnkOuter);
130 ref = InterlockedDecrement( &This->ref );
132 destroy_xmlnode(This);
133 HeapFree( GetProcessHeap(), 0, This );
139 static HRESULT WINAPI xmlnode_GetTypeInfoCount(
143 xmlnode *This = impl_from_IXMLDOMNode( iface );
145 TRACE("(%p)->(%p)\n", This, pctinfo);
152 static HRESULT WINAPI xmlnode_GetTypeInfo(
156 ITypeInfo** ppTInfo )
158 xmlnode *This = impl_from_IXMLDOMNode( iface );
161 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
163 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
168 static HRESULT WINAPI xmlnode_GetIDsOfNames(
176 xmlnode *This = impl_from_IXMLDOMNode( iface );
181 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
184 if(!rgszNames || cNames == 0 || !rgDispId)
187 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
190 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
191 ITypeInfo_Release(typeinfo);
197 static HRESULT WINAPI xmlnode_Invoke(
203 DISPPARAMS* pDispParams,
205 EXCEPINFO* pExcepInfo,
208 xmlnode *This = impl_from_IXMLDOMNode( iface );
212 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
213 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
215 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
218 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
219 pVarResult, pExcepInfo, puArgErr);
220 ITypeInfo_Release(typeinfo);
226 static HRESULT WINAPI xmlnode_get_nodeName(
230 xmlnode *This = impl_from_IXMLDOMNode( iface );
233 TRACE("%p\n", This );
241 switch( This->node->type )
243 case XML_CDATA_SECTION_NODE:
244 str = (const xmlChar*) "#cdata-section";
246 case XML_COMMENT_NODE:
247 str = (const xmlChar*) "#comment";
249 case XML_DOCUMENT_FRAG_NODE:
250 str = (const xmlChar*) "#document-fragment";
253 str = (const xmlChar*) "#text";
255 case XML_DOCUMENT_NODE:
256 str = (const xmlChar*) "#document";
258 case XML_ATTRIBUTE_NODE:
259 case XML_ELEMENT_NODE:
261 str = This->node->name;
264 FIXME("nodeName not mapped correctly (%d)\n", This->node->type);
265 str = This->node->name;
269 *name = bstr_from_xmlChar( str );
276 static HRESULT WINAPI xmlnode_get_nodeValue(
280 xmlnode *This = impl_from_IXMLDOMNode( iface );
283 TRACE("%p %p\n", This, value);
288 V_BSTR(value) = NULL;
289 V_VT(value) = VT_NULL;
291 switch ( This->node->type )
293 case XML_CDATA_SECTION_NODE:
294 case XML_COMMENT_NODE:
296 case XML_ATTRIBUTE_NODE:
298 xmlChar *content = xmlNodeGetContent(This->node);
299 V_VT(value) = VT_BSTR;
300 V_BSTR(value) = bstr_from_xmlChar( content );
306 V_VT(value) = VT_BSTR;
307 V_BSTR(value) = bstr_from_xmlChar( This->node->content );
310 case XML_ELEMENT_NODE:
311 case XML_DOCUMENT_NODE:
312 /* these seem to return NULL */
316 FIXME("node %p type %d\n", This, This->node->type);
319 TRACE("%p returned %s\n", This, debugstr_w( V_BSTR(value) ) );
324 static HRESULT WINAPI xmlnode_put_nodeValue(
328 xmlnode *This = impl_from_IXMLDOMNode( iface );
331 VARIANT string_value;
333 TRACE("%p type(%d)\n", This, This->node->type);
335 VariantInit(&string_value);
336 hr = VariantChangeType(&string_value, &value, 0, VT_BSTR);
339 VariantClear(&string_value);
340 WARN("Couldn't convert to VT_BSTR\n");
345 /* Document, Document Fragment, Document Type, Element,
346 Entity, Entity Reference, Notation aren't supported. */
347 switch ( This->node->type )
349 case XML_ATTRIBUTE_NODE:
350 case XML_CDATA_SECTION_NODE:
351 case XML_COMMENT_NODE:
355 str = xmlChar_from_wchar(V_BSTR(&string_value));
356 xmlNodeSetContent(This->node, str);
357 HeapFree(GetProcessHeap(),0,str);
362 /* Do nothing for unsupported types. */
366 VariantClear(&string_value);
371 static HRESULT WINAPI xmlnode_get_nodeType(
375 xmlnode *This = impl_from_IXMLDOMNode( iface );
377 TRACE("%p %p\n", This, type);
379 assert( (int)NODE_ELEMENT == (int)XML_ELEMENT_NODE );
380 assert( (int)NODE_NOTATION == (int)XML_NOTATION_NODE );
382 *type = This->node->type;
387 static HRESULT get_node(
393 TRACE("%p->%s %p\n", This, name, node );
398 /* if we don't have a doc, use our parent. */
399 if(node && !node->doc && node->parent)
400 node->doc = node->parent->doc;
402 *out = create_node( node );
408 static HRESULT WINAPI xmlnode_get_parentNode(
410 IXMLDOMNode** parent)
412 xmlnode *This = impl_from_IXMLDOMNode( iface );
413 return get_node( This, "parent", This->node->parent, parent );
416 static HRESULT WINAPI xmlnode_get_childNodes(
418 IXMLDOMNodeList** childList)
420 xmlnode *This = impl_from_IXMLDOMNode( iface );
422 TRACE("%p %p\n", This, childList );
427 *childList = create_children_nodelist(This->node);
428 if (*childList == NULL)
429 return E_OUTOFMEMORY;
434 static HRESULT WINAPI xmlnode_get_firstChild(
436 IXMLDOMNode** firstChild)
438 xmlnode *This = impl_from_IXMLDOMNode( iface );
439 return get_node( This, "firstChild", This->node->children, firstChild );
442 static HRESULT WINAPI xmlnode_get_lastChild(
444 IXMLDOMNode** lastChild)
446 xmlnode *This = impl_from_IXMLDOMNode( iface );
448 TRACE("%p\n", This );
453 switch( This->node->type )
455 /* CDATASection, Comment, PI and Text Nodes do not support lastChild */
457 case XML_CDATA_SECTION_NODE:
459 case XML_COMMENT_NODE:
463 return get_node( This, "lastChild", This->node->last, lastChild );
467 static HRESULT WINAPI xmlnode_get_previousSibling(
469 IXMLDOMNode** previousSibling)
471 xmlnode *This = impl_from_IXMLDOMNode( iface );
473 TRACE("%p\n", This );
475 if (!previousSibling)
478 switch( This->node->type )
480 /* Attribute, Document and Document Fragment Nodes do not support previousSibling */
481 case XML_DOCUMENT_NODE:
482 case XML_DOCUMENT_FRAG_NODE:
483 case XML_ATTRIBUTE_NODE:
484 *previousSibling = NULL;
487 return get_node( This, "previous", This->node->prev, previousSibling );
491 static HRESULT WINAPI xmlnode_get_nextSibling(
493 IXMLDOMNode** nextSibling)
495 xmlnode *This = impl_from_IXMLDOMNode( iface );
497 TRACE("%p\n", This );
502 switch( This->node->type )
504 /* Attribute, Document and Document Fragment Nodes do not support nextSibling */
505 case XML_DOCUMENT_NODE:
506 case XML_DOCUMENT_FRAG_NODE:
507 case XML_ATTRIBUTE_NODE:
511 return get_node( This, "next", This->node->next, nextSibling );
515 static HRESULT WINAPI xmlnode_get_attributes(
517 IXMLDOMNamedNodeMap** attributeMap)
519 xmlnode *This = impl_from_IXMLDOMNode( iface );
525 switch( This->node->type )
527 /* Attribute, CDataSection, Comment, Documents, Documents Fragments,
528 Entity and Text Nodes does not support get_attributes */
529 case XML_ATTRIBUTE_NODE:
530 case XML_CDATA_SECTION_NODE:
531 case XML_COMMENT_NODE:
532 case XML_DOCUMENT_NODE:
533 case XML_DOCUMENT_FRAG_NODE:
534 case XML_ENTITY_NODE:
535 case XML_ENTITY_REF_NODE:
537 *attributeMap = NULL;
540 *attributeMap = create_nodemap( iface );
545 static HRESULT WINAPI xmlnode_insertBefore(
547 IXMLDOMNode* newChild,
549 IXMLDOMNode** outNewChild)
551 xmlnode *This = impl_from_IXMLDOMNode( iface );
552 xmlNodePtr before_node, new_child_node;
553 IXMLDOMNode *before = NULL, *new;
556 TRACE("(%p)->(%p,var,%p)\n",This,newChild,outNewChild);
561 switch(V_VT(&refChild))
568 hr = IUnknown_QueryInterface(V_UNKNOWN(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
569 if(FAILED(hr)) return hr;
573 hr = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
574 if(FAILED(hr)) return hr;
578 FIXME("refChild var type %x\n", V_VT(&refChild));
582 IXMLDOMNode_QueryInterface(newChild, &IID_IXMLDOMNode, (LPVOID)&new);
583 new_child_node = impl_from_IXMLDOMNode(new)->node;
584 TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
586 if(!new_child_node->parent)
587 if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
588 WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
592 before_node = impl_from_IXMLDOMNode(before)->node;
593 xmlAddPrevSibling(before_node, new_child_node);
594 IXMLDOMNode_Release(before);
598 xmlAddChild(This->node, new_child_node);
601 IXMLDOMNode_Release(new);
602 IXMLDOMNode_AddRef(newChild);
604 *outNewChild = newChild;
610 static HRESULT WINAPI xmlnode_replaceChild(
612 IXMLDOMNode* newChild,
613 IXMLDOMNode* oldChild,
614 IXMLDOMNode** outOldChild)
616 xmlnode *This = impl_from_IXMLDOMNode( iface );
617 xmlNode *old_child_ptr, *new_child_ptr;
618 xmlDocPtr leaving_doc;
619 xmlNode *my_ancestor;
620 IXMLDOMNode *realOldChild;
623 TRACE("%p->(%p,%p,%p)\n",This,newChild,oldChild,outOldChild);
625 /* Do not believe any documentation telling that newChild == NULL
626 means removal. It does certainly *not* apply to msxml3! */
627 if(!newChild || !oldChild)
633 hr = IXMLDOMNode_QueryInterface(oldChild,&IID_IXMLDOMNode,(LPVOID*)&realOldChild);
637 old_child_ptr = impl_from_IXMLDOMNode(realOldChild)->node;
638 IXMLDOMNode_Release(realOldChild);
639 if(old_child_ptr->parent != This->node)
641 WARN("childNode %p is not a child of %p\n", oldChild, iface);
645 new_child_ptr = impl_from_IXMLDOMNode(newChild)->node;
646 my_ancestor = This->node;
649 if(my_ancestor == new_child_ptr)
651 WARN("tried to create loop\n");
654 my_ancestor = my_ancestor->parent;
657 if(!new_child_ptr->parent)
658 if(xmldoc_remove_orphan(new_child_ptr->doc, new_child_ptr) != S_OK)
659 WARN("%p is not an orphan of %p\n", new_child_ptr, new_child_ptr->doc);
661 leaving_doc = new_child_ptr->doc;
662 xmldoc_add_ref(old_child_ptr->doc);
663 xmlReplaceNode(old_child_ptr, new_child_ptr);
664 xmldoc_release(leaving_doc);
666 xmldoc_add_orphan(old_child_ptr->doc, old_child_ptr);
670 IXMLDOMNode_AddRef(oldChild);
671 *outOldChild = oldChild;
677 static HRESULT WINAPI xmlnode_removeChild(
679 IXMLDOMNode* childNode,
680 IXMLDOMNode** oldChild)
682 xmlnode *This = impl_from_IXMLDOMNode( iface );
683 xmlNode *child_node_ptr;
687 TRACE("%p->(%p, %p)\n", This, childNode, oldChild);
689 if(!childNode) return E_INVALIDARG;
694 hr = IXMLDOMNode_QueryInterface(childNode, &IID_IXMLDOMNode, (LPVOID)&child);
698 child_node_ptr = impl_from_IXMLDOMNode(child)->node;
699 if(child_node_ptr->parent != This->node)
701 WARN("childNode %p is not a child of %p\n", childNode, iface);
702 IXMLDOMNode_Release(child);
706 xmlUnlinkNode(child_node_ptr);
708 IXMLDOMNode_Release(child);
712 IXMLDOMNode_AddRef(childNode);
713 *oldChild = childNode;
719 static HRESULT WINAPI xmlnode_appendChild(
721 IXMLDOMNode* newChild,
722 IXMLDOMNode** outNewChild)
724 xmlnode *This = impl_from_IXMLDOMNode( iface );
729 TRACE("(%p)->(%p,%p)\n", This, newChild, outNewChild);
731 hr = IXMLDOMNode_get_nodeType(newChild, &type);
732 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
733 if(outNewChild) *outNewChild = NULL;
738 return IXMLDOMNode_insertBefore(iface, newChild, var, outNewChild);
741 static HRESULT WINAPI xmlnode_hasChildNodes(
743 VARIANT_BOOL* hasChild)
745 xmlnode *This = impl_from_IXMLDOMNode( iface );
751 if (!This->node->children)
753 *hasChild = VARIANT_FALSE;
757 *hasChild = VARIANT_TRUE;
761 static HRESULT WINAPI xmlnode_get_ownerDocument(
763 IXMLDOMDocument** DOMDocument)
765 xmlnode *This = impl_from_IXMLDOMNode( iface );
767 TRACE("%p (%p)\n", This, DOMDocument);
769 return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument2**)DOMDocument);
772 static HRESULT WINAPI xmlnode_cloneNode(
775 IXMLDOMNode** cloneRoot)
777 xmlnode *This = impl_from_IXMLDOMNode( iface );
778 xmlNodePtr pClone = NULL;
779 IXMLDOMNode *pNode = NULL;
781 TRACE("%p (%d)\n", This, deep);
786 pClone = xmlCopyNode(This->node, deep ? 1 : 2);
789 pClone->doc = This->node->doc;
790 xmldoc_add_orphan(pClone->doc, pClone);
792 pNode = create_node(pClone);
795 ERR("Copy failed\n");
803 ERR("Copy failed\n");
810 static HRESULT WINAPI xmlnode_get_nodeTypeString(
814 xmlnode *This = impl_from_IXMLDOMNode( iface );
817 TRACE("%p\n", This );
825 switch( This->node->type )
827 case XML_ATTRIBUTE_NODE:
828 str = (const xmlChar*) "attribute";
830 case XML_CDATA_SECTION_NODE:
831 str = (const xmlChar*) "cdatasection";
833 case XML_COMMENT_NODE:
834 str = (const xmlChar*) "comment";
836 case XML_DOCUMENT_NODE:
837 str = (const xmlChar*) "document";
839 case XML_DOCUMENT_FRAG_NODE:
840 str = (const xmlChar*) "documentfragment";
842 case XML_ELEMENT_NODE:
843 str = (const xmlChar*) "element";
845 case XML_ENTITY_NODE:
846 str = (const xmlChar*) "entity";
848 case XML_ENTITY_REF_NODE:
849 str = (const xmlChar*) "entityreference";
851 case XML_NOTATION_NODE:
852 str = (const xmlChar*) "notation";
855 str = (const xmlChar*) "processinginstruction";
858 str = (const xmlChar*) "text";
861 FIXME("Unknown node type (%d)\n", This->node->type);
862 str = This->node->name;
866 *xmlnodeType = bstr_from_xmlChar( str );
873 static HRESULT WINAPI xmlnode_get_text(
877 xmlnode *This = impl_from_IXMLDOMNode( iface );
881 TRACE("%p type %d\n", This, This->node->type);
886 pContent = xmlNodeGetContent((xmlNodePtr)This->node);
889 str = bstr_from_xmlChar(pContent);
893 /* Always return a string. */
894 if (!str) str = SysAllocStringLen( NULL, 0 );
896 TRACE("%p %s\n", This, debugstr_w(str) );
902 static HRESULT WINAPI xmlnode_put_text(
906 xmlnode *This = impl_from_IXMLDOMNode( iface );
911 switch(This->node->type)
913 case XML_DOCUMENT_NODE:
919 str = xmlChar_from_wchar(text);
921 /* Escape the string. */
922 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
923 HeapFree(GetProcessHeap(), 0, str);
925 xmlNodeSetContent(This->node, str2);
931 static HRESULT WINAPI xmlnode_get_specified(
933 VARIANT_BOOL* isSpecified)
939 static HRESULT WINAPI xmlnode_get_definition(
941 IXMLDOMNode** definitionNode)
947 static HRESULT WINAPI xmlnode_get_dataType(IXMLDOMNode*, VARIANT*);
949 static inline BYTE hex_to_byte(xmlChar c)
951 if(c <= '9') return c-'0';
952 if(c <= 'F') return c-'A'+10;
956 static inline BYTE base64_to_byte(xmlChar c)
958 if(c == '+') return 62;
959 if(c == '/') return 63;
960 if(c <= '9') return c-'0'+52;
961 if(c <= 'Z') return c-'A';
965 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
967 if(!type || !lstrcmpiW(type, szString) ||
968 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
971 V_BSTR(v) = bstr_from_xmlChar(str);
974 return E_OUTOFMEMORY;
976 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
977 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
978 !lstrcmpiW(type, szTimeTZ))
988 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
990 V_VT(&src) = VT_BSTR;
991 V_BSTR(&src) = bstr_from_xmlChar(str);
994 return E_OUTOFMEMORY;
997 e = p + SysStringLen(V_BSTR(&src));
999 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
1001 st.wYear = atoiW(p);
1002 st.wMonth = atoiW(p+5);
1003 st.wDay = atoiW(p+8);
1009 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
1011 st.wHour = atoiW(p);
1012 st.wMinute = atoiW(p+3);
1013 st.wSecond = atoiW(p+6);
1019 while(isdigitW(*p)) p++;
1023 SystemTimeToVariantTime(&st, &date);
1027 if(*p == '+') /* parse timezone offset (+hh:mm) */
1028 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1029 else if(*p == '-') /* parse timezone offset (-hh:mm) */
1030 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1034 else if(!lstrcmpiW(type, szBinHex))
1039 len = xmlStrlen(str)/2;
1041 sab.cElements = len;
1043 V_VT(v) = (VT_ARRAY|VT_UI1);
1044 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1047 return E_OUTOFMEMORY;
1049 for(i=0; i<len; i++)
1050 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
1051 + hex_to_byte(str[2*i+1]);
1053 else if(!lstrcmpiW(type, szBinBase64))
1058 len = xmlStrlen(str);
1059 if(str[len-2] == '=') i = 2;
1060 else if(str[len-1] == '=') i = 1;
1064 sab.cElements = len/4*3-i;
1066 V_VT(v) = (VT_ARRAY|VT_UI1);
1067 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1070 return E_OUTOFMEMORY;
1072 for(i=0; i<len/4; i++)
1074 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
1075 + (base64_to_byte(str[4*i+1])>>4);
1076 if(3*i+1 < sab.cElements)
1077 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
1078 + (base64_to_byte(str[4*i+2])>>2);
1079 if(3*i+2 < sab.cElements)
1080 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
1081 + base64_to_byte(str[4*i+3]);
1089 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
1091 else if(!lstrcmpiW(type, szFixed))
1093 else if(!lstrcmpiW(type, szBoolean))
1095 else if(!lstrcmpiW(type, szI1))
1097 else if(!lstrcmpiW(type, szI2))
1099 else if(!lstrcmpiW(type, szIU1))
1101 else if(!lstrcmpiW(type, szIU2))
1103 else if(!lstrcmpiW(type, szIU4))
1105 else if(!lstrcmpiW(type, szR4))
1107 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
1111 FIXME("Type handling not yet implemented\n");
1115 V_VT(&src) = VT_BSTR;
1116 V_BSTR(&src) = bstr_from_xmlChar(str);
1119 return E_OUTOFMEMORY;
1121 hres = VariantChangeType(v, &src, 0, V_VT(v));
1129 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
1131 VARIANT* typedValue)
1133 xmlnode *This = impl_from_IXMLDOMNode( iface );
1136 HRESULT hres = S_FALSE;
1138 TRACE("iface %p\n", iface);
1141 return E_INVALIDARG;
1143 V_VT(typedValue) = VT_NULL;
1145 if(This->node->type == XML_ELEMENT_NODE ||
1146 This->node->type == XML_TEXT_NODE ||
1147 This->node->type == XML_ENTITY_REF_NODE)
1148 hres = xmlnode_get_dataType(iface, &type);
1150 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
1151 return xmlnode_get_nodeValue(iface, typedValue);
1153 content = xmlNodeGetContent(This->node);
1154 hres = VARIANT_from_xmlChar(content, typedValue,
1155 hres==S_OK ? V_BSTR(&type) : NULL);
1157 VariantClear(&type);
1162 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
1170 static HRESULT WINAPI xmlnode_get_dataType(
1172 VARIANT* dataTypeName)
1174 xmlnode *This = impl_from_IXMLDOMNode( iface );
1177 TRACE("iface %p\n", iface);
1180 return E_INVALIDARG;
1182 /* Attribute, CDATA Section, Comment, Document, Document Fragment,
1183 Entity, Notation, PI, and Text Node are non-typed. */
1184 V_BSTR(dataTypeName) = NULL;
1185 V_VT(dataTypeName) = VT_NULL;
1187 switch ( This->node->type )
1189 case XML_ELEMENT_NODE:
1190 pVal = xmlGetNsProp(This->node, (xmlChar*)"dt",
1191 (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1194 V_VT(dataTypeName) = VT_BSTR;
1195 V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
1199 case XML_ENTITY_REF_NODE:
1200 FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
1203 TRACE("Type %d returning NULL\n", This->node->type);
1206 /* non-typed nodes return S_FALSE */
1207 if(V_VT(dataTypeName) == VT_NULL)
1215 static HRESULT WINAPI xmlnode_put_dataType(
1219 xmlnode *This = impl_from_IXMLDOMNode( iface );
1220 HRESULT hr = E_FAIL;
1222 TRACE("iface %p\n", iface);
1224 if(dataTypeName == NULL)
1225 return E_INVALIDARG;
1227 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1228 This applies to changing types (string->bool) or setting a new one
1230 FIXME("Need to Validate the data before allowing a type to be set.\n");
1232 /* Check all supported types. */
1233 if(lstrcmpiW(dataTypeName,szString) == 0 ||
1234 lstrcmpiW(dataTypeName,szNumber) == 0 ||
1235 lstrcmpiW(dataTypeName,szUUID) == 0 ||
1236 lstrcmpiW(dataTypeName,szInt) == 0 ||
1237 lstrcmpiW(dataTypeName,szI4) == 0 ||
1238 lstrcmpiW(dataTypeName,szFixed) == 0 ||
1239 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1240 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1241 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1242 lstrcmpiW(dataTypeName,szDate) == 0 ||
1243 lstrcmpiW(dataTypeName,szTime) == 0 ||
1244 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
1245 lstrcmpiW(dataTypeName,szI1) == 0 ||
1246 lstrcmpiW(dataTypeName,szI2) == 0 ||
1247 lstrcmpiW(dataTypeName,szIU1) == 0 ||
1248 lstrcmpiW(dataTypeName,szIU2) == 0 ||
1249 lstrcmpiW(dataTypeName,szIU4) == 0 ||
1250 lstrcmpiW(dataTypeName,szR4) == 0 ||
1251 lstrcmpiW(dataTypeName,szR8) == 0 ||
1252 lstrcmpiW(dataTypeName,szFloat) == 0 ||
1253 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
1254 lstrcmpiW(dataTypeName,szBinBase64) == 0)
1256 xmlNsPtr pNS = NULL;
1257 xmlAttrPtr pAttr = NULL;
1258 xmlChar* str = xmlChar_from_wchar(dataTypeName);
1260 pAttr = xmlHasNsProp(This->node, (xmlChar*)"dt",
1261 (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1264 pAttr = xmlSetNsProp(This->node, pAttr->ns, (xmlChar*)"dt", str);
1270 pNS = xmlNewNs(This->node, (xmlChar*)"urn:schemas-microsoft-com:datatypes", (xmlChar*)"dt");
1273 pAttr = xmlNewNsProp(This->node, pNS, (xmlChar*)"dt", str);
1276 xmlAddChild(This->node, (xmlNodePtr)pAttr);
1281 ERR("Failed to create Attribute\n");
1284 ERR("Failed to Create Namepsace\n");
1286 HeapFree( GetProcessHeap(), 0, str );
1292 static BSTR EnsureCorrectEOL(BSTR sInput)
1294 static const WCHAR SZ_RETURN[] = {'\n',0};
1295 static const WCHAR SZ_LINEFEED[] = {'\r',0};
1301 nLen = lstrlenW(sInput);
1302 /* Count line endings */
1303 for(i=0; i < nLen; i++)
1305 if(sInput[i] == SZ_RETURN[0])
1309 TRACE("len=%d, num=%d\n", nLen, nNum);
1311 /* Add linefeed as needed */
1315 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1316 for(i=0; i < nLen; i++)
1318 if(sInput[i] == SZ_RETURN[0])
1320 sNew[i+nPlace] = SZ_LINEFEED[0];
1323 sNew[i+nPlace] = sInput[i];
1326 SysFreeString(sInput);
1333 TRACE("len %d\n", lstrlenW(sNew));
1338 /* Removes encoding information and last character (nullbyte) */
1339 static BSTR EnsureNoEncoding(BSTR sInput)
1341 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1346 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1351 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1356 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1357 while(*pEnd != '\"') pEnd++;
1360 sNew = SysAllocStringLen(NULL,
1361 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1362 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1363 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1365 SysFreeString(sInput);
1370 * We are trying to replicate the same behaviour as msxml by converting
1371 * line endings to \r\n and using idents as \t. The problem is that msxml
1372 * only formats nodes that have a line ending. Using libxml we cannot
1373 * reproduce behaviour exactly.
1376 static HRESULT WINAPI xmlnode_get_xml(
1380 xmlnode *This = impl_from_IXMLDOMNode( iface );
1381 xmlBufferPtr pXmlBuf;
1384 TRACE("iface %p %d\n", iface, This->node->type);
1387 return E_INVALIDARG;
1391 pXmlBuf = xmlBufferCreate();
1394 nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1397 const xmlChar *pContent;
1400 /* Attribute Nodes return a space in front of their name */
1401 pContent = xmlBufferContent(pXmlBuf);
1402 if( ((char*)pContent)[0] == ' ')
1403 bstrContent = bstr_from_xmlChar(pContent+1);
1405 bstrContent = bstr_from_xmlChar(pContent);
1407 switch(This->node->type)
1409 case XML_ELEMENT_NODE:
1410 *xmlString = EnsureCorrectEOL(bstrContent);
1412 case XML_DOCUMENT_NODE:
1413 *xmlString = EnsureCorrectEOL(bstrContent);
1414 *xmlString = EnsureNoEncoding(*xmlString);
1417 *xmlString = bstrContent;
1421 xmlBufferFree(pXmlBuf);
1424 /* Always returns a string. */
1425 if(*xmlString == NULL) *xmlString = SysAllocStringLen( NULL, 0 );
1430 static HRESULT WINAPI xmlnode_transformNode(
1432 IXMLDOMNode* styleSheet,
1435 #ifdef SONAME_LIBXSLT
1436 xmlnode *This = impl_from_IXMLDOMNode( iface );
1437 xmlnode *pStyleSheet = NULL;
1438 xsltStylesheetPtr xsltSS = NULL;
1439 xmlDocPtr result = NULL;
1442 TRACE("%p %p %p\n", This, styleSheet, xmlString);
1444 if (!libxslt_handle)
1446 if(!styleSheet || !xmlString)
1447 return E_INVALIDARG;
1451 if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1453 pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1455 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1458 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1461 const xmlChar *pContent;
1463 if(result->type == XML_HTML_DOCUMENT_NODE)
1465 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1468 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1469 pContent = xmlBufferContent(pOutput->buffer);
1470 *xmlString = bstr_from_xmlChar(pContent);
1471 xmlOutputBufferClose(pOutput);
1476 xmlBufferPtr pXmlBuf;
1479 pXmlBuf = xmlBufferCreate();
1482 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1485 pContent = xmlBufferContent(pXmlBuf);
1486 *xmlString = bstr_from_xmlChar(pContent);
1488 xmlBufferFree(pXmlBuf);
1493 /* libxslt "helpfully" frees the XML document the stylesheet was
1494 generated from, too */
1496 pxsltFreeStylesheet(xsltSS);
1499 IXMLDOMNode_Release(ssNew);
1502 if(*xmlString == NULL)
1503 *xmlString = SysAllocStringLen(NULL, 0);
1507 FIXME("libxslt headers were not found at compile time\n");
1512 static HRESULT WINAPI xmlnode_selectNodes(
1515 IXMLDOMNodeList** resultList)
1517 xmlnode *This = impl_from_IXMLDOMNode( iface );
1519 TRACE("%p %s %p\n", This, debugstr_w(queryString), resultList );
1521 return queryresult_create( This->node, queryString, resultList );
1524 static HRESULT WINAPI xmlnode_selectSingleNode(
1527 IXMLDOMNode** resultNode)
1529 xmlnode *This = impl_from_IXMLDOMNode( iface );
1530 IXMLDOMNodeList *list;
1533 TRACE("%p %s %p\n", This, debugstr_w(queryString), resultNode );
1536 r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1539 r = IXMLDOMNodeList_nextNode(list, resultNode);
1540 IXMLDOMNodeList_Release(list);
1545 static HRESULT WINAPI xmlnode_get_parsed(
1547 VARIANT_BOOL* isParsed)
1553 static HRESULT WINAPI xmlnode_get_namespaceURI(
1557 xmlnode *This = impl_from_IXMLDOMNode( iface );
1558 HRESULT hr = S_FALSE;
1561 TRACE("%p %p\n", This, namespaceURI );
1564 return E_INVALIDARG;
1566 *namespaceURI = NULL;
1568 pNSList = xmlGetNsList(This->node->doc, This->node);
1571 *namespaceURI = bstr_from_xmlChar( pNSList[0]->href );
1580 static HRESULT WINAPI xmlnode_get_prefix(
1584 xmlnode *This = impl_from_IXMLDOMNode( iface );
1585 HRESULT hr = S_FALSE;
1588 TRACE("%p %p\n", This, prefixString );
1591 return E_INVALIDARG;
1593 *prefixString = NULL;
1595 pNSList = xmlGetNsList(This->node->doc, This->node);
1598 *prefixString = bstr_from_xmlChar( pNSList[0]->prefix );
1607 static HRESULT WINAPI xmlnode_get_baseName(
1611 xmlnode *This = impl_from_IXMLDOMNode( iface );
1613 HRESULT r = S_FALSE;
1615 TRACE("%p %p\n", This, nameString );
1618 return E_INVALIDARG;
1620 switch ( This->node->type )
1622 case XML_ELEMENT_NODE:
1623 case XML_ATTRIBUTE_NODE:
1624 str = bstr_from_xmlChar( This->node->name );
1630 ERR("Unhandled type %d\n", This->node->type );
1634 TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1640 static HRESULT WINAPI xmlnode_transformNodeToObject(
1642 IXMLDOMNode* stylesheet,
1643 VARIANT outputObject)
1649 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1651 xmlnode_QueryInterface,
1654 xmlnode_GetTypeInfoCount,
1655 xmlnode_GetTypeInfo,
1656 xmlnode_GetIDsOfNames,
1658 xmlnode_get_nodeName,
1659 xmlnode_get_nodeValue,
1660 xmlnode_put_nodeValue,
1661 xmlnode_get_nodeType,
1662 xmlnode_get_parentNode,
1663 xmlnode_get_childNodes,
1664 xmlnode_get_firstChild,
1665 xmlnode_get_lastChild,
1666 xmlnode_get_previousSibling,
1667 xmlnode_get_nextSibling,
1668 xmlnode_get_attributes,
1669 xmlnode_insertBefore,
1670 xmlnode_replaceChild,
1671 xmlnode_removeChild,
1672 xmlnode_appendChild,
1673 xmlnode_hasChildNodes,
1674 xmlnode_get_ownerDocument,
1676 xmlnode_get_nodeTypeString,
1679 xmlnode_get_specified,
1680 xmlnode_get_definition,
1681 xmlnode_get_nodeTypedValue,
1682 xmlnode_put_nodeTypedValue,
1683 xmlnode_get_dataType,
1684 xmlnode_put_dataType,
1686 xmlnode_transformNode,
1687 xmlnode_selectNodes,
1688 xmlnode_selectSingleNode,
1690 xmlnode_get_namespaceURI,
1692 xmlnode_get_baseName,
1693 xmlnode_transformNodeToObject,
1696 void destroy_xmlnode(xmlnode *This)
1699 xmldoc_release(This->node->doc);
1702 void init_xmlnode(xmlnode *This, xmlNodePtr node, IUnknown *outer, dispex_static_data_t *dispex_data )
1705 xmldoc_add_ref( node->doc );
1707 This->lpVtbl = &xmlnode_vtbl;
1710 This->pUnkOuter = outer;
1713 init_dispex(&This->dispex, This->pUnkOuter, dispex_data);
1716 IXMLDOMNode *create_node( xmlNodePtr node )
1725 TRACE("type %d\n", node->type);
1728 case XML_ELEMENT_NODE:
1729 pUnk = create_element( node );
1731 case XML_ATTRIBUTE_NODE:
1732 pUnk = create_attribute( node );
1735 pUnk = create_text( node );
1737 case XML_CDATA_SECTION_NODE:
1738 pUnk = create_cdata( node );
1740 case XML_COMMENT_NODE:
1741 pUnk = create_comment( node );
1743 case XML_DOCUMENT_NODE:
1744 pUnk = create_domdoc( node );
1749 FIXME("only creating basic node for type %d\n", node->type);
1751 new_node = heap_alloc(sizeof(xmlnode));
1755 init_xmlnode(new_node, node, NULL, NULL);
1756 pUnk = (IUnknown*)IXMLDOMNode_from_impl(new_node);
1760 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1761 IUnknown_Release(pUnk);
1762 if(FAILED(hr)) return NULL;