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 if(This->dispex.outer)
117 return dispex_query_interface(&This->dispex, riid, ppv);
122 xmlnode *get_node_obj(IXMLDOMNode *node)
127 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
128 if (!obj) WARN("node is not our IXMLDOMNode implementation\n");
129 return SUCCEEDED(hres) ? obj : NULL;
132 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
137 *name = bstr_from_xmlChar(This->node->name);
144 HRESULT node_get_content(xmlnode *This, VARIANT *value)
151 content = xmlNodeGetContent(This->node);
152 V_VT(value) = VT_BSTR;
153 V_BSTR(value) = bstr_from_xmlChar( content );
156 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
160 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
164 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
165 str = xmlChar_from_wchar(value);
167 return E_OUTOFMEMORY;
169 xmlNodeSetContent(This->node, str);
174 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
176 xmlChar *str, *escaped;
178 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
179 str = xmlChar_from_wchar(value);
181 return E_OUTOFMEMORY;
183 escaped = xmlEncodeSpecialChars(NULL, str);
187 return E_OUTOFMEMORY;
190 xmlNodeSetContent(This->node, escaped);
198 HRESULT node_put_value(xmlnode *This, VARIANT *value)
200 VARIANT string_value;
203 VariantInit(&string_value);
204 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
206 WARN("Couldn't convert to VT_BSTR\n");
210 hr = node_set_content(This, V_BSTR(&string_value));
211 VariantClear(&string_value);
216 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
218 VARIANT string_value;
221 VariantInit(&string_value);
222 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
224 WARN("Couldn't convert to VT_BSTR\n");
228 hr = node_set_content_escaped(This, V_BSTR(&string_value));
229 VariantClear(&string_value);
234 static HRESULT get_node(
240 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
245 /* if we don't have a doc, use our parent. */
246 if(node && !node->doc && node->parent)
247 node->doc = node->parent->doc;
249 *out = create_node( node );
255 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
257 return get_node( This, "parent", This->node->parent, parent );
260 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
265 *ret = create_children_nodelist(This->node);
267 return E_OUTOFMEMORY;
272 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
274 return get_node(This, "firstChild", This->node->children, ret);
277 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
279 return get_node(This, "lastChild", This->node->last, ret);
282 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
284 return get_node(This, "previous", This->node->prev, ret);
287 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
289 return get_node(This, "next", This->node->next, ret);
292 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
295 xmlNodePtr new_child_node;
296 IXMLDOMNode *before = NULL;
304 node_obj = get_node_obj(new_child);
305 if(!node_obj) return E_FAIL;
307 switch(V_VT(ref_child))
315 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
316 if(FAILED(hr)) return hr;
320 FIXME("refChild var type %x\n", V_VT(ref_child));
324 new_child_node = node_obj->node;
325 TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
327 if(!new_child_node->parent)
328 if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
329 WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
333 xmlnode *before_node_obj = get_node_obj(before);
334 IXMLDOMNode_Release(before);
335 if(!before_node_obj) return E_FAIL;
337 /* unlink from current parent first */
339 IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
340 doc = new_child_node->doc;
341 xmldoc_add_ref(before_node_obj->node->doc);
342 xmlAddPrevSibling(before_node_obj->node, new_child_node);
344 node_obj->parent = This->parent;
348 /* unlink from current parent first */
350 IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
351 doc = new_child_node->doc;
352 xmldoc_add_ref(This->node->doc);
353 xmlAddChild(This->node, new_child_node);
355 node_obj->parent = This->iface;
360 IXMLDOMNode_AddRef(new_child);
368 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
371 xmlnode *old_child, *new_child;
372 xmlDocPtr leaving_doc;
373 xmlNode *my_ancestor;
375 /* Do not believe any documentation telling that newChild == NULL
376 means removal. It does certainly *not* apply to msxml3! */
377 if(!newChild || !oldChild)
383 old_child = get_node_obj(oldChild);
384 if(!old_child) return E_FAIL;
386 if(old_child->node->parent != This->node)
388 WARN("childNode %p is not a child of %p\n", oldChild, This);
392 new_child = get_node_obj(newChild);
393 if(!new_child) return E_FAIL;
395 my_ancestor = This->node;
398 if(my_ancestor == new_child->node)
400 WARN("tried to create loop\n");
403 my_ancestor = my_ancestor->parent;
406 if(!new_child->node->parent)
407 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
408 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
410 leaving_doc = new_child->node->doc;
411 xmldoc_add_ref(old_child->node->doc);
412 xmlReplaceNode(old_child->node, new_child->node);
413 xmldoc_release(leaving_doc);
414 new_child->parent = old_child->parent;
415 old_child->parent = NULL;
417 xmldoc_add_orphan(old_child->node->doc, old_child->node);
421 IXMLDOMNode_AddRef(oldChild);
428 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
432 if(!child) return E_INVALIDARG;
437 child_node = get_node_obj(child);
438 if(!child_node) return E_FAIL;
440 if(child_node->node->parent != This->node)
442 WARN("childNode %p is not a child of %p\n", child, This);
446 xmlUnlinkNode(child_node->node);
447 child_node->parent = NULL;
451 IXMLDOMNode_AddRef(child);
458 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
464 hr = IXMLDOMNode_get_nodeType(child, &type);
465 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
466 if (outChild) *outChild = NULL;
471 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
474 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
476 if (!ret) return E_INVALIDARG;
478 if (!This->node->children)
480 *ret = VARIANT_FALSE;
488 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
490 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
493 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
498 if(!cloneNode) return E_INVALIDARG;
500 clone = xmlCopyNode(This->node, deep ? 1 : 2);
503 clone->doc = This->node->doc;
504 xmldoc_add_orphan(clone->doc, clone);
506 node = create_node(clone);
509 ERR("Copy failed\n");
517 ERR("Copy failed\n");
524 static inline xmlChar* trim_whitespace(xmlChar* str)
532 while (*ret && isspace(*ret))
534 len = xmlStrlen(ret);
536 while (isspace(ret[len-1])) --len;
538 ret = xmlStrndup(ret, len);
543 static xmlChar* do_get_text(xmlNodePtr node)
547 BOOL preserving = is_preserving_whitespace(node);
551 str = xmlNodeGetContent(node);
555 xmlElementType prev_type = XML_TEXT_NODE;
557 str = xmlStrdup(BAD_CAST "");
558 for (child = node->children; child != NULL; child = child->next)
562 case XML_ELEMENT_NODE:
563 tmp = do_get_text(child);
566 case XML_CDATA_SECTION_NODE:
567 case XML_ENTITY_REF_NODE:
568 case XML_ENTITY_NODE:
569 tmp = xmlNodeGetContent(child);
580 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
581 str = xmlStrcat(str, BAD_CAST " ");
582 str = xmlStrcat(str, tmp);
583 prev_type = child->type;
592 case XML_ELEMENT_NODE:
594 case XML_ENTITY_REF_NODE:
595 case XML_ENTITY_NODE:
596 case XML_DOCUMENT_NODE:
597 case XML_DOCUMENT_FRAG_NODE:
599 str = trim_whitespace(str);
608 HRESULT node_get_text(const xmlnode *This, BSTR *text)
613 if (!text) return E_INVALIDARG;
615 content = do_get_text(This->node);
618 str = bstr_from_xmlChar(content);
622 /* Always return a string. */
623 if (!str) str = SysAllocStringLen( NULL, 0 );
625 TRACE("%p %s\n", This, debugstr_w(str) );
631 HRESULT node_put_text(xmlnode *This, BSTR text)
635 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
637 str = xmlChar_from_wchar(text);
639 /* Escape the string. */
640 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
643 xmlNodeSetContent(This->node, str2);
649 static inline BYTE hex_to_byte(xmlChar c)
651 if(c <= '9') return c-'0';
652 if(c <= 'F') return c-'A'+10;
656 static inline BYTE base64_to_byte(xmlChar c)
658 if(c == '+') return 62;
659 if(c == '/') return 63;
660 if(c <= '9') return c-'0'+52;
661 if(c <= 'Z') return c-'A';
665 /* TODO: phasing this version out */
666 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
668 if(!type || !lstrcmpiW(type, szString) ||
669 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
672 V_BSTR(v) = bstr_from_xmlChar(str);
675 return E_OUTOFMEMORY;
677 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
678 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
679 !lstrcmpiW(type, szTimeTZ))
689 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
691 V_VT(&src) = VT_BSTR;
692 V_BSTR(&src) = bstr_from_xmlChar(str);
695 return E_OUTOFMEMORY;
698 e = p + SysStringLen(V_BSTR(&src));
700 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
703 st.wMonth = atoiW(p+5);
704 st.wDay = atoiW(p+8);
710 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
713 st.wMinute = atoiW(p+3);
714 st.wSecond = atoiW(p+6);
720 while(isdigitW(*p)) p++;
724 SystemTimeToVariantTime(&st, &date);
728 if(*p == '+') /* parse timezone offset (+hh:mm) */
729 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
730 else if(*p == '-') /* parse timezone offset (-hh:mm) */
731 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
735 else if(!lstrcmpiW(type, szBinHex))
740 len = xmlStrlen(str)/2;
744 V_VT(v) = (VT_ARRAY|VT_UI1);
745 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
748 return E_OUTOFMEMORY;
751 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
752 + hex_to_byte(str[2*i+1]);
754 else if(!lstrcmpiW(type, szBinBase64))
759 len = xmlStrlen(str);
760 if(str[len-2] == '=') i = 2;
761 else if(str[len-1] == '=') i = 1;
765 sab.cElements = len/4*3-i;
767 V_VT(v) = (VT_ARRAY|VT_UI1);
768 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
771 return E_OUTOFMEMORY;
773 for(i=0; i<len/4; i++)
775 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
776 + (base64_to_byte(str[4*i+1])>>4);
777 if(3*i+1 < sab.cElements)
778 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
779 + (base64_to_byte(str[4*i+2])>>2);
780 if(3*i+2 < sab.cElements)
781 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
782 + base64_to_byte(str[4*i+3]);
790 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
792 else if(!lstrcmpiW(type, szFixed))
794 else if(!lstrcmpiW(type, szBoolean))
796 else if(!lstrcmpiW(type, szI1))
798 else if(!lstrcmpiW(type, szI2))
800 else if(!lstrcmpiW(type, szIU1))
802 else if(!lstrcmpiW(type, szIU2))
804 else if(!lstrcmpiW(type, szIU4))
806 else if(!lstrcmpiW(type, szR4))
808 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
812 FIXME("Type handling not yet implemented\n");
816 V_VT(&src) = VT_BSTR;
817 V_BSTR(&src) = bstr_from_xmlChar(str);
820 return E_OUTOFMEMORY;
822 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
823 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
831 BSTR EnsureCorrectEOL(BSTR sInput)
838 nLen = SysStringLen(sInput);
839 /* Count line endings */
840 for(i=0; i < nLen; i++)
842 if(sInput[i] == '\n')
846 TRACE("len=%d, num=%d\n", nLen, nNum);
848 /* Add linefeed as needed */
852 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
853 for(i=0; i < nLen; i++)
855 if(sInput[i] == '\n')
857 sNew[i+nPlace] = '\r';
860 sNew[i+nPlace] = sInput[i];
863 SysFreeString(sInput);
870 TRACE("len %d\n", SysStringLen(sNew));
875 /* Removes encoding information and last character (nullbyte) */
876 static BSTR EnsureNoEncoding(BSTR sInput)
878 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
883 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
888 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
893 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
894 while(*pEnd != '\"') pEnd++;
897 sNew = SysAllocStringLen(NULL,
898 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
899 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
900 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
902 SysFreeString(sInput);
907 * We are trying to replicate the same behaviour as msxml by converting
908 * line endings to \r\n and using indents as \t. The problem is that msxml
909 * only formats nodes that have a line ending. Using libxml we cannot
910 * reproduce behaviour exactly.
913 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
915 xmlBufferPtr xml_buf;
924 xml_buf = xmlBufferCreate();
926 return E_OUTOFMEMORY;
928 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
930 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
932 const xmlChar *buf_content;
935 /* Attribute Nodes return a space in front of their name */
936 buf_content = xmlBufferContent(xml_buf);
938 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
940 content = EnsureCorrectEOL(content);
941 if(ensure_no_encoding)
942 content = EnsureNoEncoding(content);
946 *ret = SysAllocStringLen(NULL, 0);
949 xmlBufferFree(xml_buf);
950 xmldoc_link_xmldecl( This->node->doc, xmldecl );
951 return *ret ? S_OK : E_OUTOFMEMORY;
954 HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p)
956 #ifdef SONAME_LIBXSLT
957 xsltStylesheetPtr xsltSS;
960 if (!libxslt_handle) return E_NOTIMPL;
961 if (!stylesheet || !p) return E_INVALIDARG;
965 sheet = get_node_obj(stylesheet);
966 if(!sheet) return E_FAIL;
968 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
971 xmlDocPtr result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
974 const xmlChar *content;
976 if(result->type == XML_HTML_DOCUMENT_NODE)
978 xmlOutputBufferPtr output = xmlAllocOutputBuffer(NULL);
981 htmlDocContentDumpOutput(output, result->doc, NULL);
982 content = xmlBufferContent(output->buffer);
983 *p = bstr_from_xmlChar(content);
984 xmlOutputBufferClose(output);
989 xmlBufferPtr buf = xmlBufferCreate();
992 int size = xmlNodeDump(buf, NULL, (xmlNodePtr)result, 0, 0);
995 content = xmlBufferContent(buf);
996 *p = bstr_from_xmlChar(content);
1003 /* libxslt "helpfully" frees the XML document the stylesheet was
1004 generated from, too */
1006 pxsltFreeStylesheet(xsltSS);
1009 if(!*p) *p = SysAllocStringLen(NULL, 0);
1013 FIXME("libxslt headers were not found at compile time\n");
1018 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1023 if (!query || !nodes) return E_INVALIDARG;
1025 str = xmlChar_from_wchar(query);
1026 hr = queryresult_create(This->node, str, nodes);
1032 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1034 IXMLDOMNodeList *list;
1037 hr = node_select_nodes(This, query, &list);
1040 hr = IXMLDOMNodeList_nextNode(list, node);
1041 IXMLDOMNodeList_Release(list);
1046 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1051 return E_INVALIDARG;
1053 *namespaceURI = NULL;
1055 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1057 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1061 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1063 return *namespaceURI ? S_OK : S_FALSE;
1066 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1070 if (!prefix) return E_INVALIDARG;
1074 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1076 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1080 TRACE("prefix: %s\n", debugstr_w(*prefix));
1082 return *prefix ? S_OK : S_FALSE;
1085 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1087 if (!name) return E_INVALIDARG;
1089 *name = bstr_from_xmlChar(This->node->name);
1090 if (!*name) return E_OUTOFMEMORY;
1092 TRACE("returning %s\n", debugstr_w(*name));
1097 void destroy_xmlnode(xmlnode *This)
1100 xmldoc_release(This->node->doc);
1103 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1106 xmldoc_add_ref( node->doc );
1109 This->iface = node_iface;
1110 This->parent = NULL;
1113 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1115 This->dispex.outer = NULL;
1120 IXMLDOMNode IXMLDOMNode_iface;
1124 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1126 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1129 static HRESULT WINAPI unknode_QueryInterface(
1134 unknode *This = unknode_from_IXMLDOMNode( iface );
1136 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1138 if (IsEqualGUID(riid, &IID_IUnknown)) {
1140 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1141 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1142 *ppvObject = &This->IXMLDOMNode_iface;
1143 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1144 return *ppvObject ? S_OK : E_NOINTERFACE;
1146 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1148 return E_NOINTERFACE;
1151 IUnknown_AddRef((IUnknown*)*ppvObject);
1155 static ULONG WINAPI unknode_AddRef(
1156 IXMLDOMNode *iface )
1158 unknode *This = unknode_from_IXMLDOMNode( iface );
1160 return InterlockedIncrement(&This->ref);
1163 static ULONG WINAPI unknode_Release(
1164 IXMLDOMNode *iface )
1166 unknode *This = unknode_from_IXMLDOMNode( iface );
1169 ref = InterlockedDecrement( &This->ref );
1171 destroy_xmlnode(&This->node);
1178 static HRESULT WINAPI unknode_GetTypeInfoCount(
1182 unknode *This = unknode_from_IXMLDOMNode( iface );
1184 TRACE("(%p)->(%p)\n", This, pctinfo);
1191 static HRESULT WINAPI unknode_GetTypeInfo(
1195 ITypeInfo** ppTInfo )
1197 unknode *This = unknode_from_IXMLDOMNode( iface );
1200 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1202 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1207 static HRESULT WINAPI unknode_GetIDsOfNames(
1210 LPOLESTR* rgszNames,
1215 unknode *This = unknode_from_IXMLDOMNode( iface );
1217 ITypeInfo *typeinfo;
1220 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1223 if(!rgszNames || cNames == 0 || !rgDispId)
1224 return E_INVALIDARG;
1226 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1229 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1230 ITypeInfo_Release(typeinfo);
1236 static HRESULT WINAPI unknode_Invoke(
1238 DISPID dispIdMember,
1242 DISPPARAMS* pDispParams,
1243 VARIANT* pVarResult,
1244 EXCEPINFO* pExcepInfo,
1247 unknode *This = unknode_from_IXMLDOMNode( iface );
1248 ITypeInfo *typeinfo;
1251 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1252 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1254 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1257 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1258 pVarResult, pExcepInfo, puArgErr);
1259 ITypeInfo_Release(typeinfo);
1265 static HRESULT WINAPI unknode_get_nodeName(
1269 unknode *This = unknode_from_IXMLDOMNode( iface );
1271 FIXME("(%p)->(%p)\n", This, p);
1273 return node_get_nodeName(&This->node, p);
1276 static HRESULT WINAPI unknode_get_nodeValue(
1280 unknode *This = unknode_from_IXMLDOMNode( iface );
1282 FIXME("(%p)->(%p)\n", This, value);
1285 return E_INVALIDARG;
1287 V_VT(value) = VT_NULL;
1291 static HRESULT WINAPI unknode_put_nodeValue(
1295 unknode *This = unknode_from_IXMLDOMNode( iface );
1296 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1300 static HRESULT WINAPI unknode_get_nodeType(
1302 DOMNodeType* domNodeType )
1304 unknode *This = unknode_from_IXMLDOMNode( iface );
1306 FIXME("(%p)->(%p)\n", This, domNodeType);
1308 *domNodeType = This->node.node->type;
1312 static HRESULT WINAPI unknode_get_parentNode(
1314 IXMLDOMNode** parent )
1316 unknode *This = unknode_from_IXMLDOMNode( iface );
1317 FIXME("(%p)->(%p)\n", This, parent);
1318 if (!parent) return E_INVALIDARG;
1323 static HRESULT WINAPI unknode_get_childNodes(
1325 IXMLDOMNodeList** outList)
1327 unknode *This = unknode_from_IXMLDOMNode( iface );
1329 TRACE("(%p)->(%p)\n", This, outList);
1331 return node_get_child_nodes(&This->node, outList);
1334 static HRESULT WINAPI unknode_get_firstChild(
1336 IXMLDOMNode** domNode)
1338 unknode *This = unknode_from_IXMLDOMNode( iface );
1340 TRACE("(%p)->(%p)\n", This, domNode);
1342 return node_get_first_child(&This->node, domNode);
1345 static HRESULT WINAPI unknode_get_lastChild(
1347 IXMLDOMNode** domNode)
1349 unknode *This = unknode_from_IXMLDOMNode( iface );
1351 TRACE("(%p)->(%p)\n", This, domNode);
1353 return node_get_last_child(&This->node, domNode);
1356 static HRESULT WINAPI unknode_get_previousSibling(
1358 IXMLDOMNode** domNode)
1360 unknode *This = unknode_from_IXMLDOMNode( iface );
1362 TRACE("(%p)->(%p)\n", This, domNode);
1364 return node_get_previous_sibling(&This->node, domNode);
1367 static HRESULT WINAPI unknode_get_nextSibling(
1369 IXMLDOMNode** domNode)
1371 unknode *This = unknode_from_IXMLDOMNode( iface );
1373 TRACE("(%p)->(%p)\n", This, domNode);
1375 return node_get_next_sibling(&This->node, domNode);
1378 static HRESULT WINAPI unknode_get_attributes(
1380 IXMLDOMNamedNodeMap** attributeMap)
1382 unknode *This = unknode_from_IXMLDOMNode( iface );
1384 FIXME("(%p)->(%p)\n", This, attributeMap);
1386 return return_null_ptr((void**)attributeMap);
1389 static HRESULT WINAPI unknode_insertBefore(
1391 IXMLDOMNode* newNode, VARIANT refChild,
1392 IXMLDOMNode** outOldNode)
1394 unknode *This = unknode_from_IXMLDOMNode( iface );
1396 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1398 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1401 static HRESULT WINAPI unknode_replaceChild(
1403 IXMLDOMNode* newNode,
1404 IXMLDOMNode* oldNode,
1405 IXMLDOMNode** outOldNode)
1407 unknode *This = unknode_from_IXMLDOMNode( iface );
1409 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1411 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1414 static HRESULT WINAPI unknode_removeChild(
1416 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1418 unknode *This = unknode_from_IXMLDOMNode( iface );
1419 return node_remove_child(&This->node, domNode, oldNode);
1422 static HRESULT WINAPI unknode_appendChild(
1424 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1426 unknode *This = unknode_from_IXMLDOMNode( iface );
1427 return node_append_child(&This->node, newNode, outNewNode);
1430 static HRESULT WINAPI unknode_hasChildNodes(
1432 VARIANT_BOOL* pbool)
1434 unknode *This = unknode_from_IXMLDOMNode( iface );
1435 return node_has_childnodes(&This->node, pbool);
1438 static HRESULT WINAPI unknode_get_ownerDocument(
1440 IXMLDOMDocument** domDocument)
1442 unknode *This = unknode_from_IXMLDOMNode( iface );
1443 return node_get_owner_doc(&This->node, domDocument);
1446 static HRESULT WINAPI unknode_cloneNode(
1448 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1450 unknode *This = unknode_from_IXMLDOMNode( iface );
1451 return node_clone(&This->node, pbool, outNode );
1454 static HRESULT WINAPI unknode_get_nodeTypeString(
1458 unknode *This = unknode_from_IXMLDOMNode( iface );
1460 FIXME("(%p)->(%p)\n", This, p);
1462 return node_get_nodeName(&This->node, p);
1465 static HRESULT WINAPI unknode_get_text(
1469 unknode *This = unknode_from_IXMLDOMNode( iface );
1470 return node_get_text(&This->node, p);
1473 static HRESULT WINAPI unknode_put_text(
1477 unknode *This = unknode_from_IXMLDOMNode( iface );
1478 return node_put_text(&This->node, p);
1481 static HRESULT WINAPI unknode_get_specified(
1483 VARIANT_BOOL* isSpecified)
1485 unknode *This = unknode_from_IXMLDOMNode( iface );
1486 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1487 *isSpecified = VARIANT_TRUE;
1491 static HRESULT WINAPI unknode_get_definition(
1493 IXMLDOMNode** definitionNode)
1495 unknode *This = unknode_from_IXMLDOMNode( iface );
1496 FIXME("(%p)->(%p)\n", This, definitionNode);
1500 static HRESULT WINAPI unknode_get_nodeTypedValue(
1504 unknode *This = unknode_from_IXMLDOMNode( iface );
1505 FIXME("(%p)->(%p)\n", This, var1);
1506 return return_null_var(var1);
1509 static HRESULT WINAPI unknode_put_nodeTypedValue(
1513 unknode *This = unknode_from_IXMLDOMNode( iface );
1514 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1518 static HRESULT WINAPI unknode_get_dataType(
1522 unknode *This = unknode_from_IXMLDOMNode( iface );
1523 TRACE("(%p)->(%p)\n", This, var1);
1524 return return_null_var(var1);
1527 static HRESULT WINAPI unknode_put_dataType(
1531 unknode *This = unknode_from_IXMLDOMNode( iface );
1533 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1536 return E_INVALIDARG;
1541 static HRESULT WINAPI unknode_get_xml(
1545 unknode *This = unknode_from_IXMLDOMNode( iface );
1547 FIXME("(%p)->(%p)\n", This, p);
1549 return node_get_xml(&This->node, FALSE, FALSE, p);
1552 static HRESULT WINAPI unknode_transformNode(
1554 IXMLDOMNode* domNode, BSTR* p)
1556 unknode *This = unknode_from_IXMLDOMNode( iface );
1557 return node_transform_node(&This->node, domNode, p);
1560 static HRESULT WINAPI unknode_selectNodes(
1562 BSTR p, IXMLDOMNodeList** outList)
1564 unknode *This = unknode_from_IXMLDOMNode( iface );
1565 return node_select_nodes(&This->node, p, outList);
1568 static HRESULT WINAPI unknode_selectSingleNode(
1570 BSTR p, IXMLDOMNode** outNode)
1572 unknode *This = unknode_from_IXMLDOMNode( iface );
1573 return node_select_singlenode(&This->node, p, outNode);
1576 static HRESULT WINAPI unknode_get_parsed(
1578 VARIANT_BOOL* isParsed)
1580 unknode *This = unknode_from_IXMLDOMNode( iface );
1581 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1582 *isParsed = VARIANT_TRUE;
1586 static HRESULT WINAPI unknode_get_namespaceURI(
1590 unknode *This = unknode_from_IXMLDOMNode( iface );
1591 TRACE("(%p)->(%p)\n", This, p);
1592 return node_get_namespaceURI(&This->node, p);
1595 static HRESULT WINAPI unknode_get_prefix(
1599 unknode *This = unknode_from_IXMLDOMNode( iface );
1600 return node_get_prefix(&This->node, p);
1603 static HRESULT WINAPI unknode_get_baseName(
1607 unknode *This = unknode_from_IXMLDOMNode( iface );
1608 return node_get_base_name(&This->node, p);
1611 static HRESULT WINAPI unknode_transformNodeToObject(
1613 IXMLDOMNode* domNode, VARIANT var1)
1615 unknode *This = unknode_from_IXMLDOMNode( iface );
1616 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1620 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1622 unknode_QueryInterface,
1625 unknode_GetTypeInfoCount,
1626 unknode_GetTypeInfo,
1627 unknode_GetIDsOfNames,
1629 unknode_get_nodeName,
1630 unknode_get_nodeValue,
1631 unknode_put_nodeValue,
1632 unknode_get_nodeType,
1633 unknode_get_parentNode,
1634 unknode_get_childNodes,
1635 unknode_get_firstChild,
1636 unknode_get_lastChild,
1637 unknode_get_previousSibling,
1638 unknode_get_nextSibling,
1639 unknode_get_attributes,
1640 unknode_insertBefore,
1641 unknode_replaceChild,
1642 unknode_removeChild,
1643 unknode_appendChild,
1644 unknode_hasChildNodes,
1645 unknode_get_ownerDocument,
1647 unknode_get_nodeTypeString,
1650 unknode_get_specified,
1651 unknode_get_definition,
1652 unknode_get_nodeTypedValue,
1653 unknode_put_nodeTypedValue,
1654 unknode_get_dataType,
1655 unknode_put_dataType,
1657 unknode_transformNode,
1658 unknode_selectNodes,
1659 unknode_selectSingleNode,
1661 unknode_get_namespaceURI,
1663 unknode_get_baseName,
1664 unknode_transformNodeToObject
1667 IXMLDOMNode *create_node( xmlNodePtr node )
1676 TRACE("type %d\n", node->type);
1679 case XML_ELEMENT_NODE:
1680 pUnk = create_element( node );
1682 case XML_ATTRIBUTE_NODE:
1683 pUnk = create_attribute( node );
1686 pUnk = create_text( node );
1688 case XML_CDATA_SECTION_NODE:
1689 pUnk = create_cdata( node );
1691 case XML_ENTITY_REF_NODE:
1692 pUnk = create_doc_entity_ref( node );
1695 pUnk = create_pi( node );
1697 case XML_COMMENT_NODE:
1698 pUnk = create_comment( node );
1700 case XML_DOCUMENT_NODE:
1701 pUnk = create_domdoc( node );
1703 case XML_DOCUMENT_FRAG_NODE:
1704 pUnk = create_doc_fragment( node );
1707 pUnk = create_doc_type( node );
1712 FIXME("only creating basic node for type %d\n", node->type);
1714 new_node = heap_alloc(sizeof(unknode));
1718 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1720 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1721 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1725 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1726 IUnknown_Release(pUnk);
1727 if(FAILED(hr)) return NULL;