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);
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);
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);
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 = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
1122 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
1130 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
1132 VARIANT* typedValue)
1134 xmlnode *This = impl_from_IXMLDOMNode( iface );
1137 HRESULT hres = S_FALSE;
1139 TRACE("iface %p\n", iface);
1142 return E_INVALIDARG;
1144 V_VT(typedValue) = VT_NULL;
1146 if(This->node->type == XML_ELEMENT_NODE ||
1147 This->node->type == XML_TEXT_NODE ||
1148 This->node->type == XML_ENTITY_REF_NODE)
1149 hres = xmlnode_get_dataType(iface, &type);
1151 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
1152 return xmlnode_get_nodeValue(iface, typedValue);
1154 content = xmlNodeGetContent(This->node);
1155 hres = VARIANT_from_xmlChar(content, typedValue,
1156 hres==S_OK ? V_BSTR(&type) : NULL);
1158 VariantClear(&type);
1163 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
1171 static HRESULT WINAPI xmlnode_get_dataType(
1173 VARIANT* dataTypeName)
1175 xmlnode *This = impl_from_IXMLDOMNode( iface );
1178 TRACE("iface %p\n", iface);
1181 return E_INVALIDARG;
1183 /* Attribute, CDATA Section, Comment, Document, Document Fragment,
1184 Entity, Notation, PI, and Text Node are non-typed. */
1185 V_BSTR(dataTypeName) = NULL;
1186 V_VT(dataTypeName) = VT_NULL;
1188 switch ( This->node->type )
1190 case XML_ELEMENT_NODE:
1191 pVal = xmlGetNsProp(This->node, (xmlChar*)"dt",
1192 (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1195 V_VT(dataTypeName) = VT_BSTR;
1196 V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
1200 case XML_ENTITY_REF_NODE:
1201 FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
1204 TRACE("Type %d returning NULL\n", This->node->type);
1207 /* non-typed nodes return S_FALSE */
1208 if(V_VT(dataTypeName) == VT_NULL)
1216 static HRESULT WINAPI xmlnode_put_dataType(
1220 xmlnode *This = impl_from_IXMLDOMNode( iface );
1221 HRESULT hr = E_FAIL;
1223 TRACE("iface %p\n", iface);
1225 if(dataTypeName == NULL)
1226 return E_INVALIDARG;
1228 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1229 This applies to changing types (string->bool) or setting a new one
1231 FIXME("Need to Validate the data before allowing a type to be set.\n");
1233 /* Check all supported types. */
1234 if(lstrcmpiW(dataTypeName,szString) == 0 ||
1235 lstrcmpiW(dataTypeName,szNumber) == 0 ||
1236 lstrcmpiW(dataTypeName,szUUID) == 0 ||
1237 lstrcmpiW(dataTypeName,szInt) == 0 ||
1238 lstrcmpiW(dataTypeName,szI4) == 0 ||
1239 lstrcmpiW(dataTypeName,szFixed) == 0 ||
1240 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1241 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1242 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1243 lstrcmpiW(dataTypeName,szDate) == 0 ||
1244 lstrcmpiW(dataTypeName,szTime) == 0 ||
1245 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
1246 lstrcmpiW(dataTypeName,szI1) == 0 ||
1247 lstrcmpiW(dataTypeName,szI2) == 0 ||
1248 lstrcmpiW(dataTypeName,szIU1) == 0 ||
1249 lstrcmpiW(dataTypeName,szIU2) == 0 ||
1250 lstrcmpiW(dataTypeName,szIU4) == 0 ||
1251 lstrcmpiW(dataTypeName,szR4) == 0 ||
1252 lstrcmpiW(dataTypeName,szR8) == 0 ||
1253 lstrcmpiW(dataTypeName,szFloat) == 0 ||
1254 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
1255 lstrcmpiW(dataTypeName,szBinBase64) == 0)
1257 xmlNsPtr pNS = NULL;
1258 xmlAttrPtr pAttr = NULL;
1259 xmlChar* str = xmlChar_from_wchar(dataTypeName);
1261 pAttr = xmlHasNsProp(This->node, (xmlChar*)"dt",
1262 (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1265 pAttr = xmlSetNsProp(This->node, pAttr->ns, (xmlChar*)"dt", str);
1271 pNS = xmlNewNs(This->node, (xmlChar*)"urn:schemas-microsoft-com:datatypes", (xmlChar*)"dt");
1274 pAttr = xmlNewNsProp(This->node, pNS, (xmlChar*)"dt", str);
1277 xmlAddChild(This->node, (xmlNodePtr)pAttr);
1282 ERR("Failed to create Attribute\n");
1285 ERR("Failed to Create Namepsace\n");
1293 static BSTR EnsureCorrectEOL(BSTR sInput)
1295 static const WCHAR SZ_RETURN[] = {'\n',0};
1296 static const WCHAR SZ_LINEFEED[] = {'\r',0};
1302 nLen = lstrlenW(sInput);
1303 /* Count line endings */
1304 for(i=0; i < nLen; i++)
1306 if(sInput[i] == SZ_RETURN[0])
1310 TRACE("len=%d, num=%d\n", nLen, nNum);
1312 /* Add linefeed as needed */
1316 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1317 for(i=0; i < nLen; i++)
1319 if(sInput[i] == SZ_RETURN[0])
1321 sNew[i+nPlace] = SZ_LINEFEED[0];
1324 sNew[i+nPlace] = sInput[i];
1327 SysFreeString(sInput);
1334 TRACE("len %d\n", lstrlenW(sNew));
1339 /* Removes encoding information and last character (nullbyte) */
1340 static BSTR EnsureNoEncoding(BSTR sInput)
1342 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1347 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1352 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1357 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1358 while(*pEnd != '\"') pEnd++;
1361 sNew = SysAllocStringLen(NULL,
1362 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1363 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1364 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1366 SysFreeString(sInput);
1371 * We are trying to replicate the same behaviour as msxml by converting
1372 * line endings to \r\n and using idents as \t. The problem is that msxml
1373 * only formats nodes that have a line ending. Using libxml we cannot
1374 * reproduce behaviour exactly.
1377 static HRESULT WINAPI xmlnode_get_xml(
1381 xmlnode *This = impl_from_IXMLDOMNode( iface );
1382 xmlBufferPtr pXmlBuf;
1385 TRACE("iface %p %d\n", iface, This->node->type);
1388 return E_INVALIDARG;
1392 pXmlBuf = xmlBufferCreate();
1395 nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1398 const xmlChar *pContent;
1401 /* Attribute Nodes return a space in front of their name */
1402 pContent = xmlBufferContent(pXmlBuf);
1403 if( ((char*)pContent)[0] == ' ')
1404 bstrContent = bstr_from_xmlChar(pContent+1);
1406 bstrContent = bstr_from_xmlChar(pContent);
1408 switch(This->node->type)
1410 case XML_ELEMENT_NODE:
1411 *xmlString = EnsureCorrectEOL(bstrContent);
1413 case XML_DOCUMENT_NODE:
1414 *xmlString = EnsureCorrectEOL(bstrContent);
1415 *xmlString = EnsureNoEncoding(*xmlString);
1418 *xmlString = bstrContent;
1422 xmlBufferFree(pXmlBuf);
1425 /* Always returns a string. */
1426 if(*xmlString == NULL) *xmlString = SysAllocStringLen( NULL, 0 );
1431 static HRESULT WINAPI xmlnode_transformNode(
1433 IXMLDOMNode* styleSheet,
1436 #ifdef SONAME_LIBXSLT
1437 xmlnode *This = impl_from_IXMLDOMNode( iface );
1438 xmlnode *pStyleSheet = NULL;
1439 xsltStylesheetPtr xsltSS = NULL;
1440 xmlDocPtr result = NULL;
1443 TRACE("%p %p %p\n", This, styleSheet, xmlString);
1445 if (!libxslt_handle)
1447 if(!styleSheet || !xmlString)
1448 return E_INVALIDARG;
1452 if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1454 pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1456 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1459 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1462 const xmlChar *pContent;
1464 if(result->type == XML_HTML_DOCUMENT_NODE)
1466 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1469 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1470 pContent = xmlBufferContent(pOutput->buffer);
1471 *xmlString = bstr_from_xmlChar(pContent);
1472 xmlOutputBufferClose(pOutput);
1477 xmlBufferPtr pXmlBuf;
1480 pXmlBuf = xmlBufferCreate();
1483 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1486 pContent = xmlBufferContent(pXmlBuf);
1487 *xmlString = bstr_from_xmlChar(pContent);
1489 xmlBufferFree(pXmlBuf);
1494 /* libxslt "helpfully" frees the XML document the stylesheet was
1495 generated from, too */
1497 pxsltFreeStylesheet(xsltSS);
1500 IXMLDOMNode_Release(ssNew);
1503 if(*xmlString == NULL)
1504 *xmlString = SysAllocStringLen(NULL, 0);
1508 FIXME("libxslt headers were not found at compile time\n");
1513 static HRESULT WINAPI xmlnode_selectNodes(
1516 IXMLDOMNodeList** resultList)
1518 xmlnode *This = impl_from_IXMLDOMNode( iface );
1520 TRACE("%p %s %p\n", This, debugstr_w(queryString), resultList );
1522 return queryresult_create( This->node, queryString, resultList );
1525 static HRESULT WINAPI xmlnode_selectSingleNode(
1528 IXMLDOMNode** resultNode)
1530 xmlnode *This = impl_from_IXMLDOMNode( iface );
1531 IXMLDOMNodeList *list;
1534 TRACE("%p %s %p\n", This, debugstr_w(queryString), resultNode );
1537 r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1540 r = IXMLDOMNodeList_nextNode(list, resultNode);
1541 IXMLDOMNodeList_Release(list);
1546 static HRESULT WINAPI xmlnode_get_parsed(
1548 VARIANT_BOOL* isParsed)
1554 static HRESULT WINAPI xmlnode_get_namespaceURI(
1558 xmlnode *This = impl_from_IXMLDOMNode( iface );
1559 HRESULT hr = S_FALSE;
1562 TRACE("%p %p\n", This, namespaceURI );
1565 return E_INVALIDARG;
1567 *namespaceURI = NULL;
1569 pNSList = xmlGetNsList(This->node->doc, This->node);
1572 *namespaceURI = bstr_from_xmlChar( pNSList[0]->href );
1581 static HRESULT WINAPI xmlnode_get_prefix(
1585 xmlnode *This = impl_from_IXMLDOMNode( iface );
1586 HRESULT hr = S_FALSE;
1589 TRACE("%p %p\n", This, prefixString );
1592 return E_INVALIDARG;
1594 *prefixString = NULL;
1596 pNSList = xmlGetNsList(This->node->doc, This->node);
1599 *prefixString = bstr_from_xmlChar( pNSList[0]->prefix );
1608 static HRESULT WINAPI xmlnode_get_baseName(
1612 xmlnode *This = impl_from_IXMLDOMNode( iface );
1614 HRESULT r = S_FALSE;
1616 TRACE("%p %p\n", This, nameString );
1619 return E_INVALIDARG;
1621 switch ( This->node->type )
1623 case XML_ELEMENT_NODE:
1624 case XML_ATTRIBUTE_NODE:
1626 str = bstr_from_xmlChar( This->node->name );
1630 case XML_COMMENT_NODE:
1633 ERR("Unhandled type %d\n", This->node->type );
1637 TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1643 static HRESULT WINAPI xmlnode_transformNodeToObject(
1645 IXMLDOMNode* stylesheet,
1646 VARIANT outputObject)
1652 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1654 xmlnode_QueryInterface,
1657 xmlnode_GetTypeInfoCount,
1658 xmlnode_GetTypeInfo,
1659 xmlnode_GetIDsOfNames,
1661 xmlnode_get_nodeName,
1662 xmlnode_get_nodeValue,
1663 xmlnode_put_nodeValue,
1664 xmlnode_get_nodeType,
1665 xmlnode_get_parentNode,
1666 xmlnode_get_childNodes,
1667 xmlnode_get_firstChild,
1668 xmlnode_get_lastChild,
1669 xmlnode_get_previousSibling,
1670 xmlnode_get_nextSibling,
1671 xmlnode_get_attributes,
1672 xmlnode_insertBefore,
1673 xmlnode_replaceChild,
1674 xmlnode_removeChild,
1675 xmlnode_appendChild,
1676 xmlnode_hasChildNodes,
1677 xmlnode_get_ownerDocument,
1679 xmlnode_get_nodeTypeString,
1682 xmlnode_get_specified,
1683 xmlnode_get_definition,
1684 xmlnode_get_nodeTypedValue,
1685 xmlnode_put_nodeTypedValue,
1686 xmlnode_get_dataType,
1687 xmlnode_put_dataType,
1689 xmlnode_transformNode,
1690 xmlnode_selectNodes,
1691 xmlnode_selectSingleNode,
1693 xmlnode_get_namespaceURI,
1695 xmlnode_get_baseName,
1696 xmlnode_transformNodeToObject,
1699 void destroy_xmlnode(xmlnode *This)
1702 xmldoc_release(This->node->doc);
1705 void init_xmlnode(xmlnode *This, xmlNodePtr node, IUnknown *outer, dispex_static_data_t *dispex_data )
1708 xmldoc_add_ref( node->doc );
1710 This->lpVtbl = &xmlnode_vtbl;
1713 This->pUnkOuter = outer;
1716 init_dispex(&This->dispex, This->pUnkOuter, dispex_data);
1719 IXMLDOMNode *create_node( xmlNodePtr node )
1728 TRACE("type %d\n", node->type);
1731 case XML_ELEMENT_NODE:
1732 pUnk = create_element( node );
1734 case XML_ATTRIBUTE_NODE:
1735 pUnk = create_attribute( node );
1738 pUnk = create_text( node );
1740 case XML_CDATA_SECTION_NODE:
1741 pUnk = create_cdata( node );
1743 case XML_ENTITY_REF_NODE:
1744 pUnk = create_doc_entity_ref( node );
1747 pUnk = create_pi( node );
1749 case XML_COMMENT_NODE:
1750 pUnk = create_comment( node );
1752 case XML_DOCUMENT_NODE:
1753 pUnk = create_domdoc( node );
1758 FIXME("only creating basic node for type %d\n", node->type);
1760 new_node = heap_alloc(sizeof(xmlnode));
1764 init_xmlnode(new_node, node, NULL, NULL);
1765 pUnk = (IUnknown*)IXMLDOMNode_from_impl(new_node);
1769 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1770 IUnknown_Release(pUnk);
1771 if(FAILED(hr)) return NULL;