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 TRACE("(%p)->(%p)\n", This, firstChild);
441 return get_node( This, "firstChild", This->node->children, firstChild );
444 static HRESULT WINAPI xmlnode_get_lastChild(
446 IXMLDOMNode** lastChild)
448 xmlnode *This = impl_from_IXMLDOMNode( iface );
450 TRACE("(%p)->(%p)\n", This, lastChild );
455 switch( This->node->type )
457 /* CDATASection, Comment, PI and Text Nodes do not support lastChild */
459 case XML_CDATA_SECTION_NODE:
461 case XML_COMMENT_NODE:
465 return get_node( This, "lastChild", This->node->last, lastChild );
469 static HRESULT WINAPI xmlnode_get_previousSibling(
471 IXMLDOMNode** previousSibling)
473 xmlnode *This = impl_from_IXMLDOMNode( iface );
475 TRACE("(%p)->(%p)\n", This, previousSibling );
477 if (!previousSibling)
480 switch( This->node->type )
482 /* Attribute, Document and Document Fragment Nodes do not support previousSibling */
483 case XML_DOCUMENT_NODE:
484 case XML_DOCUMENT_FRAG_NODE:
485 case XML_ATTRIBUTE_NODE:
486 *previousSibling = NULL;
489 return get_node( This, "previous", This->node->prev, previousSibling );
493 static HRESULT WINAPI xmlnode_get_nextSibling(
495 IXMLDOMNode** nextSibling)
497 xmlnode *This = impl_from_IXMLDOMNode( iface );
499 TRACE("(%p)->(%p)\n", This, nextSibling );
504 switch( This->node->type )
506 /* Attribute, Document and Document Fragment Nodes do not support nextSibling */
507 case XML_DOCUMENT_NODE:
508 case XML_DOCUMENT_FRAG_NODE:
509 case XML_ATTRIBUTE_NODE:
513 return get_node( This, "next", This->node->next, nextSibling );
517 static HRESULT WINAPI xmlnode_get_attributes(
519 IXMLDOMNamedNodeMap** attributeMap)
521 xmlnode *This = impl_from_IXMLDOMNode( iface );
522 TRACE("(%p)->(%p)\n", This, attributeMap);
527 switch( This->node->type )
529 /* Attribute, CDataSection, Comment, Documents, Documents Fragments,
530 Entity and Text Nodes does not support get_attributes */
531 case XML_ATTRIBUTE_NODE:
532 case XML_CDATA_SECTION_NODE:
533 case XML_COMMENT_NODE:
534 case XML_DOCUMENT_NODE:
535 case XML_DOCUMENT_FRAG_NODE:
536 case XML_ENTITY_NODE:
537 case XML_ENTITY_REF_NODE:
539 *attributeMap = NULL;
542 *attributeMap = create_nodemap( iface );
547 static HRESULT WINAPI xmlnode_insertBefore(
549 IXMLDOMNode* newChild,
551 IXMLDOMNode** outNewChild)
553 xmlnode *This = impl_from_IXMLDOMNode( iface );
554 xmlNodePtr before_node, new_child_node;
555 IXMLDOMNode *before = NULL, *new;
558 TRACE("(%p)->(%p var %p)\n",This,newChild,outNewChild);
563 switch(V_VT(&refChild))
570 hr = IUnknown_QueryInterface(V_UNKNOWN(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
571 if(FAILED(hr)) return hr;
575 hr = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IXMLDOMNode, (LPVOID)&before);
576 if(FAILED(hr)) return hr;
580 FIXME("refChild var type %x\n", V_VT(&refChild));
584 IXMLDOMNode_QueryInterface(newChild, &IID_IXMLDOMNode, (LPVOID)&new);
585 new_child_node = impl_from_IXMLDOMNode(new)->node;
586 TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
588 if(!new_child_node->parent)
589 if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
590 WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
594 before_node = impl_from_IXMLDOMNode(before)->node;
595 xmlAddPrevSibling(before_node, new_child_node);
596 IXMLDOMNode_Release(before);
600 xmlAddChild(This->node, new_child_node);
603 IXMLDOMNode_Release(new);
604 IXMLDOMNode_AddRef(newChild);
606 *outNewChild = newChild;
612 static HRESULT WINAPI xmlnode_replaceChild(
614 IXMLDOMNode* newChild,
615 IXMLDOMNode* oldChild,
616 IXMLDOMNode** outOldChild)
618 xmlnode *This = impl_from_IXMLDOMNode( iface );
619 xmlNode *old_child_ptr, *new_child_ptr;
620 xmlDocPtr leaving_doc;
621 xmlNode *my_ancestor;
622 IXMLDOMNode *realOldChild;
625 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
627 /* Do not believe any documentation telling that newChild == NULL
628 means removal. It does certainly *not* apply to msxml3! */
629 if(!newChild || !oldChild)
635 hr = IXMLDOMNode_QueryInterface(oldChild,&IID_IXMLDOMNode,(LPVOID*)&realOldChild);
639 old_child_ptr = impl_from_IXMLDOMNode(realOldChild)->node;
640 IXMLDOMNode_Release(realOldChild);
641 if(old_child_ptr->parent != This->node)
643 WARN("childNode %p is not a child of %p\n", oldChild, iface);
647 new_child_ptr = impl_from_IXMLDOMNode(newChild)->node;
648 my_ancestor = This->node;
651 if(my_ancestor == new_child_ptr)
653 WARN("tried to create loop\n");
656 my_ancestor = my_ancestor->parent;
659 if(!new_child_ptr->parent)
660 if(xmldoc_remove_orphan(new_child_ptr->doc, new_child_ptr) != S_OK)
661 WARN("%p is not an orphan of %p\n", new_child_ptr, new_child_ptr->doc);
663 leaving_doc = new_child_ptr->doc;
664 xmldoc_add_ref(old_child_ptr->doc);
665 xmlReplaceNode(old_child_ptr, new_child_ptr);
666 xmldoc_release(leaving_doc);
668 xmldoc_add_orphan(old_child_ptr->doc, old_child_ptr);
672 IXMLDOMNode_AddRef(oldChild);
673 *outOldChild = oldChild;
679 static HRESULT WINAPI xmlnode_removeChild(
681 IXMLDOMNode* childNode,
682 IXMLDOMNode** oldChild)
684 xmlnode *This = impl_from_IXMLDOMNode( iface );
685 xmlNode *child_node_ptr;
689 TRACE("(%p)->(%p %p)\n", This, childNode, oldChild);
691 if(!childNode) return E_INVALIDARG;
696 hr = IXMLDOMNode_QueryInterface(childNode, &IID_IXMLDOMNode, (LPVOID)&child);
700 child_node_ptr = impl_from_IXMLDOMNode(child)->node;
701 if(child_node_ptr->parent != This->node)
703 WARN("childNode %p is not a child of %p\n", childNode, iface);
704 IXMLDOMNode_Release(child);
708 xmlUnlinkNode(child_node_ptr);
710 IXMLDOMNode_Release(child);
714 IXMLDOMNode_AddRef(childNode);
715 *oldChild = childNode;
721 static HRESULT WINAPI xmlnode_appendChild(
723 IXMLDOMNode* newChild,
724 IXMLDOMNode** outNewChild)
726 xmlnode *This = impl_from_IXMLDOMNode( iface );
731 TRACE("(%p)->(%p %p)\n", This, newChild, outNewChild);
733 hr = IXMLDOMNode_get_nodeType(newChild, &type);
734 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
735 if(outNewChild) *outNewChild = NULL;
740 return IXMLDOMNode_insertBefore(iface, newChild, var, outNewChild);
743 static HRESULT WINAPI xmlnode_hasChildNodes(
745 VARIANT_BOOL* hasChild)
747 xmlnode *This = impl_from_IXMLDOMNode( iface );
749 TRACE("(%p)->(%p)\n", This, hasChild);
753 if (!This->node->children)
755 *hasChild = VARIANT_FALSE;
759 *hasChild = VARIANT_TRUE;
763 static HRESULT WINAPI xmlnode_get_ownerDocument(
765 IXMLDOMDocument** DOMDocument)
767 xmlnode *This = impl_from_IXMLDOMNode( iface );
769 TRACE("(%p)->(%p)\n", This, DOMDocument);
771 return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument2**)DOMDocument);
774 static HRESULT WINAPI xmlnode_cloneNode(
777 IXMLDOMNode** cloneRoot)
779 xmlnode *This = impl_from_IXMLDOMNode( iface );
780 xmlNodePtr pClone = NULL;
781 IXMLDOMNode *pNode = NULL;
783 TRACE("(%p)->(%d %p)\n", This, deep, cloneRoot);
788 pClone = xmlCopyNode(This->node, deep ? 1 : 2);
791 pClone->doc = This->node->doc;
792 xmldoc_add_orphan(pClone->doc, pClone);
794 pNode = create_node(pClone);
797 ERR("Copy failed\n");
805 ERR("Copy failed\n");
812 static HRESULT WINAPI xmlnode_get_nodeTypeString(
816 xmlnode *This = impl_from_IXMLDOMNode( iface );
819 TRACE("(%p)->(%p)\n", This, xmlnodeType );
827 switch( This->node->type )
829 case XML_ATTRIBUTE_NODE:
830 str = (const xmlChar*) "attribute";
832 case XML_CDATA_SECTION_NODE:
833 str = (const xmlChar*) "cdatasection";
835 case XML_COMMENT_NODE:
836 str = (const xmlChar*) "comment";
838 case XML_DOCUMENT_NODE:
839 str = (const xmlChar*) "document";
841 case XML_DOCUMENT_FRAG_NODE:
842 str = (const xmlChar*) "documentfragment";
844 case XML_ELEMENT_NODE:
845 str = (const xmlChar*) "element";
847 case XML_ENTITY_NODE:
848 str = (const xmlChar*) "entity";
850 case XML_ENTITY_REF_NODE:
851 str = (const xmlChar*) "entityreference";
853 case XML_NOTATION_NODE:
854 str = (const xmlChar*) "notation";
857 str = (const xmlChar*) "processinginstruction";
860 str = (const xmlChar*) "text";
863 FIXME("Unknown node type (%d)\n", This->node->type);
864 str = This->node->name;
868 *xmlnodeType = bstr_from_xmlChar( str );
875 static HRESULT WINAPI xmlnode_get_text(
879 xmlnode *This = impl_from_IXMLDOMNode( iface );
883 TRACE("(%p, type %d)->(%p)\n", This, This->node->type, text);
888 pContent = xmlNodeGetContent((xmlNodePtr)This->node);
891 str = bstr_from_xmlChar(pContent);
895 /* Always return a string. */
896 if (!str) str = SysAllocStringLen( NULL, 0 );
898 TRACE("%p %s\n", This, debugstr_w(str) );
904 static HRESULT WINAPI xmlnode_put_text(
908 xmlnode *This = impl_from_IXMLDOMNode( iface );
911 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
913 switch(This->node->type)
915 case XML_DOCUMENT_NODE:
921 str = xmlChar_from_wchar(text);
923 /* Escape the string. */
924 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
927 xmlNodeSetContent(This->node, str2);
933 static HRESULT WINAPI xmlnode_get_specified(
935 VARIANT_BOOL* isSpecified)
937 xmlnode *This = impl_from_IXMLDOMNode( iface );
938 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
939 *isSpecified = VARIANT_TRUE;
943 static HRESULT WINAPI xmlnode_get_definition(
945 IXMLDOMNode** definitionNode)
947 xmlnode *This = impl_from_IXMLDOMNode( iface );
948 FIXME("(%p)->(%p)\n", This, definitionNode);
952 static inline BYTE hex_to_byte(xmlChar c)
954 if(c <= '9') return c-'0';
955 if(c <= 'F') return c-'A'+10;
959 static inline BYTE base64_to_byte(xmlChar c)
961 if(c == '+') return 62;
962 if(c == '/') return 63;
963 if(c <= '9') return c-'0'+52;
964 if(c <= 'Z') return c-'A';
968 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
970 if(!type || !lstrcmpiW(type, szString) ||
971 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
974 V_BSTR(v) = bstr_from_xmlChar(str);
977 return E_OUTOFMEMORY;
979 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
980 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
981 !lstrcmpiW(type, szTimeTZ))
991 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
993 V_VT(&src) = VT_BSTR;
994 V_BSTR(&src) = bstr_from_xmlChar(str);
997 return E_OUTOFMEMORY;
1000 e = p + SysStringLen(V_BSTR(&src));
1002 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
1004 st.wYear = atoiW(p);
1005 st.wMonth = atoiW(p+5);
1006 st.wDay = atoiW(p+8);
1012 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
1014 st.wHour = atoiW(p);
1015 st.wMinute = atoiW(p+3);
1016 st.wSecond = atoiW(p+6);
1022 while(isdigitW(*p)) p++;
1026 SystemTimeToVariantTime(&st, &date);
1030 if(*p == '+') /* parse timezone offset (+hh:mm) */
1031 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1032 else if(*p == '-') /* parse timezone offset (-hh:mm) */
1033 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
1037 else if(!lstrcmpiW(type, szBinHex))
1042 len = xmlStrlen(str)/2;
1044 sab.cElements = len;
1046 V_VT(v) = (VT_ARRAY|VT_UI1);
1047 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1050 return E_OUTOFMEMORY;
1052 for(i=0; i<len; i++)
1053 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
1054 + hex_to_byte(str[2*i+1]);
1056 else if(!lstrcmpiW(type, szBinBase64))
1061 len = xmlStrlen(str);
1062 if(str[len-2] == '=') i = 2;
1063 else if(str[len-1] == '=') i = 1;
1067 sab.cElements = len/4*3-i;
1069 V_VT(v) = (VT_ARRAY|VT_UI1);
1070 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
1073 return E_OUTOFMEMORY;
1075 for(i=0; i<len/4; i++)
1077 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
1078 + (base64_to_byte(str[4*i+1])>>4);
1079 if(3*i+1 < sab.cElements)
1080 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
1081 + (base64_to_byte(str[4*i+2])>>2);
1082 if(3*i+2 < sab.cElements)
1083 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
1084 + base64_to_byte(str[4*i+3]);
1092 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
1094 else if(!lstrcmpiW(type, szFixed))
1096 else if(!lstrcmpiW(type, szBoolean))
1098 else if(!lstrcmpiW(type, szI1))
1100 else if(!lstrcmpiW(type, szI2))
1102 else if(!lstrcmpiW(type, szIU1))
1104 else if(!lstrcmpiW(type, szIU2))
1106 else if(!lstrcmpiW(type, szIU4))
1108 else if(!lstrcmpiW(type, szR4))
1110 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
1114 FIXME("Type handling not yet implemented\n");
1118 V_VT(&src) = VT_BSTR;
1119 V_BSTR(&src) = bstr_from_xmlChar(str);
1122 return E_OUTOFMEMORY;
1124 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
1125 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
1133 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
1135 VARIANT* typedValue)
1137 xmlnode *This = impl_from_IXMLDOMNode( iface );
1140 HRESULT hres = S_FALSE;
1142 TRACE("(%p)->(%p)\n", This, typedValue);
1145 return E_INVALIDARG;
1147 V_VT(typedValue) = VT_NULL;
1149 if(This->node->type == XML_ELEMENT_NODE ||
1150 This->node->type == XML_TEXT_NODE ||
1151 This->node->type == XML_ENTITY_REF_NODE)
1152 hres = IXMLDOMNode_get_dataType(iface, &type);
1154 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
1155 return IXMLDOMNode_get_nodeValue(iface, typedValue);
1157 content = xmlNodeGetContent(This->node);
1158 hres = VARIANT_from_xmlChar(content, typedValue,
1159 hres==S_OK ? V_BSTR(&type) : NULL);
1161 VariantClear(&type);
1166 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
1170 xmlnode *This = impl_from_IXMLDOMNode( iface );
1171 FIXME("%p\n", This);
1175 static HRESULT WINAPI xmlnode_get_dataType(
1177 VARIANT* dataTypeName)
1179 xmlnode *This = impl_from_IXMLDOMNode( iface );
1182 TRACE("(%p)->(%p)\n", This, dataTypeName);
1185 return E_INVALIDARG;
1187 /* Attribute, CDATA Section, Comment, Document, Document Fragment,
1188 Entity, Notation, PI, and Text Node are non-typed. */
1189 V_BSTR(dataTypeName) = NULL;
1190 V_VT(dataTypeName) = VT_NULL;
1192 switch ( This->node->type )
1194 case XML_ELEMENT_NODE:
1195 pVal = xmlGetNsProp(This->node, (const xmlChar*)"dt",
1196 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
1199 V_VT(dataTypeName) = VT_BSTR;
1200 V_BSTR(dataTypeName) = bstr_from_xmlChar( pVal );
1204 case XML_ENTITY_REF_NODE:
1205 FIXME("XML_ENTITY_REF_NODE should return a valid value.\n");
1208 TRACE("Type %d returning NULL\n", This->node->type);
1211 /* non-typed nodes return S_FALSE */
1212 if(V_VT(dataTypeName) == VT_NULL)
1220 static HRESULT WINAPI xmlnode_put_dataType(
1224 xmlnode *This = impl_from_IXMLDOMNode( iface );
1225 HRESULT hr = E_FAIL;
1227 TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1229 if(dataTypeName == NULL)
1230 return E_INVALIDARG;
1232 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
1233 This applies to changing types (string->bool) or setting a new one
1235 FIXME("Need to Validate the data before allowing a type to be set.\n");
1237 /* Check all supported types. */
1238 if(lstrcmpiW(dataTypeName,szString) == 0 ||
1239 lstrcmpiW(dataTypeName,szNumber) == 0 ||
1240 lstrcmpiW(dataTypeName,szUUID) == 0 ||
1241 lstrcmpiW(dataTypeName,szInt) == 0 ||
1242 lstrcmpiW(dataTypeName,szI4) == 0 ||
1243 lstrcmpiW(dataTypeName,szFixed) == 0 ||
1244 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
1245 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
1246 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
1247 lstrcmpiW(dataTypeName,szDate) == 0 ||
1248 lstrcmpiW(dataTypeName,szTime) == 0 ||
1249 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
1250 lstrcmpiW(dataTypeName,szI1) == 0 ||
1251 lstrcmpiW(dataTypeName,szI2) == 0 ||
1252 lstrcmpiW(dataTypeName,szIU1) == 0 ||
1253 lstrcmpiW(dataTypeName,szIU2) == 0 ||
1254 lstrcmpiW(dataTypeName,szIU4) == 0 ||
1255 lstrcmpiW(dataTypeName,szR4) == 0 ||
1256 lstrcmpiW(dataTypeName,szR8) == 0 ||
1257 lstrcmpiW(dataTypeName,szFloat) == 0 ||
1258 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
1259 lstrcmpiW(dataTypeName,szBinBase64) == 0)
1261 xmlNsPtr pNS = NULL;
1262 xmlAttrPtr pAttr = NULL;
1263 xmlChar* str = xmlChar_from_wchar(dataTypeName);
1265 pAttr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
1266 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
1269 pAttr = xmlSetNsProp(This->node, pAttr->ns, (const xmlChar*)"dt", str);
1275 pNS = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
1278 pAttr = xmlNewNsProp(This->node, pNS, (const xmlChar*)"dt", str);
1281 xmlAddChild(This->node, (xmlNodePtr)pAttr);
1286 ERR("Failed to create Attribute\n");
1289 ERR("Failed to Create Namepsace\n");
1297 static BSTR EnsureCorrectEOL(BSTR sInput)
1304 nLen = lstrlenW(sInput);
1305 /* Count line endings */
1306 for(i=0; i < nLen; i++)
1308 if(sInput[i] == '\n')
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] == '\n')
1323 sNew[i+nPlace] = '\r';
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 indents 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;
1388 TRACE("(%p %d)->(%p)\n", This, This->node->type, xmlString);
1391 return E_INVALIDARG;
1395 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
1397 pXmlBuf = xmlBufferCreate();
1400 nSize = xmlNodeDump(pXmlBuf, This->node->doc, This->node, 0, 1);
1403 const xmlChar *pContent;
1406 /* Attribute Nodes return a space in front of their name */
1407 pContent = xmlBufferContent(pXmlBuf);
1408 if( ((const char*)pContent)[0] == ' ')
1409 bstrContent = bstr_from_xmlChar(pContent+1);
1411 bstrContent = bstr_from_xmlChar(pContent);
1413 switch(This->node->type)
1415 case XML_ELEMENT_NODE:
1416 *xmlString = EnsureCorrectEOL(bstrContent);
1418 case XML_DOCUMENT_NODE:
1419 *xmlString = EnsureCorrectEOL(bstrContent);
1420 *xmlString = EnsureNoEncoding(*xmlString);
1423 *xmlString = bstrContent;
1427 xmlBufferFree(pXmlBuf);
1430 xmldoc_link_xmldecl( This->node->doc, xmldecl );
1432 /* Always returns a string. */
1433 if(*xmlString == NULL) *xmlString = SysAllocStringLen( NULL, 0 );
1438 static HRESULT WINAPI xmlnode_transformNode(
1440 IXMLDOMNode* styleSheet,
1443 #ifdef SONAME_LIBXSLT
1444 xmlnode *This = impl_from_IXMLDOMNode( iface );
1445 xmlnode *pStyleSheet = NULL;
1446 xsltStylesheetPtr xsltSS = NULL;
1447 xmlDocPtr result = NULL;
1450 TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1452 if (!libxslt_handle)
1454 if(!styleSheet || !xmlString)
1455 return E_INVALIDARG;
1459 if(IXMLDOMNode_QueryInterface(styleSheet, &IID_IXMLDOMNode, (LPVOID)&ssNew) == S_OK)
1461 pStyleSheet = impl_from_IXMLDOMNode( ssNew );
1463 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1466 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1469 const xmlChar *pContent;
1471 if(result->type == XML_HTML_DOCUMENT_NODE)
1473 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1476 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1477 pContent = xmlBufferContent(pOutput->buffer);
1478 *xmlString = bstr_from_xmlChar(pContent);
1479 xmlOutputBufferClose(pOutput);
1484 xmlBufferPtr pXmlBuf;
1487 pXmlBuf = xmlBufferCreate();
1490 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1493 pContent = xmlBufferContent(pXmlBuf);
1494 *xmlString = bstr_from_xmlChar(pContent);
1496 xmlBufferFree(pXmlBuf);
1501 /* libxslt "helpfully" frees the XML document the stylesheet was
1502 generated from, too */
1504 pxsltFreeStylesheet(xsltSS);
1507 IXMLDOMNode_Release(ssNew);
1510 if(*xmlString == NULL)
1511 *xmlString = SysAllocStringLen(NULL, 0);
1515 FIXME("libxslt headers were not found at compile time\n");
1520 static HRESULT WINAPI xmlnode_selectNodes(
1523 IXMLDOMNodeList** resultList)
1525 xmlnode *This = impl_from_IXMLDOMNode( iface );
1527 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1529 return queryresult_create( This->node, queryString, resultList );
1532 static HRESULT WINAPI xmlnode_selectSingleNode(
1535 IXMLDOMNode** resultNode)
1537 xmlnode *This = impl_from_IXMLDOMNode( iface );
1538 IXMLDOMNodeList *list;
1541 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1544 r = IXMLDOMNode_selectNodes(iface, queryString, &list);
1547 r = IXMLDOMNodeList_nextNode(list, resultNode);
1548 IXMLDOMNodeList_Release(list);
1553 static HRESULT WINAPI xmlnode_get_parsed(
1555 VARIANT_BOOL* isParsed)
1557 xmlnode *This = impl_from_IXMLDOMNode( iface );
1558 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1559 *isParsed = VARIANT_TRUE;
1563 static HRESULT WINAPI xmlnode_get_namespaceURI(
1567 xmlnode *This = impl_from_IXMLDOMNode( iface );
1568 HRESULT hr = S_FALSE;
1571 TRACE("(%p)->(%p)\n", This, namespaceURI );
1574 return E_INVALIDARG;
1576 *namespaceURI = NULL;
1578 pNSList = xmlGetNsList(This->node->doc, This->node);
1581 *namespaceURI = bstr_from_xmlChar( pNSList[0]->href );
1590 static HRESULT WINAPI xmlnode_get_prefix(
1594 xmlnode *This = impl_from_IXMLDOMNode( iface );
1595 HRESULT hr = S_FALSE;
1598 TRACE("(%p)->(%p)\n", This, prefixString );
1601 return E_INVALIDARG;
1603 *prefixString = NULL;
1605 pNSList = xmlGetNsList(This->node->doc, This->node);
1608 *prefixString = bstr_from_xmlChar( pNSList[0]->prefix );
1617 static HRESULT WINAPI xmlnode_get_baseName(
1621 xmlnode *This = impl_from_IXMLDOMNode( iface );
1623 HRESULT r = S_FALSE;
1625 TRACE("(%p)->(%p)\n", This, nameString );
1628 return E_INVALIDARG;
1630 switch ( This->node->type )
1632 case XML_ELEMENT_NODE:
1633 case XML_ATTRIBUTE_NODE:
1635 str = bstr_from_xmlChar( This->node->name );
1639 case XML_COMMENT_NODE:
1640 case XML_DOCUMENT_NODE:
1643 ERR("Unhandled type %d\n", This->node->type );
1647 TRACE("returning %08x str = %s\n", r, debugstr_w( str ) );
1653 static HRESULT WINAPI xmlnode_transformNodeToObject(
1655 IXMLDOMNode* stylesheet,
1656 VARIANT outputObject)
1658 xmlnode *This = impl_from_IXMLDOMNode( iface );
1659 FIXME("(%p)->(%p)\n", This, stylesheet);
1663 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1665 xmlnode_QueryInterface,
1668 xmlnode_GetTypeInfoCount,
1669 xmlnode_GetTypeInfo,
1670 xmlnode_GetIDsOfNames,
1672 xmlnode_get_nodeName,
1673 xmlnode_get_nodeValue,
1674 xmlnode_put_nodeValue,
1675 xmlnode_get_nodeType,
1676 xmlnode_get_parentNode,
1677 xmlnode_get_childNodes,
1678 xmlnode_get_firstChild,
1679 xmlnode_get_lastChild,
1680 xmlnode_get_previousSibling,
1681 xmlnode_get_nextSibling,
1682 xmlnode_get_attributes,
1683 xmlnode_insertBefore,
1684 xmlnode_replaceChild,
1685 xmlnode_removeChild,
1686 xmlnode_appendChild,
1687 xmlnode_hasChildNodes,
1688 xmlnode_get_ownerDocument,
1690 xmlnode_get_nodeTypeString,
1693 xmlnode_get_specified,
1694 xmlnode_get_definition,
1695 xmlnode_get_nodeTypedValue,
1696 xmlnode_put_nodeTypedValue,
1697 xmlnode_get_dataType,
1698 xmlnode_put_dataType,
1700 xmlnode_transformNode,
1701 xmlnode_selectNodes,
1702 xmlnode_selectSingleNode,
1704 xmlnode_get_namespaceURI,
1706 xmlnode_get_baseName,
1707 xmlnode_transformNodeToObject,
1710 void destroy_xmlnode(xmlnode *This)
1713 xmldoc_release(This->node->doc);
1716 void init_xmlnode(xmlnode *This, xmlNodePtr node, IUnknown *outer, dispex_static_data_t *dispex_data )
1719 xmldoc_add_ref( node->doc );
1721 This->lpVtbl = &xmlnode_vtbl;
1724 This->pUnkOuter = outer;
1727 init_dispex(&This->dispex, This->pUnkOuter, dispex_data);
1730 IXMLDOMNode *create_node( xmlNodePtr node )
1739 TRACE("type %d\n", node->type);
1742 case XML_ELEMENT_NODE:
1743 pUnk = create_element( node );
1745 case XML_ATTRIBUTE_NODE:
1746 pUnk = create_attribute( node );
1749 pUnk = create_text( node );
1751 case XML_CDATA_SECTION_NODE:
1752 pUnk = create_cdata( node );
1754 case XML_ENTITY_REF_NODE:
1755 pUnk = create_doc_entity_ref( node );
1758 pUnk = create_pi( node );
1760 case XML_COMMENT_NODE:
1761 pUnk = create_comment( node );
1763 case XML_DOCUMENT_NODE:
1764 pUnk = create_domdoc( node );
1766 case XML_DOCUMENT_FRAG_NODE:
1767 pUnk = create_doc_fragment( node );
1772 FIXME("only creating basic node for type %d\n", node->type);
1774 new_node = heap_alloc(sizeof(xmlnode));
1778 init_xmlnode(new_node, node, NULL, NULL);
1779 pUnk = (IUnknown*)IXMLDOMNode_from_impl(new_node);
1783 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1784 IUnknown_Release(pUnk);
1785 if(FAILED(hr)) return NULL;