4 * Copyright 2005 Mike McCormack
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 # include <libxml/parser.h>
29 # include <libxml/xmlerror.h>
30 # include <libxml/HTMLtree.h>
31 # ifdef SONAME_LIBXSLT
32 # ifdef HAVE_LIBXSLT_PATTERN_H
33 # include <libxslt/pattern.h>
35 # ifdef HAVE_LIBXSLT_TRANSFORM_H
36 # include <libxslt/transform.h>
38 # include <libxslt/xsltutils.h>
39 # include <libxslt/xsltInternals.h>
50 #include "msxml_private.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
59 extern void* libxslt_handle;
60 # define MAKE_FUNCPTR(f) extern typeof(f) * p##f
61 MAKE_FUNCPTR(xsltApplyStylesheet);
62 MAKE_FUNCPTR(xsltCleanupGlobals);
63 MAKE_FUNCPTR(xsltFreeStylesheet);
64 MAKE_FUNCPTR(xsltParseStylesheetDoc);
68 /* TODO: get rid of these and use the enum */
69 static const WCHAR szBinBase64[] = {'b','i','n','.','b','a','s','e','6','4',0};
70 static const WCHAR szString[] = {'s','t','r','i','n','g',0};
71 static const WCHAR szNumber[] = {'n','u','m','b','e','r',0};
72 static const WCHAR szInt[] = {'I','n','t',0};
73 static const WCHAR szFixed[] = {'F','i','x','e','d','.','1','4','.','4',0};
74 static const WCHAR szBoolean[] = {'B','o','o','l','e','a','n',0};
75 static const WCHAR szDateTime[] = {'d','a','t','e','T','i','m','e',0};
76 static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
77 static const WCHAR szDate[] = {'D','a','t','e',0};
78 static const WCHAR szTime[] = {'T','i','m','e',0};
79 static const WCHAR szTimeTZ[] = {'T','i','m','e','.','t','z',0};
80 static const WCHAR szI1[] = {'i','1',0};
81 static const WCHAR szI2[] = {'i','2',0};
82 static const WCHAR szI4[] = {'i','4',0};
83 static const WCHAR szIU1[] = {'u','i','1',0};
84 static const WCHAR szIU2[] = {'u','i','2',0};
85 static const WCHAR szIU4[] = {'u','i','4',0};
86 static const WCHAR szR4[] = {'r','4',0};
87 static const WCHAR szR8[] = {'r','8',0};
88 static const WCHAR szFloat[] = {'f','l','o','a','t',0};
89 static const WCHAR szUUID[] = {'u','u','i','d',0};
90 static const WCHAR szBinHex[] = {'b','i','n','.','h','e','x',0};
92 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
94 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
100 This = get_node_obj( iface );
101 if ( !This || !This->node )
103 if ( type && This->node->type != type )
108 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
110 if(IsEqualGUID(&IID_xmlnode, riid)) {
111 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
116 return dispex_query_interface(&This->dispex, riid, ppv);
119 xmlnode *get_node_obj(IXMLDOMNode *node)
124 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
125 if (!obj) WARN("node is not our IXMLDOMNode implementation\n");
126 return SUCCEEDED(hres) ? obj : NULL;
129 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
134 *name = bstr_from_xmlChar(This->node->name);
141 HRESULT node_get_content(xmlnode *This, VARIANT *value)
148 content = xmlNodeGetContent(This->node);
149 V_VT(value) = VT_BSTR;
150 V_BSTR(value) = bstr_from_xmlChar( content );
153 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
157 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
161 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
162 str = xmlchar_from_wchar(value);
164 return E_OUTOFMEMORY;
166 xmlNodeSetContent(This->node, str);
171 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
173 xmlChar *str, *escaped;
175 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
176 str = xmlchar_from_wchar(value);
178 return E_OUTOFMEMORY;
180 escaped = xmlEncodeSpecialChars(NULL, str);
184 return E_OUTOFMEMORY;
187 xmlNodeSetContent(This->node, escaped);
195 HRESULT node_put_value(xmlnode *This, VARIANT *value)
197 VARIANT string_value;
200 VariantInit(&string_value);
201 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
203 WARN("Couldn't convert to VT_BSTR\n");
207 hr = node_set_content(This, V_BSTR(&string_value));
208 VariantClear(&string_value);
213 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
215 VARIANT string_value;
218 VariantInit(&string_value);
219 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
221 WARN("Couldn't convert to VT_BSTR\n");
225 hr = node_set_content_escaped(This, V_BSTR(&string_value));
226 VariantClear(&string_value);
231 static HRESULT get_node(
237 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
242 /* if we don't have a doc, use our parent. */
243 if(node && !node->doc && node->parent)
244 node->doc = node->parent->doc;
246 *out = create_node( node );
252 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
254 return get_node( This, "parent", This->node->parent, parent );
257 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
262 *ret = create_children_nodelist(This->node);
264 return E_OUTOFMEMORY;
269 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
271 return get_node(This, "firstChild", This->node->children, ret);
274 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
276 return get_node(This, "lastChild", This->node->last, ret);
279 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
281 return get_node(This, "previous", This->node->prev, ret);
284 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
286 return get_node(This, "next", This->node->next, ret);
289 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
292 IXMLDOMNode *before = NULL;
300 node_obj = get_node_obj(new_child);
301 if(!node_obj) return E_FAIL;
303 switch(V_VT(ref_child))
311 if (V_UNKNOWN(ref_child))
313 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
314 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);
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);
1110 release_dispex(&This->dispex);
1113 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1116 xmldoc_add_ref( node->doc );
1119 This->iface = node_iface;
1120 This->parent = NULL;
1122 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
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;