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)->(%p)\n", This, name );
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 TRACE("%p type(%d)\n", This, This->node->type);
333 /* Document, Document Fragment, Document Type, Element,
334 Entity, Entity Reference, Notation aren't supported. */
335 switch ( This->node->type )
337 case XML_ATTRIBUTE_NODE:
338 case XML_CDATA_SECTION_NODE:
339 case XML_COMMENT_NODE:
343 VARIANT string_value;
346 VariantInit(&string_value);
347 hr = VariantChangeType(&string_value, &value, 0, VT_BSTR);
350 VariantClear(&string_value);
351 WARN("Couldn't convert to VT_BSTR\n");
355 str = xmlChar_from_wchar(V_BSTR(&string_value));
356 VariantClear(&string_value);
358 xmlNodeSetContent(This->node, str);
364 /* Do nothing for unsupported types. */
372 static HRESULT WINAPI xmlnode_get_nodeType(
376 xmlnode *This = impl_from_IXMLDOMNode( iface );
378 TRACE("(%p)->(%p)\n", This, type);
380 assert( (int)NODE_ELEMENT == (int)XML_ELEMENT_NODE );
381 assert( (int)NODE_NOTATION == (int)XML_NOTATION_NODE );
383 *type = This->node->type;
388 static HRESULT get_node(
394 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
399 /* if we don't have a doc, use our parent. */
400 if(node && !node->doc && node->parent)
401 node->doc = node->parent->doc;
403 *out = create_node( node );
409 static HRESULT WINAPI xmlnode_get_parentNode(
411 IXMLDOMNode** parent)
413 xmlnode *This = impl_from_IXMLDOMNode( iface );
414 return get_node( This, "parent", This->node->parent, parent );
417 static HRESULT WINAPI xmlnode_get_childNodes(
419 IXMLDOMNodeList** childList)
421 xmlnode *This = impl_from_IXMLDOMNode( iface );
423 TRACE("(%p)->(%p)\n", This, childList );
428 *childList = create_children_nodelist(This->node);
429 if (*childList == NULL)
430 return E_OUTOFMEMORY;
435 static HRESULT WINAPI xmlnode_get_firstChild(
437 IXMLDOMNode** firstChild)
439 xmlnode *This = impl_from_IXMLDOMNode( iface );
440 return get_node( This, "firstChild", This->node->children, firstChild );
443 static HRESULT WINAPI xmlnode_get_lastChild(
445 IXMLDOMNode** lastChild)
447 xmlnode *This = impl_from_IXMLDOMNode( iface );
449 TRACE("(%p)->(%p)\n", This, lastChild );
454 switch( This->node->type )
456 /* CDATASection, Comment, PI and Text Nodes do not support lastChild */
458 case XML_CDATA_SECTION_NODE:
460 case XML_COMMENT_NODE:
464 return get_node( This, "lastChild", This->node->last, lastChild );
468 static HRESULT WINAPI xmlnode_get_previousSibling(
470 IXMLDOMNode** previousSibling)
472 xmlnode *This = impl_from_IXMLDOMNode( iface );
474 TRACE("(%p)->(%p)\n", This, previousSibling );
476 if (!previousSibling)
479 switch( This->node->type )
481 /* Attribute, Document and Document Fragment Nodes do not support previousSibling */
482 case XML_DOCUMENT_NODE:
483 case XML_DOCUMENT_FRAG_NODE:
484 case XML_ATTRIBUTE_NODE:
485 *previousSibling = NULL;
488 return get_node( This, "previous", This->node->prev, previousSibling );
492 static HRESULT WINAPI xmlnode_get_nextSibling(
494 IXMLDOMNode** nextSibling)
496 xmlnode *This = impl_from_IXMLDOMNode( iface );
498 TRACE("(%p)->(%p)\n", This, nextSibling );
503 switch( This->node->type )
505 /* Attribute, Document and Document Fragment Nodes do not support nextSibling */
506 case XML_DOCUMENT_NODE:
507 case XML_DOCUMENT_FRAG_NODE:
508 case XML_ATTRIBUTE_NODE:
512 return get_node( This, "next", This->node->next, nextSibling );
516 static HRESULT WINAPI xmlnode_get_attributes(
518 IXMLDOMNamedNodeMap** attributeMap)
520 xmlnode *This = impl_from_IXMLDOMNode( iface );
521 TRACE("(%p)->(%p)\n", This, attributeMap);
526 switch( This->node->type )
528 /* Attribute, CDataSection, Comment, Documents, Documents Fragments,
529 Entity and Text Nodes does not support get_attributes */
530 case XML_ATTRIBUTE_NODE:
531 case XML_CDATA_SECTION_NODE:
532 case XML_COMMENT_NODE:
533 case XML_DOCUMENT_NODE:
534 case XML_DOCUMENT_FRAG_NODE:
535 case XML_ENTITY_NODE:
536 case XML_ENTITY_REF_NODE:
538 *attributeMap = NULL;
541 *attributeMap = create_nodemap( iface );
546 static HRESULT WINAPI xmlnode_insertBefore(
548 IXMLDOMNode* newChild,
550 IXMLDOMNode** outNewChild)
552 xmlnode *This = impl_from_IXMLDOMNode( iface );
553 xmlNodePtr before_node, new_child_node;
554 IXMLDOMNode *before = NULL, *new;
557 TRACE("(%p)->(%p var %p)\n",This,newChild,outNewChild);
562 switch(V_VT(&refChild))
569 hr = IUnknown_QueryInterface(V_UNKNOWN(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
570 if(FAILED(hr)) return hr;
574 hr = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
575 if(FAILED(hr)) return hr;
579 FIXME("refChild var type %x\n", V_VT(&refChild));
583 IXMLDOMNode_QueryInterface(newChild, &IID_IXMLDOMNode, (LPVOID)&new);
584 new_child_node = impl_from_IXMLDOMNode(new)->node;
585 TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
587 if(!new_child_node->parent)
588 if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
589 WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
593 before_node = impl_from_IXMLDOMNode(before)->node;
594 xmlAddPrevSibling(before_node, new_child_node);
595 IXMLDOMNode_Release(before);
599 xmlAddChild(This->node, new_child_node);
602 IXMLDOMNode_Release(new);
603 IXMLDOMNode_AddRef(newChild);
605 *outNewChild = newChild;
611 static HRESULT WINAPI xmlnode_replaceChild(
613 IXMLDOMNode* newChild,
614 IXMLDOMNode* oldChild,
615 IXMLDOMNode** outOldChild)
617 xmlnode *This = impl_from_IXMLDOMNode( iface );
618 xmlNode *old_child_ptr, *new_child_ptr;
619 xmlDocPtr leaving_doc;
620 xmlNode *my_ancestor;
621 IXMLDOMNode *realOldChild;
624 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
626 /* Do not believe any documentation telling that newChild == NULL
627 means removal. It does certainly *not* apply to msxml3! */
628 if(!newChild || !oldChild)
634 hr = IXMLDOMNode_QueryInterface(oldChild,&IID_IXMLDOMNode,(LPVOID*)&realOldChild);
638 old_child_ptr = impl_from_IXMLDOMNode(realOldChild)->node;
639 IXMLDOMNode_Release(realOldChild);
640 if(old_child_ptr->parent != This->node)
642 WARN("childNode %p is not a child of %p\n", oldChild, iface);
646 new_child_ptr = impl_from_IXMLDOMNode(newChild)->node;
647 my_ancestor = This->node;
650 if(my_ancestor == new_child_ptr)
652 WARN("tried to create loop\n");
655 my_ancestor = my_ancestor->parent;
658 if(!new_child_ptr->parent)
659 if(xmldoc_remove_orphan(new_child_ptr->doc, new_child_ptr) != S_OK)
660 WARN("%p is not an orphan of %p\n", new_child_ptr, new_child_ptr->doc);
662 leaving_doc = new_child_ptr->doc;
663 xmldoc_add_ref(old_child_ptr->doc);
664 xmlReplaceNode(old_child_ptr, new_child_ptr);
665 xmldoc_release(leaving_doc);
667 xmldoc_add_orphan(old_child_ptr->doc, old_child_ptr);
671 IXMLDOMNode_AddRef(oldChild);
672 *outOldChild = oldChild;
678 static HRESULT WINAPI xmlnode_removeChild(
680 IXMLDOMNode* childNode,
681 IXMLDOMNode** oldChild)
683 xmlnode *This = impl_from_IXMLDOMNode( iface );
684 xmlNode *child_node_ptr;
688 TRACE("(%p)->(%p %p)\n", This, childNode, oldChild);
690 if(!childNode) return E_INVALIDARG;
695 hr = IXMLDOMNode_QueryInterface(childNode, &IID_IXMLDOMNode, (LPVOID)&child);
699 child_node_ptr = impl_from_IXMLDOMNode(child)->node;
700 if(child_node_ptr->parent != This->node)
702 WARN("childNode %p is not a child of %p\n", childNode, iface);
703 IXMLDOMNode_Release(child);
707 xmlUnlinkNode(child_node_ptr);
709 IXMLDOMNode_Release(child);
713 IXMLDOMNode_AddRef(childNode);
714 *oldChild = childNode;
720 static HRESULT WINAPI xmlnode_appendChild(
722 IXMLDOMNode* newChild,
723 IXMLDOMNode** outNewChild)
725 xmlnode *This = impl_from_IXMLDOMNode( iface );
730 TRACE("(%p)->(%p %p)\n", This, newChild, outNewChild);
732 hr = IXMLDOMNode_get_nodeType(newChild, &type);
733 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
734 if(outNewChild) *outNewChild = NULL;
739 return IXMLDOMNode_insertBefore(iface, newChild, var, outNewChild);
742 static HRESULT WINAPI xmlnode_hasChildNodes(
744 VARIANT_BOOL* hasChild)
746 xmlnode *This = impl_from_IXMLDOMNode( iface );
748 TRACE("(%p)->(%p)\n", This, hasChild);
752 if (!This->node->children)
754 *hasChild = VARIANT_FALSE;
758 *hasChild = VARIANT_TRUE;
762 static HRESULT WINAPI xmlnode_get_ownerDocument(
764 IXMLDOMDocument** DOMDocument)
766 xmlnode *This = impl_from_IXMLDOMNode( iface );
768 TRACE("(%p)->(%p)\n", This, DOMDocument);
770 return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument2**)DOMDocument);
773 static HRESULT WINAPI xmlnode_cloneNode(
776 IXMLDOMNode** cloneRoot)
778 xmlnode *This = impl_from_IXMLDOMNode( iface );
779 xmlNodePtr pClone = NULL;
780 IXMLDOMNode *pNode = NULL;
782 TRACE("(%p)->(%d %p)\n", This, deep, cloneRoot);
787 pClone = xmlCopyNode(This->node, deep ? 1 : 2);
790 pClone->doc = This->node->doc;
791 xmldoc_add_orphan(pClone->doc, pClone);
793 pNode = create_node(pClone);
796 ERR("Copy failed\n");
804 ERR("Copy failed\n");
811 static HRESULT WINAPI xmlnode_get_nodeTypeString(
815 xmlnode *This = impl_from_IXMLDOMNode( iface );
818 TRACE("(%p)->(%p)\n", This, xmlnodeType );
826 switch( This->node->type )
828 case XML_ATTRIBUTE_NODE:
829 str = (const xmlChar*) "attribute";
831 case XML_CDATA_SECTION_NODE:
832 str = (const xmlChar*) "cdatasection";
834 case XML_COMMENT_NODE:
835 str = (const xmlChar*) "comment";
837 case XML_DOCUMENT_NODE:
838 str = (const xmlChar*) "document";
840 case XML_DOCUMENT_FRAG_NODE:
841 str = (const xmlChar*) "documentfragment";
843 case XML_ELEMENT_NODE:
844 str = (const xmlChar*) "element";
846 case XML_ENTITY_NODE:
847 str = (const xmlChar*) "entity";
849 case XML_ENTITY_REF_NODE:
850 str = (const xmlChar*) "entityreference";
852 case XML_NOTATION_NODE:
853 str = (const xmlChar*) "notation";
856 str = (const xmlChar*) "processinginstruction";
859 str = (const xmlChar*) "text";
862 FIXME("Unknown node type (%d)\n", This->node->type);
863 str = This->node->name;
867 *xmlnodeType = bstr_from_xmlChar( str );
874 static HRESULT WINAPI xmlnode_get_text(
878 xmlnode *This = impl_from_IXMLDOMNode( iface );
882 TRACE("(%p, type %d)->(%p)\n", This, This->node->type, text);
887 pContent = xmlNodeGetContent((xmlNodePtr)This->node);
890 str = bstr_from_xmlChar(pContent);
894 /* Always return a string. */
895 if (!str) str = SysAllocStringLen( NULL, 0 );
897 TRACE("%p %s\n", This, debugstr_w(str) );
903 static HRESULT WINAPI xmlnode_put_text(
907 xmlnode *This = impl_from_IXMLDOMNode( iface );
910 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
912 switch(This->node->type)
914 case XML_DOCUMENT_NODE:
920 str = xmlChar_from_wchar(text);
922 /* Escape the string. */
923 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
926 xmlNodeSetContent(This->node, str2);
932 static HRESULT WINAPI xmlnode_get_specified(
934 VARIANT_BOOL* isSpecified)
936 xmlnode *This = impl_from_IXMLDOMNode( iface );
937 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
938 *isSpecified = VARIANT_TRUE;
942 static HRESULT WINAPI xmlnode_get_definition(
944 IXMLDOMNode** definitionNode)
946 xmlnode *This = impl_from_IXMLDOMNode( iface );
947 FIXME("(%p)->(%p)\n", This, definitionNode);
951 static inline BYTE hex_to_byte(xmlChar c)
953 if(c <= '9') return c-'0';
954 if(c <= 'F') return c-'A'+10;
958 static inline BYTE base64_to_byte(xmlChar c)
960 if(c == '+') return 62;
961 if(c == '/') return 63;
962 if(c <= '9') return c-'0'+52;
963 if(c <= 'Z') return c-'A';
967 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
969 if(!type || !lstrcmpiW(type, szString) ||
970 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
973 V_BSTR(v) = bstr_from_xmlChar(str);
976 return E_OUTOFMEMORY;
978 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
979 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
980 !lstrcmpiW(type, szTimeTZ))
990 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
992 V_VT(&src) = VT_BSTR;
993 V_BSTR(&src) = bstr_from_xmlChar(str);
996 return E_OUTOFMEMORY;
999 e = p + SysStringLen(V_BSTR(&src));
1001 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
1003 st.wYear = atoiW(p);
1004 st.wMonth = atoiW(p+5);
1005 st.wDay = atoiW(p+8);
1011 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
1013 st.wHour = atoiW(p);
1014 st.wMinute = atoiW(p+3);
1015 st.wSecond = atoiW(p+6);
1021 while(isdigitW(*p)) p++;
1025 SystemTimeToVariantTime(&st, &date);
1029 if(*p == '+') /* parse timezone offset (+hh:mm) */
1030 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1031 else if(*p == '-') /* parse timezone offset (-hh:mm) */
1032 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1036 else if(!lstrcmpiW(type, szBinHex))
1041 len = xmlStrlen(str)/2;
1043 sab.cElements = len;
1045 V_VT(v) = (VT_ARRAY|VT_UI1);
1046 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1049 return E_OUTOFMEMORY;
1051 for(i=0; i<len; i++)
1052 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
1053 + hex_to_byte(str[2*i+1]);
1055 else if(!lstrcmpiW(type, szBinBase64))
1060 len = xmlStrlen(str);
1061 if(str[len-2] == '=') i = 2;
1062 else if(str[len-1] == '=') i = 1;
1066 sab.cElements = len/4*3-i;
1068 V_VT(v) = (VT_ARRAY|VT_UI1);
1069 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1072 return E_OUTOFMEMORY;
1074 for(i=0; i<len/4; i++)
1076 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
1077 + (base64_to_byte(str[4*i+1])>>4);
1078 if(3*i+1 < sab.cElements)
1079 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
1080 + (base64_to_byte(str[4*i+2])>>2);
1081 if(3*i+2 < sab.cElements)
1082 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
1083 + base64_to_byte(str[4*i+3]);
1091 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
1093 else if(!lstrcmpiW(type, szFixed))
1095 else if(!lstrcmpiW(type, szBoolean))
1097 else if(!lstrcmpiW(type, szI1))
1099 else if(!lstrcmpiW(type, szI2))
1101 else if(!lstrcmpiW(type, szIU1))
1103 else if(!lstrcmpiW(type, szIU2))
1105 else if(!lstrcmpiW(type, szIU4))
1107 else if(!lstrcmpiW(type, szR4))
1109 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
1113 FIXME("Type handling not yet implemented\n");
1117 V_VT(&src) = VT_BSTR;
1118 V_BSTR(&src) = bstr_from_xmlChar(str);
1121 return E_OUTOFMEMORY;
1123 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
1124 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
1132 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
1134 VARIANT* typedValue)
1136 xmlnode *This = impl_from_IXMLDOMNode( iface );
1139 HRESULT hres = S_FALSE;
1141 TRACE("(%p)->(%p)\n", This, typedValue);
1144 return E_INVALIDARG;
1146 V_VT(typedValue) = VT_NULL;
1148 if(This->node->type == XML_ELEMENT_NODE ||
1149 This->node->type == XML_TEXT_NODE ||
1150 This->node->type == XML_ENTITY_REF_NODE)
1151 hres = IXMLDOMNode_get_dataType(iface, &type);
1153 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
1154 return IXMLDOMNode_get_nodeValue(iface, typedValue);
1156 content = xmlNodeGetContent(This->node);
1157 hres = VARIANT_from_xmlChar(content, typedValue,
1158 hres==S_OK ? V_BSTR(&type) : NULL);
1160 VariantClear(&type);
1165 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
1169 xmlnode *This = impl_from_IXMLDOMNode( iface );
1170 FIXME("%p\n", This);
1174 static HRESULT WINAPI xmlnode_get_dataType(
1176 VARIANT* dataTypeName)
1178 xmlnode *This = impl_from_IXMLDOMNode( iface );
1181 TRACE("(%p)->(%p)\n", This, dataTypeName);
1184 return E_INVALIDARG;
1186 /* Attribute, CDATA Section, Comment, Document, Document Fragment,
1187 Entity, Notation, PI, and Text Node are non-typed. */
1188 V_BSTR(dataTypeName) = NULL;
1189 V_VT(dataTypeName) = VT_NULL;
1191 switch ( This->node->type )
1193 case XML_ELEMENT_NODE:
1194 pVal = xmlGetNsProp(This->node, (const xmlChar*)"dt",
1195 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
1198 V_VT(dataTypeName) = VT_BSTR;
1199 V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
1203 case XML_ENTITY_REF_NODE:
1204 FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
1207 TRACE("Type %d returning NULL\n", This->node->type);
1210 /* non-typed nodes return S_FALSE */
1211 if(V_VT(dataTypeName) == VT_NULL)
1219 static HRESULT WINAPI xmlnode_put_dataType(
1223 xmlnode *This = impl_from_IXMLDOMNode( iface );
1224 HRESULT hr = E_FAIL;
1226 TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1228 if(dataTypeName == NULL)
1229 return E_INVALIDARG;
1231 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1232 This applies to changing types (string->bool) or setting a new one
1234 FIXME("Need to Validate the data before allowing a type to be set.\n");
1236 /* Check all supported types. */
1237 if(lstrcmpiW(dataTypeName,szString) == 0 ||
1238 lstrcmpiW(dataTypeName,szNumber) == 0 ||
1239 lstrcmpiW(dataTypeName,szUUID) == 0 ||
1240 lstrcmpiW(dataTypeName,szInt) == 0 ||
1241 lstrcmpiW(dataTypeName,szI4) == 0 ||
1242 lstrcmpiW(dataTypeName,szFixed) == 0 ||
1243 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1244 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1245 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1246 lstrcmpiW(dataTypeName,szDate) == 0 ||
1247 lstrcmpiW(dataTypeName,szTime) == 0 ||
1248 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
1249 lstrcmpiW(dataTypeName,szI1) == 0 ||
1250 lstrcmpiW(dataTypeName,szI2) == 0 ||
1251 lstrcmpiW(dataTypeName,szIU1) == 0 ||
1252 lstrcmpiW(dataTypeName,szIU2) == 0 ||
1253 lstrcmpiW(dataTypeName,szIU4) == 0 ||
1254 lstrcmpiW(dataTypeName,szR4) == 0 ||
1255 lstrcmpiW(dataTypeName,szR8) == 0 ||
1256 lstrcmpiW(dataTypeName,szFloat) == 0 ||
1257 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
1258 lstrcmpiW(dataTypeName,szBinBase64) == 0)
1260 xmlNsPtr pNS = NULL;
1261 xmlAttrPtr pAttr = NULL;
1262 xmlChar* str = xmlChar_from_wchar(dataTypeName);
1264 pAttr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
1265 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
1268 pAttr = xmlSetNsProp(This->node, pAttr->ns, (const xmlChar*)"dt", str);
1274 pNS = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
1277 pAttr = xmlNewNsProp(This->node, pNS, (const xmlChar*)"dt", str);
1280 xmlAddChild(This->node, (xmlNodePtr)pAttr);
1285 ERR("Failed to create Attribute\n");
1288 ERR("Failed to Create Namepsace\n");
1296 static BSTR EnsureCorrectEOL(BSTR sInput)
1303 nLen = lstrlenW(sInput);
1304 /* Count line endings */
1305 for(i=0; i < nLen; i++)
1307 if(sInput[i] == '\n')
1311 TRACE("len=%d, num=%d\n", nLen, nNum);
1313 /* Add linefeed as needed */
1317 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1318 for(i=0; i < nLen; i++)
1320 if(sInput[i] == '\n')
1322 sNew[i+nPlace] = '\r';
1325 sNew[i+nPlace] = sInput[i];
1328 SysFreeString(sInput);
1335 TRACE("len %d\n", lstrlenW(sNew));
1340 /* Removes encoding information and last character (nullbyte) */
1341 static BSTR EnsureNoEncoding(BSTR sInput)
1343 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1348 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1353 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1358 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1359 while(*pEnd != '\"') pEnd++;
1362 sNew = SysAllocStringLen(NULL,
1363 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1364 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1365 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1367 SysFreeString(sInput);
1372 * We are trying to replicate the same behaviour as msxml by converting
1373 * line endings to \r\n and using indents as \t. The problem is that msxml
1374 * only formats nodes that have a line ending. Using libxml we cannot
1375 * reproduce behaviour exactly.
1378 static HRESULT WINAPI xmlnode_get_xml(
1382 xmlnode *This = impl_from_IXMLDOMNode( iface );
1383 xmlBufferPtr pXmlBuf;
1386 TRACE("(%p %d)->(%p)\n", This, This->node->type, xmlString);
1389 return E_INVALIDARG;
1393 pXmlBuf = xmlBufferCreate();
1396 nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1399 const xmlChar *pContent;
1402 /* Attribute Nodes return a space in front of their name */
1403 pContent = xmlBufferContent(pXmlBuf);
1404 if( ((const char*)pContent)[0] == ' ')
1405 bstrContent = bstr_from_xmlChar(pContent+1);
1407 bstrContent = bstr_from_xmlChar(pContent);
1409 switch(This->node->type)
1411 case XML_ELEMENT_NODE:
1412 *xmlString = EnsureCorrectEOL(bstrContent);
1414 case XML_DOCUMENT_NODE:
1415 *xmlString = EnsureCorrectEOL(bstrContent);
1416 *xmlString = EnsureNoEncoding(*xmlString);
1419 *xmlString = bstrContent;
1423 xmlBufferFree(pXmlBuf);
1426 /* Always returns a string. */
1427 if(*xmlString == NULL) *xmlString = SysAllocStringLen( NULL, 0 );
1432 static HRESULT WINAPI xmlnode_transformNode(
1434 IXMLDOMNode* styleSheet,
1437 #ifdef SONAME_LIBXSLT
1438 xmlnode *This = impl_from_IXMLDOMNode( iface );
1439 xmlnode *pStyleSheet = NULL;
1440 xsltStylesheetPtr xsltSS = NULL;
1441 xmlDocPtr result = NULL;
1444 TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1446 if (!libxslt_handle)
1448 if(!styleSheet || !xmlString)
1449 return E_INVALIDARG;
1453 if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1455 pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1457 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1460 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1463 const xmlChar *pContent;
1465 if(result->type == XML_HTML_DOCUMENT_NODE)
1467 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1470 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1471 pContent = xmlBufferContent(pOutput->buffer);
1472 *xmlString = bstr_from_xmlChar(pContent);
1473 xmlOutputBufferClose(pOutput);
1478 xmlBufferPtr pXmlBuf;
1481 pXmlBuf = xmlBufferCreate();
1484 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1487 pContent = xmlBufferContent(pXmlBuf);
1488 *xmlString = bstr_from_xmlChar(pContent);
1490 xmlBufferFree(pXmlBuf);
1495 /* libxslt "helpfully" frees the XML document the stylesheet was
1496 generated from, too */
1498 pxsltFreeStylesheet(xsltSS);
1501 IXMLDOMNode_Release(ssNew);
1504 if(*xmlString == NULL)
1505 *xmlString = SysAllocStringLen(NULL, 0);
1509 FIXME("libxslt headers were not found at compile time\n");
1514 static HRESULT WINAPI xmlnode_selectNodes(
1517 IXMLDOMNodeList** resultList)
1519 xmlnode *This = impl_from_IXMLDOMNode( iface );
1521 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1523 return queryresult_create( This->node, queryString, resultList );
1526 static HRESULT WINAPI xmlnode_selectSingleNode(
1529 IXMLDOMNode** resultNode)
1531 xmlnode *This = impl_from_IXMLDOMNode( iface );
1532 IXMLDOMNodeList *list;
1535 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1538 r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1541 r = IXMLDOMNodeList_nextNode(list, resultNode);
1542 IXMLDOMNodeList_Release(list);
1547 static HRESULT WINAPI xmlnode_get_parsed(
1549 VARIANT_BOOL* isParsed)
1551 xmlnode *This = impl_from_IXMLDOMNode( iface );
1552 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1553 *isParsed = VARIANT_TRUE;
1557 static HRESULT WINAPI xmlnode_get_namespaceURI(
1561 xmlnode *This = impl_from_IXMLDOMNode( iface );
1562 HRESULT hr = S_FALSE;
1565 TRACE("(%p)->(%p)\n", This, namespaceURI );
1568 return E_INVALIDARG;
1570 *namespaceURI = NULL;
1572 pNSList = xmlGetNsList(This->node->doc, This->node);
1575 *namespaceURI = bstr_from_xmlChar( pNSList[0]->href );
1584 static HRESULT WINAPI xmlnode_get_prefix(
1588 xmlnode *This = impl_from_IXMLDOMNode( iface );
1589 HRESULT hr = S_FALSE;
1592 TRACE("(%p)->(%p)\n", This, prefixString );
1595 return E_INVALIDARG;
1597 *prefixString = NULL;
1599 pNSList = xmlGetNsList(This->node->doc, This->node);
1602 *prefixString = bstr_from_xmlChar( pNSList[0]->prefix );
1611 static HRESULT WINAPI xmlnode_get_baseName(
1615 xmlnode *This = impl_from_IXMLDOMNode( iface );
1617 HRESULT r = S_FALSE;
1619 TRACE("(%p)->(%p)\n", This, nameString );
1622 return E_INVALIDARG;
1624 switch ( This->node->type )
1626 case XML_ELEMENT_NODE:
1627 case XML_ATTRIBUTE_NODE:
1629 str = bstr_from_xmlChar( This->node->name );
1633 case XML_COMMENT_NODE:
1636 ERR("Unhandled type %d\n", This->node->type );
1640 TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1646 static HRESULT WINAPI xmlnode_transformNodeToObject(
1648 IXMLDOMNode* stylesheet,
1649 VARIANT outputObject)
1651 xmlnode *This = impl_from_IXMLDOMNode( iface );
1652 FIXME("(%p)->(%p)\n", This, stylesheet);
1656 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1658 xmlnode_QueryInterface,
1661 xmlnode_GetTypeInfoCount,
1662 xmlnode_GetTypeInfo,
1663 xmlnode_GetIDsOfNames,
1665 xmlnode_get_nodeName,
1666 xmlnode_get_nodeValue,
1667 xmlnode_put_nodeValue,
1668 xmlnode_get_nodeType,
1669 xmlnode_get_parentNode,
1670 xmlnode_get_childNodes,
1671 xmlnode_get_firstChild,
1672 xmlnode_get_lastChild,
1673 xmlnode_get_previousSibling,
1674 xmlnode_get_nextSibling,
1675 xmlnode_get_attributes,
1676 xmlnode_insertBefore,
1677 xmlnode_replaceChild,
1678 xmlnode_removeChild,
1679 xmlnode_appendChild,
1680 xmlnode_hasChildNodes,
1681 xmlnode_get_ownerDocument,
1683 xmlnode_get_nodeTypeString,
1686 xmlnode_get_specified,
1687 xmlnode_get_definition,
1688 xmlnode_get_nodeTypedValue,
1689 xmlnode_put_nodeTypedValue,
1690 xmlnode_get_dataType,
1691 xmlnode_put_dataType,
1693 xmlnode_transformNode,
1694 xmlnode_selectNodes,
1695 xmlnode_selectSingleNode,
1697 xmlnode_get_namespaceURI,
1699 xmlnode_get_baseName,
1700 xmlnode_transformNodeToObject,
1703 void destroy_xmlnode(xmlnode *This)
1706 xmldoc_release(This->node->doc);
1709 void init_xmlnode(xmlnode *This, xmlNodePtr node, IUnknown *outer, dispex_static_data_t *dispex_data )
1712 xmldoc_add_ref( node->doc );
1714 This->lpVtbl = &xmlnode_vtbl;
1717 This->pUnkOuter = outer;
1720 init_dispex(&This->dispex, This->pUnkOuter, dispex_data);
1723 IXMLDOMNode *create_node( xmlNodePtr node )
1732 TRACE("type %d\n", node->type);
1735 case XML_ELEMENT_NODE:
1736 pUnk = create_element( node );
1738 case XML_ATTRIBUTE_NODE:
1739 pUnk = create_attribute( node );
1742 pUnk = create_text( node );
1744 case XML_CDATA_SECTION_NODE:
1745 pUnk = create_cdata( node );
1747 case XML_ENTITY_REF_NODE:
1748 pUnk = create_doc_entity_ref( node );
1751 pUnk = create_pi( node );
1753 case XML_COMMENT_NODE:
1754 pUnk = create_comment( node );
1756 case XML_DOCUMENT_NODE:
1757 pUnk = create_domdoc( node );
1759 case XML_DOCUMENT_FRAG_NODE:
1760 pUnk = create_doc_fragment( node );
1765 FIXME("only creating basic node for type %d\n", node->type);
1767 new_node = heap_alloc(sizeof(xmlnode));
1771 init_xmlnode(new_node, node, NULL, NULL);
1772 pUnk = (IUnknown*)IXMLDOMNode_from_impl(new_node);
1776 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1777 IUnknown_Release(pUnk);
1778 if(FAILED(hr)) return NULL;