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)\n", This, isSpecified);
941 static HRESULT WINAPI xmlnode_get_definition(
943 IXMLDOMNode** definitionNode)
945 xmlnode *This = impl_from_IXMLDOMNode( iface );
946 FIXME("(%p)->(%p)\n", This, definitionNode);
950 static inline BYTE hex_to_byte(xmlChar c)
952 if(c <= '9') return c-'0';
953 if(c <= 'F') return c-'A'+10;
957 static inline BYTE base64_to_byte(xmlChar c)
959 if(c == '+') return 62;
960 if(c == '/') return 63;
961 if(c <= '9') return c-'0'+52;
962 if(c <= 'Z') return c-'A';
966 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
968 if(!type || !lstrcmpiW(type, szString) ||
969 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
972 V_BSTR(v) = bstr_from_xmlChar(str);
975 return E_OUTOFMEMORY;
977 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
978 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
979 !lstrcmpiW(type, szTimeTZ))
989 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
991 V_VT(&src) = VT_BSTR;
992 V_BSTR(&src) = bstr_from_xmlChar(str);
995 return E_OUTOFMEMORY;
998 e = p + SysStringLen(V_BSTR(&src));
1000 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
1002 st.wYear = atoiW(p);
1003 st.wMonth = atoiW(p+5);
1004 st.wDay = atoiW(p+8);
1010 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
1012 st.wHour = atoiW(p);
1013 st.wMinute = atoiW(p+3);
1014 st.wSecond = atoiW(p+6);
1020 while(isdigitW(*p)) p++;
1024 SystemTimeToVariantTime(&st, &date);
1028 if(*p == '+') /* parse timezone offset (+hh:mm) */
1029 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1030 else if(*p == '-') /* parse timezone offset (-hh:mm) */
1031 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1035 else if(!lstrcmpiW(type, szBinHex))
1040 len = xmlStrlen(str)/2;
1042 sab.cElements = len;
1044 V_VT(v) = (VT_ARRAY|VT_UI1);
1045 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1048 return E_OUTOFMEMORY;
1050 for(i=0; i<len; i++)
1051 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
1052 + hex_to_byte(str[2*i+1]);
1054 else if(!lstrcmpiW(type, szBinBase64))
1059 len = xmlStrlen(str);
1060 if(str[len-2] == '=') i = 2;
1061 else if(str[len-1] == '=') i = 1;
1065 sab.cElements = len/4*3-i;
1067 V_VT(v) = (VT_ARRAY|VT_UI1);
1068 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1071 return E_OUTOFMEMORY;
1073 for(i=0; i<len/4; i++)
1075 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
1076 + (base64_to_byte(str[4*i+1])>>4);
1077 if(3*i+1 < sab.cElements)
1078 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
1079 + (base64_to_byte(str[4*i+2])>>2);
1080 if(3*i+2 < sab.cElements)
1081 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
1082 + base64_to_byte(str[4*i+3]);
1090 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
1092 else if(!lstrcmpiW(type, szFixed))
1094 else if(!lstrcmpiW(type, szBoolean))
1096 else if(!lstrcmpiW(type, szI1))
1098 else if(!lstrcmpiW(type, szI2))
1100 else if(!lstrcmpiW(type, szIU1))
1102 else if(!lstrcmpiW(type, szIU2))
1104 else if(!lstrcmpiW(type, szIU4))
1106 else if(!lstrcmpiW(type, szR4))
1108 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
1112 FIXME("Type handling not yet implemented\n");
1116 V_VT(&src) = VT_BSTR;
1117 V_BSTR(&src) = bstr_from_xmlChar(str);
1120 return E_OUTOFMEMORY;
1122 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
1123 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
1131 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
1133 VARIANT* typedValue)
1135 xmlnode *This = impl_from_IXMLDOMNode( iface );
1138 HRESULT hres = S_FALSE;
1140 TRACE("(%p)->(%p)\n", This, typedValue);
1143 return E_INVALIDARG;
1145 V_VT(typedValue) = VT_NULL;
1147 if(This->node->type == XML_ELEMENT_NODE ||
1148 This->node->type == XML_TEXT_NODE ||
1149 This->node->type == XML_ENTITY_REF_NODE)
1150 hres = IXMLDOMNode_get_dataType(iface, &type);
1152 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
1153 return IXMLDOMNode_get_nodeValue(iface, typedValue);
1155 content = xmlNodeGetContent(This->node);
1156 hres = VARIANT_from_xmlChar(content, typedValue,
1157 hres==S_OK ? V_BSTR(&type) : NULL);
1159 VariantClear(&type);
1164 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
1168 xmlnode *This = impl_from_IXMLDOMNode( iface );
1169 FIXME("%p\n", This);
1173 static HRESULT WINAPI xmlnode_get_dataType(
1175 VARIANT* dataTypeName)
1177 xmlnode *This = impl_from_IXMLDOMNode( iface );
1180 TRACE("(%p)->(%p)\n", This, dataTypeName);
1183 return E_INVALIDARG;
1185 /* Attribute, CDATA Section, Comment, Document, Document Fragment,
1186 Entity, Notation, PI, and Text Node are non-typed. */
1187 V_BSTR(dataTypeName) = NULL;
1188 V_VT(dataTypeName) = VT_NULL;
1190 switch ( This->node->type )
1192 case XML_ELEMENT_NODE:
1193 pVal = xmlGetNsProp(This->node, (xmlChar*)"dt",
1194 (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1197 V_VT(dataTypeName) = VT_BSTR;
1198 V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
1202 case XML_ENTITY_REF_NODE:
1203 FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
1206 TRACE("Type %d returning NULL\n", This->node->type);
1209 /* non-typed nodes return S_FALSE */
1210 if(V_VT(dataTypeName) == VT_NULL)
1218 static HRESULT WINAPI xmlnode_put_dataType(
1222 xmlnode *This = impl_from_IXMLDOMNode( iface );
1223 HRESULT hr = E_FAIL;
1225 TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1227 if(dataTypeName == NULL)
1228 return E_INVALIDARG;
1230 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1231 This applies to changing types (string->bool) or setting a new one
1233 FIXME("Need to Validate the data before allowing a type to be set.\n");
1235 /* Check all supported types. */
1236 if(lstrcmpiW(dataTypeName,szString) == 0 ||
1237 lstrcmpiW(dataTypeName,szNumber) == 0 ||
1238 lstrcmpiW(dataTypeName,szUUID) == 0 ||
1239 lstrcmpiW(dataTypeName,szInt) == 0 ||
1240 lstrcmpiW(dataTypeName,szI4) == 0 ||
1241 lstrcmpiW(dataTypeName,szFixed) == 0 ||
1242 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1243 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1244 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1245 lstrcmpiW(dataTypeName,szDate) == 0 ||
1246 lstrcmpiW(dataTypeName,szTime) == 0 ||
1247 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
1248 lstrcmpiW(dataTypeName,szI1) == 0 ||
1249 lstrcmpiW(dataTypeName,szI2) == 0 ||
1250 lstrcmpiW(dataTypeName,szIU1) == 0 ||
1251 lstrcmpiW(dataTypeName,szIU2) == 0 ||
1252 lstrcmpiW(dataTypeName,szIU4) == 0 ||
1253 lstrcmpiW(dataTypeName,szR4) == 0 ||
1254 lstrcmpiW(dataTypeName,szR8) == 0 ||
1255 lstrcmpiW(dataTypeName,szFloat) == 0 ||
1256 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
1257 lstrcmpiW(dataTypeName,szBinBase64) == 0)
1259 xmlNsPtr pNS = NULL;
1260 xmlAttrPtr pAttr = NULL;
1261 xmlChar* str = xmlChar_from_wchar(dataTypeName);
1263 pAttr = xmlHasNsProp(This->node, (xmlChar*)"dt",
1264 (xmlChar*)"urn:schemas-microsoft-com:datatypes");
1267 pAttr = xmlSetNsProp(This->node, pAttr->ns, (xmlChar*)"dt", str);
1273 pNS = xmlNewNs(This->node, (xmlChar*)"urn:schemas-microsoft-com:datatypes", (xmlChar*)"dt");
1276 pAttr = xmlNewNsProp(This->node, pNS, (xmlChar*)"dt", str);
1279 xmlAddChild(This->node, (xmlNodePtr)pAttr);
1284 ERR("Failed to create Attribute\n");
1287 ERR("Failed to Create Namepsace\n");
1295 static BSTR EnsureCorrectEOL(BSTR sInput)
1297 static const WCHAR SZ_RETURN[] = {'\n',0};
1298 static const WCHAR SZ_LINEFEED[] = {'\r',0};
1304 nLen = lstrlenW(sInput);
1305 /* Count line endings */
1306 for(i=0; i < nLen; i++)
1308 if(sInput[i] == SZ_RETURN[0])
1312 TRACE("len=%d, num=%d\n", nLen, nNum);
1314 /* Add linefeed as needed */
1318 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
1319 for(i=0; i < nLen; i++)
1321 if(sInput[i] == SZ_RETURN[0])
1323 sNew[i+nPlace] = SZ_LINEFEED[0];
1326 sNew[i+nPlace] = sInput[i];
1329 SysFreeString(sInput);
1336 TRACE("len %d\n", lstrlenW(sNew));
1341 /* Removes encoding information and last character (nullbyte) */
1342 static BSTR EnsureNoEncoding(BSTR sInput)
1344 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1349 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1354 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1359 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1360 while(*pEnd != '\"') pEnd++;
1363 sNew = SysAllocStringLen(NULL,
1364 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1365 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1366 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1368 SysFreeString(sInput);
1373 * We are trying to replicate the same behaviour as msxml by converting
1374 * line endings to \r\n and using idents as \t. The problem is that msxml
1375 * only formats nodes that have a line ending. Using libxml we cannot
1376 * reproduce behaviour exactly.
1379 static HRESULT WINAPI xmlnode_get_xml(
1383 xmlnode *This = impl_from_IXMLDOMNode( iface );
1384 xmlBufferPtr pXmlBuf;
1387 TRACE("(%p %d)->(%p)\n", This, This->node->type, xmlString);
1390 return E_INVALIDARG;
1394 pXmlBuf = xmlBufferCreate();
1397 nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1400 const xmlChar *pContent;
1403 /* Attribute Nodes return a space in front of their name */
1404 pContent = xmlBufferContent(pXmlBuf);
1405 if( ((char*)pContent)[0] == ' ')
1406 bstrContent = bstr_from_xmlChar(pContent+1);
1408 bstrContent = bstr_from_xmlChar(pContent);
1410 switch(This->node->type)
1412 case XML_ELEMENT_NODE:
1413 *xmlString = EnsureCorrectEOL(bstrContent);
1415 case XML_DOCUMENT_NODE:
1416 *xmlString = EnsureCorrectEOL(bstrContent);
1417 *xmlString = EnsureNoEncoding(*xmlString);
1420 *xmlString = bstrContent;
1424 xmlBufferFree(pXmlBuf);
1427 /* Always returns a string. */
1428 if(*xmlString == NULL) *xmlString = SysAllocStringLen( NULL, 0 );
1433 static HRESULT WINAPI xmlnode_transformNode(
1435 IXMLDOMNode* styleSheet,
1438 #ifdef SONAME_LIBXSLT
1439 xmlnode *This = impl_from_IXMLDOMNode( iface );
1440 xmlnode *pStyleSheet = NULL;
1441 xsltStylesheetPtr xsltSS = NULL;
1442 xmlDocPtr result = NULL;
1445 TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1447 if (!libxslt_handle)
1449 if(!styleSheet || !xmlString)
1450 return E_INVALIDARG;
1454 if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1456 pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1458 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1461 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1464 const xmlChar *pContent;
1466 if(result->type == XML_HTML_DOCUMENT_NODE)
1468 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1471 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1472 pContent = xmlBufferContent(pOutput->buffer);
1473 *xmlString = bstr_from_xmlChar(pContent);
1474 xmlOutputBufferClose(pOutput);
1479 xmlBufferPtr pXmlBuf;
1482 pXmlBuf = xmlBufferCreate();
1485 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1488 pContent = xmlBufferContent(pXmlBuf);
1489 *xmlString = bstr_from_xmlChar(pContent);
1491 xmlBufferFree(pXmlBuf);
1496 /* libxslt "helpfully" frees the XML document the stylesheet was
1497 generated from, too */
1499 pxsltFreeStylesheet(xsltSS);
1502 IXMLDOMNode_Release(ssNew);
1505 if(*xmlString == NULL)
1506 *xmlString = SysAllocStringLen(NULL, 0);
1510 FIXME("libxslt headers were not found at compile time\n");
1515 static HRESULT WINAPI xmlnode_selectNodes(
1518 IXMLDOMNodeList** resultList)
1520 xmlnode *This = impl_from_IXMLDOMNode( iface );
1522 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1524 return queryresult_create( This->node, queryString, resultList );
1527 static HRESULT WINAPI xmlnode_selectSingleNode(
1530 IXMLDOMNode** resultNode)
1532 xmlnode *This = impl_from_IXMLDOMNode( iface );
1533 IXMLDOMNodeList *list;
1536 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1539 r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1542 r = IXMLDOMNodeList_nextNode(list, resultNode);
1543 IXMLDOMNodeList_Release(list);
1548 static HRESULT WINAPI xmlnode_get_parsed(
1550 VARIANT_BOOL* isParsed)
1552 xmlnode *This = impl_from_IXMLDOMNode( iface );
1553 FIXME("(%p)->(%p)\n", This, isParsed);
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;