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
28 # include <libxml/parser.h>
29 # include <libxml/xmlerror.h>
30 # include <libxml/HTMLtree.h>
31 # ifdef SONAME_LIBXSLT
32 # ifdef HAVE_LIBXSLT_PATTERN_H
33 # include <libxslt/pattern.h>
35 # ifdef HAVE_LIBXSLT_TRANSFORM_H
36 # include <libxslt/transform.h>
38 # include <libxslt/xsltutils.h>
39 # include <libxslt/xsltInternals.h>
50 #include "msxml_private.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
59 extern void* libxslt_handle;
60 # define MAKE_FUNCPTR(f) extern typeof(f) * p##f
61 MAKE_FUNCPTR(xsltApplyStylesheet);
62 MAKE_FUNCPTR(xsltCleanupGlobals);
63 MAKE_FUNCPTR(xsltFreeStylesheet);
64 MAKE_FUNCPTR(xsltParseStylesheetDoc);
68 /* TODO: get rid of these and use the enum */
69 static const WCHAR szBinBase64[] = {'b','i','n','.','b','a','s','e','6','4',0};
70 static const WCHAR szString[] = {'s','t','r','i','n','g',0};
71 static const WCHAR szNumber[] = {'n','u','m','b','e','r',0};
72 static const WCHAR szInt[] = {'I','n','t',0};
73 static const WCHAR szFixed[] = {'F','i','x','e','d','.','1','4','.','4',0};
74 static const WCHAR szBoolean[] = {'B','o','o','l','e','a','n',0};
75 static const WCHAR szDateTime[] = {'d','a','t','e','T','i','m','e',0};
76 static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
77 static const WCHAR szDate[] = {'D','a','t','e',0};
78 static const WCHAR szTime[] = {'T','i','m','e',0};
79 static const WCHAR szTimeTZ[] = {'T','i','m','e','.','t','z',0};
80 static const WCHAR szI1[] = {'i','1',0};
81 static const WCHAR szI2[] = {'i','2',0};
82 static const WCHAR szI4[] = {'i','4',0};
83 static const WCHAR szIU1[] = {'u','i','1',0};
84 static const WCHAR szIU2[] = {'u','i','2',0};
85 static const WCHAR szIU4[] = {'u','i','4',0};
86 static const WCHAR szR4[] = {'r','4',0};
87 static const WCHAR szR8[] = {'r','8',0};
88 static const WCHAR szFloat[] = {'f','l','o','a','t',0};
89 static const WCHAR szUUID[] = {'u','u','i','d',0};
90 static const WCHAR szBinHex[] = {'b','i','n','.','h','e','x',0};
92 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
94 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
100 This = get_node_obj( iface );
101 if ( !This || !This->node )
103 if ( type && This->node->type != type )
108 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
110 if(IsEqualGUID(&IID_xmlnode, riid)) {
111 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
116 return dispex_query_interface(&This->dispex, riid, ppv);
119 /* common ISupportErrorInfo implementation */
121 ISupportErrorInfo ISupportErrorInfo_iface;
127 static inline SupportErrorInfo *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
129 return CONTAINING_RECORD(iface, SupportErrorInfo, ISupportErrorInfo_iface);
132 static HRESULT WINAPI SupportErrorInfo_QueryInterface(ISupportErrorInfo *iface, REFIID riid, void **obj)
134 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
135 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
139 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISupportErrorInfo)) {
141 ISupportErrorInfo_AddRef(iface);
145 return E_NOINTERFACE;
148 static ULONG WINAPI SupportErrorInfo_AddRef(ISupportErrorInfo *iface)
150 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
151 ULONG ref = InterlockedIncrement(&This->ref);
152 TRACE("(%p)->(%d)\n", This, ref );
156 static ULONG WINAPI SupportErrorInfo_Release(ISupportErrorInfo *iface)
158 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
159 LONG ref = InterlockedDecrement(&This->ref);
161 TRACE("(%p)->(%d)\n", This, ref);
169 static HRESULT WINAPI SupportErrorInfo_InterfaceSupportsErrorInfo(ISupportErrorInfo *iface, REFIID riid)
171 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
172 enum tid_t const *tid;
174 TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
179 if (IsEqualGUID(riid, get_riid_from_tid(*tid)))
187 static const struct ISupportErrorInfoVtbl SupportErrorInfoVtbl = {
188 SupportErrorInfo_QueryInterface,
189 SupportErrorInfo_AddRef,
190 SupportErrorInfo_Release,
191 SupportErrorInfo_InterfaceSupportsErrorInfo
194 HRESULT node_create_supporterrorinfo(enum tid_t const *iids, void **obj)
196 SupportErrorInfo *This;
198 This = heap_alloc(sizeof(*This));
199 if (!This) return E_OUTOFMEMORY;
201 This->ISupportErrorInfo_iface.lpVtbl = &SupportErrorInfoVtbl;
205 *obj = &This->ISupportErrorInfo_iface;
210 xmlnode *get_node_obj(IXMLDOMNode *node)
215 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
216 if (!obj) WARN("node is not our IXMLDOMNode implementation\n");
217 return SUCCEEDED(hres) ? obj : NULL;
220 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
228 hr = node_get_base_name(This, &base);
229 if (hr != S_OK) return hr;
231 hr = node_get_prefix(This, &prefix);
234 static const WCHAR colW = ':';
238 ptr = *name = SysAllocStringLen(NULL, SysStringLen(base) + SysStringLen(prefix) + 1);
239 memcpy(ptr, prefix, SysStringByteLen(prefix));
240 ptr += SysStringLen(prefix);
241 memcpy(ptr++, &colW, sizeof(WCHAR));
242 memcpy(ptr, base, SysStringByteLen(base));
245 SysFreeString(prefix);
253 HRESULT node_get_content(xmlnode *This, VARIANT *value)
260 content = xmlNodeGetContent(This->node);
261 V_VT(value) = VT_BSTR;
262 V_BSTR(value) = bstr_from_xmlChar( content );
265 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
269 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
273 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
274 str = xmlchar_from_wchar(value);
276 return E_OUTOFMEMORY;
278 xmlNodeSetContent(This->node, str);
283 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
285 xmlChar *str, *escaped;
287 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
288 str = xmlchar_from_wchar(value);
290 return E_OUTOFMEMORY;
292 escaped = xmlEncodeSpecialChars(NULL, str);
296 return E_OUTOFMEMORY;
299 xmlNodeSetContent(This->node, escaped);
307 HRESULT node_put_value(xmlnode *This, VARIANT *value)
309 VARIANT string_value;
312 VariantInit(&string_value);
313 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
315 WARN("Couldn't convert to VT_BSTR\n");
319 hr = node_set_content(This, V_BSTR(&string_value));
320 VariantClear(&string_value);
325 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
327 VARIANT string_value;
330 VariantInit(&string_value);
331 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
333 WARN("Couldn't convert to VT_BSTR\n");
337 hr = node_set_content_escaped(This, V_BSTR(&string_value));
338 VariantClear(&string_value);
343 static HRESULT get_node(
349 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
354 /* if we don't have a doc, use our parent. */
355 if(node && !node->doc && node->parent)
356 node->doc = node->parent->doc;
358 *out = create_node( node );
364 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
366 return get_node( This, "parent", This->node->parent, parent );
369 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
374 *ret = create_children_nodelist(This->node);
376 return E_OUTOFMEMORY;
381 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
383 return get_node(This, "firstChild", This->node->children, ret);
386 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
388 return get_node(This, "lastChild", This->node->last, ret);
391 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
393 return get_node(This, "previous", This->node->prev, ret);
396 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
398 return get_node(This, "next", This->node->next, ret);
401 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
404 IXMLDOMNode *before = NULL;
412 node_obj = get_node_obj(new_child);
413 if(!node_obj) return E_FAIL;
415 switch(V_VT(ref_child))
423 if (V_UNKNOWN(ref_child))
425 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
426 if(FAILED(hr)) return hr;
431 FIXME("refChild var type %x\n", V_VT(ref_child));
435 TRACE("new child %p, This->node %p\n", node_obj->node, This->node);
437 if(!node_obj->node->parent)
438 if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK)
439 WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc);
443 xmlnode *before_node_obj = get_node_obj(before);
444 IXMLDOMNode_Release(before);
445 if(!before_node_obj) return E_FAIL;
447 /* unlink from current parent first */
450 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
451 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
453 doc = node_obj->node->doc;
454 xmldoc_add_ref(before_node_obj->node->doc);
455 xmlAddPrevSibling(before_node_obj->node, node_obj->node);
457 node_obj->parent = This->parent;
461 /* unlink from current parent first */
464 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
465 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
467 doc = node_obj->node->doc;
468 xmldoc_add_ref(This->node->doc);
469 /* xmlAddChild doesn't unlink node from previous parent */
470 xmlUnlinkNode(node_obj->node);
471 xmlAddChild(This->node, node_obj->node);
473 node_obj->parent = This->iface;
478 IXMLDOMNode_AddRef(new_child);
486 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
489 xmlnode *old_child, *new_child;
490 xmlDocPtr leaving_doc;
491 xmlNode *my_ancestor;
493 /* Do not believe any documentation telling that newChild == NULL
494 means removal. It does certainly *not* apply to msxml3! */
495 if(!newChild || !oldChild)
501 old_child = get_node_obj(oldChild);
502 if(!old_child) return E_FAIL;
504 if(old_child->node->parent != This->node)
506 WARN("childNode %p is not a child of %p\n", oldChild, This);
510 new_child = get_node_obj(newChild);
511 if(!new_child) return E_FAIL;
513 my_ancestor = This->node;
516 if(my_ancestor == new_child->node)
518 WARN("tried to create loop\n");
521 my_ancestor = my_ancestor->parent;
524 if(!new_child->node->parent)
525 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
526 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
528 leaving_doc = new_child->node->doc;
529 xmldoc_add_ref(old_child->node->doc);
530 xmlReplaceNode(old_child->node, new_child->node);
531 xmldoc_release(leaving_doc);
532 new_child->parent = old_child->parent;
533 old_child->parent = NULL;
535 xmldoc_add_orphan(old_child->node->doc, old_child->node);
539 IXMLDOMNode_AddRef(oldChild);
546 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
550 if(!child) return E_INVALIDARG;
555 child_node = get_node_obj(child);
556 if(!child_node) return E_FAIL;
558 if(child_node->node->parent != This->node)
560 WARN("childNode %p is not a child of %p\n", child, This);
564 xmlUnlinkNode(child_node->node);
565 child_node->parent = NULL;
566 xmldoc_add_orphan(child_node->node->doc, child_node->node);
570 IXMLDOMNode_AddRef(child);
577 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
583 hr = IXMLDOMNode_get_nodeType(child, &type);
584 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
585 if (outChild) *outChild = NULL;
590 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
593 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
595 if (!ret) return E_INVALIDARG;
597 if (!This->node->children)
599 *ret = VARIANT_FALSE;
607 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
609 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
612 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
617 if(!cloneNode) return E_INVALIDARG;
619 clone = xmlCopyNode(This->node, deep ? 1 : 2);
622 clone->doc = This->node->doc;
623 xmldoc_add_orphan(clone->doc, clone);
625 node = create_node(clone);
628 ERR("Copy failed\n");
629 xmldoc_remove_orphan(clone->doc, clone);
638 ERR("Copy failed\n");
645 static inline xmlChar* trim_whitespace(xmlChar* str)
653 while (*ret && isspace(*ret))
655 len = xmlStrlen(ret);
657 while (isspace(ret[len-1])) --len;
659 ret = xmlStrndup(ret, len);
664 static xmlChar* do_get_text(xmlNodePtr node)
668 BOOL preserving = is_preserving_whitespace(node);
672 str = xmlNodeGetContent(node);
676 xmlElementType prev_type = XML_TEXT_NODE;
678 str = xmlStrdup(BAD_CAST "");
679 for (child = node->children; child != NULL; child = child->next)
683 case XML_ELEMENT_NODE:
684 tmp = do_get_text(child);
687 case XML_CDATA_SECTION_NODE:
688 case XML_ENTITY_REF_NODE:
689 case XML_ENTITY_NODE:
690 tmp = xmlNodeGetContent(child);
701 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
702 str = xmlStrcat(str, BAD_CAST " ");
703 str = xmlStrcat(str, tmp);
704 prev_type = child->type;
713 case XML_ELEMENT_NODE:
715 case XML_ENTITY_REF_NODE:
716 case XML_ENTITY_NODE:
717 case XML_DOCUMENT_NODE:
718 case XML_DOCUMENT_FRAG_NODE:
720 str = trim_whitespace(str);
729 HRESULT node_get_text(const xmlnode *This, BSTR *text)
734 if (!text) return E_INVALIDARG;
736 content = do_get_text(This->node);
739 str = bstr_from_xmlChar(content);
743 /* Always return a string. */
744 if (!str) str = SysAllocStringLen( NULL, 0 );
746 TRACE("%p %s\n", This, debugstr_w(str) );
752 HRESULT node_put_text(xmlnode *This, BSTR text)
756 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
758 str = xmlchar_from_wchar(text);
760 /* Escape the string. */
761 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
764 xmlNodeSetContent(This->node, str2);
770 static inline BYTE hex_to_byte(xmlChar c)
772 if(c <= '9') return c-'0';
773 if(c <= 'F') return c-'A'+10;
777 static inline BYTE base64_to_byte(xmlChar c)
779 if(c == '+') return 62;
780 if(c == '/') return 63;
781 if(c <= '9') return c-'0'+52;
782 if(c <= 'Z') return c-'A';
786 /* TODO: phasing this version out */
787 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
789 if(!type || !lstrcmpiW(type, szString) ||
790 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
793 V_BSTR(v) = bstr_from_xmlChar(str);
796 return E_OUTOFMEMORY;
798 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
799 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
800 !lstrcmpiW(type, szTimeTZ))
810 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
812 V_VT(&src) = VT_BSTR;
813 V_BSTR(&src) = bstr_from_xmlChar(str);
816 return E_OUTOFMEMORY;
819 e = p + SysStringLen(V_BSTR(&src));
821 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
824 st.wMonth = atoiW(p+5);
825 st.wDay = atoiW(p+8);
831 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
834 st.wMinute = atoiW(p+3);
835 st.wSecond = atoiW(p+6);
841 while(isdigitW(*p)) p++;
845 SystemTimeToVariantTime(&st, &date);
849 if(*p == '+') /* parse timezone offset (+hh:mm) */
850 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
851 else if(*p == '-') /* parse timezone offset (-hh:mm) */
852 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
856 else if(!lstrcmpiW(type, szBinHex))
861 len = xmlStrlen(str)/2;
865 V_VT(v) = (VT_ARRAY|VT_UI1);
866 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
869 return E_OUTOFMEMORY;
872 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
873 + hex_to_byte(str[2*i+1]);
875 else if(!lstrcmpiW(type, szBinBase64))
880 len = xmlStrlen(str);
881 if(str[len-2] == '=') i = 2;
882 else if(str[len-1] == '=') i = 1;
886 sab.cElements = len/4*3-i;
888 V_VT(v) = (VT_ARRAY|VT_UI1);
889 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
892 return E_OUTOFMEMORY;
894 for(i=0; i<len/4; i++)
896 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
897 + (base64_to_byte(str[4*i+1])>>4);
898 if(3*i+1 < sab.cElements)
899 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
900 + (base64_to_byte(str[4*i+2])>>2);
901 if(3*i+2 < sab.cElements)
902 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
903 + base64_to_byte(str[4*i+3]);
911 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
913 else if(!lstrcmpiW(type, szFixed))
915 else if(!lstrcmpiW(type, szBoolean))
917 else if(!lstrcmpiW(type, szI1))
919 else if(!lstrcmpiW(type, szI2))
921 else if(!lstrcmpiW(type, szIU1))
923 else if(!lstrcmpiW(type, szIU2))
925 else if(!lstrcmpiW(type, szIU4))
927 else if(!lstrcmpiW(type, szR4))
929 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
933 FIXME("Type handling not yet implemented\n");
937 V_VT(&src) = VT_BSTR;
938 V_BSTR(&src) = bstr_from_xmlChar(str);
941 return E_OUTOFMEMORY;
943 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
944 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
952 BSTR EnsureCorrectEOL(BSTR sInput)
959 nLen = SysStringLen(sInput);
960 /* Count line endings */
961 for(i=0; i < nLen; i++)
963 if(sInput[i] == '\n')
967 TRACE("len=%d, num=%d\n", nLen, nNum);
969 /* Add linefeed as needed */
973 sNew = SysAllocStringLen(NULL, nLen + nNum);
974 for(i=0; i < nLen; i++)
976 if(sInput[i] == '\n')
978 sNew[i+nPlace] = '\r';
981 sNew[i+nPlace] = sInput[i];
984 SysFreeString(sInput);
991 TRACE("len %d\n", SysStringLen(sNew));
996 /* Removes encoding information and last character (nullbyte) */
997 static BSTR EnsureNoEncoding(BSTR sInput)
999 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1004 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1009 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1014 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1015 while(*pEnd != '\"') pEnd++;
1018 sNew = SysAllocStringLen(NULL,
1019 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1020 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1021 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1023 SysFreeString(sInput);
1028 * We are trying to replicate the same behaviour as msxml by converting
1029 * line endings to \r\n and using indents as \t. The problem is that msxml
1030 * only formats nodes that have a line ending. Using libxml we cannot
1031 * reproduce behaviour exactly.
1034 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
1036 xmlBufferPtr xml_buf;
1041 return E_INVALIDARG;
1045 xml_buf = xmlBufferCreate();
1047 return E_OUTOFMEMORY;
1049 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
1051 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
1053 const xmlChar *buf_content;
1056 /* Attribute Nodes return a space in front of their name */
1057 buf_content = xmlBufferContent(xml_buf);
1059 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
1061 content = EnsureCorrectEOL(content);
1062 if(ensure_no_encoding)
1063 content = EnsureNoEncoding(content);
1067 *ret = SysAllocStringLen(NULL, 0);
1070 xmlBufferFree(xml_buf);
1071 xmldoc_link_xmldecl( This->node->doc, xmldecl );
1072 return *ret ? S_OK : E_OUTOFMEMORY;
1075 HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p)
1077 #ifdef SONAME_LIBXSLT
1078 xsltStylesheetPtr xsltSS;
1081 if (!libxslt_handle) return E_NOTIMPL;
1082 if (!stylesheet || !p) return E_INVALIDARG;
1086 sheet = get_node_obj(stylesheet);
1087 if(!sheet) return E_FAIL;
1089 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
1092 xmlDocPtr result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1095 const xmlChar *content;
1097 if(result->type == XML_HTML_DOCUMENT_NODE)
1099 xmlOutputBufferPtr output = xmlAllocOutputBuffer(NULL);
1102 htmlDocContentDumpOutput(output, result->doc, NULL);
1103 content = xmlBufferContent(output->buffer);
1104 *p = bstr_from_xmlChar(content);
1105 xmlOutputBufferClose(output);
1110 xmlBufferPtr buf = xmlBufferCreate();
1113 int size = xmlNodeDump(buf, NULL, (xmlNodePtr)result, 0, 0);
1116 content = xmlBufferContent(buf);
1117 *p = bstr_from_xmlChar(content);
1124 /* libxslt "helpfully" frees the XML document the stylesheet was
1125 generated from, too */
1127 pxsltFreeStylesheet(xsltSS);
1130 if(!*p) *p = SysAllocStringLen(NULL, 0);
1134 FIXME("libxslt headers were not found at compile time\n");
1139 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1144 if (!query || !nodes) return E_INVALIDARG;
1146 str = xmlchar_from_wchar(query);
1147 hr = create_selection(This->node, str, nodes);
1153 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1155 IXMLDOMNodeList *list;
1158 hr = node_select_nodes(This, query, &list);
1161 hr = IXMLDOMNodeList_nextNode(list, node);
1162 IXMLDOMNodeList_Release(list);
1167 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1169 xmlNsPtr ns = This->node->ns;
1172 return E_INVALIDARG;
1174 *namespaceURI = NULL;
1177 *namespaceURI = bstr_from_xmlChar(ns->href);
1179 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1181 return *namespaceURI ? S_OK : S_FALSE;
1184 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1186 xmlNsPtr ns = This->node->ns;
1188 if (!prefix) return E_INVALIDARG;
1192 if (ns && ns->prefix)
1193 *prefix = bstr_from_xmlChar(ns->prefix);
1195 TRACE("prefix: %s\n", debugstr_w(*prefix));
1197 return *prefix ? S_OK : S_FALSE;
1200 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1202 if (!name) return E_INVALIDARG;
1204 *name = bstr_from_xmlChar(This->node->name);
1205 if (!*name) return E_OUTOFMEMORY;
1207 TRACE("returning %s\n", debugstr_w(*name));
1212 void destroy_xmlnode(xmlnode *This)
1215 xmldoc_release(This->node->doc);
1216 release_dispex(&This->dispex);
1219 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1222 xmldoc_add_ref( node->doc );
1225 This->iface = node_iface;
1226 This->parent = NULL;
1228 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1233 IXMLDOMNode IXMLDOMNode_iface;
1237 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1239 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1242 static HRESULT WINAPI unknode_QueryInterface(
1247 unknode *This = unknode_from_IXMLDOMNode( iface );
1249 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1251 if (IsEqualGUID(riid, &IID_IUnknown)) {
1253 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1254 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1255 *ppvObject = &This->IXMLDOMNode_iface;
1256 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1257 return *ppvObject ? S_OK : E_NOINTERFACE;
1259 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1261 return E_NOINTERFACE;
1264 IUnknown_AddRef((IUnknown*)*ppvObject);
1268 static ULONG WINAPI unknode_AddRef(
1269 IXMLDOMNode *iface )
1271 unknode *This = unknode_from_IXMLDOMNode( iface );
1273 return InterlockedIncrement(&This->ref);
1276 static ULONG WINAPI unknode_Release(
1277 IXMLDOMNode *iface )
1279 unknode *This = unknode_from_IXMLDOMNode( iface );
1282 ref = InterlockedDecrement( &This->ref );
1284 destroy_xmlnode(&This->node);
1291 static HRESULT WINAPI unknode_GetTypeInfoCount(
1295 unknode *This = unknode_from_IXMLDOMNode( iface );
1297 TRACE("(%p)->(%p)\n", This, pctinfo);
1304 static HRESULT WINAPI unknode_GetTypeInfo(
1308 ITypeInfo** ppTInfo )
1310 unknode *This = unknode_from_IXMLDOMNode( iface );
1313 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1315 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1320 static HRESULT WINAPI unknode_GetIDsOfNames(
1323 LPOLESTR* rgszNames,
1328 unknode *This = unknode_from_IXMLDOMNode( iface );
1330 ITypeInfo *typeinfo;
1333 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1336 if(!rgszNames || cNames == 0 || !rgDispId)
1337 return E_INVALIDARG;
1339 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1342 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1343 ITypeInfo_Release(typeinfo);
1349 static HRESULT WINAPI unknode_Invoke(
1351 DISPID dispIdMember,
1355 DISPPARAMS* pDispParams,
1356 VARIANT* pVarResult,
1357 EXCEPINFO* pExcepInfo,
1360 unknode *This = unknode_from_IXMLDOMNode( iface );
1361 ITypeInfo *typeinfo;
1364 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1365 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1367 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1370 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1371 pVarResult, pExcepInfo, puArgErr);
1372 ITypeInfo_Release(typeinfo);
1378 static HRESULT WINAPI unknode_get_nodeName(
1382 unknode *This = unknode_from_IXMLDOMNode( iface );
1384 FIXME("(%p)->(%p)\n", This, p);
1386 return node_get_nodeName(&This->node, p);
1389 static HRESULT WINAPI unknode_get_nodeValue(
1393 unknode *This = unknode_from_IXMLDOMNode( iface );
1395 FIXME("(%p)->(%p)\n", This, value);
1398 return E_INVALIDARG;
1400 V_VT(value) = VT_NULL;
1404 static HRESULT WINAPI unknode_put_nodeValue(
1408 unknode *This = unknode_from_IXMLDOMNode( iface );
1409 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1413 static HRESULT WINAPI unknode_get_nodeType(
1415 DOMNodeType* domNodeType )
1417 unknode *This = unknode_from_IXMLDOMNode( iface );
1419 FIXME("(%p)->(%p)\n", This, domNodeType);
1421 *domNodeType = This->node.node->type;
1425 static HRESULT WINAPI unknode_get_parentNode(
1427 IXMLDOMNode** parent )
1429 unknode *This = unknode_from_IXMLDOMNode( iface );
1430 FIXME("(%p)->(%p)\n", This, parent);
1431 if (!parent) return E_INVALIDARG;
1436 static HRESULT WINAPI unknode_get_childNodes(
1438 IXMLDOMNodeList** outList)
1440 unknode *This = unknode_from_IXMLDOMNode( iface );
1442 TRACE("(%p)->(%p)\n", This, outList);
1444 return node_get_child_nodes(&This->node, outList);
1447 static HRESULT WINAPI unknode_get_firstChild(
1449 IXMLDOMNode** domNode)
1451 unknode *This = unknode_from_IXMLDOMNode( iface );
1453 TRACE("(%p)->(%p)\n", This, domNode);
1455 return node_get_first_child(&This->node, domNode);
1458 static HRESULT WINAPI unknode_get_lastChild(
1460 IXMLDOMNode** domNode)
1462 unknode *This = unknode_from_IXMLDOMNode( iface );
1464 TRACE("(%p)->(%p)\n", This, domNode);
1466 return node_get_last_child(&This->node, domNode);
1469 static HRESULT WINAPI unknode_get_previousSibling(
1471 IXMLDOMNode** domNode)
1473 unknode *This = unknode_from_IXMLDOMNode( iface );
1475 TRACE("(%p)->(%p)\n", This, domNode);
1477 return node_get_previous_sibling(&This->node, domNode);
1480 static HRESULT WINAPI unknode_get_nextSibling(
1482 IXMLDOMNode** domNode)
1484 unknode *This = unknode_from_IXMLDOMNode( iface );
1486 TRACE("(%p)->(%p)\n", This, domNode);
1488 return node_get_next_sibling(&This->node, domNode);
1491 static HRESULT WINAPI unknode_get_attributes(
1493 IXMLDOMNamedNodeMap** attributeMap)
1495 unknode *This = unknode_from_IXMLDOMNode( iface );
1497 FIXME("(%p)->(%p)\n", This, attributeMap);
1499 return return_null_ptr((void**)attributeMap);
1502 static HRESULT WINAPI unknode_insertBefore(
1504 IXMLDOMNode* newNode, VARIANT refChild,
1505 IXMLDOMNode** outOldNode)
1507 unknode *This = unknode_from_IXMLDOMNode( iface );
1509 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1511 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1514 static HRESULT WINAPI unknode_replaceChild(
1516 IXMLDOMNode* newNode,
1517 IXMLDOMNode* oldNode,
1518 IXMLDOMNode** outOldNode)
1520 unknode *This = unknode_from_IXMLDOMNode( iface );
1522 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1524 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1527 static HRESULT WINAPI unknode_removeChild(
1529 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1531 unknode *This = unknode_from_IXMLDOMNode( iface );
1532 return node_remove_child(&This->node, domNode, oldNode);
1535 static HRESULT WINAPI unknode_appendChild(
1537 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1539 unknode *This = unknode_from_IXMLDOMNode( iface );
1540 return node_append_child(&This->node, newNode, outNewNode);
1543 static HRESULT WINAPI unknode_hasChildNodes(
1545 VARIANT_BOOL* pbool)
1547 unknode *This = unknode_from_IXMLDOMNode( iface );
1548 return node_has_childnodes(&This->node, pbool);
1551 static HRESULT WINAPI unknode_get_ownerDocument(
1553 IXMLDOMDocument** domDocument)
1555 unknode *This = unknode_from_IXMLDOMNode( iface );
1556 return node_get_owner_doc(&This->node, domDocument);
1559 static HRESULT WINAPI unknode_cloneNode(
1561 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1563 unknode *This = unknode_from_IXMLDOMNode( iface );
1564 return node_clone(&This->node, pbool, outNode );
1567 static HRESULT WINAPI unknode_get_nodeTypeString(
1571 unknode *This = unknode_from_IXMLDOMNode( iface );
1573 FIXME("(%p)->(%p)\n", This, p);
1575 return node_get_nodeName(&This->node, p);
1578 static HRESULT WINAPI unknode_get_text(
1582 unknode *This = unknode_from_IXMLDOMNode( iface );
1583 return node_get_text(&This->node, p);
1586 static HRESULT WINAPI unknode_put_text(
1590 unknode *This = unknode_from_IXMLDOMNode( iface );
1591 return node_put_text(&This->node, p);
1594 static HRESULT WINAPI unknode_get_specified(
1596 VARIANT_BOOL* isSpecified)
1598 unknode *This = unknode_from_IXMLDOMNode( iface );
1599 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1600 *isSpecified = VARIANT_TRUE;
1604 static HRESULT WINAPI unknode_get_definition(
1606 IXMLDOMNode** definitionNode)
1608 unknode *This = unknode_from_IXMLDOMNode( iface );
1609 FIXME("(%p)->(%p)\n", This, definitionNode);
1613 static HRESULT WINAPI unknode_get_nodeTypedValue(
1617 unknode *This = unknode_from_IXMLDOMNode( iface );
1618 FIXME("(%p)->(%p)\n", This, var1);
1619 return return_null_var(var1);
1622 static HRESULT WINAPI unknode_put_nodeTypedValue(
1626 unknode *This = unknode_from_IXMLDOMNode( iface );
1627 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1631 static HRESULT WINAPI unknode_get_dataType(
1635 unknode *This = unknode_from_IXMLDOMNode( iface );
1636 TRACE("(%p)->(%p)\n", This, var1);
1637 return return_null_var(var1);
1640 static HRESULT WINAPI unknode_put_dataType(
1644 unknode *This = unknode_from_IXMLDOMNode( iface );
1646 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1649 return E_INVALIDARG;
1654 static HRESULT WINAPI unknode_get_xml(
1658 unknode *This = unknode_from_IXMLDOMNode( iface );
1660 FIXME("(%p)->(%p)\n", This, p);
1662 return node_get_xml(&This->node, FALSE, FALSE, p);
1665 static HRESULT WINAPI unknode_transformNode(
1667 IXMLDOMNode* domNode, BSTR* p)
1669 unknode *This = unknode_from_IXMLDOMNode( iface );
1670 return node_transform_node(&This->node, domNode, p);
1673 static HRESULT WINAPI unknode_selectNodes(
1675 BSTR p, IXMLDOMNodeList** outList)
1677 unknode *This = unknode_from_IXMLDOMNode( iface );
1678 return node_select_nodes(&This->node, p, outList);
1681 static HRESULT WINAPI unknode_selectSingleNode(
1683 BSTR p, IXMLDOMNode** outNode)
1685 unknode *This = unknode_from_IXMLDOMNode( iface );
1686 return node_select_singlenode(&This->node, p, outNode);
1689 static HRESULT WINAPI unknode_get_parsed(
1691 VARIANT_BOOL* isParsed)
1693 unknode *This = unknode_from_IXMLDOMNode( iface );
1694 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1695 *isParsed = VARIANT_TRUE;
1699 static HRESULT WINAPI unknode_get_namespaceURI(
1703 unknode *This = unknode_from_IXMLDOMNode( iface );
1704 TRACE("(%p)->(%p)\n", This, p);
1705 return node_get_namespaceURI(&This->node, p);
1708 static HRESULT WINAPI unknode_get_prefix(
1712 unknode *This = unknode_from_IXMLDOMNode( iface );
1713 return node_get_prefix(&This->node, p);
1716 static HRESULT WINAPI unknode_get_baseName(
1720 unknode *This = unknode_from_IXMLDOMNode( iface );
1721 return node_get_base_name(&This->node, p);
1724 static HRESULT WINAPI unknode_transformNodeToObject(
1726 IXMLDOMNode* domNode, VARIANT var1)
1728 unknode *This = unknode_from_IXMLDOMNode( iface );
1729 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1733 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1735 unknode_QueryInterface,
1738 unknode_GetTypeInfoCount,
1739 unknode_GetTypeInfo,
1740 unknode_GetIDsOfNames,
1742 unknode_get_nodeName,
1743 unknode_get_nodeValue,
1744 unknode_put_nodeValue,
1745 unknode_get_nodeType,
1746 unknode_get_parentNode,
1747 unknode_get_childNodes,
1748 unknode_get_firstChild,
1749 unknode_get_lastChild,
1750 unknode_get_previousSibling,
1751 unknode_get_nextSibling,
1752 unknode_get_attributes,
1753 unknode_insertBefore,
1754 unknode_replaceChild,
1755 unknode_removeChild,
1756 unknode_appendChild,
1757 unknode_hasChildNodes,
1758 unknode_get_ownerDocument,
1760 unknode_get_nodeTypeString,
1763 unknode_get_specified,
1764 unknode_get_definition,
1765 unknode_get_nodeTypedValue,
1766 unknode_put_nodeTypedValue,
1767 unknode_get_dataType,
1768 unknode_put_dataType,
1770 unknode_transformNode,
1771 unknode_selectNodes,
1772 unknode_selectSingleNode,
1774 unknode_get_namespaceURI,
1776 unknode_get_baseName,
1777 unknode_transformNodeToObject
1780 IXMLDOMNode *create_node( xmlNodePtr node )
1789 TRACE("type %d\n", node->type);
1792 case XML_ELEMENT_NODE:
1793 pUnk = create_element( node );
1795 case XML_ATTRIBUTE_NODE:
1796 pUnk = create_attribute( node );
1799 pUnk = create_text( node );
1801 case XML_CDATA_SECTION_NODE:
1802 pUnk = create_cdata( node );
1804 case XML_ENTITY_REF_NODE:
1805 pUnk = create_doc_entity_ref( node );
1808 pUnk = create_pi( node );
1810 case XML_COMMENT_NODE:
1811 pUnk = create_comment( node );
1813 case XML_DOCUMENT_NODE:
1814 pUnk = create_domdoc( node );
1816 case XML_DOCUMENT_FRAG_NODE:
1817 pUnk = create_doc_fragment( node );
1820 pUnk = create_doc_type( node );
1825 FIXME("only creating basic node for type %d\n", node->type);
1827 new_node = heap_alloc(sizeof(unknode));
1831 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1833 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1834 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1838 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1839 IUnknown_Release(pUnk);
1840 if(FAILED(hr)) return NULL;