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 if (V_UNKNOWN(ref_child))
316 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
317 if(FAILED(hr)) return hr;
322 FIXME("refChild var type %x\n", V_VT(ref_child));
326 TRACE("new child %p, This->node %p\n", node_obj->node, This->node);
328 if(!node_obj->node->parent)
329 if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK)
330 WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc);
334 xmlnode *before_node_obj = get_node_obj(before);
335 IXMLDOMNode_Release(before);
336 if(!before_node_obj) return E_FAIL;
338 /* unlink from current parent first */
341 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
342 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
344 doc = node_obj->node->doc;
345 xmldoc_add_ref(before_node_obj->node->doc);
346 xmlAddPrevSibling(before_node_obj->node, node_obj->node);
348 node_obj->parent = This->parent;
352 /* unlink from current parent first */
355 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
356 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
358 doc = node_obj->node->doc;
359 xmldoc_add_ref(This->node->doc);
360 /* xmlAddChild doesn't unlink node from previous parent */
361 xmlUnlinkNode(node_obj->node);
362 xmlAddChild(This->node, node_obj->node);
364 node_obj->parent = This->iface;
369 IXMLDOMNode_AddRef(new_child);
377 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
380 xmlnode *old_child, *new_child;
381 xmlDocPtr leaving_doc;
382 xmlNode *my_ancestor;
384 /* Do not believe any documentation telling that newChild == NULL
385 means removal. It does certainly *not* apply to msxml3! */
386 if(!newChild || !oldChild)
392 old_child = get_node_obj(oldChild);
393 if(!old_child) return E_FAIL;
395 if(old_child->node->parent != This->node)
397 WARN("childNode %p is not a child of %p\n", oldChild, This);
401 new_child = get_node_obj(newChild);
402 if(!new_child) return E_FAIL;
404 my_ancestor = This->node;
407 if(my_ancestor == new_child->node)
409 WARN("tried to create loop\n");
412 my_ancestor = my_ancestor->parent;
415 if(!new_child->node->parent)
416 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
417 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
419 leaving_doc = new_child->node->doc;
420 xmldoc_add_ref(old_child->node->doc);
421 xmlReplaceNode(old_child->node, new_child->node);
422 xmldoc_release(leaving_doc);
423 new_child->parent = old_child->parent;
424 old_child->parent = NULL;
426 xmldoc_add_orphan(old_child->node->doc, old_child->node);
430 IXMLDOMNode_AddRef(oldChild);
437 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
441 if(!child) return E_INVALIDARG;
446 child_node = get_node_obj(child);
447 if(!child_node) return E_FAIL;
449 if(child_node->node->parent != This->node)
451 WARN("childNode %p is not a child of %p\n", child, This);
455 xmlUnlinkNode(child_node->node);
456 child_node->parent = NULL;
457 xmldoc_add_orphan(child_node->node->doc, child_node->node);
461 IXMLDOMNode_AddRef(child);
468 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
474 hr = IXMLDOMNode_get_nodeType(child, &type);
475 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
476 if (outChild) *outChild = NULL;
481 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
484 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
486 if (!ret) return E_INVALIDARG;
488 if (!This->node->children)
490 *ret = VARIANT_FALSE;
498 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
500 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
503 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
508 if(!cloneNode) return E_INVALIDARG;
510 clone = xmlCopyNode(This->node, deep ? 1 : 2);
513 clone->doc = This->node->doc;
514 xmldoc_add_orphan(clone->doc, clone);
516 node = create_node(clone);
519 ERR("Copy failed\n");
520 xmldoc_remove_orphan(clone->doc, clone);
529 ERR("Copy failed\n");
536 static inline xmlChar* trim_whitespace(xmlChar* str)
544 while (*ret && isspace(*ret))
546 len = xmlStrlen(ret);
548 while (isspace(ret[len-1])) --len;
550 ret = xmlStrndup(ret, len);
555 static xmlChar* do_get_text(xmlNodePtr node)
559 BOOL preserving = is_preserving_whitespace(node);
563 str = xmlNodeGetContent(node);
567 xmlElementType prev_type = XML_TEXT_NODE;
569 str = xmlStrdup(BAD_CAST "");
570 for (child = node->children; child != NULL; child = child->next)
574 case XML_ELEMENT_NODE:
575 tmp = do_get_text(child);
578 case XML_CDATA_SECTION_NODE:
579 case XML_ENTITY_REF_NODE:
580 case XML_ENTITY_NODE:
581 tmp = xmlNodeGetContent(child);
592 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
593 str = xmlStrcat(str, BAD_CAST " ");
594 str = xmlStrcat(str, tmp);
595 prev_type = child->type;
604 case XML_ELEMENT_NODE:
606 case XML_ENTITY_REF_NODE:
607 case XML_ENTITY_NODE:
608 case XML_DOCUMENT_NODE:
609 case XML_DOCUMENT_FRAG_NODE:
611 str = trim_whitespace(str);
620 HRESULT node_get_text(const xmlnode *This, BSTR *text)
625 if (!text) return E_INVALIDARG;
627 content = do_get_text(This->node);
630 str = bstr_from_xmlChar(content);
634 /* Always return a string. */
635 if (!str) str = SysAllocStringLen( NULL, 0 );
637 TRACE("%p %s\n", This, debugstr_w(str) );
643 HRESULT node_put_text(xmlnode *This, BSTR text)
647 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
649 str = xmlchar_from_wchar(text);
651 /* Escape the string. */
652 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
655 xmlNodeSetContent(This->node, str2);
661 static inline BYTE hex_to_byte(xmlChar c)
663 if(c <= '9') return c-'0';
664 if(c <= 'F') return c-'A'+10;
668 static inline BYTE base64_to_byte(xmlChar c)
670 if(c == '+') return 62;
671 if(c == '/') return 63;
672 if(c <= '9') return c-'0'+52;
673 if(c <= 'Z') return c-'A';
677 /* TODO: phasing this version out */
678 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
680 if(!type || !lstrcmpiW(type, szString) ||
681 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
684 V_BSTR(v) = bstr_from_xmlChar(str);
687 return E_OUTOFMEMORY;
689 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
690 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
691 !lstrcmpiW(type, szTimeTZ))
701 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
703 V_VT(&src) = VT_BSTR;
704 V_BSTR(&src) = bstr_from_xmlChar(str);
707 return E_OUTOFMEMORY;
710 e = p + SysStringLen(V_BSTR(&src));
712 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
715 st.wMonth = atoiW(p+5);
716 st.wDay = atoiW(p+8);
722 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
725 st.wMinute = atoiW(p+3);
726 st.wSecond = atoiW(p+6);
732 while(isdigitW(*p)) p++;
736 SystemTimeToVariantTime(&st, &date);
740 if(*p == '+') /* parse timezone offset (+hh:mm) */
741 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
742 else if(*p == '-') /* parse timezone offset (-hh:mm) */
743 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
747 else if(!lstrcmpiW(type, szBinHex))
752 len = xmlStrlen(str)/2;
756 V_VT(v) = (VT_ARRAY|VT_UI1);
757 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
760 return E_OUTOFMEMORY;
763 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
764 + hex_to_byte(str[2*i+1]);
766 else if(!lstrcmpiW(type, szBinBase64))
771 len = xmlStrlen(str);
772 if(str[len-2] == '=') i = 2;
773 else if(str[len-1] == '=') i = 1;
777 sab.cElements = len/4*3-i;
779 V_VT(v) = (VT_ARRAY|VT_UI1);
780 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
783 return E_OUTOFMEMORY;
785 for(i=0; i<len/4; i++)
787 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
788 + (base64_to_byte(str[4*i+1])>>4);
789 if(3*i+1 < sab.cElements)
790 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
791 + (base64_to_byte(str[4*i+2])>>2);
792 if(3*i+2 < sab.cElements)
793 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
794 + base64_to_byte(str[4*i+3]);
802 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
804 else if(!lstrcmpiW(type, szFixed))
806 else if(!lstrcmpiW(type, szBoolean))
808 else if(!lstrcmpiW(type, szI1))
810 else if(!lstrcmpiW(type, szI2))
812 else if(!lstrcmpiW(type, szIU1))
814 else if(!lstrcmpiW(type, szIU2))
816 else if(!lstrcmpiW(type, szIU4))
818 else if(!lstrcmpiW(type, szR4))
820 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
824 FIXME("Type handling not yet implemented\n");
828 V_VT(&src) = VT_BSTR;
829 V_BSTR(&src) = bstr_from_xmlChar(str);
832 return E_OUTOFMEMORY;
834 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
835 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
843 BSTR EnsureCorrectEOL(BSTR sInput)
850 nLen = SysStringLen(sInput);
851 /* Count line endings */
852 for(i=0; i < nLen; i++)
854 if(sInput[i] == '\n')
858 TRACE("len=%d, num=%d\n", nLen, nNum);
860 /* Add linefeed as needed */
864 sNew = SysAllocStringLen(NULL, nLen + nNum);
865 for(i=0; i < nLen; i++)
867 if(sInput[i] == '\n')
869 sNew[i+nPlace] = '\r';
872 sNew[i+nPlace] = sInput[i];
875 SysFreeString(sInput);
882 TRACE("len %d\n", SysStringLen(sNew));
887 /* Removes encoding information and last character (nullbyte) */
888 static BSTR EnsureNoEncoding(BSTR sInput)
890 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
895 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
900 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
905 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
906 while(*pEnd != '\"') pEnd++;
909 sNew = SysAllocStringLen(NULL,
910 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
911 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
912 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
914 SysFreeString(sInput);
919 * We are trying to replicate the same behaviour as msxml by converting
920 * line endings to \r\n and using indents as \t. The problem is that msxml
921 * only formats nodes that have a line ending. Using libxml we cannot
922 * reproduce behaviour exactly.
925 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
927 xmlBufferPtr xml_buf;
936 xml_buf = xmlBufferCreate();
938 return E_OUTOFMEMORY;
940 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
942 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
944 const xmlChar *buf_content;
947 /* Attribute Nodes return a space in front of their name */
948 buf_content = xmlBufferContent(xml_buf);
950 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
952 content = EnsureCorrectEOL(content);
953 if(ensure_no_encoding)
954 content = EnsureNoEncoding(content);
958 *ret = SysAllocStringLen(NULL, 0);
961 xmlBufferFree(xml_buf);
962 xmldoc_link_xmldecl( This->node->doc, xmldecl );
963 return *ret ? S_OK : E_OUTOFMEMORY;
966 HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p)
968 #ifdef SONAME_LIBXSLT
969 xsltStylesheetPtr xsltSS;
972 if (!libxslt_handle) return E_NOTIMPL;
973 if (!stylesheet || !p) return E_INVALIDARG;
977 sheet = get_node_obj(stylesheet);
978 if(!sheet) return E_FAIL;
980 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
983 xmlDocPtr result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
986 const xmlChar *content;
988 if(result->type == XML_HTML_DOCUMENT_NODE)
990 xmlOutputBufferPtr output = xmlAllocOutputBuffer(NULL);
993 htmlDocContentDumpOutput(output, result->doc, NULL);
994 content = xmlBufferContent(output->buffer);
995 *p = bstr_from_xmlChar(content);
996 xmlOutputBufferClose(output);
1001 xmlBufferPtr buf = xmlBufferCreate();
1004 int size = xmlNodeDump(buf, NULL, (xmlNodePtr)result, 0, 0);
1007 content = xmlBufferContent(buf);
1008 *p = bstr_from_xmlChar(content);
1015 /* libxslt "helpfully" frees the XML document the stylesheet was
1016 generated from, too */
1018 pxsltFreeStylesheet(xsltSS);
1021 if(!*p) *p = SysAllocStringLen(NULL, 0);
1025 FIXME("libxslt headers were not found at compile time\n");
1030 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1035 if (!query || !nodes) return E_INVALIDARG;
1037 str = xmlchar_from_wchar(query);
1038 hr = create_selection(This->node, str, nodes);
1044 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1046 IXMLDOMNodeList *list;
1049 hr = node_select_nodes(This, query, &list);
1052 hr = IXMLDOMNodeList_nextNode(list, node);
1053 IXMLDOMNodeList_Release(list);
1058 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1063 return E_INVALIDARG;
1065 *namespaceURI = NULL;
1067 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1069 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1073 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1075 return *namespaceURI ? S_OK : S_FALSE;
1078 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1082 if (!prefix) return E_INVALIDARG;
1086 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1088 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1092 TRACE("prefix: %s\n", debugstr_w(*prefix));
1094 return *prefix ? S_OK : S_FALSE;
1097 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1099 if (!name) return E_INVALIDARG;
1101 *name = bstr_from_xmlChar(This->node->name);
1102 if (!*name) return E_OUTOFMEMORY;
1104 TRACE("returning %s\n", debugstr_w(*name));
1109 void destroy_xmlnode(xmlnode *This)
1112 xmldoc_release(This->node->doc);
1115 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1118 xmldoc_add_ref( node->doc );
1121 This->iface = node_iface;
1122 This->parent = NULL;
1125 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1127 This->dispex.outer = NULL;
1132 IXMLDOMNode IXMLDOMNode_iface;
1136 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1138 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1141 static HRESULT WINAPI unknode_QueryInterface(
1146 unknode *This = unknode_from_IXMLDOMNode( iface );
1148 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1150 if (IsEqualGUID(riid, &IID_IUnknown)) {
1152 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1153 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1154 *ppvObject = &This->IXMLDOMNode_iface;
1155 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1156 return *ppvObject ? S_OK : E_NOINTERFACE;
1158 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1160 return E_NOINTERFACE;
1163 IUnknown_AddRef((IUnknown*)*ppvObject);
1167 static ULONG WINAPI unknode_AddRef(
1168 IXMLDOMNode *iface )
1170 unknode *This = unknode_from_IXMLDOMNode( iface );
1172 return InterlockedIncrement(&This->ref);
1175 static ULONG WINAPI unknode_Release(
1176 IXMLDOMNode *iface )
1178 unknode *This = unknode_from_IXMLDOMNode( iface );
1181 ref = InterlockedDecrement( &This->ref );
1183 destroy_xmlnode(&This->node);
1190 static HRESULT WINAPI unknode_GetTypeInfoCount(
1194 unknode *This = unknode_from_IXMLDOMNode( iface );
1196 TRACE("(%p)->(%p)\n", This, pctinfo);
1203 static HRESULT WINAPI unknode_GetTypeInfo(
1207 ITypeInfo** ppTInfo )
1209 unknode *This = unknode_from_IXMLDOMNode( iface );
1212 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1214 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1219 static HRESULT WINAPI unknode_GetIDsOfNames(
1222 LPOLESTR* rgszNames,
1227 unknode *This = unknode_from_IXMLDOMNode( iface );
1229 ITypeInfo *typeinfo;
1232 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1235 if(!rgszNames || cNames == 0 || !rgDispId)
1236 return E_INVALIDARG;
1238 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1241 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1242 ITypeInfo_Release(typeinfo);
1248 static HRESULT WINAPI unknode_Invoke(
1250 DISPID dispIdMember,
1254 DISPPARAMS* pDispParams,
1255 VARIANT* pVarResult,
1256 EXCEPINFO* pExcepInfo,
1259 unknode *This = unknode_from_IXMLDOMNode( iface );
1260 ITypeInfo *typeinfo;
1263 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1264 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1266 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1269 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1270 pVarResult, pExcepInfo, puArgErr);
1271 ITypeInfo_Release(typeinfo);
1277 static HRESULT WINAPI unknode_get_nodeName(
1281 unknode *This = unknode_from_IXMLDOMNode( iface );
1283 FIXME("(%p)->(%p)\n", This, p);
1285 return node_get_nodeName(&This->node, p);
1288 static HRESULT WINAPI unknode_get_nodeValue(
1292 unknode *This = unknode_from_IXMLDOMNode( iface );
1294 FIXME("(%p)->(%p)\n", This, value);
1297 return E_INVALIDARG;
1299 V_VT(value) = VT_NULL;
1303 static HRESULT WINAPI unknode_put_nodeValue(
1307 unknode *This = unknode_from_IXMLDOMNode( iface );
1308 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1312 static HRESULT WINAPI unknode_get_nodeType(
1314 DOMNodeType* domNodeType )
1316 unknode *This = unknode_from_IXMLDOMNode( iface );
1318 FIXME("(%p)->(%p)\n", This, domNodeType);
1320 *domNodeType = This->node.node->type;
1324 static HRESULT WINAPI unknode_get_parentNode(
1326 IXMLDOMNode** parent )
1328 unknode *This = unknode_from_IXMLDOMNode( iface );
1329 FIXME("(%p)->(%p)\n", This, parent);
1330 if (!parent) return E_INVALIDARG;
1335 static HRESULT WINAPI unknode_get_childNodes(
1337 IXMLDOMNodeList** outList)
1339 unknode *This = unknode_from_IXMLDOMNode( iface );
1341 TRACE("(%p)->(%p)\n", This, outList);
1343 return node_get_child_nodes(&This->node, outList);
1346 static HRESULT WINAPI unknode_get_firstChild(
1348 IXMLDOMNode** domNode)
1350 unknode *This = unknode_from_IXMLDOMNode( iface );
1352 TRACE("(%p)->(%p)\n", This, domNode);
1354 return node_get_first_child(&This->node, domNode);
1357 static HRESULT WINAPI unknode_get_lastChild(
1359 IXMLDOMNode** domNode)
1361 unknode *This = unknode_from_IXMLDOMNode( iface );
1363 TRACE("(%p)->(%p)\n", This, domNode);
1365 return node_get_last_child(&This->node, domNode);
1368 static HRESULT WINAPI unknode_get_previousSibling(
1370 IXMLDOMNode** domNode)
1372 unknode *This = unknode_from_IXMLDOMNode( iface );
1374 TRACE("(%p)->(%p)\n", This, domNode);
1376 return node_get_previous_sibling(&This->node, domNode);
1379 static HRESULT WINAPI unknode_get_nextSibling(
1381 IXMLDOMNode** domNode)
1383 unknode *This = unknode_from_IXMLDOMNode( iface );
1385 TRACE("(%p)->(%p)\n", This, domNode);
1387 return node_get_next_sibling(&This->node, domNode);
1390 static HRESULT WINAPI unknode_get_attributes(
1392 IXMLDOMNamedNodeMap** attributeMap)
1394 unknode *This = unknode_from_IXMLDOMNode( iface );
1396 FIXME("(%p)->(%p)\n", This, attributeMap);
1398 return return_null_ptr((void**)attributeMap);
1401 static HRESULT WINAPI unknode_insertBefore(
1403 IXMLDOMNode* newNode, VARIANT refChild,
1404 IXMLDOMNode** outOldNode)
1406 unknode *This = unknode_from_IXMLDOMNode( iface );
1408 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1410 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1413 static HRESULT WINAPI unknode_replaceChild(
1415 IXMLDOMNode* newNode,
1416 IXMLDOMNode* oldNode,
1417 IXMLDOMNode** outOldNode)
1419 unknode *This = unknode_from_IXMLDOMNode( iface );
1421 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1423 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1426 static HRESULT WINAPI unknode_removeChild(
1428 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1430 unknode *This = unknode_from_IXMLDOMNode( iface );
1431 return node_remove_child(&This->node, domNode, oldNode);
1434 static HRESULT WINAPI unknode_appendChild(
1436 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1438 unknode *This = unknode_from_IXMLDOMNode( iface );
1439 return node_append_child(&This->node, newNode, outNewNode);
1442 static HRESULT WINAPI unknode_hasChildNodes(
1444 VARIANT_BOOL* pbool)
1446 unknode *This = unknode_from_IXMLDOMNode( iface );
1447 return node_has_childnodes(&This->node, pbool);
1450 static HRESULT WINAPI unknode_get_ownerDocument(
1452 IXMLDOMDocument** domDocument)
1454 unknode *This = unknode_from_IXMLDOMNode( iface );
1455 return node_get_owner_doc(&This->node, domDocument);
1458 static HRESULT WINAPI unknode_cloneNode(
1460 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1462 unknode *This = unknode_from_IXMLDOMNode( iface );
1463 return node_clone(&This->node, pbool, outNode );
1466 static HRESULT WINAPI unknode_get_nodeTypeString(
1470 unknode *This = unknode_from_IXMLDOMNode( iface );
1472 FIXME("(%p)->(%p)\n", This, p);
1474 return node_get_nodeName(&This->node, p);
1477 static HRESULT WINAPI unknode_get_text(
1481 unknode *This = unknode_from_IXMLDOMNode( iface );
1482 return node_get_text(&This->node, p);
1485 static HRESULT WINAPI unknode_put_text(
1489 unknode *This = unknode_from_IXMLDOMNode( iface );
1490 return node_put_text(&This->node, p);
1493 static HRESULT WINAPI unknode_get_specified(
1495 VARIANT_BOOL* isSpecified)
1497 unknode *This = unknode_from_IXMLDOMNode( iface );
1498 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1499 *isSpecified = VARIANT_TRUE;
1503 static HRESULT WINAPI unknode_get_definition(
1505 IXMLDOMNode** definitionNode)
1507 unknode *This = unknode_from_IXMLDOMNode( iface );
1508 FIXME("(%p)->(%p)\n", This, definitionNode);
1512 static HRESULT WINAPI unknode_get_nodeTypedValue(
1516 unknode *This = unknode_from_IXMLDOMNode( iface );
1517 FIXME("(%p)->(%p)\n", This, var1);
1518 return return_null_var(var1);
1521 static HRESULT WINAPI unknode_put_nodeTypedValue(
1525 unknode *This = unknode_from_IXMLDOMNode( iface );
1526 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1530 static HRESULT WINAPI unknode_get_dataType(
1534 unknode *This = unknode_from_IXMLDOMNode( iface );
1535 TRACE("(%p)->(%p)\n", This, var1);
1536 return return_null_var(var1);
1539 static HRESULT WINAPI unknode_put_dataType(
1543 unknode *This = unknode_from_IXMLDOMNode( iface );
1545 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1548 return E_INVALIDARG;
1553 static HRESULT WINAPI unknode_get_xml(
1557 unknode *This = unknode_from_IXMLDOMNode( iface );
1559 FIXME("(%p)->(%p)\n", This, p);
1561 return node_get_xml(&This->node, FALSE, FALSE, p);
1564 static HRESULT WINAPI unknode_transformNode(
1566 IXMLDOMNode* domNode, BSTR* p)
1568 unknode *This = unknode_from_IXMLDOMNode( iface );
1569 return node_transform_node(&This->node, domNode, p);
1572 static HRESULT WINAPI unknode_selectNodes(
1574 BSTR p, IXMLDOMNodeList** outList)
1576 unknode *This = unknode_from_IXMLDOMNode( iface );
1577 return node_select_nodes(&This->node, p, outList);
1580 static HRESULT WINAPI unknode_selectSingleNode(
1582 BSTR p, IXMLDOMNode** outNode)
1584 unknode *This = unknode_from_IXMLDOMNode( iface );
1585 return node_select_singlenode(&This->node, p, outNode);
1588 static HRESULT WINAPI unknode_get_parsed(
1590 VARIANT_BOOL* isParsed)
1592 unknode *This = unknode_from_IXMLDOMNode( iface );
1593 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1594 *isParsed = VARIANT_TRUE;
1598 static HRESULT WINAPI unknode_get_namespaceURI(
1602 unknode *This = unknode_from_IXMLDOMNode( iface );
1603 TRACE("(%p)->(%p)\n", This, p);
1604 return node_get_namespaceURI(&This->node, p);
1607 static HRESULT WINAPI unknode_get_prefix(
1611 unknode *This = unknode_from_IXMLDOMNode( iface );
1612 return node_get_prefix(&This->node, p);
1615 static HRESULT WINAPI unknode_get_baseName(
1619 unknode *This = unknode_from_IXMLDOMNode( iface );
1620 return node_get_base_name(&This->node, p);
1623 static HRESULT WINAPI unknode_transformNodeToObject(
1625 IXMLDOMNode* domNode, VARIANT var1)
1627 unknode *This = unknode_from_IXMLDOMNode( iface );
1628 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1632 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1634 unknode_QueryInterface,
1637 unknode_GetTypeInfoCount,
1638 unknode_GetTypeInfo,
1639 unknode_GetIDsOfNames,
1641 unknode_get_nodeName,
1642 unknode_get_nodeValue,
1643 unknode_put_nodeValue,
1644 unknode_get_nodeType,
1645 unknode_get_parentNode,
1646 unknode_get_childNodes,
1647 unknode_get_firstChild,
1648 unknode_get_lastChild,
1649 unknode_get_previousSibling,
1650 unknode_get_nextSibling,
1651 unknode_get_attributes,
1652 unknode_insertBefore,
1653 unknode_replaceChild,
1654 unknode_removeChild,
1655 unknode_appendChild,
1656 unknode_hasChildNodes,
1657 unknode_get_ownerDocument,
1659 unknode_get_nodeTypeString,
1662 unknode_get_specified,
1663 unknode_get_definition,
1664 unknode_get_nodeTypedValue,
1665 unknode_put_nodeTypedValue,
1666 unknode_get_dataType,
1667 unknode_put_dataType,
1669 unknode_transformNode,
1670 unknode_selectNodes,
1671 unknode_selectSingleNode,
1673 unknode_get_namespaceURI,
1675 unknode_get_baseName,
1676 unknode_transformNodeToObject
1679 IXMLDOMNode *create_node( xmlNodePtr node )
1688 TRACE("type %d\n", node->type);
1691 case XML_ELEMENT_NODE:
1692 pUnk = create_element( node );
1694 case XML_ATTRIBUTE_NODE:
1695 pUnk = create_attribute( node );
1698 pUnk = create_text( node );
1700 case XML_CDATA_SECTION_NODE:
1701 pUnk = create_cdata( node );
1703 case XML_ENTITY_REF_NODE:
1704 pUnk = create_doc_entity_ref( node );
1707 pUnk = create_pi( node );
1709 case XML_COMMENT_NODE:
1710 pUnk = create_comment( node );
1712 case XML_DOCUMENT_NODE:
1713 pUnk = create_domdoc( node );
1715 case XML_DOCUMENT_FRAG_NODE:
1716 pUnk = create_doc_fragment( node );
1719 pUnk = create_doc_type( node );
1724 FIXME("only creating basic node for type %d\n", node->type);
1726 new_node = heap_alloc(sizeof(unknode));
1730 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
1732 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
1733 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
1737 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1738 IUnknown_Release(pUnk);
1739 if(FAILED(hr)) return NULL;