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 IXMLDOMNode *before = NULL;
303 node_obj = get_node_obj(new_child);
304 if(!node_obj) return E_FAIL;
306 switch(V_VT(ref_child))
314 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
315 if(FAILED(hr)) return hr;
319 FIXME("refChild var type %x\n", V_VT(ref_child));
323 TRACE("new child %p, This->node %p\n", node_obj->node, This->node);
325 if(!node_obj->node->parent)
326 if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK)
327 WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc);
331 xmlnode *before_node_obj = get_node_obj(before);
332 IXMLDOMNode_Release(before);
333 if(!before_node_obj) return E_FAIL;
335 /* unlink from current parent first */
338 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
339 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
341 doc = node_obj->node->doc;
342 xmldoc_add_ref(before_node_obj->node->doc);
343 xmlAddPrevSibling(before_node_obj->node, node_obj->node);
345 node_obj->parent = This->parent;
349 /* unlink from current parent first */
352 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
353 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
355 doc = node_obj->node->doc;
356 xmldoc_add_ref(This->node->doc);
357 /* xmlAddChild doesn't unlink node from previous parent */
358 xmlUnlinkNode(node_obj->node);
359 xmlAddChild(This->node, node_obj->node);
361 node_obj->parent = This->iface;
366 IXMLDOMNode_AddRef(new_child);
374 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
377 xmlnode *old_child, *new_child;
378 xmlDocPtr leaving_doc;
379 xmlNode *my_ancestor;
381 /* Do not believe any documentation telling that newChild == NULL
382 means removal. It does certainly *not* apply to msxml3! */
383 if(!newChild || !oldChild)
389 old_child = get_node_obj(oldChild);
390 if(!old_child) return E_FAIL;
392 if(old_child->node->parent != This->node)
394 WARN("childNode %p is not a child of %p\n", oldChild, This);
398 new_child = get_node_obj(newChild);
399 if(!new_child) return E_FAIL;
401 my_ancestor = This->node;
404 if(my_ancestor == new_child->node)
406 WARN("tried to create loop\n");
409 my_ancestor = my_ancestor->parent;
412 if(!new_child->node->parent)
413 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
414 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
416 leaving_doc = new_child->node->doc;
417 xmldoc_add_ref(old_child->node->doc);
418 xmlReplaceNode(old_child->node, new_child->node);
419 xmldoc_release(leaving_doc);
420 new_child->parent = old_child->parent;
421 old_child->parent = NULL;
423 xmldoc_add_orphan(old_child->node->doc, old_child->node);
427 IXMLDOMNode_AddRef(oldChild);
434 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
438 if(!child) return E_INVALIDARG;
443 child_node = get_node_obj(child);
444 if(!child_node) return E_FAIL;
446 if(child_node->node->parent != This->node)
448 WARN("childNode %p is not a child of %p\n", child, This);
452 xmlUnlinkNode(child_node->node);
453 child_node->parent = NULL;
454 xmldoc_add_orphan(child_node->node->doc, child_node->node);
458 IXMLDOMNode_AddRef(child);
465 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
471 hr = IXMLDOMNode_get_nodeType(child, &type);
472 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
473 if (outChild) *outChild = NULL;
478 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
481 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
483 if (!ret) return E_INVALIDARG;
485 if (!This->node->children)
487 *ret = VARIANT_FALSE;
495 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
497 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
500 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
505 if(!cloneNode) return E_INVALIDARG;
507 clone = xmlCopyNode(This->node, deep ? 1 : 2);
510 clone->doc = This->node->doc;
511 xmldoc_add_orphan(clone->doc, clone);
513 node = create_node(clone);
516 ERR("Copy failed\n");
517 xmldoc_remove_orphan(clone->doc, clone);
526 ERR("Copy failed\n");
533 static inline xmlChar* trim_whitespace(xmlChar* str)
541 while (*ret && isspace(*ret))
543 len = xmlStrlen(ret);
545 while (isspace(ret[len-1])) --len;
547 ret = xmlStrndup(ret, len);
552 static xmlChar* do_get_text(xmlNodePtr node)
556 BOOL preserving = is_preserving_whitespace(node);
560 str = xmlNodeGetContent(node);
564 xmlElementType prev_type = XML_TEXT_NODE;
566 str = xmlStrdup(BAD_CAST "");
567 for (child = node->children; child != NULL; child = child->next)
571 case XML_ELEMENT_NODE:
572 tmp = do_get_text(child);
575 case XML_CDATA_SECTION_NODE:
576 case XML_ENTITY_REF_NODE:
577 case XML_ENTITY_NODE:
578 tmp = xmlNodeGetContent(child);
589 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
590 str = xmlStrcat(str, BAD_CAST " ");
591 str = xmlStrcat(str, tmp);
592 prev_type = child->type;
601 case XML_ELEMENT_NODE:
603 case XML_ENTITY_REF_NODE:
604 case XML_ENTITY_NODE:
605 case XML_DOCUMENT_NODE:
606 case XML_DOCUMENT_FRAG_NODE:
608 str = trim_whitespace(str);
617 HRESULT node_get_text(const xmlnode *This, BSTR *text)
622 if (!text) return E_INVALIDARG;
624 content = do_get_text(This->node);
627 str = bstr_from_xmlChar(content);
631 /* Always return a string. */
632 if (!str) str = SysAllocStringLen( NULL, 0 );
634 TRACE("%p %s\n", This, debugstr_w(str) );
640 HRESULT node_put_text(xmlnode *This, BSTR text)
644 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
646 str = xmlchar_from_wchar(text);
648 /* Escape the string. */
649 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
652 xmlNodeSetContent(This->node, str2);
658 static inline BYTE hex_to_byte(xmlChar c)
660 if(c <= '9') return c-'0';
661 if(c <= 'F') return c-'A'+10;
665 static inline BYTE base64_to_byte(xmlChar c)
667 if(c == '+') return 62;
668 if(c == '/') return 63;
669 if(c <= '9') return c-'0'+52;
670 if(c <= 'Z') return c-'A';
674 /* TODO: phasing this version out */
675 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
677 if(!type || !lstrcmpiW(type, szString) ||
678 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
681 V_BSTR(v) = bstr_from_xmlChar(str);
684 return E_OUTOFMEMORY;
686 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
687 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
688 !lstrcmpiW(type, szTimeTZ))
698 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
700 V_VT(&src) = VT_BSTR;
701 V_BSTR(&src) = bstr_from_xmlChar(str);
704 return E_OUTOFMEMORY;
707 e = p + SysStringLen(V_BSTR(&src));
709 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
712 st.wMonth = atoiW(p+5);
713 st.wDay = atoiW(p+8);
719 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
722 st.wMinute = atoiW(p+3);
723 st.wSecond = atoiW(p+6);
729 while(isdigitW(*p)) p++;
733 SystemTimeToVariantTime(&st, &date);
737 if(*p == '+') /* parse timezone offset (+hh:mm) */
738 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
739 else if(*p == '-') /* parse timezone offset (-hh:mm) */
740 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
744 else if(!lstrcmpiW(type, szBinHex))
749 len = xmlStrlen(str)/2;
753 V_VT(v) = (VT_ARRAY|VT_UI1);
754 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
757 return E_OUTOFMEMORY;
760 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
761 + hex_to_byte(str[2*i+1]);
763 else if(!lstrcmpiW(type, szBinBase64))
768 len = xmlStrlen(str);
769 if(str[len-2] == '=') i = 2;
770 else if(str[len-1] == '=') i = 1;
774 sab.cElements = len/4*3-i;
776 V_VT(v) = (VT_ARRAY|VT_UI1);
777 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
780 return E_OUTOFMEMORY;
782 for(i=0; i<len/4; i++)
784 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
785 + (base64_to_byte(str[4*i+1])>>4);
786 if(3*i+1 < sab.cElements)
787 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
788 + (base64_to_byte(str[4*i+2])>>2);
789 if(3*i+2 < sab.cElements)
790 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
791 + base64_to_byte(str[4*i+3]);
799 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
801 else if(!lstrcmpiW(type, szFixed))
803 else if(!lstrcmpiW(type, szBoolean))
805 else if(!lstrcmpiW(type, szI1))
807 else if(!lstrcmpiW(type, szI2))
809 else if(!lstrcmpiW(type, szIU1))
811 else if(!lstrcmpiW(type, szIU2))
813 else if(!lstrcmpiW(type, szIU4))
815 else if(!lstrcmpiW(type, szR4))
817 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
821 FIXME("Type handling not yet implemented\n");
825 V_VT(&src) = VT_BSTR;
826 V_BSTR(&src) = bstr_from_xmlChar(str);
829 return E_OUTOFMEMORY;
831 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
832 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
840 BSTR EnsureCorrectEOL(BSTR sInput)
847 nLen = SysStringLen(sInput);
848 /* Count line endings */
849 for(i=0; i < nLen; i++)
851 if(sInput[i] == '\n')
855 TRACE("len=%d, num=%d\n", nLen, nNum);
857 /* Add linefeed as needed */
861 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
862 for(i=0; i < nLen; i++)
864 if(sInput[i] == '\n')
866 sNew[i+nPlace] = '\r';
869 sNew[i+nPlace] = sInput[i];
872 SysFreeString(sInput);
879 TRACE("len %d\n", SysStringLen(sNew));
884 /* Removes encoding information and last character (nullbyte) */
885 static BSTR EnsureNoEncoding(BSTR sInput)
887 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
892 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
897 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
902 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
903 while(*pEnd != '\"') pEnd++;
906 sNew = SysAllocStringLen(NULL,
907 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
908 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
909 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
911 SysFreeString(sInput);
916 * We are trying to replicate the same behaviour as msxml by converting
917 * line endings to \r\n and using indents as \t. The problem is that msxml
918 * only formats nodes that have a line ending. Using libxml we cannot
919 * reproduce behaviour exactly.
922 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
924 xmlBufferPtr xml_buf;
933 xml_buf = xmlBufferCreate();
935 return E_OUTOFMEMORY;
937 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
939 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
941 const xmlChar *buf_content;
944 /* Attribute Nodes return a space in front of their name */
945 buf_content = xmlBufferContent(xml_buf);
947 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
949 content = EnsureCorrectEOL(content);
950 if(ensure_no_encoding)
951 content = EnsureNoEncoding(content);
955 *ret = SysAllocStringLen(NULL, 0);
958 xmlBufferFree(xml_buf);
959 xmldoc_link_xmldecl( This->node->doc, xmldecl );
960 return *ret ? S_OK : E_OUTOFMEMORY;
963 HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p)
965 #ifdef SONAME_LIBXSLT
966 xsltStylesheetPtr xsltSS;
969 if (!libxslt_handle) return E_NOTIMPL;
970 if (!stylesheet || !p) return E_INVALIDARG;
974 sheet = get_node_obj(stylesheet);
975 if(!sheet) return E_FAIL;
977 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
980 xmlDocPtr result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
983 const xmlChar *content;
985 if(result->type == XML_HTML_DOCUMENT_NODE)
987 xmlOutputBufferPtr output = xmlAllocOutputBuffer(NULL);
990 htmlDocContentDumpOutput(output, result->doc, NULL);
991 content = xmlBufferContent(output->buffer);
992 *p = bstr_from_xmlChar(content);
993 xmlOutputBufferClose(output);
998 xmlBufferPtr buf = xmlBufferCreate();
1001 int size = xmlNodeDump(buf, NULL, (xmlNodePtr)result, 0, 0);
1004 content = xmlBufferContent(buf);
1005 *p = bstr_from_xmlChar(content);
1012 /* libxslt "helpfully" frees the XML document the stylesheet was
1013 generated from, too */
1015 pxsltFreeStylesheet(xsltSS);
1018 if(!*p) *p = SysAllocStringLen(NULL, 0);
1022 FIXME("libxslt headers were not found at compile time\n");
1027 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1032 if (!query || !nodes) return E_INVALIDARG;
1034 str = xmlchar_from_wchar(query);
1035 hr = create_selection(This->node, str, nodes);
1041 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1043 IXMLDOMNodeList *list;
1046 hr = node_select_nodes(This, query, &list);
1049 hr = IXMLDOMNodeList_nextNode(list, node);
1050 IXMLDOMNodeList_Release(list);
1055 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1060 return E_INVALIDARG;
1062 *namespaceURI = NULL;
1064 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1066 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1070 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1072 return *namespaceURI ? S_OK : S_FALSE;
1075 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1079 if (!prefix) return E_INVALIDARG;
1083 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1085 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1089 TRACE("prefix: %s\n", debugstr_w(*prefix));
1091 return *prefix ? S_OK : S_FALSE;
1094 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1096 if (!name) return E_INVALIDARG;
1098 *name = bstr_from_xmlChar(This->node->name);
1099 if (!*name) return E_OUTOFMEMORY;
1101 TRACE("returning %s\n", debugstr_w(*name));
1106 void destroy_xmlnode(xmlnode *This)
1109 xmldoc_release(This->node->doc);
1112 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1115 xmldoc_add_ref( node->doc );
1118 This->iface = node_iface;
1119 This->parent = NULL;
1122 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1124 This->dispex.outer = NULL;
1129 IXMLDOMNode IXMLDOMNode_iface;
1133 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1135 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1138 static HRESULT WINAPI unknode_QueryInterface(
1143 unknode *This = unknode_from_IXMLDOMNode( iface );
1145 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1147 if (IsEqualGUID(riid, &IID_IUnknown)) {
1149 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1150 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1151 *ppvObject = &This->IXMLDOMNode_iface;
1152 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1153 return *ppvObject ? S_OK : E_NOINTERFACE;
1155 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1157 return E_NOINTERFACE;
1160 IUnknown_AddRef((IUnknown*)*ppvObject);
1164 static ULONG WINAPI unknode_AddRef(
1165 IXMLDOMNode *iface )
1167 unknode *This = unknode_from_IXMLDOMNode( iface );
1169 return InterlockedIncrement(&This->ref);
1172 static ULONG WINAPI unknode_Release(
1173 IXMLDOMNode *iface )
1175 unknode *This = unknode_from_IXMLDOMNode( iface );
1178 ref = InterlockedDecrement( &This->ref );
1180 destroy_xmlnode(&This->node);
1187 static HRESULT WINAPI unknode_GetTypeInfoCount(
1191 unknode *This = unknode_from_IXMLDOMNode( iface );
1193 TRACE("(%p)->(%p)\n", This, pctinfo);
1200 static HRESULT WINAPI unknode_GetTypeInfo(
1204 ITypeInfo** ppTInfo )
1206 unknode *This = unknode_from_IXMLDOMNode( iface );
1209 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1211 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1216 static HRESULT WINAPI unknode_GetIDsOfNames(
1219 LPOLESTR* rgszNames,
1224 unknode *This = unknode_from_IXMLDOMNode( iface );
1226 ITypeInfo *typeinfo;
1229 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1232 if(!rgszNames || cNames == 0 || !rgDispId)
1233 return E_INVALIDARG;
1235 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1238 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1239 ITypeInfo_Release(typeinfo);
1245 static HRESULT WINAPI unknode_Invoke(
1247 DISPID dispIdMember,
1251 DISPPARAMS* pDispParams,
1252 VARIANT* pVarResult,
1253 EXCEPINFO* pExcepInfo,
1256 unknode *This = unknode_from_IXMLDOMNode( iface );
1257 ITypeInfo *typeinfo;
1260 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1261 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1263 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1266 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1267 pVarResult, pExcepInfo, puArgErr);
1268 ITypeInfo_Release(typeinfo);
1274 static HRESULT WINAPI unknode_get_nodeName(
1278 unknode *This = unknode_from_IXMLDOMNode( iface );
1280 FIXME("(%p)->(%p)\n", This, p);
1282 return node_get_nodeName(&This->node, p);
1285 static HRESULT WINAPI unknode_get_nodeValue(
1289 unknode *This = unknode_from_IXMLDOMNode( iface );
1291 FIXME("(%p)->(%p)\n", This, value);
1294 return E_INVALIDARG;
1296 V_VT(value) = VT_NULL;
1300 static HRESULT WINAPI unknode_put_nodeValue(
1304 unknode *This = unknode_from_IXMLDOMNode( iface );
1305 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1309 static HRESULT WINAPI unknode_get_nodeType(
1311 DOMNodeType* domNodeType )
1313 unknode *This = unknode_from_IXMLDOMNode( iface );
1315 FIXME("(%p)->(%p)\n", This, domNodeType);
1317 *domNodeType = This->node.node->type;
1321 static HRESULT WINAPI unknode_get_parentNode(
1323 IXMLDOMNode** parent )
1325 unknode *This = unknode_from_IXMLDOMNode( iface );
1326 FIXME("(%p)->(%p)\n", This, parent);
1327 if (!parent) return E_INVALIDARG;
1332 static HRESULT WINAPI unknode_get_childNodes(
1334 IXMLDOMNodeList** outList)
1336 unknode *This = unknode_from_IXMLDOMNode( iface );
1338 TRACE("(%p)->(%p)\n", This, outList);
1340 return node_get_child_nodes(&This->node, outList);
1343 static HRESULT WINAPI unknode_get_firstChild(
1345 IXMLDOMNode** domNode)
1347 unknode *This = unknode_from_IXMLDOMNode( iface );
1349 TRACE("(%p)->(%p)\n", This, domNode);
1351 return node_get_first_child(&This->node, domNode);
1354 static HRESULT WINAPI unknode_get_lastChild(
1356 IXMLDOMNode** domNode)
1358 unknode *This = unknode_from_IXMLDOMNode( iface );
1360 TRACE("(%p)->(%p)\n", This, domNode);
1362 return node_get_last_child(&This->node, domNode);
1365 static HRESULT WINAPI unknode_get_previousSibling(
1367 IXMLDOMNode** domNode)
1369 unknode *This = unknode_from_IXMLDOMNode( iface );
1371 TRACE("(%p)->(%p)\n", This, domNode);
1373 return node_get_previous_sibling(&This->node, domNode);
1376 static HRESULT WINAPI unknode_get_nextSibling(
1378 IXMLDOMNode** domNode)
1380 unknode *This = unknode_from_IXMLDOMNode( iface );
1382 TRACE("(%p)->(%p)\n", This, domNode);
1384 return node_get_next_sibling(&This->node, domNode);
1387 static HRESULT WINAPI unknode_get_attributes(
1389 IXMLDOMNamedNodeMap** attributeMap)
1391 unknode *This = unknode_from_IXMLDOMNode( iface );
1393 FIXME("(%p)->(%p)\n", This, attributeMap);
1395 return return_null_ptr((void**)attributeMap);
1398 static HRESULT WINAPI unknode_insertBefore(
1400 IXMLDOMNode* newNode, VARIANT refChild,
1401 IXMLDOMNode** outOldNode)
1403 unknode *This = unknode_from_IXMLDOMNode( iface );
1405 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1407 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1410 static HRESULT WINAPI unknode_replaceChild(
1412 IXMLDOMNode* newNode,
1413 IXMLDOMNode* oldNode,
1414 IXMLDOMNode** outOldNode)
1416 unknode *This = unknode_from_IXMLDOMNode( iface );
1418 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1420 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1423 static HRESULT WINAPI unknode_removeChild(
1425 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1427 unknode *This = unknode_from_IXMLDOMNode( iface );
1428 return node_remove_child(&This->node, domNode, oldNode);
1431 static HRESULT WINAPI unknode_appendChild(
1433 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1435 unknode *This = unknode_from_IXMLDOMNode( iface );
1436 return node_append_child(&This->node, newNode, outNewNode);
1439 static HRESULT WINAPI unknode_hasChildNodes(
1441 VARIANT_BOOL* pbool)
1443 unknode *This = unknode_from_IXMLDOMNode( iface );
1444 return node_has_childnodes(&This->node, pbool);
1447 static HRESULT WINAPI unknode_get_ownerDocument(
1449 IXMLDOMDocument** domDocument)
1451 unknode *This = unknode_from_IXMLDOMNode( iface );
1452 return node_get_owner_doc(&This->node, domDocument);
1455 static HRESULT WINAPI unknode_cloneNode(
1457 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1459 unknode *This = unknode_from_IXMLDOMNode( iface );
1460 return node_clone(&This->node, pbool, outNode );
1463 static HRESULT WINAPI unknode_get_nodeTypeString(
1467 unknode *This = unknode_from_IXMLDOMNode( iface );
1469 FIXME("(%p)->(%p)\n", This, p);
1471 return node_get_nodeName(&This->node, p);
1474 static HRESULT WINAPI unknode_get_text(
1478 unknode *This = unknode_from_IXMLDOMNode( iface );
1479 return node_get_text(&This->node, p);
1482 static HRESULT WINAPI unknode_put_text(
1486 unknode *This = unknode_from_IXMLDOMNode( iface );
1487 return node_put_text(&This->node, p);
1490 static HRESULT WINAPI unknode_get_specified(
1492 VARIANT_BOOL* isSpecified)
1494 unknode *This = unknode_from_IXMLDOMNode( iface );
1495 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1496 *isSpecified = VARIANT_TRUE;
1500 static HRESULT WINAPI unknode_get_definition(
1502 IXMLDOMNode** definitionNode)
1504 unknode *This = unknode_from_IXMLDOMNode( iface );
1505 FIXME("(%p)->(%p)\n", This, definitionNode);
1509 static HRESULT WINAPI unknode_get_nodeTypedValue(
1513 unknode *This = unknode_from_IXMLDOMNode( iface );
1514 FIXME("(%p)->(%p)\n", This, var1);
1515 return return_null_var(var1);
1518 static HRESULT WINAPI unknode_put_nodeTypedValue(
1522 unknode *This = unknode_from_IXMLDOMNode( iface );
1523 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1527 static HRESULT WINAPI unknode_get_dataType(
1531 unknode *This = unknode_from_IXMLDOMNode( iface );
1532 TRACE("(%p)->(%p)\n", This, var1);
1533 return return_null_var(var1);
1536 static HRESULT WINAPI unknode_put_dataType(
1540 unknode *This = unknode_from_IXMLDOMNode( iface );
1542 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1545 return E_INVALIDARG;
1550 static HRESULT WINAPI unknode_get_xml(
1554 unknode *This = unknode_from_IXMLDOMNode( iface );
1556 FIXME("(%p)->(%p)\n", This, p);
1558 return node_get_xml(&This->node, FALSE, FALSE, p);
1561 static HRESULT WINAPI unknode_transformNode(
1563 IXMLDOMNode* domNode, BSTR* p)
1565 unknode *This = unknode_from_IXMLDOMNode( iface );
1566 return node_transform_node(&This->node, domNode, p);
1569 static HRESULT WINAPI unknode_selectNodes(
1571 BSTR p, IXMLDOMNodeList** outList)
1573 unknode *This = unknode_from_IXMLDOMNode( iface );
1574 return node_select_nodes(&This->node, p, outList);
1577 static HRESULT WINAPI unknode_selectSingleNode(
1579 BSTR p, IXMLDOMNode** outNode)
1581 unknode *This = unknode_from_IXMLDOMNode( iface );
1582 return node_select_singlenode(&This->node, p, outNode);
1585 static HRESULT WINAPI unknode_get_parsed(
1587 VARIANT_BOOL* isParsed)
1589 unknode *This = unknode_from_IXMLDOMNode( iface );
1590 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1591 *isParsed = VARIANT_TRUE;
1595 static HRESULT WINAPI unknode_get_namespaceURI(
1599 unknode *This = unknode_from_IXMLDOMNode( iface );
1600 TRACE("(%p)->(%p)\n", This, p);
1601 return node_get_namespaceURI(&This->node, p);
1604 static HRESULT WINAPI unknode_get_prefix(
1608 unknode *This = unknode_from_IXMLDOMNode( iface );
1609 return node_get_prefix(&This->node, p);
1612 static HRESULT WINAPI unknode_get_baseName(
1616 unknode *This = unknode_from_IXMLDOMNode( iface );
1617 return node_get_base_name(&This->node, p);
1620 static HRESULT WINAPI unknode_transformNodeToObject(
1622 IXMLDOMNode* domNode, VARIANT var1)
1624 unknode *This = unknode_from_IXMLDOMNode( iface );
1625 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1629 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1631 unknode_QueryInterface,
1634 unknode_GetTypeInfoCount,
1635 unknode_GetTypeInfo,
1636 unknode_GetIDsOfNames,
1638 unknode_get_nodeName,
1639 unknode_get_nodeValue,
1640 unknode_put_nodeValue,
1641 unknode_get_nodeType,
1642 unknode_get_parentNode,
1643 unknode_get_childNodes,
1644 unknode_get_firstChild,
1645 unknode_get_lastChild,
1646 unknode_get_previousSibling,
1647 unknode_get_nextSibling,
1648 unknode_get_attributes,
1649 unknode_insertBefore,
1650 unknode_replaceChild,
1651 unknode_removeChild,
1652 unknode_appendChild,
1653 unknode_hasChildNodes,
1654 unknode_get_ownerDocument,
1656 unknode_get_nodeTypeString,
1659 unknode_get_specified,
1660 unknode_get_definition,
1661 unknode_get_nodeTypedValue,
1662 unknode_put_nodeTypedValue,
1663 unknode_get_dataType,
1664 unknode_put_dataType,
1666 unknode_transformNode,
1667 unknode_selectNodes,
1668 unknode_selectSingleNode,
1670 unknode_get_namespaceURI,
1672 unknode_get_baseName,
1673 unknode_transformNodeToObject
1676 IXMLDOMNode *create_node( xmlNodePtr node )
1685 TRACE("type %d\n", node->type);
1688 case XML_ELEMENT_NODE:
1689 pUnk = create_element( node );
1691 case XML_ATTRIBUTE_NODE:
1692 pUnk = create_attribute( node );
1695 pUnk = create_text( node );
1697 case XML_CDATA_SECTION_NODE:
1698 pUnk = create_cdata( node );
1700 case XML_ENTITY_REF_NODE:
1701 pUnk = create_doc_entity_ref( node );
1704 pUnk = create_pi( node );
1706 case XML_COMMENT_NODE:
1707 pUnk = create_comment( node );
1709 case XML_DOCUMENT_NODE:
1710 pUnk = create_domdoc( node );
1712 case XML_DOCUMENT_FRAG_NODE:
1713 pUnk = create_doc_fragment( node );
1716 pUnk = create_doc_type( node );
1721 FIXME("only creating basic node for type %d\n", node->type);
1723 new_node = heap_alloc(sizeof(unknode));
1727 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1729 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1730 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1734 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1735 IUnknown_Release(pUnk);
1736 if(FAILED(hr)) return NULL;