wininet/tests: Fix a couple of test failures on Internet Explorer 11.
[wine/wine-gecko.git] / dlls / msxml3 / node.c
blob47d31597c1f88051d33c7e6906e15845df425739
1 /*
2 * Node implementation
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
21 #include "config.h"
23 #define COBJMACROS
25 #include <stdarg.h>
27 #ifdef HAVE_LIBXML2
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>
34 # endif
35 # ifdef HAVE_LIBXSLT_TRANSFORM_H
36 # include <libxslt/transform.h>
37 # endif
38 # include <libxslt/imports.h>
39 # include <libxslt/variables.h>
40 # include <libxslt/xsltutils.h>
41 # include <libxslt/xsltInternals.h>
42 # endif
43 #endif
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "winnls.h"
49 #include "ole2.h"
50 #include "msxml6.h"
52 #include "msxml_private.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 #ifdef SONAME_LIBXSLT
61 extern void* libxslt_handle;
62 # define MAKE_FUNCPTR(f) extern typeof(f) * p##f
63 MAKE_FUNCPTR(xsltApplyStylesheet);
64 MAKE_FUNCPTR(xsltApplyStylesheetUser);
65 MAKE_FUNCPTR(xsltCleanupGlobals);
66 MAKE_FUNCPTR(xsltFreeStylesheet);
67 MAKE_FUNCPTR(xsltFreeTransformContext);
68 MAKE_FUNCPTR(xsltNewTransformContext);
69 MAKE_FUNCPTR(xsltNextImport);
70 MAKE_FUNCPTR(xsltParseStylesheetDoc);
71 MAKE_FUNCPTR(xsltQuoteUserParams);
72 MAKE_FUNCPTR(xsltSaveResultTo);
73 # undef MAKE_FUNCPTR
74 #else
75 WINE_DECLARE_DEBUG_CHANNEL(winediag);
76 #endif
78 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
80 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
82 xmlnode *This;
84 if ( !iface )
85 return NULL;
86 This = get_node_obj( iface );
87 if ( !This || !This->node )
88 return NULL;
89 if ( type && This->node->type != type )
90 return NULL;
91 return This->node;
94 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
96 if(IsEqualGUID(&IID_xmlnode, riid)) {
97 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
98 *ppv = This;
99 return TRUE;
102 return dispex_query_interface(&This->dispex, riid, ppv);
105 /* common ISupportErrorInfo implementation */
106 typedef struct {
107 ISupportErrorInfo ISupportErrorInfo_iface;
108 LONG ref;
110 const tid_t* iids;
111 } SupportErrorInfo;
113 static inline SupportErrorInfo *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
115 return CONTAINING_RECORD(iface, SupportErrorInfo, ISupportErrorInfo_iface);
118 static HRESULT WINAPI SupportErrorInfo_QueryInterface(ISupportErrorInfo *iface, REFIID riid, void **obj)
120 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
121 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
123 *obj = NULL;
125 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISupportErrorInfo)) {
126 *obj = iface;
127 ISupportErrorInfo_AddRef(iface);
128 return S_OK;
131 return E_NOINTERFACE;
134 static ULONG WINAPI SupportErrorInfo_AddRef(ISupportErrorInfo *iface)
136 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
137 ULONG ref = InterlockedIncrement(&This->ref);
138 TRACE("(%p)->(%d)\n", This, ref );
139 return ref;
142 static ULONG WINAPI SupportErrorInfo_Release(ISupportErrorInfo *iface)
144 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
145 LONG ref = InterlockedDecrement(&This->ref);
147 TRACE("(%p)->(%d)\n", This, ref);
149 if (ref == 0)
150 heap_free(This);
152 return ref;
155 static HRESULT WINAPI SupportErrorInfo_InterfaceSupportsErrorInfo(ISupportErrorInfo *iface, REFIID riid)
157 SupportErrorInfo *This = impl_from_ISupportErrorInfo(iface);
158 enum tid_t const *tid;
160 TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
162 tid = This->iids;
163 while (*tid != NULL_tid)
165 if (IsEqualGUID(riid, get_riid_from_tid(*tid)))
166 return S_OK;
167 tid++;
170 return S_FALSE;
173 static const struct ISupportErrorInfoVtbl SupportErrorInfoVtbl = {
174 SupportErrorInfo_QueryInterface,
175 SupportErrorInfo_AddRef,
176 SupportErrorInfo_Release,
177 SupportErrorInfo_InterfaceSupportsErrorInfo
180 HRESULT node_create_supporterrorinfo(enum tid_t const *iids, void **obj)
182 SupportErrorInfo *This;
184 This = heap_alloc(sizeof(*This));
185 if (!This) return E_OUTOFMEMORY;
187 This->ISupportErrorInfo_iface.lpVtbl = &SupportErrorInfoVtbl;
188 This->ref = 1;
189 This->iids = iids;
191 *obj = &This->ISupportErrorInfo_iface;
193 return S_OK;
196 xmlnode *get_node_obj(IXMLDOMNode *node)
198 xmlnode *obj = NULL;
199 HRESULT hres;
201 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
202 if (!obj) WARN("node is not our IXMLDOMNode implementation\n");
203 return SUCCEEDED(hres) ? obj : NULL;
206 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
208 BSTR prefix, base;
209 HRESULT hr;
211 if (!name)
212 return E_INVALIDARG;
214 hr = node_get_base_name(This, &base);
215 if (hr != S_OK) return hr;
217 hr = node_get_prefix(This, &prefix);
218 if (hr == S_OK)
220 static const WCHAR colW = ':';
221 WCHAR *ptr;
223 /* +1 for ':' */
224 ptr = *name = SysAllocStringLen(NULL, SysStringLen(base) + SysStringLen(prefix) + 1);
225 memcpy(ptr, prefix, SysStringByteLen(prefix));
226 ptr += SysStringLen(prefix);
227 memcpy(ptr++, &colW, sizeof(WCHAR));
228 memcpy(ptr, base, SysStringByteLen(base));
230 SysFreeString(base);
231 SysFreeString(prefix);
233 else
234 *name = base;
236 return S_OK;
239 HRESULT node_get_content(xmlnode *This, VARIANT *value)
241 xmlChar *content;
243 if(!value)
244 return E_INVALIDARG;
246 content = xmlNodeGetContent(This->node);
247 V_VT(value) = VT_BSTR;
248 V_BSTR(value) = bstr_from_xmlChar( content );
249 xmlFree(content);
251 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
252 return S_OK;
255 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
257 xmlChar *str;
259 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
260 str = xmlchar_from_wchar(value);
261 if(!str)
262 return E_OUTOFMEMORY;
264 xmlNodeSetContent(This->node, str);
265 heap_free(str);
266 return S_OK;
269 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
271 xmlChar *str, *escaped;
273 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
274 str = xmlchar_from_wchar(value);
275 if(!str)
276 return E_OUTOFMEMORY;
278 escaped = xmlEncodeSpecialChars(NULL, str);
279 if(!escaped)
281 heap_free(str);
282 return E_OUTOFMEMORY;
285 xmlNodeSetContent(This->node, escaped);
287 heap_free(str);
288 xmlFree(escaped);
290 return S_OK;
293 HRESULT node_put_value(xmlnode *This, VARIANT *value)
295 HRESULT hr;
297 if (V_VT(value) != VT_BSTR)
299 VARIANT string_value;
301 VariantInit(&string_value);
302 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
303 if(FAILED(hr)) {
304 WARN("Couldn't convert to VT_BSTR\n");
305 return hr;
308 hr = node_set_content(This, V_BSTR(&string_value));
309 VariantClear(&string_value);
311 else
312 hr = node_set_content(This, V_BSTR(value));
314 return hr;
317 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
319 HRESULT hr;
321 if (V_VT(value) != VT_BSTR)
323 VARIANT string_value;
325 VariantInit(&string_value);
326 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
327 if(FAILED(hr)) {
328 WARN("Couldn't convert to VT_BSTR\n");
329 return hr;
332 hr = node_set_content_escaped(This, V_BSTR(&string_value));
333 VariantClear(&string_value);
335 else
336 hr = node_set_content_escaped(This, V_BSTR(value));
338 return hr;
341 static HRESULT get_node(
342 xmlnode *This,
343 const char *name,
344 xmlNodePtr node,
345 IXMLDOMNode **out )
347 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
349 if ( !out )
350 return E_INVALIDARG;
352 /* if we don't have a doc, use our parent. */
353 if(node && !node->doc && node->parent)
354 node->doc = node->parent->doc;
356 *out = create_node( node );
357 if (!*out)
358 return S_FALSE;
359 return S_OK;
362 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
364 return get_node( This, "parent", This->node->parent, parent );
367 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
369 if(!ret)
370 return E_INVALIDARG;
372 *ret = create_children_nodelist(This->node);
373 if(!*ret)
374 return E_OUTOFMEMORY;
376 return S_OK;
379 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
381 return get_node(This, "firstChild", This->node->children, ret);
384 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
386 return get_node(This, "lastChild", This->node->last, ret);
389 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
391 return get_node(This, "previous", This->node->prev, ret);
394 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
396 return get_node(This, "next", This->node->next, ret);
399 static int node_get_inst_cnt(xmlNodePtr node)
401 int ret = *(LONG *)&node->_private;
402 xmlNodePtr child;
404 /* add attribute counts */
405 if (node->type == XML_ELEMENT_NODE)
407 xmlAttrPtr prop = node->properties;
409 while (prop)
411 ret += node_get_inst_cnt((xmlNodePtr)prop);
412 prop = prop->next;
416 /* add children counts */
417 child = node->children;
418 while (child)
420 ret += node_get_inst_cnt(child);
421 child = child->next;
424 return ret;
427 int xmlnode_get_inst_cnt(xmlnode *node)
429 return node_get_inst_cnt(node->node);
432 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
433 IXMLDOMNode **ret)
435 IXMLDOMNode *before = NULL;
436 xmlnode *node_obj;
437 int refcount = 0;
438 xmlDocPtr doc;
439 HRESULT hr;
441 if(!new_child)
442 return E_INVALIDARG;
444 node_obj = get_node_obj(new_child);
445 if(!node_obj) return E_FAIL;
447 switch(V_VT(ref_child))
449 case VT_EMPTY:
450 case VT_NULL:
451 break;
453 case VT_UNKNOWN:
454 case VT_DISPATCH:
455 if (V_UNKNOWN(ref_child))
457 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before);
458 if(FAILED(hr)) return hr;
460 break;
462 default:
463 FIXME("refChild var type %x\n", V_VT(ref_child));
464 return E_FAIL;
467 TRACE("new child %p, This->node %p\n", node_obj->node, This->node);
469 if(!node_obj->node->parent)
470 if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK)
471 WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc);
473 refcount = xmlnode_get_inst_cnt(node_obj);
475 if(before)
477 xmlnode *before_node_obj = get_node_obj(before);
478 IXMLDOMNode_Release(before);
479 if(!before_node_obj) return E_FAIL;
481 /* unlink from current parent first */
482 if(node_obj->parent)
484 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
485 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
488 doc = node_obj->node->doc;
490 /* refs count including subtree */
491 if (doc != before_node_obj->node->doc)
492 refcount = xmlnode_get_inst_cnt(node_obj);
494 if (refcount) xmldoc_add_refs(before_node_obj->node->doc, refcount);
495 xmlAddPrevSibling(before_node_obj->node, node_obj->node);
496 if (refcount) xmldoc_release_refs(doc, refcount);
497 node_obj->parent = This->parent;
499 else
501 /* unlink from current parent first */
502 if(node_obj->parent)
504 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
505 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
507 doc = node_obj->node->doc;
509 if (doc != This->node->doc)
510 refcount = xmlnode_get_inst_cnt(node_obj);
512 if (refcount) xmldoc_add_refs(This->node->doc, refcount);
513 /* xmlAddChild doesn't unlink node from previous parent */
514 xmlUnlinkNode(node_obj->node);
515 xmlAddChild(This->node, node_obj->node);
516 if (refcount) xmldoc_release_refs(doc, refcount);
517 node_obj->parent = This->iface;
520 if(ret)
522 IXMLDOMNode_AddRef(new_child);
523 *ret = new_child;
526 TRACE("ret S_OK\n");
527 return S_OK;
530 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
531 IXMLDOMNode **ret)
533 xmlnode *old_child, *new_child;
534 xmlDocPtr leaving_doc;
535 xmlNode *my_ancestor;
536 int refcount = 0;
538 /* Do not believe any documentation telling that newChild == NULL
539 means removal. It does certainly *not* apply to msxml3! */
540 if(!newChild || !oldChild)
541 return E_INVALIDARG;
543 if(ret)
544 *ret = NULL;
546 old_child = get_node_obj(oldChild);
547 if(!old_child) return E_FAIL;
549 if(old_child->node->parent != This->node)
551 WARN("childNode %p is not a child of %p\n", oldChild, This);
552 return E_INVALIDARG;
555 new_child = get_node_obj(newChild);
556 if(!new_child) return E_FAIL;
558 my_ancestor = This->node;
559 while(my_ancestor)
561 if(my_ancestor == new_child->node)
563 WARN("tried to create loop\n");
564 return E_FAIL;
566 my_ancestor = my_ancestor->parent;
569 if(!new_child->node->parent)
570 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
571 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
573 leaving_doc = new_child->node->doc;
575 if (leaving_doc != old_child->node->doc)
576 refcount = xmlnode_get_inst_cnt(new_child);
578 if (refcount) xmldoc_add_refs(old_child->node->doc, refcount);
579 xmlReplaceNode(old_child->node, new_child->node);
580 if (refcount) xmldoc_release_refs(leaving_doc, refcount);
581 new_child->parent = old_child->parent;
582 old_child->parent = NULL;
584 xmldoc_add_orphan(old_child->node->doc, old_child->node);
586 if(ret)
588 IXMLDOMNode_AddRef(oldChild);
589 *ret = oldChild;
592 return S_OK;
595 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
597 xmlnode *child_node;
599 if(!child) return E_INVALIDARG;
601 if(oldChild)
602 *oldChild = NULL;
604 child_node = get_node_obj(child);
605 if(!child_node) return E_FAIL;
607 if(child_node->node->parent != This->node)
609 WARN("childNode %p is not a child of %p\n", child, This);
610 return E_INVALIDARG;
613 xmlUnlinkNode(child_node->node);
614 child_node->parent = NULL;
615 xmldoc_add_orphan(child_node->node->doc, child_node->node);
617 if(oldChild)
619 IXMLDOMNode_AddRef(child);
620 *oldChild = child;
623 return S_OK;
626 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
628 DOMNodeType type;
629 VARIANT var;
630 HRESULT hr;
632 if (!child)
633 return E_INVALIDARG;
635 hr = IXMLDOMNode_get_nodeType(child, &type);
636 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
637 if (outChild) *outChild = NULL;
638 return E_FAIL;
641 VariantInit(&var);
642 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
645 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
647 if (!ret) return E_INVALIDARG;
649 if (!This->node->children)
651 *ret = VARIANT_FALSE;
652 return S_FALSE;
655 *ret = VARIANT_TRUE;
656 return S_OK;
659 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
661 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
664 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
666 IXMLDOMNode *node;
667 xmlNodePtr clone;
669 if(!cloneNode) return E_INVALIDARG;
671 clone = xmlCopyNode(This->node, deep ? 1 : 2);
672 if (clone)
674 xmlSetTreeDoc(clone, This->node->doc);
675 xmldoc_add_orphan(clone->doc, clone);
677 node = create_node(clone);
678 if (!node)
680 ERR("Copy failed\n");
681 xmldoc_remove_orphan(clone->doc, clone);
682 xmlFreeNode(clone);
683 return E_FAIL;
686 *cloneNode = node;
688 else
690 ERR("Copy failed\n");
691 return E_FAIL;
694 return S_OK;
697 static inline xmlChar* trim_whitespace(xmlChar* str)
699 xmlChar* ret = str;
700 int len;
702 if (!str)
703 return NULL;
705 while (*ret && isspace(*ret))
706 ++ret;
707 len = xmlStrlen(ret);
708 if (len)
709 while (isspace(ret[len-1])) --len;
711 ret = xmlStrndup(ret, len);
712 xmlFree(str);
713 return ret;
716 static xmlChar* do_get_text(xmlNodePtr node)
718 xmlNodePtr child;
719 xmlChar* str;
720 BOOL preserving = is_preserving_whitespace(node);
722 if (!node->children)
724 str = xmlNodeGetContent(node);
726 else
728 xmlElementType prev_type = XML_TEXT_NODE;
729 xmlChar* tmp;
730 str = xmlStrdup(BAD_CAST "");
731 for (child = node->children; child != NULL; child = child->next)
733 switch (child->type)
735 case XML_ELEMENT_NODE:
736 tmp = do_get_text(child);
737 break;
738 case XML_TEXT_NODE:
739 case XML_CDATA_SECTION_NODE:
740 case XML_ENTITY_REF_NODE:
741 case XML_ENTITY_NODE:
742 tmp = xmlNodeGetContent(child);
743 break;
744 default:
745 tmp = NULL;
746 break;
749 if (tmp)
751 if (*tmp)
753 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
754 str = xmlStrcat(str, BAD_CAST " ");
755 str = xmlStrcat(str, tmp);
756 prev_type = child->type;
758 xmlFree(tmp);
763 switch (node->type)
765 case XML_ELEMENT_NODE:
766 case XML_TEXT_NODE:
767 case XML_ENTITY_REF_NODE:
768 case XML_ENTITY_NODE:
769 case XML_DOCUMENT_NODE:
770 case XML_DOCUMENT_FRAG_NODE:
771 if (!preserving)
772 str = trim_whitespace(str);
773 break;
774 default:
775 break;
778 return str;
781 HRESULT node_get_text(const xmlnode *This, BSTR *text)
783 BSTR str = NULL;
784 xmlChar *content;
786 if (!text) return E_INVALIDARG;
788 content = do_get_text(This->node);
789 if (content)
791 str = bstr_from_xmlChar(content);
792 xmlFree(content);
795 /* Always return a string. */
796 if (!str) str = SysAllocStringLen( NULL, 0 );
798 TRACE("%p %s\n", This, debugstr_w(str) );
799 *text = str;
801 return S_OK;
804 HRESULT node_put_text(xmlnode *This, BSTR text)
806 xmlChar *str, *str2;
808 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
810 str = xmlchar_from_wchar(text);
812 /* Escape the string. */
813 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
814 heap_free(str);
816 xmlNodeSetContent(This->node, str2);
817 xmlFree(str2);
819 return S_OK;
822 BSTR EnsureCorrectEOL(BSTR sInput)
824 int nNum = 0;
825 BSTR sNew;
826 int nLen;
827 int i;
829 nLen = SysStringLen(sInput);
830 /* Count line endings */
831 for(i=0; i < nLen; i++)
833 if(sInput[i] == '\n')
834 nNum++;
837 TRACE("len=%d, num=%d\n", nLen, nNum);
839 /* Add linefeed as needed */
840 if(nNum > 0)
842 int nPlace = 0;
843 sNew = SysAllocStringLen(NULL, nLen + nNum);
844 for(i=0; i < nLen; i++)
846 if(sInput[i] == '\n')
848 sNew[i+nPlace] = '\r';
849 nPlace++;
851 sNew[i+nPlace] = sInput[i];
854 SysFreeString(sInput);
856 else
858 sNew = sInput;
861 TRACE("len %d\n", SysStringLen(sNew));
863 return sNew;
867 * We are trying to replicate the same behaviour as msxml by converting
868 * line endings to \r\n and using indents as \t. The problem is that msxml
869 * only formats nodes that have a line ending. Using libxml we cannot
870 * reproduce behaviour exactly.
873 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BSTR *ret)
875 xmlBufferPtr xml_buf;
876 xmlNodePtr xmldecl;
877 int size;
879 if(!ret)
880 return E_INVALIDARG;
882 *ret = NULL;
884 xml_buf = xmlBufferCreate();
885 if(!xml_buf)
886 return E_OUTOFMEMORY;
888 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
890 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
891 if(size > 0) {
892 const xmlChar *buf_content;
893 BSTR content;
895 /* Attribute Nodes return a space in front of their name */
896 buf_content = xmlBufferContent(xml_buf);
898 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
899 if(ensure_eol)
900 content = EnsureCorrectEOL(content);
902 *ret = content;
903 }else {
904 *ret = SysAllocStringLen(NULL, 0);
907 xmlBufferFree(xml_buf);
908 xmldoc_link_xmldecl( This->node->doc, xmldecl );
909 return *ret ? S_OK : E_OUTOFMEMORY;
912 #ifdef SONAME_LIBXSLT
914 /* duplicates xmlBufferWriteQuotedString() logic */
915 static void xml_write_quotedstring(xmlOutputBufferPtr buf, const xmlChar *string)
917 const xmlChar *cur, *base;
919 if (xmlStrchr(string, '\"'))
921 if (xmlStrchr(string, '\''))
923 xmlOutputBufferWrite(buf, 1, "\"");
924 base = cur = string;
926 while (*cur)
928 if (*cur == '"')
930 if (base != cur)
931 xmlOutputBufferWrite(buf, cur-base, (const char*)base);
932 xmlOutputBufferWrite(buf, 6, "&quot;");
933 cur++;
934 base = cur;
936 else
937 cur++;
939 if (base != cur)
940 xmlOutputBufferWrite(buf, cur-base, (const char*)base);
941 xmlOutputBufferWrite(buf, 1, "\"");
943 else
945 xmlOutputBufferWrite(buf, 1, "\'");
946 xmlOutputBufferWriteString(buf, (const char*)string);
947 xmlOutputBufferWrite(buf, 1, "\'");
950 else
952 xmlOutputBufferWrite(buf, 1, "\"");
953 xmlOutputBufferWriteString(buf, (const char*)string);
954 xmlOutputBufferWrite(buf, 1, "\"");
958 static int XMLCALL transform_to_stream_write(void *context, const char *buffer, int len)
960 DWORD written;
961 HRESULT hr = IStream_Write((IStream*)context, buffer, len, &written);
962 return hr == S_OK ? written : -1;
965 /* Output for method "text" */
966 static void transform_write_text(xmlDocPtr result, xsltStylesheetPtr style, xmlOutputBufferPtr output)
968 xmlNodePtr cur = result->children;
969 while (cur)
971 if (cur->type == XML_TEXT_NODE)
972 xmlOutputBufferWriteString(output, (const char*)cur->content);
974 /* skip to next node */
975 if (cur->children)
977 if ((cur->children->type != XML_ENTITY_DECL) &&
978 (cur->children->type != XML_ENTITY_REF_NODE) &&
979 (cur->children->type != XML_ENTITY_NODE))
981 cur = cur->children;
982 continue;
986 if (cur->next) {
987 cur = cur->next;
988 continue;
993 cur = cur->parent;
994 if (cur == NULL)
995 break;
996 if (cur == (xmlNodePtr) style->doc) {
997 cur = NULL;
998 break;
1000 if (cur->next) {
1001 cur = cur->next;
1002 break;
1004 } while (cur);
1008 #undef XSLT_GET_IMPORT_PTR
1009 #define XSLT_GET_IMPORT_PTR(res, style, name) { \
1010 xsltStylesheetPtr st = style; \
1011 res = NULL; \
1012 while (st != NULL) { \
1013 if (st->name != NULL) { res = st->name; break; } \
1014 st = pxsltNextImport(st); \
1017 #undef XSLT_GET_IMPORT_INT
1018 #define XSLT_GET_IMPORT_INT(res, style, name) { \
1019 xsltStylesheetPtr st = style; \
1020 res = -1; \
1021 while (st != NULL) { \
1022 if (st->name != -1) { res = st->name; break; } \
1023 st = pxsltNextImport(st); \
1026 static void transform_write_xmldecl(xmlDocPtr result, xsltStylesheetPtr style, BOOL omit_encoding, xmlOutputBufferPtr output)
1028 int omit_xmldecl, standalone;
1030 XSLT_GET_IMPORT_INT(omit_xmldecl, style, omitXmlDeclaration);
1031 if (omit_xmldecl == 1) return;
1033 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1035 xmlOutputBufferWriteString(output, "<?xml version=");
1036 if (result->version)
1038 xmlOutputBufferWriteString(output, "\"");
1039 xmlOutputBufferWriteString(output, (const char *)result->version);
1040 xmlOutputBufferWriteString(output, "\"");
1042 else
1043 xmlOutputBufferWriteString(output, "\"1.0\"");
1045 if (!omit_encoding)
1047 const xmlChar *encoding;
1049 /* default encoding is UTF-16 */
1050 XSLT_GET_IMPORT_PTR(encoding, style, encoding);
1051 xmlOutputBufferWriteString(output, " encoding=");
1052 xmlOutputBufferWriteString(output, "\"");
1053 xmlOutputBufferWriteString(output, encoding ? (const char *)encoding : "UTF-16");
1054 xmlOutputBufferWriteString(output, "\"");
1057 /* standalone attribute */
1058 if (standalone != -1)
1059 xmlOutputBufferWriteString(output, standalone == 0 ? " standalone=\"no\"" : " standalone=\"yes\"");
1061 xmlOutputBufferWriteString(output, "?>");
1064 static void htmldtd_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc)
1066 xmlDtdPtr cur = doc->intSubset;
1068 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
1069 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1070 if (cur->ExternalID)
1072 xmlOutputBufferWriteString(buf, " PUBLIC ");
1073 xml_write_quotedstring(buf, cur->ExternalID);
1074 if (cur->SystemID)
1076 xmlOutputBufferWriteString(buf, " ");
1077 xml_write_quotedstring(buf, cur->SystemID);
1080 else if (cur->SystemID)
1082 xmlOutputBufferWriteString(buf, " SYSTEM ");
1083 xml_write_quotedstring(buf, cur->SystemID);
1085 xmlOutputBufferWriteString(buf, ">\n");
1088 /* Duplicates htmlDocContentDumpFormatOutput() the way we need it - doesn't add trailing newline. */
1089 static void htmldoc_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc, const char *encoding, int format)
1091 xmlElementType type;
1093 /* force HTML output */
1094 type = doc->type;
1095 doc->type = XML_HTML_DOCUMENT_NODE;
1096 if (doc->intSubset)
1097 htmldtd_dumpcontent(buf, doc);
1098 if (doc->children) {
1099 xmlNodePtr cur = doc->children;
1100 while (cur) {
1101 htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
1102 cur = cur->next;
1105 doc->type = type;
1108 static inline BOOL transform_is_empty_resultdoc(xmlDocPtr result)
1110 return !result->children || ((result->children->type == XML_DTD_NODE) && !result->children->next);
1113 static inline BOOL transform_is_valid_method(xsltStylesheetPtr style)
1115 return !style->methodURI || !(style->method && xmlStrEqual(style->method, (const xmlChar *)"xhtml"));
1118 /* Helper to write transformation result to specified output buffer. */
1119 static HRESULT node_transform_write(xsltStylesheetPtr style, xmlDocPtr result, BOOL omit_encoding, const char *encoding, xmlOutputBufferPtr output)
1121 const xmlChar *method;
1122 int indent;
1124 if (!transform_is_valid_method(style))
1126 ERR("unknown output method\n");
1127 return E_FAIL;
1130 XSLT_GET_IMPORT_PTR(method, style, method)
1131 XSLT_GET_IMPORT_INT(indent, style, indent);
1133 if (!method && (result->type == XML_HTML_DOCUMENT_NODE))
1134 method = (const xmlChar *) "html";
1136 if (method && xmlStrEqual(method, (const xmlChar *)"html"))
1138 htmlSetMetaEncoding(result, (const xmlChar *)encoding);
1139 if (indent == -1)
1140 indent = 1;
1141 htmldoc_dumpcontent(output, result, (const char*)encoding, indent);
1143 else if (method && xmlStrEqual(method, (const xmlChar *)"xhtml"))
1145 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1146 htmlDocContentDumpOutput(output, result, encoding);
1148 else if (method && xmlStrEqual(method, (const xmlChar *)"text"))
1149 transform_write_text(result, style, output);
1150 else
1152 transform_write_xmldecl(result, style, omit_encoding, output);
1154 if (result->children)
1156 xmlNodePtr child = result->children;
1158 while (child)
1160 xmlNodeDumpOutput(output, result, child, 0, indent == 1, encoding);
1161 if (indent && ((child->type == XML_DTD_NODE) || ((child->type == XML_COMMENT_NODE) && child->next)))
1162 xmlOutputBufferWriteString(output, "\r\n");
1163 child = child->next;
1168 xmlOutputBufferFlush(output);
1169 return S_OK;
1172 /* For BSTR output is always UTF-16, without 'encoding' attribute */
1173 static HRESULT node_transform_write_to_bstr(xsltStylesheetPtr style, xmlDocPtr result, BSTR *str)
1175 HRESULT hr = S_OK;
1177 if (transform_is_empty_resultdoc(result))
1178 *str = SysAllocStringLen(NULL, 0);
1179 else
1181 xmlOutputBufferPtr output = xmlAllocOutputBuffer(xmlFindCharEncodingHandler("UTF-16"));
1182 const xmlChar *content;
1183 size_t len;
1185 *str = NULL;
1186 if (!output)
1187 return E_OUTOFMEMORY;
1189 hr = node_transform_write(style, result, TRUE, "UTF-16", output);
1190 #ifdef LIBXML2_NEW_BUFFER
1191 content = xmlBufContent(output->conv);
1192 len = xmlBufUse(output->conv);
1193 #else
1194 content = xmlBufferContent(output->conv);
1195 len = xmlBufferLength(output->conv);
1196 #endif
1197 /* UTF-16 encoder places UTF-16 bom, we don't need it for BSTR */
1198 content += sizeof(WCHAR);
1199 *str = SysAllocStringLen((WCHAR*)content, len/sizeof(WCHAR) - 1);
1200 xmlOutputBufferClose(output);
1203 return *str ? hr : E_OUTOFMEMORY;
1206 static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr result, IStream *stream)
1208 static const xmlChar *utf16 = (const xmlChar*)"UTF-16";
1209 xmlOutputBufferPtr output;
1210 const xmlChar *encoding;
1211 HRESULT hr;
1213 if (transform_is_empty_resultdoc(result))
1215 WARN("empty result document\n");
1216 return S_OK;
1219 if (style->methodURI && (!style->method || !xmlStrEqual(style->method, (const xmlChar *) "xhtml")))
1221 ERR("unknown output method\n");
1222 return E_FAIL;
1225 /* default encoding is UTF-16 */
1226 XSLT_GET_IMPORT_PTR(encoding, style, encoding);
1227 if (!encoding)
1228 encoding = utf16;
1230 output = xmlOutputBufferCreateIO(transform_to_stream_write, NULL, stream, xmlFindCharEncodingHandler((const char*)encoding));
1231 if (!output)
1232 return E_OUTOFMEMORY;
1234 hr = node_transform_write(style, result, FALSE, (const char*)encoding, output);
1235 xmlOutputBufferClose(output);
1236 return hr;
1239 #endif
1241 HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p,
1242 IStream *stream, const struct xslprocessor_params *params)
1244 #ifdef SONAME_LIBXSLT
1245 xsltStylesheetPtr xsltSS;
1246 HRESULT hr = S_OK;
1247 xmlnode *sheet;
1249 if (!libxslt_handle) return E_NOTIMPL;
1250 if (!stylesheet || !p) return E_INVALIDARG;
1252 *p = NULL;
1254 sheet = get_node_obj(stylesheet);
1255 if(!sheet) return E_FAIL;
1257 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
1258 if(xsltSS)
1260 const char **xslparams = NULL;
1261 xmlDocPtr result;
1262 unsigned int i;
1264 /* convert our parameter list to libxml2 format */
1265 if (params && params->count)
1267 struct xslprocessor_par *par;
1269 i = 0;
1270 xslparams = heap_alloc((params->count*2 + 1)*sizeof(char*));
1271 LIST_FOR_EACH_ENTRY(par, &params->list, struct xslprocessor_par, entry)
1273 xslparams[i++] = (char*)xmlchar_from_wchar(par->name);
1274 xslparams[i++] = (char*)xmlchar_from_wchar(par->value);
1276 xslparams[i] = NULL;
1279 if (xslparams)
1281 xsltTransformContextPtr ctxt = pxsltNewTransformContext(xsltSS, This->node->doc);
1283 /* push parameters to user context */
1284 pxsltQuoteUserParams(ctxt, xslparams);
1285 result = pxsltApplyStylesheetUser(xsltSS, This->node->doc, NULL, NULL, NULL, ctxt);
1286 pxsltFreeTransformContext(ctxt);
1288 for (i = 0; i < params->count*2; i++)
1289 heap_free((char*)xslparams[i]);
1290 heap_free(xslparams);
1292 else
1293 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1295 if (result)
1297 if (stream)
1298 hr = node_transform_write_to_stream(xsltSS, result, stream);
1299 else
1300 hr = node_transform_write_to_bstr(xsltSS, result, p);
1301 xmlFreeDoc(result);
1303 /* libxslt "helpfully" frees the XML document the stylesheet was
1304 generated from, too */
1305 xsltSS->doc = NULL;
1306 pxsltFreeStylesheet(xsltSS);
1309 if(!*p) *p = SysAllocStringLen(NULL, 0);
1311 return hr;
1312 #else
1313 ERR_(winediag)("libxslt headers were not found at compile time. Expect problems.\n");
1315 return E_NOTIMPL;
1316 #endif
1319 HRESULT node_transform_node(const xmlnode *node, IXMLDOMNode *stylesheet, BSTR *p)
1321 return node_transform_node_params(node, stylesheet, p, NULL, NULL);
1324 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1326 xmlChar* str;
1327 HRESULT hr;
1329 if (!query || !nodes) return E_INVALIDARG;
1331 str = xmlchar_from_wchar(query);
1332 hr = create_selection(This->node, str, nodes);
1333 heap_free(str);
1335 return hr;
1338 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1340 IXMLDOMNodeList *list;
1341 HRESULT hr;
1343 hr = node_select_nodes(This, query, &list);
1344 if (hr == S_OK)
1346 hr = IXMLDOMNodeList_nextNode(list, node);
1347 IXMLDOMNodeList_Release(list);
1349 return hr;
1352 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1354 xmlNsPtr ns = This->node->ns;
1356 if(!namespaceURI)
1357 return E_INVALIDARG;
1359 *namespaceURI = NULL;
1361 if (ns && ns->href)
1362 *namespaceURI = bstr_from_xmlChar(ns->href);
1364 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1366 return *namespaceURI ? S_OK : S_FALSE;
1369 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1371 xmlNsPtr ns = This->node->ns;
1373 if (!prefix) return E_INVALIDARG;
1375 *prefix = NULL;
1377 if (ns && ns->prefix)
1378 *prefix = bstr_from_xmlChar(ns->prefix);
1380 TRACE("prefix: %s\n", debugstr_w(*prefix));
1382 return *prefix ? S_OK : S_FALSE;
1385 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1387 if (!name) return E_INVALIDARG;
1389 *name = bstr_from_xmlChar(This->node->name);
1390 if (!*name) return E_OUTOFMEMORY;
1392 TRACE("returning %s\n", debugstr_w(*name));
1394 return S_OK;
1397 /* _private field holds a number of COM instances spawned from this libxml2 node */
1398 static void xmlnode_add_ref(xmlNodePtr node)
1400 if (node->type == XML_DOCUMENT_NODE) return;
1401 InterlockedIncrement((LONG*)&node->_private);
1404 static void xmlnode_release(xmlNodePtr node)
1406 if (node->type == XML_DOCUMENT_NODE) return;
1407 InterlockedDecrement((LONG*)&node->_private);
1410 void destroy_xmlnode(xmlnode *This)
1412 if(This->node)
1414 xmlnode_release(This->node);
1415 xmldoc_release(This->node->doc);
1419 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1421 if(node)
1423 xmlnode_add_ref(node);
1424 xmldoc_add_ref(node->doc);
1427 This->node = node;
1428 This->iface = node_iface;
1429 This->parent = NULL;
1431 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1434 typedef struct {
1435 xmlnode node;
1436 IXMLDOMNode IXMLDOMNode_iface;
1437 LONG ref;
1438 } unknode;
1440 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1442 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1445 static HRESULT WINAPI unknode_QueryInterface(
1446 IXMLDOMNode *iface,
1447 REFIID riid,
1448 void** ppvObject )
1450 unknode *This = unknode_from_IXMLDOMNode( iface );
1452 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1454 if (IsEqualGUID(riid, &IID_IUnknown)) {
1455 *ppvObject = iface;
1456 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1457 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1458 *ppvObject = &This->IXMLDOMNode_iface;
1459 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1460 return *ppvObject ? S_OK : E_NOINTERFACE;
1461 }else {
1462 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1463 *ppvObject = NULL;
1464 return E_NOINTERFACE;
1467 IUnknown_AddRef((IUnknown*)*ppvObject);
1468 return S_OK;
1471 static ULONG WINAPI unknode_AddRef(
1472 IXMLDOMNode *iface )
1474 unknode *This = unknode_from_IXMLDOMNode( iface );
1476 return InterlockedIncrement(&This->ref);
1479 static ULONG WINAPI unknode_Release(
1480 IXMLDOMNode *iface )
1482 unknode *This = unknode_from_IXMLDOMNode( iface );
1483 LONG ref;
1485 ref = InterlockedDecrement( &This->ref );
1486 if(!ref) {
1487 destroy_xmlnode(&This->node);
1488 heap_free(This);
1491 return ref;
1494 static HRESULT WINAPI unknode_GetTypeInfoCount(
1495 IXMLDOMNode *iface,
1496 UINT* pctinfo )
1498 unknode *This = unknode_from_IXMLDOMNode( iface );
1500 TRACE("(%p)->(%p)\n", This, pctinfo);
1502 *pctinfo = 1;
1504 return S_OK;
1507 static HRESULT WINAPI unknode_GetTypeInfo(
1508 IXMLDOMNode *iface,
1509 UINT iTInfo,
1510 LCID lcid,
1511 ITypeInfo** ppTInfo )
1513 unknode *This = unknode_from_IXMLDOMNode( iface );
1514 HRESULT hr;
1516 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1518 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1520 return hr;
1523 static HRESULT WINAPI unknode_GetIDsOfNames(
1524 IXMLDOMNode *iface,
1525 REFIID riid,
1526 LPOLESTR* rgszNames,
1527 UINT cNames,
1528 LCID lcid,
1529 DISPID* rgDispId )
1531 unknode *This = unknode_from_IXMLDOMNode( iface );
1533 ITypeInfo *typeinfo;
1534 HRESULT hr;
1536 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1537 lcid, rgDispId);
1539 if(!rgszNames || cNames == 0 || !rgDispId)
1540 return E_INVALIDARG;
1542 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1543 if(SUCCEEDED(hr))
1545 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1546 ITypeInfo_Release(typeinfo);
1549 return hr;
1552 static HRESULT WINAPI unknode_Invoke(
1553 IXMLDOMNode *iface,
1554 DISPID dispIdMember,
1555 REFIID riid,
1556 LCID lcid,
1557 WORD wFlags,
1558 DISPPARAMS* pDispParams,
1559 VARIANT* pVarResult,
1560 EXCEPINFO* pExcepInfo,
1561 UINT* puArgErr )
1563 unknode *This = unknode_from_IXMLDOMNode( iface );
1564 ITypeInfo *typeinfo;
1565 HRESULT hr;
1567 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1568 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1570 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1571 if(SUCCEEDED(hr))
1573 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1574 pVarResult, pExcepInfo, puArgErr);
1575 ITypeInfo_Release(typeinfo);
1578 return hr;
1581 static HRESULT WINAPI unknode_get_nodeName(
1582 IXMLDOMNode *iface,
1583 BSTR* p )
1585 unknode *This = unknode_from_IXMLDOMNode( iface );
1587 FIXME("(%p)->(%p)\n", This, p);
1589 return node_get_nodeName(&This->node, p);
1592 static HRESULT WINAPI unknode_get_nodeValue(
1593 IXMLDOMNode *iface,
1594 VARIANT* value)
1596 unknode *This = unknode_from_IXMLDOMNode( iface );
1598 FIXME("(%p)->(%p)\n", This, value);
1600 if(!value)
1601 return E_INVALIDARG;
1603 V_VT(value) = VT_NULL;
1604 return S_FALSE;
1607 static HRESULT WINAPI unknode_put_nodeValue(
1608 IXMLDOMNode *iface,
1609 VARIANT value)
1611 unknode *This = unknode_from_IXMLDOMNode( iface );
1612 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1613 return E_FAIL;
1616 static HRESULT WINAPI unknode_get_nodeType(
1617 IXMLDOMNode *iface,
1618 DOMNodeType* domNodeType )
1620 unknode *This = unknode_from_IXMLDOMNode( iface );
1622 FIXME("(%p)->(%p)\n", This, domNodeType);
1624 *domNodeType = This->node.node->type;
1625 return S_OK;
1628 static HRESULT WINAPI unknode_get_parentNode(
1629 IXMLDOMNode *iface,
1630 IXMLDOMNode** parent )
1632 unknode *This = unknode_from_IXMLDOMNode( iface );
1633 FIXME("(%p)->(%p)\n", This, parent);
1634 if (!parent) return E_INVALIDARG;
1635 *parent = NULL;
1636 return S_FALSE;
1639 static HRESULT WINAPI unknode_get_childNodes(
1640 IXMLDOMNode *iface,
1641 IXMLDOMNodeList** outList)
1643 unknode *This = unknode_from_IXMLDOMNode( iface );
1645 TRACE("(%p)->(%p)\n", This, outList);
1647 return node_get_child_nodes(&This->node, outList);
1650 static HRESULT WINAPI unknode_get_firstChild(
1651 IXMLDOMNode *iface,
1652 IXMLDOMNode** domNode)
1654 unknode *This = unknode_from_IXMLDOMNode( iface );
1656 TRACE("(%p)->(%p)\n", This, domNode);
1658 return node_get_first_child(&This->node, domNode);
1661 static HRESULT WINAPI unknode_get_lastChild(
1662 IXMLDOMNode *iface,
1663 IXMLDOMNode** domNode)
1665 unknode *This = unknode_from_IXMLDOMNode( iface );
1667 TRACE("(%p)->(%p)\n", This, domNode);
1669 return node_get_last_child(&This->node, domNode);
1672 static HRESULT WINAPI unknode_get_previousSibling(
1673 IXMLDOMNode *iface,
1674 IXMLDOMNode** domNode)
1676 unknode *This = unknode_from_IXMLDOMNode( iface );
1678 TRACE("(%p)->(%p)\n", This, domNode);
1680 return node_get_previous_sibling(&This->node, domNode);
1683 static HRESULT WINAPI unknode_get_nextSibling(
1684 IXMLDOMNode *iface,
1685 IXMLDOMNode** domNode)
1687 unknode *This = unknode_from_IXMLDOMNode( iface );
1689 TRACE("(%p)->(%p)\n", This, domNode);
1691 return node_get_next_sibling(&This->node, domNode);
1694 static HRESULT WINAPI unknode_get_attributes(
1695 IXMLDOMNode *iface,
1696 IXMLDOMNamedNodeMap** attributeMap)
1698 unknode *This = unknode_from_IXMLDOMNode( iface );
1700 FIXME("(%p)->(%p)\n", This, attributeMap);
1702 return return_null_ptr((void**)attributeMap);
1705 static HRESULT WINAPI unknode_insertBefore(
1706 IXMLDOMNode *iface,
1707 IXMLDOMNode* newNode, VARIANT refChild,
1708 IXMLDOMNode** outOldNode)
1710 unknode *This = unknode_from_IXMLDOMNode( iface );
1712 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1714 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1717 static HRESULT WINAPI unknode_replaceChild(
1718 IXMLDOMNode *iface,
1719 IXMLDOMNode* newNode,
1720 IXMLDOMNode* oldNode,
1721 IXMLDOMNode** outOldNode)
1723 unknode *This = unknode_from_IXMLDOMNode( iface );
1725 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1727 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1730 static HRESULT WINAPI unknode_removeChild(
1731 IXMLDOMNode *iface,
1732 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1734 unknode *This = unknode_from_IXMLDOMNode( iface );
1735 return node_remove_child(&This->node, domNode, oldNode);
1738 static HRESULT WINAPI unknode_appendChild(
1739 IXMLDOMNode *iface,
1740 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1742 unknode *This = unknode_from_IXMLDOMNode( iface );
1743 return node_append_child(&This->node, newNode, outNewNode);
1746 static HRESULT WINAPI unknode_hasChildNodes(
1747 IXMLDOMNode *iface,
1748 VARIANT_BOOL* pbool)
1750 unknode *This = unknode_from_IXMLDOMNode( iface );
1751 return node_has_childnodes(&This->node, pbool);
1754 static HRESULT WINAPI unknode_get_ownerDocument(
1755 IXMLDOMNode *iface,
1756 IXMLDOMDocument** domDocument)
1758 unknode *This = unknode_from_IXMLDOMNode( iface );
1759 return node_get_owner_doc(&This->node, domDocument);
1762 static HRESULT WINAPI unknode_cloneNode(
1763 IXMLDOMNode *iface,
1764 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1766 unknode *This = unknode_from_IXMLDOMNode( iface );
1767 return node_clone(&This->node, pbool, outNode );
1770 static HRESULT WINAPI unknode_get_nodeTypeString(
1771 IXMLDOMNode *iface,
1772 BSTR* p)
1774 unknode *This = unknode_from_IXMLDOMNode( iface );
1776 FIXME("(%p)->(%p)\n", This, p);
1778 return node_get_nodeName(&This->node, p);
1781 static HRESULT WINAPI unknode_get_text(
1782 IXMLDOMNode *iface,
1783 BSTR* p)
1785 unknode *This = unknode_from_IXMLDOMNode( iface );
1786 return node_get_text(&This->node, p);
1789 static HRESULT WINAPI unknode_put_text(
1790 IXMLDOMNode *iface,
1791 BSTR p)
1793 unknode *This = unknode_from_IXMLDOMNode( iface );
1794 return node_put_text(&This->node, p);
1797 static HRESULT WINAPI unknode_get_specified(
1798 IXMLDOMNode *iface,
1799 VARIANT_BOOL* isSpecified)
1801 unknode *This = unknode_from_IXMLDOMNode( iface );
1802 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1803 *isSpecified = VARIANT_TRUE;
1804 return S_OK;
1807 static HRESULT WINAPI unknode_get_definition(
1808 IXMLDOMNode *iface,
1809 IXMLDOMNode** definitionNode)
1811 unknode *This = unknode_from_IXMLDOMNode( iface );
1812 FIXME("(%p)->(%p)\n", This, definitionNode);
1813 return E_NOTIMPL;
1816 static HRESULT WINAPI unknode_get_nodeTypedValue(
1817 IXMLDOMNode *iface,
1818 VARIANT* var1)
1820 unknode *This = unknode_from_IXMLDOMNode( iface );
1821 FIXME("(%p)->(%p)\n", This, var1);
1822 return return_null_var(var1);
1825 static HRESULT WINAPI unknode_put_nodeTypedValue(
1826 IXMLDOMNode *iface,
1827 VARIANT typedValue)
1829 unknode *This = unknode_from_IXMLDOMNode( iface );
1830 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1831 return E_NOTIMPL;
1834 static HRESULT WINAPI unknode_get_dataType(
1835 IXMLDOMNode *iface,
1836 VARIANT* var1)
1838 unknode *This = unknode_from_IXMLDOMNode( iface );
1839 TRACE("(%p)->(%p)\n", This, var1);
1840 return return_null_var(var1);
1843 static HRESULT WINAPI unknode_put_dataType(
1844 IXMLDOMNode *iface,
1845 BSTR p)
1847 unknode *This = unknode_from_IXMLDOMNode( iface );
1849 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1851 if(!p)
1852 return E_INVALIDARG;
1854 return E_FAIL;
1857 static HRESULT WINAPI unknode_get_xml(
1858 IXMLDOMNode *iface,
1859 BSTR* p)
1861 unknode *This = unknode_from_IXMLDOMNode( iface );
1863 FIXME("(%p)->(%p)\n", This, p);
1865 return node_get_xml(&This->node, FALSE, p);
1868 static HRESULT WINAPI unknode_transformNode(
1869 IXMLDOMNode *iface,
1870 IXMLDOMNode* domNode, BSTR* p)
1872 unknode *This = unknode_from_IXMLDOMNode( iface );
1873 return node_transform_node(&This->node, domNode, p);
1876 static HRESULT WINAPI unknode_selectNodes(
1877 IXMLDOMNode *iface,
1878 BSTR p, IXMLDOMNodeList** outList)
1880 unknode *This = unknode_from_IXMLDOMNode( iface );
1881 return node_select_nodes(&This->node, p, outList);
1884 static HRESULT WINAPI unknode_selectSingleNode(
1885 IXMLDOMNode *iface,
1886 BSTR p, IXMLDOMNode** outNode)
1888 unknode *This = unknode_from_IXMLDOMNode( iface );
1889 return node_select_singlenode(&This->node, p, outNode);
1892 static HRESULT WINAPI unknode_get_parsed(
1893 IXMLDOMNode *iface,
1894 VARIANT_BOOL* isParsed)
1896 unknode *This = unknode_from_IXMLDOMNode( iface );
1897 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1898 *isParsed = VARIANT_TRUE;
1899 return S_OK;
1902 static HRESULT WINAPI unknode_get_namespaceURI(
1903 IXMLDOMNode *iface,
1904 BSTR* p)
1906 unknode *This = unknode_from_IXMLDOMNode( iface );
1907 TRACE("(%p)->(%p)\n", This, p);
1908 return node_get_namespaceURI(&This->node, p);
1911 static HRESULT WINAPI unknode_get_prefix(
1912 IXMLDOMNode *iface,
1913 BSTR* p)
1915 unknode *This = unknode_from_IXMLDOMNode( iface );
1916 return node_get_prefix(&This->node, p);
1919 static HRESULT WINAPI unknode_get_baseName(
1920 IXMLDOMNode *iface,
1921 BSTR* p)
1923 unknode *This = unknode_from_IXMLDOMNode( iface );
1924 return node_get_base_name(&This->node, p);
1927 static HRESULT WINAPI unknode_transformNodeToObject(
1928 IXMLDOMNode *iface,
1929 IXMLDOMNode* domNode, VARIANT var1)
1931 unknode *This = unknode_from_IXMLDOMNode( iface );
1932 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1933 return E_NOTIMPL;
1936 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1938 unknode_QueryInterface,
1939 unknode_AddRef,
1940 unknode_Release,
1941 unknode_GetTypeInfoCount,
1942 unknode_GetTypeInfo,
1943 unknode_GetIDsOfNames,
1944 unknode_Invoke,
1945 unknode_get_nodeName,
1946 unknode_get_nodeValue,
1947 unknode_put_nodeValue,
1948 unknode_get_nodeType,
1949 unknode_get_parentNode,
1950 unknode_get_childNodes,
1951 unknode_get_firstChild,
1952 unknode_get_lastChild,
1953 unknode_get_previousSibling,
1954 unknode_get_nextSibling,
1955 unknode_get_attributes,
1956 unknode_insertBefore,
1957 unknode_replaceChild,
1958 unknode_removeChild,
1959 unknode_appendChild,
1960 unknode_hasChildNodes,
1961 unknode_get_ownerDocument,
1962 unknode_cloneNode,
1963 unknode_get_nodeTypeString,
1964 unknode_get_text,
1965 unknode_put_text,
1966 unknode_get_specified,
1967 unknode_get_definition,
1968 unknode_get_nodeTypedValue,
1969 unknode_put_nodeTypedValue,
1970 unknode_get_dataType,
1971 unknode_put_dataType,
1972 unknode_get_xml,
1973 unknode_transformNode,
1974 unknode_selectNodes,
1975 unknode_selectSingleNode,
1976 unknode_get_parsed,
1977 unknode_get_namespaceURI,
1978 unknode_get_prefix,
1979 unknode_get_baseName,
1980 unknode_transformNodeToObject
1983 IXMLDOMNode *create_node( xmlNodePtr node )
1985 IUnknown *pUnk;
1986 IXMLDOMNode *ret;
1987 HRESULT hr;
1989 if ( !node )
1990 return NULL;
1992 TRACE("type %d\n", node->type);
1993 switch(node->type)
1995 case XML_ELEMENT_NODE:
1996 pUnk = create_element( node );
1997 break;
1998 case XML_ATTRIBUTE_NODE:
1999 pUnk = create_attribute( node );
2000 break;
2001 case XML_TEXT_NODE:
2002 pUnk = create_text( node );
2003 break;
2004 case XML_CDATA_SECTION_NODE:
2005 pUnk = create_cdata( node );
2006 break;
2007 case XML_ENTITY_REF_NODE:
2008 pUnk = create_doc_entity_ref( node );
2009 break;
2010 case XML_PI_NODE:
2011 pUnk = create_pi( node );
2012 break;
2013 case XML_COMMENT_NODE:
2014 pUnk = create_comment( node );
2015 break;
2016 case XML_DOCUMENT_NODE:
2017 pUnk = create_domdoc( node );
2018 break;
2019 case XML_DOCUMENT_FRAG_NODE:
2020 pUnk = create_doc_fragment( node );
2021 break;
2022 case XML_DTD_NODE:
2023 pUnk = create_doc_type( node );
2024 break;
2025 default: {
2026 unknode *new_node;
2028 FIXME("only creating basic node for type %d\n", node->type);
2030 new_node = heap_alloc(sizeof(unknode));
2031 if(!new_node)
2032 return NULL;
2034 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
2035 new_node->ref = 1;
2036 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
2037 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
2041 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
2042 IUnknown_Release(pUnk);
2043 if(FAILED(hr)) return NULL;
2044 return ret;
2046 #endif