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(This->node, node_obj->node);
359 node_obj->parent = This->iface;
364 IXMLDOMNode_AddRef(new_child);
372 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
375 xmlnode *old_child, *new_child;
376 xmlDocPtr leaving_doc;
377 xmlNode *my_ancestor;
379 /* Do not believe any documentation telling that newChild == NULL
380 means removal. It does certainly *not* apply to msxml3! */
381 if(!newChild || !oldChild)
387 old_child = get_node_obj(oldChild);
388 if(!old_child) return E_FAIL;
390 if(old_child->node->parent != This->node)
392 WARN("childNode %p is not a child of %p\n", oldChild, This);
396 new_child = get_node_obj(newChild);
397 if(!new_child) return E_FAIL;
399 my_ancestor = This->node;
402 if(my_ancestor == new_child->node)
404 WARN("tried to create loop\n");
407 my_ancestor = my_ancestor->parent;
410 if(!new_child->node->parent)
411 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
412 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
414 leaving_doc = new_child->node->doc;
415 xmldoc_add_ref(old_child->node->doc);
416 xmlReplaceNode(old_child->node, new_child->node);
417 xmldoc_release(leaving_doc);
418 new_child->parent = old_child->parent;
419 old_child->parent = NULL;
421 xmldoc_add_orphan(old_child->node->doc, old_child->node);
425 IXMLDOMNode_AddRef(oldChild);
432 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
436 if(!child) return E_INVALIDARG;
441 child_node = get_node_obj(child);
442 if(!child_node) return E_FAIL;
444 if(child_node->node->parent != This->node)
446 WARN("childNode %p is not a child of %p\n", child, This);
450 xmlUnlinkNode(child_node->node);
451 child_node->parent = NULL;
452 xmldoc_add_orphan(child_node->node->doc, child_node->node);
456 IXMLDOMNode_AddRef(child);
463 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
469 hr = IXMLDOMNode_get_nodeType(child, &type);
470 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
471 if (outChild) *outChild = NULL;
476 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
479 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
481 if (!ret) return E_INVALIDARG;
483 if (!This->node->children)
485 *ret = VARIANT_FALSE;
493 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
495 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
498 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
503 if(!cloneNode) return E_INVALIDARG;
505 clone = xmlCopyNode(This->node, deep ? 1 : 2);
508 clone->doc = This->node->doc;
509 xmldoc_add_orphan(clone->doc, clone);
511 node = create_node(clone);
514 ERR("Copy failed\n");
515 xmldoc_remove_orphan(clone->doc, clone);
524 ERR("Copy failed\n");
531 static inline xmlChar* trim_whitespace(xmlChar* str)
539 while (*ret && isspace(*ret))
541 len = xmlStrlen(ret);
543 while (isspace(ret[len-1])) --len;
545 ret = xmlStrndup(ret, len);
550 static xmlChar* do_get_text(xmlNodePtr node)
554 BOOL preserving = is_preserving_whitespace(node);
558 str = xmlNodeGetContent(node);
562 xmlElementType prev_type = XML_TEXT_NODE;
564 str = xmlStrdup(BAD_CAST "");
565 for (child = node->children; child != NULL; child = child->next)
569 case XML_ELEMENT_NODE:
570 tmp = do_get_text(child);
573 case XML_CDATA_SECTION_NODE:
574 case XML_ENTITY_REF_NODE:
575 case XML_ENTITY_NODE:
576 tmp = xmlNodeGetContent(child);
587 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
588 str = xmlStrcat(str, BAD_CAST " ");
589 str = xmlStrcat(str, tmp);
590 prev_type = child->type;
599 case XML_ELEMENT_NODE:
601 case XML_ENTITY_REF_NODE:
602 case XML_ENTITY_NODE:
603 case XML_DOCUMENT_NODE:
604 case XML_DOCUMENT_FRAG_NODE:
606 str = trim_whitespace(str);
615 HRESULT node_get_text(const xmlnode *This, BSTR *text)
620 if (!text) return E_INVALIDARG;
622 content = do_get_text(This->node);
625 str = bstr_from_xmlChar(content);
629 /* Always return a string. */
630 if (!str) str = SysAllocStringLen( NULL, 0 );
632 TRACE("%p %s\n", This, debugstr_w(str) );
638 HRESULT node_put_text(xmlnode *This, BSTR text)
642 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
644 str = xmlChar_from_wchar(text);
646 /* Escape the string. */
647 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
650 xmlNodeSetContent(This->node, str2);
656 static inline BYTE hex_to_byte(xmlChar c)
658 if(c <= '9') return c-'0';
659 if(c <= 'F') return c-'A'+10;
663 static inline BYTE base64_to_byte(xmlChar c)
665 if(c == '+') return 62;
666 if(c == '/') return 63;
667 if(c <= '9') return c-'0'+52;
668 if(c <= 'Z') return c-'A';
672 /* TODO: phasing this version out */
673 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
675 if(!type || !lstrcmpiW(type, szString) ||
676 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
679 V_BSTR(v) = bstr_from_xmlChar(str);
682 return E_OUTOFMEMORY;
684 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
685 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
686 !lstrcmpiW(type, szTimeTZ))
696 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
698 V_VT(&src) = VT_BSTR;
699 V_BSTR(&src) = bstr_from_xmlChar(str);
702 return E_OUTOFMEMORY;
705 e = p + SysStringLen(V_BSTR(&src));
707 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
710 st.wMonth = atoiW(p+5);
711 st.wDay = atoiW(p+8);
717 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
720 st.wMinute = atoiW(p+3);
721 st.wSecond = atoiW(p+6);
727 while(isdigitW(*p)) p++;
731 SystemTimeToVariantTime(&st, &date);
735 if(*p == '+') /* parse timezone offset (+hh:mm) */
736 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
737 else if(*p == '-') /* parse timezone offset (-hh:mm) */
738 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
742 else if(!lstrcmpiW(type, szBinHex))
747 len = xmlStrlen(str)/2;
751 V_VT(v) = (VT_ARRAY|VT_UI1);
752 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
755 return E_OUTOFMEMORY;
758 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
759 + hex_to_byte(str[2*i+1]);
761 else if(!lstrcmpiW(type, szBinBase64))
766 len = xmlStrlen(str);
767 if(str[len-2] == '=') i = 2;
768 else if(str[len-1] == '=') i = 1;
772 sab.cElements = len/4*3-i;
774 V_VT(v) = (VT_ARRAY|VT_UI1);
775 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
778 return E_OUTOFMEMORY;
780 for(i=0; i<len/4; i++)
782 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
783 + (base64_to_byte(str[4*i+1])>>4);
784 if(3*i+1 < sab.cElements)
785 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
786 + (base64_to_byte(str[4*i+2])>>2);
787 if(3*i+2 < sab.cElements)
788 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
789 + base64_to_byte(str[4*i+3]);
797 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
799 else if(!lstrcmpiW(type, szFixed))
801 else if(!lstrcmpiW(type, szBoolean))
803 else if(!lstrcmpiW(type, szI1))
805 else if(!lstrcmpiW(type, szI2))
807 else if(!lstrcmpiW(type, szIU1))
809 else if(!lstrcmpiW(type, szIU2))
811 else if(!lstrcmpiW(type, szIU4))
813 else if(!lstrcmpiW(type, szR4))
815 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
819 FIXME("Type handling not yet implemented\n");
823 V_VT(&src) = VT_BSTR;
824 V_BSTR(&src) = bstr_from_xmlChar(str);
827 return E_OUTOFMEMORY;
829 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
830 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
838 BSTR EnsureCorrectEOL(BSTR sInput)
845 nLen = SysStringLen(sInput);
846 /* Count line endings */
847 for(i=0; i < nLen; i++)
849 if(sInput[i] == '\n')
853 TRACE("len=%d, num=%d\n", nLen, nNum);
855 /* Add linefeed as needed */
859 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
860 for(i=0; i < nLen; i++)
862 if(sInput[i] == '\n')
864 sNew[i+nPlace] = '\r';
867 sNew[i+nPlace] = sInput[i];
870 SysFreeString(sInput);
877 TRACE("len %d\n", SysStringLen(sNew));
882 /* Removes encoding information and last character (nullbyte) */
883 static BSTR EnsureNoEncoding(BSTR sInput)
885 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
890 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
895 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
900 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
901 while(*pEnd != '\"') pEnd++;
904 sNew = SysAllocStringLen(NULL,
905 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
906 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
907 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
909 SysFreeString(sInput);
914 * We are trying to replicate the same behaviour as msxml by converting
915 * line endings to \r\n and using indents as \t. The problem is that msxml
916 * only formats nodes that have a line ending. Using libxml we cannot
917 * reproduce behaviour exactly.
920 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
922 xmlBufferPtr xml_buf;
931 xml_buf = xmlBufferCreate();
933 return E_OUTOFMEMORY;
935 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
937 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
939 const xmlChar *buf_content;
942 /* Attribute Nodes return a space in front of their name */
943 buf_content = xmlBufferContent(xml_buf);
945 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
947 content = EnsureCorrectEOL(content);
948 if(ensure_no_encoding)
949 content = EnsureNoEncoding(content);
953 *ret = SysAllocStringLen(NULL, 0);
956 xmlBufferFree(xml_buf);
957 xmldoc_link_xmldecl( This->node->doc, xmldecl );
958 return *ret ? S_OK : E_OUTOFMEMORY;
961 HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p)
963 #ifdef SONAME_LIBXSLT
964 xsltStylesheetPtr xsltSS;
967 if (!libxslt_handle) return E_NOTIMPL;
968 if (!stylesheet || !p) return E_INVALIDARG;
972 sheet = get_node_obj(stylesheet);
973 if(!sheet) return E_FAIL;
975 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
978 xmlDocPtr result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
981 const xmlChar *content;
983 if(result->type == XML_HTML_DOCUMENT_NODE)
985 xmlOutputBufferPtr output = xmlAllocOutputBuffer(NULL);
988 htmlDocContentDumpOutput(output, result->doc, NULL);
989 content = xmlBufferContent(output->buffer);
990 *p = bstr_from_xmlChar(content);
991 xmlOutputBufferClose(output);
996 xmlBufferPtr buf = xmlBufferCreate();
999 int size = xmlNodeDump(buf, NULL, (xmlNodePtr)result, 0, 0);
1002 content = xmlBufferContent(buf);
1003 *p = bstr_from_xmlChar(content);
1010 /* libxslt "helpfully" frees the XML document the stylesheet was
1011 generated from, too */
1013 pxsltFreeStylesheet(xsltSS);
1016 if(!*p) *p = SysAllocStringLen(NULL, 0);
1020 FIXME("libxslt headers were not found at compile time\n");
1025 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1030 if (!query || !nodes) return E_INVALIDARG;
1032 str = xmlChar_from_wchar(query);
1033 hr = queryresult_create(This->node, str, nodes);
1039 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1041 IXMLDOMNodeList *list;
1044 hr = node_select_nodes(This, query, &list);
1047 hr = IXMLDOMNodeList_nextNode(list, node);
1048 IXMLDOMNodeList_Release(list);
1053 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1058 return E_INVALIDARG;
1060 *namespaceURI = NULL;
1062 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1064 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1068 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1070 return *namespaceURI ? S_OK : S_FALSE;
1073 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1077 if (!prefix) return E_INVALIDARG;
1081 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1083 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1087 TRACE("prefix: %s\n", debugstr_w(*prefix));
1089 return *prefix ? S_OK : S_FALSE;
1092 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1094 if (!name) return E_INVALIDARG;
1096 *name = bstr_from_xmlChar(This->node->name);
1097 if (!*name) return E_OUTOFMEMORY;
1099 TRACE("returning %s\n", debugstr_w(*name));
1104 void destroy_xmlnode(xmlnode *This)
1107 xmldoc_release(This->node->doc);
1110 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1113 xmldoc_add_ref( node->doc );
1116 This->iface = node_iface;
1117 This->parent = NULL;
1120 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1122 This->dispex.outer = NULL;
1127 IXMLDOMNode IXMLDOMNode_iface;
1131 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1133 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1136 static HRESULT WINAPI unknode_QueryInterface(
1141 unknode *This = unknode_from_IXMLDOMNode( iface );
1143 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1145 if (IsEqualGUID(riid, &IID_IUnknown)) {
1147 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1148 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1149 *ppvObject = &This->IXMLDOMNode_iface;
1150 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1151 return *ppvObject ? S_OK : E_NOINTERFACE;
1153 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1155 return E_NOINTERFACE;
1158 IUnknown_AddRef((IUnknown*)*ppvObject);
1162 static ULONG WINAPI unknode_AddRef(
1163 IXMLDOMNode *iface )
1165 unknode *This = unknode_from_IXMLDOMNode( iface );
1167 return InterlockedIncrement(&This->ref);
1170 static ULONG WINAPI unknode_Release(
1171 IXMLDOMNode *iface )
1173 unknode *This = unknode_from_IXMLDOMNode( iface );
1176 ref = InterlockedDecrement( &This->ref );
1178 destroy_xmlnode(&This->node);
1185 static HRESULT WINAPI unknode_GetTypeInfoCount(
1189 unknode *This = unknode_from_IXMLDOMNode( iface );
1191 TRACE("(%p)->(%p)\n", This, pctinfo);
1198 static HRESULT WINAPI unknode_GetTypeInfo(
1202 ITypeInfo** ppTInfo )
1204 unknode *This = unknode_from_IXMLDOMNode( iface );
1207 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1209 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1214 static HRESULT WINAPI unknode_GetIDsOfNames(
1217 LPOLESTR* rgszNames,
1222 unknode *This = unknode_from_IXMLDOMNode( iface );
1224 ITypeInfo *typeinfo;
1227 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1230 if(!rgszNames || cNames == 0 || !rgDispId)
1231 return E_INVALIDARG;
1233 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1236 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1237 ITypeInfo_Release(typeinfo);
1243 static HRESULT WINAPI unknode_Invoke(
1245 DISPID dispIdMember,
1249 DISPPARAMS* pDispParams,
1250 VARIANT* pVarResult,
1251 EXCEPINFO* pExcepInfo,
1254 unknode *This = unknode_from_IXMLDOMNode( iface );
1255 ITypeInfo *typeinfo;
1258 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1259 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1261 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1264 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1265 pVarResult, pExcepInfo, puArgErr);
1266 ITypeInfo_Release(typeinfo);
1272 static HRESULT WINAPI unknode_get_nodeName(
1276 unknode *This = unknode_from_IXMLDOMNode( iface );
1278 FIXME("(%p)->(%p)\n", This, p);
1280 return node_get_nodeName(&This->node, p);
1283 static HRESULT WINAPI unknode_get_nodeValue(
1287 unknode *This = unknode_from_IXMLDOMNode( iface );
1289 FIXME("(%p)->(%p)\n", This, value);
1292 return E_INVALIDARG;
1294 V_VT(value) = VT_NULL;
1298 static HRESULT WINAPI unknode_put_nodeValue(
1302 unknode *This = unknode_from_IXMLDOMNode( iface );
1303 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1307 static HRESULT WINAPI unknode_get_nodeType(
1309 DOMNodeType* domNodeType )
1311 unknode *This = unknode_from_IXMLDOMNode( iface );
1313 FIXME("(%p)->(%p)\n", This, domNodeType);
1315 *domNodeType = This->node.node->type;
1319 static HRESULT WINAPI unknode_get_parentNode(
1321 IXMLDOMNode** parent )
1323 unknode *This = unknode_from_IXMLDOMNode( iface );
1324 FIXME("(%p)->(%p)\n", This, parent);
1325 if (!parent) return E_INVALIDARG;
1330 static HRESULT WINAPI unknode_get_childNodes(
1332 IXMLDOMNodeList** outList)
1334 unknode *This = unknode_from_IXMLDOMNode( iface );
1336 TRACE("(%p)->(%p)\n", This, outList);
1338 return node_get_child_nodes(&This->node, outList);
1341 static HRESULT WINAPI unknode_get_firstChild(
1343 IXMLDOMNode** domNode)
1345 unknode *This = unknode_from_IXMLDOMNode( iface );
1347 TRACE("(%p)->(%p)\n", This, domNode);
1349 return node_get_first_child(&This->node, domNode);
1352 static HRESULT WINAPI unknode_get_lastChild(
1354 IXMLDOMNode** domNode)
1356 unknode *This = unknode_from_IXMLDOMNode( iface );
1358 TRACE("(%p)->(%p)\n", This, domNode);
1360 return node_get_last_child(&This->node, domNode);
1363 static HRESULT WINAPI unknode_get_previousSibling(
1365 IXMLDOMNode** domNode)
1367 unknode *This = unknode_from_IXMLDOMNode( iface );
1369 TRACE("(%p)->(%p)\n", This, domNode);
1371 return node_get_previous_sibling(&This->node, domNode);
1374 static HRESULT WINAPI unknode_get_nextSibling(
1376 IXMLDOMNode** domNode)
1378 unknode *This = unknode_from_IXMLDOMNode( iface );
1380 TRACE("(%p)->(%p)\n", This, domNode);
1382 return node_get_next_sibling(&This->node, domNode);
1385 static HRESULT WINAPI unknode_get_attributes(
1387 IXMLDOMNamedNodeMap** attributeMap)
1389 unknode *This = unknode_from_IXMLDOMNode( iface );
1391 FIXME("(%p)->(%p)\n", This, attributeMap);
1393 return return_null_ptr((void**)attributeMap);
1396 static HRESULT WINAPI unknode_insertBefore(
1398 IXMLDOMNode* newNode, VARIANT refChild,
1399 IXMLDOMNode** outOldNode)
1401 unknode *This = unknode_from_IXMLDOMNode( iface );
1403 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1405 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1408 static HRESULT WINAPI unknode_replaceChild(
1410 IXMLDOMNode* newNode,
1411 IXMLDOMNode* oldNode,
1412 IXMLDOMNode** outOldNode)
1414 unknode *This = unknode_from_IXMLDOMNode( iface );
1416 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1418 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1421 static HRESULT WINAPI unknode_removeChild(
1423 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1425 unknode *This = unknode_from_IXMLDOMNode( iface );
1426 return node_remove_child(&This->node, domNode, oldNode);
1429 static HRESULT WINAPI unknode_appendChild(
1431 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1433 unknode *This = unknode_from_IXMLDOMNode( iface );
1434 return node_append_child(&This->node, newNode, outNewNode);
1437 static HRESULT WINAPI unknode_hasChildNodes(
1439 VARIANT_BOOL* pbool)
1441 unknode *This = unknode_from_IXMLDOMNode( iface );
1442 return node_has_childnodes(&This->node, pbool);
1445 static HRESULT WINAPI unknode_get_ownerDocument(
1447 IXMLDOMDocument** domDocument)
1449 unknode *This = unknode_from_IXMLDOMNode( iface );
1450 return node_get_owner_doc(&This->node, domDocument);
1453 static HRESULT WINAPI unknode_cloneNode(
1455 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1457 unknode *This = unknode_from_IXMLDOMNode( iface );
1458 return node_clone(&This->node, pbool, outNode );
1461 static HRESULT WINAPI unknode_get_nodeTypeString(
1465 unknode *This = unknode_from_IXMLDOMNode( iface );
1467 FIXME("(%p)->(%p)\n", This, p);
1469 return node_get_nodeName(&This->node, p);
1472 static HRESULT WINAPI unknode_get_text(
1476 unknode *This = unknode_from_IXMLDOMNode( iface );
1477 return node_get_text(&This->node, p);
1480 static HRESULT WINAPI unknode_put_text(
1484 unknode *This = unknode_from_IXMLDOMNode( iface );
1485 return node_put_text(&This->node, p);
1488 static HRESULT WINAPI unknode_get_specified(
1490 VARIANT_BOOL* isSpecified)
1492 unknode *This = unknode_from_IXMLDOMNode( iface );
1493 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1494 *isSpecified = VARIANT_TRUE;
1498 static HRESULT WINAPI unknode_get_definition(
1500 IXMLDOMNode** definitionNode)
1502 unknode *This = unknode_from_IXMLDOMNode( iface );
1503 FIXME("(%p)->(%p)\n", This, definitionNode);
1507 static HRESULT WINAPI unknode_get_nodeTypedValue(
1511 unknode *This = unknode_from_IXMLDOMNode( iface );
1512 FIXME("(%p)->(%p)\n", This, var1);
1513 return return_null_var(var1);
1516 static HRESULT WINAPI unknode_put_nodeTypedValue(
1520 unknode *This = unknode_from_IXMLDOMNode( iface );
1521 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1525 static HRESULT WINAPI unknode_get_dataType(
1529 unknode *This = unknode_from_IXMLDOMNode( iface );
1530 TRACE("(%p)->(%p)\n", This, var1);
1531 return return_null_var(var1);
1534 static HRESULT WINAPI unknode_put_dataType(
1538 unknode *This = unknode_from_IXMLDOMNode( iface );
1540 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1543 return E_INVALIDARG;
1548 static HRESULT WINAPI unknode_get_xml(
1552 unknode *This = unknode_from_IXMLDOMNode( iface );
1554 FIXME("(%p)->(%p)\n", This, p);
1556 return node_get_xml(&This->node, FALSE, FALSE, p);
1559 static HRESULT WINAPI unknode_transformNode(
1561 IXMLDOMNode* domNode, BSTR* p)
1563 unknode *This = unknode_from_IXMLDOMNode( iface );
1564 return node_transform_node(&This->node, domNode, p);
1567 static HRESULT WINAPI unknode_selectNodes(
1569 BSTR p, IXMLDOMNodeList** outList)
1571 unknode *This = unknode_from_IXMLDOMNode( iface );
1572 return node_select_nodes(&This->node, p, outList);
1575 static HRESULT WINAPI unknode_selectSingleNode(
1577 BSTR p, IXMLDOMNode** outNode)
1579 unknode *This = unknode_from_IXMLDOMNode( iface );
1580 return node_select_singlenode(&This->node, p, outNode);
1583 static HRESULT WINAPI unknode_get_parsed(
1585 VARIANT_BOOL* isParsed)
1587 unknode *This = unknode_from_IXMLDOMNode( iface );
1588 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1589 *isParsed = VARIANT_TRUE;
1593 static HRESULT WINAPI unknode_get_namespaceURI(
1597 unknode *This = unknode_from_IXMLDOMNode( iface );
1598 TRACE("(%p)->(%p)\n", This, p);
1599 return node_get_namespaceURI(&This->node, p);
1602 static HRESULT WINAPI unknode_get_prefix(
1606 unknode *This = unknode_from_IXMLDOMNode( iface );
1607 return node_get_prefix(&This->node, p);
1610 static HRESULT WINAPI unknode_get_baseName(
1614 unknode *This = unknode_from_IXMLDOMNode( iface );
1615 return node_get_base_name(&This->node, p);
1618 static HRESULT WINAPI unknode_transformNodeToObject(
1620 IXMLDOMNode* domNode, VARIANT var1)
1622 unknode *This = unknode_from_IXMLDOMNode( iface );
1623 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1627 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1629 unknode_QueryInterface,
1632 unknode_GetTypeInfoCount,
1633 unknode_GetTypeInfo,
1634 unknode_GetIDsOfNames,
1636 unknode_get_nodeName,
1637 unknode_get_nodeValue,
1638 unknode_put_nodeValue,
1639 unknode_get_nodeType,
1640 unknode_get_parentNode,
1641 unknode_get_childNodes,
1642 unknode_get_firstChild,
1643 unknode_get_lastChild,
1644 unknode_get_previousSibling,
1645 unknode_get_nextSibling,
1646 unknode_get_attributes,
1647 unknode_insertBefore,
1648 unknode_replaceChild,
1649 unknode_removeChild,
1650 unknode_appendChild,
1651 unknode_hasChildNodes,
1652 unknode_get_ownerDocument,
1654 unknode_get_nodeTypeString,
1657 unknode_get_specified,
1658 unknode_get_definition,
1659 unknode_get_nodeTypedValue,
1660 unknode_put_nodeTypedValue,
1661 unknode_get_dataType,
1662 unknode_put_dataType,
1664 unknode_transformNode,
1665 unknode_selectNodes,
1666 unknode_selectSingleNode,
1668 unknode_get_namespaceURI,
1670 unknode_get_baseName,
1671 unknode_transformNodeToObject
1674 IXMLDOMNode *create_node( xmlNodePtr node )
1683 TRACE("type %d\n", node->type);
1686 case XML_ELEMENT_NODE:
1687 pUnk = create_element( node );
1689 case XML_ATTRIBUTE_NODE:
1690 pUnk = create_attribute( node );
1693 pUnk = create_text( node );
1695 case XML_CDATA_SECTION_NODE:
1696 pUnk = create_cdata( node );
1698 case XML_ENTITY_REF_NODE:
1699 pUnk = create_doc_entity_ref( node );
1702 pUnk = create_pi( node );
1704 case XML_COMMENT_NODE:
1705 pUnk = create_comment( node );
1707 case XML_DOCUMENT_NODE:
1708 pUnk = create_domdoc( node );
1710 case XML_DOCUMENT_FRAG_NODE:
1711 pUnk = create_doc_fragment( node );
1714 pUnk = create_doc_type( node );
1719 FIXME("only creating basic node for type %d\n", node->type);
1721 new_node = heap_alloc(sizeof(unknode));
1725 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1727 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1728 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1732 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1733 IUnknown_Release(pUnk);
1734 if(FAILED(hr)) return NULL;