msxml3: Handle NULL parameter in IXMLDOMElement::get_ownerDocument().
[wine/multimedia.git] / dlls / msxml3 / node.c
blob90b5bde61d95b78dd6bb0a659947b3e97d304fac
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 #ifdef HAVE_LIBXML2
58 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
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;
482 /* unlink from current parent first */
483 if(node_obj->parent)
485 hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL);
486 if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node);
488 doc = node_obj->node->doc;
490 if(before)
492 xmlnode *before_node_obj = get_node_obj(before);
494 /* refs count including subtree */
495 if (doc != before_node_obj->node->doc)
496 refcount = xmlnode_get_inst_cnt(node_obj);
498 if (refcount) xmldoc_add_refs(before_node_obj->node->doc, refcount);
499 xmlAddPrevSibling(before_node_obj->node, node_obj->node);
500 if (refcount) xmldoc_release_refs(doc, refcount);
501 node_obj->parent = This->parent;
503 else
505 if (doc != This->node->doc)
506 refcount = xmlnode_get_inst_cnt(node_obj);
508 if (refcount) xmldoc_add_refs(This->node->doc, refcount);
509 /* xmlAddChild doesn't unlink node from previous parent */
510 xmlUnlinkNode(node_obj->node);
511 xmlAddChild(This->node, node_obj->node);
512 if (refcount) xmldoc_release_refs(doc, refcount);
513 node_obj->parent = This->iface;
516 if(ret)
518 IXMLDOMNode_AddRef(new_child);
519 *ret = new_child;
522 TRACE("ret S_OK\n");
523 return S_OK;
526 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
527 IXMLDOMNode **ret)
529 xmlnode *old_child, *new_child;
530 xmlDocPtr leaving_doc;
531 xmlNode *my_ancestor;
532 int refcount = 0;
534 /* Do not believe any documentation telling that newChild == NULL
535 means removal. It does certainly *not* apply to msxml3! */
536 if(!newChild || !oldChild)
537 return E_INVALIDARG;
539 if(ret)
540 *ret = NULL;
542 old_child = get_node_obj(oldChild);
543 if(!old_child) return E_FAIL;
545 if(old_child->node->parent != This->node)
547 WARN("childNode %p is not a child of %p\n", oldChild, This);
548 return E_INVALIDARG;
551 new_child = get_node_obj(newChild);
552 if(!new_child) return E_FAIL;
554 my_ancestor = This->node;
555 while(my_ancestor)
557 if(my_ancestor == new_child->node)
559 WARN("tried to create loop\n");
560 return E_FAIL;
562 my_ancestor = my_ancestor->parent;
565 if(!new_child->node->parent)
566 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
567 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
569 leaving_doc = new_child->node->doc;
571 if (leaving_doc != old_child->node->doc)
572 refcount = xmlnode_get_inst_cnt(new_child);
574 if (refcount) xmldoc_add_refs(old_child->node->doc, refcount);
575 xmlReplaceNode(old_child->node, new_child->node);
576 if (refcount) xmldoc_release_refs(leaving_doc, refcount);
577 new_child->parent = old_child->parent;
578 old_child->parent = NULL;
580 xmldoc_add_orphan(old_child->node->doc, old_child->node);
582 if(ret)
584 IXMLDOMNode_AddRef(oldChild);
585 *ret = oldChild;
588 return S_OK;
591 HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild)
593 xmlnode *child_node;
595 if(!child) return E_INVALIDARG;
597 if(oldChild)
598 *oldChild = NULL;
600 child_node = get_node_obj(child);
601 if(!child_node) return E_FAIL;
603 if(child_node->node->parent != This->node)
605 WARN("childNode %p is not a child of %p\n", child, This);
606 return E_INVALIDARG;
609 xmlUnlinkNode(child_node->node);
610 child_node->parent = NULL;
611 xmldoc_add_orphan(child_node->node->doc, child_node->node);
613 if(oldChild)
615 IXMLDOMNode_AddRef(child);
616 *oldChild = child;
619 return S_OK;
622 HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild)
624 DOMNodeType type;
625 VARIANT var;
626 HRESULT hr;
628 if (!child)
629 return E_INVALIDARG;
631 hr = IXMLDOMNode_get_nodeType(child, &type);
632 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
633 if (outChild) *outChild = NULL;
634 return E_FAIL;
637 VariantInit(&var);
638 return IXMLDOMNode_insertBefore(This->iface, child, var, outChild);
641 HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret)
643 if (!ret) return E_INVALIDARG;
645 if (!This->node->children)
647 *ret = VARIANT_FALSE;
648 return S_FALSE;
651 *ret = VARIANT_TRUE;
652 return S_OK;
655 HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc)
657 if(!doc)
658 return E_INVALIDARG;
659 return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc);
662 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
664 IXMLDOMNode *node;
665 xmlNodePtr clone;
667 if(!cloneNode) return E_INVALIDARG;
669 clone = xmlCopyNode(This->node, deep ? 1 : 2);
670 if (clone)
672 xmlSetTreeDoc(clone, This->node->doc);
673 xmldoc_add_orphan(clone->doc, clone);
675 node = create_node(clone);
676 if (!node)
678 ERR("Copy failed\n");
679 xmldoc_remove_orphan(clone->doc, clone);
680 xmlFreeNode(clone);
681 return E_FAIL;
684 *cloneNode = node;
686 else
688 ERR("Copy failed\n");
689 return E_FAIL;
692 return S_OK;
695 static inline xmlChar* trim_whitespace(xmlChar* str)
697 xmlChar* ret = str;
698 int len;
700 if (!str)
701 return NULL;
703 while (*ret && isspace(*ret))
704 ++ret;
705 len = xmlStrlen(ret);
706 if (len)
707 while (isspace(ret[len-1])) --len;
709 ret = xmlStrndup(ret, len);
710 xmlFree(str);
711 return ret;
714 static xmlChar* do_get_text(xmlNodePtr node)
716 xmlNodePtr child;
717 xmlChar* str;
718 BOOL preserving = is_preserving_whitespace(node);
720 if (!node->children)
722 str = xmlNodeGetContent(node);
724 else
726 xmlElementType prev_type = XML_TEXT_NODE;
727 xmlChar* tmp;
728 str = xmlStrdup(BAD_CAST "");
729 for (child = node->children; child != NULL; child = child->next)
731 switch (child->type)
733 case XML_ELEMENT_NODE:
734 tmp = do_get_text(child);
735 break;
736 case XML_TEXT_NODE:
737 case XML_CDATA_SECTION_NODE:
738 case XML_ENTITY_REF_NODE:
739 case XML_ENTITY_NODE:
740 tmp = xmlNodeGetContent(child);
741 break;
742 default:
743 tmp = NULL;
744 break;
747 if (tmp)
749 if (*tmp)
751 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
752 str = xmlStrcat(str, BAD_CAST " ");
753 str = xmlStrcat(str, tmp);
754 prev_type = child->type;
756 xmlFree(tmp);
761 switch (node->type)
763 case XML_ELEMENT_NODE:
764 case XML_TEXT_NODE:
765 case XML_ENTITY_REF_NODE:
766 case XML_ENTITY_NODE:
767 case XML_DOCUMENT_NODE:
768 case XML_DOCUMENT_FRAG_NODE:
769 if (!preserving)
770 str = trim_whitespace(str);
771 break;
772 default:
773 break;
776 return str;
779 HRESULT node_get_text(const xmlnode *This, BSTR *text)
781 BSTR str = NULL;
782 xmlChar *content;
784 if (!text) return E_INVALIDARG;
786 content = do_get_text(This->node);
787 if (content)
789 str = bstr_from_xmlChar(content);
790 xmlFree(content);
793 /* Always return a string. */
794 if (!str) str = SysAllocStringLen( NULL, 0 );
796 TRACE("%p %s\n", This, debugstr_w(str) );
797 *text = str;
799 return S_OK;
802 HRESULT node_put_text(xmlnode *This, BSTR text)
804 xmlChar *str, *str2;
806 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
808 str = xmlchar_from_wchar(text);
810 /* Escape the string. */
811 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
812 heap_free(str);
814 xmlNodeSetContent(This->node, str2);
815 xmlFree(str2);
817 return S_OK;
820 BSTR EnsureCorrectEOL(BSTR sInput)
822 int nNum = 0;
823 BSTR sNew;
824 int nLen;
825 int i;
827 nLen = SysStringLen(sInput);
828 /* Count line endings */
829 for(i=0; i < nLen; i++)
831 if(sInput[i] == '\n')
832 nNum++;
835 TRACE("len=%d, num=%d\n", nLen, nNum);
837 /* Add linefeed as needed */
838 if(nNum > 0)
840 int nPlace = 0;
841 sNew = SysAllocStringLen(NULL, nLen + nNum);
842 for(i=0; i < nLen; i++)
844 if(sInput[i] == '\n')
846 sNew[i+nPlace] = '\r';
847 nPlace++;
849 sNew[i+nPlace] = sInput[i];
852 SysFreeString(sInput);
854 else
856 sNew = sInput;
859 TRACE("len %d\n", SysStringLen(sNew));
861 return sNew;
865 * We are trying to replicate the same behaviour as msxml by converting
866 * line endings to \r\n and using indents as \t. The problem is that msxml
867 * only formats nodes that have a line ending. Using libxml we cannot
868 * reproduce behaviour exactly.
871 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BSTR *ret)
873 xmlBufferPtr xml_buf;
874 xmlNodePtr xmldecl;
875 int size;
877 if(!ret)
878 return E_INVALIDARG;
880 *ret = NULL;
882 xml_buf = xmlBufferCreate();
883 if(!xml_buf)
884 return E_OUTOFMEMORY;
886 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
888 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
889 if(size > 0) {
890 const xmlChar *buf_content;
891 BSTR content;
893 /* Attribute Nodes return a space in front of their name */
894 buf_content = xmlBufferContent(xml_buf);
896 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
897 if(ensure_eol)
898 content = EnsureCorrectEOL(content);
900 *ret = content;
901 }else {
902 *ret = SysAllocStringLen(NULL, 0);
905 xmlBufferFree(xml_buf);
906 xmldoc_link_xmldecl( This->node->doc, xmldecl );
907 return *ret ? S_OK : E_OUTOFMEMORY;
910 #ifdef SONAME_LIBXSLT
912 /* duplicates xmlBufferWriteQuotedString() logic */
913 static void xml_write_quotedstring(xmlOutputBufferPtr buf, const xmlChar *string)
915 const xmlChar *cur, *base;
917 if (xmlStrchr(string, '\"'))
919 if (xmlStrchr(string, '\''))
921 xmlOutputBufferWrite(buf, 1, "\"");
922 base = cur = string;
924 while (*cur)
926 if (*cur == '"')
928 if (base != cur)
929 xmlOutputBufferWrite(buf, cur-base, (const char*)base);
930 xmlOutputBufferWrite(buf, 6, "&quot;");
931 cur++;
932 base = cur;
934 else
935 cur++;
937 if (base != cur)
938 xmlOutputBufferWrite(buf, cur-base, (const char*)base);
939 xmlOutputBufferWrite(buf, 1, "\"");
941 else
943 xmlOutputBufferWrite(buf, 1, "\'");
944 xmlOutputBufferWriteString(buf, (const char*)string);
945 xmlOutputBufferWrite(buf, 1, "\'");
948 else
950 xmlOutputBufferWrite(buf, 1, "\"");
951 xmlOutputBufferWriteString(buf, (const char*)string);
952 xmlOutputBufferWrite(buf, 1, "\"");
956 static int XMLCALL transform_to_stream_write(void *context, const char *buffer, int len)
958 DWORD written;
959 HRESULT hr = IStream_Write((IStream*)context, buffer, len, &written);
960 return hr == S_OK ? written : -1;
963 /* Output for method "text" */
964 static void transform_write_text(xmlDocPtr result, xsltStylesheetPtr style, xmlOutputBufferPtr output)
966 xmlNodePtr cur = result->children;
967 while (cur)
969 if (cur->type == XML_TEXT_NODE)
970 xmlOutputBufferWriteString(output, (const char*)cur->content);
972 /* skip to next node */
973 if (cur->children)
975 if ((cur->children->type != XML_ENTITY_DECL) &&
976 (cur->children->type != XML_ENTITY_REF_NODE) &&
977 (cur->children->type != XML_ENTITY_NODE))
979 cur = cur->children;
980 continue;
984 if (cur->next) {
985 cur = cur->next;
986 continue;
991 cur = cur->parent;
992 if (cur == NULL)
993 break;
994 if (cur == (xmlNodePtr) style->doc) {
995 cur = NULL;
996 break;
998 if (cur->next) {
999 cur = cur->next;
1000 break;
1002 } while (cur);
1006 #undef XSLT_GET_IMPORT_PTR
1007 #define XSLT_GET_IMPORT_PTR(res, style, name) { \
1008 xsltStylesheetPtr st = style; \
1009 res = NULL; \
1010 while (st != NULL) { \
1011 if (st->name != NULL) { res = st->name; break; } \
1012 st = pxsltNextImport(st); \
1015 #undef XSLT_GET_IMPORT_INT
1016 #define XSLT_GET_IMPORT_INT(res, style, name) { \
1017 xsltStylesheetPtr st = style; \
1018 res = -1; \
1019 while (st != NULL) { \
1020 if (st->name != -1) { res = st->name; break; } \
1021 st = pxsltNextImport(st); \
1024 static void transform_write_xmldecl(xmlDocPtr result, xsltStylesheetPtr style, BOOL omit_encoding, xmlOutputBufferPtr output)
1026 int omit_xmldecl, standalone;
1028 XSLT_GET_IMPORT_INT(omit_xmldecl, style, omitXmlDeclaration);
1029 if (omit_xmldecl == 1) return;
1031 XSLT_GET_IMPORT_INT(standalone, style, standalone);
1033 xmlOutputBufferWriteString(output, "<?xml version=");
1034 if (result->version)
1036 xmlOutputBufferWriteString(output, "\"");
1037 xmlOutputBufferWriteString(output, (const char *)result->version);
1038 xmlOutputBufferWriteString(output, "\"");
1040 else
1041 xmlOutputBufferWriteString(output, "\"1.0\"");
1043 if (!omit_encoding)
1045 const xmlChar *encoding;
1047 /* default encoding is UTF-16 */
1048 XSLT_GET_IMPORT_PTR(encoding, style, encoding);
1049 xmlOutputBufferWriteString(output, " encoding=");
1050 xmlOutputBufferWriteString(output, "\"");
1051 xmlOutputBufferWriteString(output, encoding ? (const char *)encoding : "UTF-16");
1052 xmlOutputBufferWriteString(output, "\"");
1055 /* standalone attribute */
1056 if (standalone != -1)
1057 xmlOutputBufferWriteString(output, standalone == 0 ? " standalone=\"no\"" : " standalone=\"yes\"");
1059 xmlOutputBufferWriteString(output, "?>");
1062 static void htmldtd_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc)
1064 xmlDtdPtr cur = doc->intSubset;
1066 xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
1067 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1068 if (cur->ExternalID)
1070 xmlOutputBufferWriteString(buf, " PUBLIC ");
1071 xml_write_quotedstring(buf, cur->ExternalID);
1072 if (cur->SystemID)
1074 xmlOutputBufferWriteString(buf, " ");
1075 xml_write_quotedstring(buf, cur->SystemID);
1078 else if (cur->SystemID)
1080 xmlOutputBufferWriteString(buf, " SYSTEM ");
1081 xml_write_quotedstring(buf, cur->SystemID);
1083 xmlOutputBufferWriteString(buf, ">\n");
1086 /* Duplicates htmlDocContentDumpFormatOutput() the way we need it - doesn't add trailing newline. */
1087 static void htmldoc_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc, const char *encoding, int format)
1089 xmlElementType type;
1091 /* force HTML output */
1092 type = doc->type;
1093 doc->type = XML_HTML_DOCUMENT_NODE;
1094 if (doc->intSubset)
1095 htmldtd_dumpcontent(buf, doc);
1096 if (doc->children) {
1097 xmlNodePtr cur = doc->children;
1098 while (cur) {
1099 htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
1100 cur = cur->next;
1103 doc->type = type;
1106 static inline BOOL transform_is_empty_resultdoc(xmlDocPtr result)
1108 return !result->children || ((result->children->type == XML_DTD_NODE) && !result->children->next);
1111 static inline BOOL transform_is_valid_method(xsltStylesheetPtr style)
1113 return !style->methodURI || !(style->method && xmlStrEqual(style->method, (const xmlChar *)"xhtml"));
1116 /* Helper to write transformation result to specified output buffer. */
1117 static HRESULT node_transform_write(xsltStylesheetPtr style, xmlDocPtr result, BOOL omit_encoding, const char *encoding, xmlOutputBufferPtr output)
1119 const xmlChar *method;
1120 int indent;
1122 if (!transform_is_valid_method(style))
1124 ERR("unknown output method\n");
1125 return E_FAIL;
1128 XSLT_GET_IMPORT_PTR(method, style, method)
1129 XSLT_GET_IMPORT_INT(indent, style, indent);
1131 if (!method && (result->type == XML_HTML_DOCUMENT_NODE))
1132 method = (const xmlChar *) "html";
1134 if (method && xmlStrEqual(method, (const xmlChar *)"html"))
1136 htmlSetMetaEncoding(result, (const xmlChar *)encoding);
1137 if (indent == -1)
1138 indent = 1;
1139 htmldoc_dumpcontent(output, result, (const char*)encoding, indent);
1141 else if (method && xmlStrEqual(method, (const xmlChar *)"xhtml"))
1143 htmlSetMetaEncoding(result, (const xmlChar *) encoding);
1144 htmlDocContentDumpOutput(output, result, encoding);
1146 else if (method && xmlStrEqual(method, (const xmlChar *)"text"))
1147 transform_write_text(result, style, output);
1148 else
1150 transform_write_xmldecl(result, style, omit_encoding, output);
1152 if (result->children)
1154 xmlNodePtr child = result->children;
1156 while (child)
1158 xmlNodeDumpOutput(output, result, child, 0, indent == 1, encoding);
1159 if (indent && ((child->type == XML_DTD_NODE) || ((child->type == XML_COMMENT_NODE) && child->next)))
1160 xmlOutputBufferWriteString(output, "\r\n");
1161 child = child->next;
1166 xmlOutputBufferFlush(output);
1167 return S_OK;
1170 /* For BSTR output is always UTF-16, without 'encoding' attribute */
1171 static HRESULT node_transform_write_to_bstr(xsltStylesheetPtr style, xmlDocPtr result, BSTR *str)
1173 HRESULT hr = S_OK;
1175 if (transform_is_empty_resultdoc(result))
1176 *str = SysAllocStringLen(NULL, 0);
1177 else
1179 xmlOutputBufferPtr output = xmlAllocOutputBuffer(xmlFindCharEncodingHandler("UTF-16"));
1180 const xmlChar *content;
1181 size_t len;
1183 *str = NULL;
1184 if (!output)
1185 return E_OUTOFMEMORY;
1187 hr = node_transform_write(style, result, TRUE, "UTF-16", output);
1188 #ifdef LIBXML2_NEW_BUFFER
1189 content = xmlBufContent(output->conv);
1190 len = xmlBufUse(output->conv);
1191 #else
1192 content = xmlBufferContent(output->conv);
1193 len = xmlBufferLength(output->conv);
1194 #endif
1195 /* UTF-16 encoder places UTF-16 bom, we don't need it for BSTR */
1196 content += sizeof(WCHAR);
1197 *str = SysAllocStringLen((WCHAR*)content, len/sizeof(WCHAR) - 1);
1198 xmlOutputBufferClose(output);
1201 return *str ? hr : E_OUTOFMEMORY;
1204 static HRESULT node_transform_write_to_stream(xsltStylesheetPtr style, xmlDocPtr result, IStream *stream)
1206 static const xmlChar *utf16 = (const xmlChar*)"UTF-16";
1207 xmlOutputBufferPtr output;
1208 const xmlChar *encoding;
1209 HRESULT hr;
1211 if (transform_is_empty_resultdoc(result))
1213 WARN("empty result document\n");
1214 return S_OK;
1217 if (style->methodURI && (!style->method || !xmlStrEqual(style->method, (const xmlChar *) "xhtml")))
1219 ERR("unknown output method\n");
1220 return E_FAIL;
1223 /* default encoding is UTF-16 */
1224 XSLT_GET_IMPORT_PTR(encoding, style, encoding);
1225 if (!encoding)
1226 encoding = utf16;
1228 output = xmlOutputBufferCreateIO(transform_to_stream_write, NULL, stream, xmlFindCharEncodingHandler((const char*)encoding));
1229 if (!output)
1230 return E_OUTOFMEMORY;
1232 hr = node_transform_write(style, result, FALSE, (const char*)encoding, output);
1233 xmlOutputBufferClose(output);
1234 return hr;
1237 #endif
1239 HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p,
1240 IStream *stream, const struct xslprocessor_params *params)
1242 #ifdef SONAME_LIBXSLT
1243 xsltStylesheetPtr xsltSS;
1244 HRESULT hr = S_OK;
1245 xmlnode *sheet;
1247 if (!libxslt_handle) return E_NOTIMPL;
1248 if (!stylesheet || !p) return E_INVALIDARG;
1250 *p = NULL;
1252 sheet = get_node_obj(stylesheet);
1253 if(!sheet) return E_FAIL;
1255 xsltSS = pxsltParseStylesheetDoc(sheet->node->doc);
1256 if(xsltSS)
1258 const char **xslparams = NULL;
1259 xmlDocPtr result;
1260 unsigned int i;
1262 /* convert our parameter list to libxml2 format */
1263 if (params && params->count)
1265 struct xslprocessor_par *par;
1267 i = 0;
1268 xslparams = heap_alloc((params->count*2 + 1)*sizeof(char*));
1269 LIST_FOR_EACH_ENTRY(par, &params->list, struct xslprocessor_par, entry)
1271 xslparams[i++] = (char*)xmlchar_from_wchar(par->name);
1272 xslparams[i++] = (char*)xmlchar_from_wchar(par->value);
1274 xslparams[i] = NULL;
1277 if (xslparams)
1279 xsltTransformContextPtr ctxt = pxsltNewTransformContext(xsltSS, This->node->doc);
1281 /* push parameters to user context */
1282 pxsltQuoteUserParams(ctxt, xslparams);
1283 result = pxsltApplyStylesheetUser(xsltSS, This->node->doc, NULL, NULL, NULL, ctxt);
1284 pxsltFreeTransformContext(ctxt);
1286 for (i = 0; i < params->count*2; i++)
1287 heap_free((char*)xslparams[i]);
1288 heap_free(xslparams);
1290 else
1291 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1293 if (result)
1295 if (stream)
1296 hr = node_transform_write_to_stream(xsltSS, result, stream);
1297 else
1298 hr = node_transform_write_to_bstr(xsltSS, result, p);
1299 xmlFreeDoc(result);
1301 /* libxslt "helpfully" frees the XML document the stylesheet was
1302 generated from, too */
1303 xsltSS->doc = NULL;
1304 pxsltFreeStylesheet(xsltSS);
1307 if(!*p) *p = SysAllocStringLen(NULL, 0);
1309 return hr;
1310 #else
1311 ERR_(winediag)("libxslt headers were not found at compile time. Expect problems.\n");
1313 return E_NOTIMPL;
1314 #endif
1317 HRESULT node_transform_node(const xmlnode *node, IXMLDOMNode *stylesheet, BSTR *p)
1319 return node_transform_node_params(node, stylesheet, p, NULL, NULL);
1322 HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes)
1324 xmlChar* str;
1325 HRESULT hr;
1327 if (!query || !nodes) return E_INVALIDARG;
1329 str = xmlchar_from_wchar(query);
1330 hr = create_selection(This->node, str, nodes);
1331 heap_free(str);
1333 return hr;
1336 HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node)
1338 IXMLDOMNodeList *list;
1339 HRESULT hr;
1341 hr = node_select_nodes(This, query, &list);
1342 if (hr == S_OK)
1344 hr = IXMLDOMNodeList_nextNode(list, node);
1345 IXMLDOMNodeList_Release(list);
1347 return hr;
1350 HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI)
1352 xmlNsPtr ns = This->node->ns;
1354 if(!namespaceURI)
1355 return E_INVALIDARG;
1357 *namespaceURI = NULL;
1359 if (ns && ns->href)
1360 *namespaceURI = bstr_from_xmlChar(ns->href);
1362 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1364 return *namespaceURI ? S_OK : S_FALSE;
1367 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1369 xmlNsPtr ns = This->node->ns;
1371 if (!prefix) return E_INVALIDARG;
1373 *prefix = NULL;
1375 if (ns && ns->prefix)
1376 *prefix = bstr_from_xmlChar(ns->prefix);
1378 TRACE("prefix: %s\n", debugstr_w(*prefix));
1380 return *prefix ? S_OK : S_FALSE;
1383 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1385 if (!name) return E_INVALIDARG;
1387 *name = bstr_from_xmlChar(This->node->name);
1388 if (!*name) return E_OUTOFMEMORY;
1390 TRACE("returning %s\n", debugstr_w(*name));
1392 return S_OK;
1395 /* _private field holds a number of COM instances spawned from this libxml2 node */
1396 static void xmlnode_add_ref(xmlNodePtr node)
1398 if (node->type == XML_DOCUMENT_NODE) return;
1399 InterlockedIncrement((LONG*)&node->_private);
1402 static void xmlnode_release(xmlNodePtr node)
1404 if (node->type == XML_DOCUMENT_NODE) return;
1405 InterlockedDecrement((LONG*)&node->_private);
1408 void destroy_xmlnode(xmlnode *This)
1410 if(This->node)
1412 xmlnode_release(This->node);
1413 xmldoc_release(This->node->doc);
1417 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1419 if(node)
1421 xmlnode_add_ref(node);
1422 xmldoc_add_ref(node->doc);
1425 This->node = node;
1426 This->iface = node_iface;
1427 This->parent = NULL;
1429 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1432 typedef struct {
1433 xmlnode node;
1434 IXMLDOMNode IXMLDOMNode_iface;
1435 LONG ref;
1436 } unknode;
1438 static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface)
1440 return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface);
1443 static HRESULT WINAPI unknode_QueryInterface(
1444 IXMLDOMNode *iface,
1445 REFIID riid,
1446 void** ppvObject )
1448 unknode *This = unknode_from_IXMLDOMNode( iface );
1450 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1452 if (IsEqualGUID(riid, &IID_IUnknown)) {
1453 *ppvObject = iface;
1454 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1455 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1456 *ppvObject = &This->IXMLDOMNode_iface;
1457 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1458 return *ppvObject ? S_OK : E_NOINTERFACE;
1459 }else {
1460 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1461 *ppvObject = NULL;
1462 return E_NOINTERFACE;
1465 IUnknown_AddRef((IUnknown*)*ppvObject);
1466 return S_OK;
1469 static ULONG WINAPI unknode_AddRef(
1470 IXMLDOMNode *iface )
1472 unknode *This = unknode_from_IXMLDOMNode( iface );
1474 return InterlockedIncrement(&This->ref);
1477 static ULONG WINAPI unknode_Release(
1478 IXMLDOMNode *iface )
1480 unknode *This = unknode_from_IXMLDOMNode( iface );
1481 LONG ref;
1483 ref = InterlockedDecrement( &This->ref );
1484 if(!ref) {
1485 destroy_xmlnode(&This->node);
1486 heap_free(This);
1489 return ref;
1492 static HRESULT WINAPI unknode_GetTypeInfoCount(
1493 IXMLDOMNode *iface,
1494 UINT* pctinfo )
1496 unknode *This = unknode_from_IXMLDOMNode( iface );
1498 TRACE("(%p)->(%p)\n", This, pctinfo);
1500 *pctinfo = 1;
1502 return S_OK;
1505 static HRESULT WINAPI unknode_GetTypeInfo(
1506 IXMLDOMNode *iface,
1507 UINT iTInfo,
1508 LCID lcid,
1509 ITypeInfo** ppTInfo )
1511 unknode *This = unknode_from_IXMLDOMNode( iface );
1512 HRESULT hr;
1514 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1516 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1518 return hr;
1521 static HRESULT WINAPI unknode_GetIDsOfNames(
1522 IXMLDOMNode *iface,
1523 REFIID riid,
1524 LPOLESTR* rgszNames,
1525 UINT cNames,
1526 LCID lcid,
1527 DISPID* rgDispId )
1529 unknode *This = unknode_from_IXMLDOMNode( iface );
1531 ITypeInfo *typeinfo;
1532 HRESULT hr;
1534 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1535 lcid, rgDispId);
1537 if(!rgszNames || cNames == 0 || !rgDispId)
1538 return E_INVALIDARG;
1540 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1541 if(SUCCEEDED(hr))
1543 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1544 ITypeInfo_Release(typeinfo);
1547 return hr;
1550 static HRESULT WINAPI unknode_Invoke(
1551 IXMLDOMNode *iface,
1552 DISPID dispIdMember,
1553 REFIID riid,
1554 LCID lcid,
1555 WORD wFlags,
1556 DISPPARAMS* pDispParams,
1557 VARIANT* pVarResult,
1558 EXCEPINFO* pExcepInfo,
1559 UINT* puArgErr )
1561 unknode *This = unknode_from_IXMLDOMNode( iface );
1562 ITypeInfo *typeinfo;
1563 HRESULT hr;
1565 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1566 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1568 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1569 if(SUCCEEDED(hr))
1571 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams,
1572 pVarResult, pExcepInfo, puArgErr);
1573 ITypeInfo_Release(typeinfo);
1576 return hr;
1579 static HRESULT WINAPI unknode_get_nodeName(
1580 IXMLDOMNode *iface,
1581 BSTR* p )
1583 unknode *This = unknode_from_IXMLDOMNode( iface );
1585 FIXME("(%p)->(%p)\n", This, p);
1587 return node_get_nodeName(&This->node, p);
1590 static HRESULT WINAPI unknode_get_nodeValue(
1591 IXMLDOMNode *iface,
1592 VARIANT* value)
1594 unknode *This = unknode_from_IXMLDOMNode( iface );
1596 FIXME("(%p)->(%p)\n", This, value);
1598 if(!value)
1599 return E_INVALIDARG;
1601 V_VT(value) = VT_NULL;
1602 return S_FALSE;
1605 static HRESULT WINAPI unknode_put_nodeValue(
1606 IXMLDOMNode *iface,
1607 VARIANT value)
1609 unknode *This = unknode_from_IXMLDOMNode( iface );
1610 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1611 return E_FAIL;
1614 static HRESULT WINAPI unknode_get_nodeType(
1615 IXMLDOMNode *iface,
1616 DOMNodeType* domNodeType )
1618 unknode *This = unknode_from_IXMLDOMNode( iface );
1620 FIXME("(%p)->(%p)\n", This, domNodeType);
1622 switch (This->node.node->type)
1624 case XML_ELEMENT_NODE:
1625 case XML_ATTRIBUTE_NODE:
1626 case XML_TEXT_NODE:
1627 case XML_CDATA_SECTION_NODE:
1628 case XML_ENTITY_REF_NODE:
1629 case XML_ENTITY_NODE:
1630 case XML_PI_NODE:
1631 case XML_COMMENT_NODE:
1632 case XML_DOCUMENT_NODE:
1633 case XML_DOCUMENT_TYPE_NODE:
1634 case XML_DOCUMENT_FRAG_NODE:
1635 case XML_NOTATION_NODE:
1636 /* we only care about this set of types, libxml2 type values are
1637 exactly what we need */
1638 *domNodeType = (DOMNodeType)This->node.node->type;
1639 break;
1640 default:
1641 *domNodeType = NODE_INVALID;
1642 break;
1645 return S_OK;
1648 static HRESULT WINAPI unknode_get_parentNode(
1649 IXMLDOMNode *iface,
1650 IXMLDOMNode** parent )
1652 unknode *This = unknode_from_IXMLDOMNode( iface );
1653 FIXME("(%p)->(%p)\n", This, parent);
1654 if (!parent) return E_INVALIDARG;
1655 *parent = NULL;
1656 return S_FALSE;
1659 static HRESULT WINAPI unknode_get_childNodes(
1660 IXMLDOMNode *iface,
1661 IXMLDOMNodeList** outList)
1663 unknode *This = unknode_from_IXMLDOMNode( iface );
1665 TRACE("(%p)->(%p)\n", This, outList);
1667 return node_get_child_nodes(&This->node, outList);
1670 static HRESULT WINAPI unknode_get_firstChild(
1671 IXMLDOMNode *iface,
1672 IXMLDOMNode** domNode)
1674 unknode *This = unknode_from_IXMLDOMNode( iface );
1676 TRACE("(%p)->(%p)\n", This, domNode);
1678 return node_get_first_child(&This->node, domNode);
1681 static HRESULT WINAPI unknode_get_lastChild(
1682 IXMLDOMNode *iface,
1683 IXMLDOMNode** domNode)
1685 unknode *This = unknode_from_IXMLDOMNode( iface );
1687 TRACE("(%p)->(%p)\n", This, domNode);
1689 return node_get_last_child(&This->node, domNode);
1692 static HRESULT WINAPI unknode_get_previousSibling(
1693 IXMLDOMNode *iface,
1694 IXMLDOMNode** domNode)
1696 unknode *This = unknode_from_IXMLDOMNode( iface );
1698 TRACE("(%p)->(%p)\n", This, domNode);
1700 return node_get_previous_sibling(&This->node, domNode);
1703 static HRESULT WINAPI unknode_get_nextSibling(
1704 IXMLDOMNode *iface,
1705 IXMLDOMNode** domNode)
1707 unknode *This = unknode_from_IXMLDOMNode( iface );
1709 TRACE("(%p)->(%p)\n", This, domNode);
1711 return node_get_next_sibling(&This->node, domNode);
1714 static HRESULT WINAPI unknode_get_attributes(
1715 IXMLDOMNode *iface,
1716 IXMLDOMNamedNodeMap** attributeMap)
1718 unknode *This = unknode_from_IXMLDOMNode( iface );
1720 FIXME("(%p)->(%p)\n", This, attributeMap);
1722 return return_null_ptr((void**)attributeMap);
1725 static HRESULT WINAPI unknode_insertBefore(
1726 IXMLDOMNode *iface,
1727 IXMLDOMNode* newNode, VARIANT refChild,
1728 IXMLDOMNode** outOldNode)
1730 unknode *This = unknode_from_IXMLDOMNode( iface );
1732 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1734 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1737 static HRESULT WINAPI unknode_replaceChild(
1738 IXMLDOMNode *iface,
1739 IXMLDOMNode* newNode,
1740 IXMLDOMNode* oldNode,
1741 IXMLDOMNode** outOldNode)
1743 unknode *This = unknode_from_IXMLDOMNode( iface );
1745 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1747 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1750 static HRESULT WINAPI unknode_removeChild(
1751 IXMLDOMNode *iface,
1752 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1754 unknode *This = unknode_from_IXMLDOMNode( iface );
1755 return node_remove_child(&This->node, domNode, oldNode);
1758 static HRESULT WINAPI unknode_appendChild(
1759 IXMLDOMNode *iface,
1760 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1762 unknode *This = unknode_from_IXMLDOMNode( iface );
1763 return node_append_child(&This->node, newNode, outNewNode);
1766 static HRESULT WINAPI unknode_hasChildNodes(
1767 IXMLDOMNode *iface,
1768 VARIANT_BOOL* pbool)
1770 unknode *This = unknode_from_IXMLDOMNode( iface );
1771 return node_has_childnodes(&This->node, pbool);
1774 static HRESULT WINAPI unknode_get_ownerDocument(
1775 IXMLDOMNode *iface,
1776 IXMLDOMDocument** domDocument)
1778 unknode *This = unknode_from_IXMLDOMNode( iface );
1779 return node_get_owner_doc(&This->node, domDocument);
1782 static HRESULT WINAPI unknode_cloneNode(
1783 IXMLDOMNode *iface,
1784 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1786 unknode *This = unknode_from_IXMLDOMNode( iface );
1787 return node_clone(&This->node, pbool, outNode );
1790 static HRESULT WINAPI unknode_get_nodeTypeString(
1791 IXMLDOMNode *iface,
1792 BSTR* p)
1794 unknode *This = unknode_from_IXMLDOMNode( iface );
1796 FIXME("(%p)->(%p)\n", This, p);
1798 return node_get_nodeName(&This->node, p);
1801 static HRESULT WINAPI unknode_get_text(
1802 IXMLDOMNode *iface,
1803 BSTR* p)
1805 unknode *This = unknode_from_IXMLDOMNode( iface );
1806 return node_get_text(&This->node, p);
1809 static HRESULT WINAPI unknode_put_text(
1810 IXMLDOMNode *iface,
1811 BSTR p)
1813 unknode *This = unknode_from_IXMLDOMNode( iface );
1814 return node_put_text(&This->node, p);
1817 static HRESULT WINAPI unknode_get_specified(
1818 IXMLDOMNode *iface,
1819 VARIANT_BOOL* isSpecified)
1821 unknode *This = unknode_from_IXMLDOMNode( iface );
1822 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1823 *isSpecified = VARIANT_TRUE;
1824 return S_OK;
1827 static HRESULT WINAPI unknode_get_definition(
1828 IXMLDOMNode *iface,
1829 IXMLDOMNode** definitionNode)
1831 unknode *This = unknode_from_IXMLDOMNode( iface );
1832 FIXME("(%p)->(%p)\n", This, definitionNode);
1833 return E_NOTIMPL;
1836 static HRESULT WINAPI unknode_get_nodeTypedValue(
1837 IXMLDOMNode *iface,
1838 VARIANT* var1)
1840 unknode *This = unknode_from_IXMLDOMNode( iface );
1841 FIXME("(%p)->(%p)\n", This, var1);
1842 return return_null_var(var1);
1845 static HRESULT WINAPI unknode_put_nodeTypedValue(
1846 IXMLDOMNode *iface,
1847 VARIANT typedValue)
1849 unknode *This = unknode_from_IXMLDOMNode( iface );
1850 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1851 return E_NOTIMPL;
1854 static HRESULT WINAPI unknode_get_dataType(
1855 IXMLDOMNode *iface,
1856 VARIANT* var1)
1858 unknode *This = unknode_from_IXMLDOMNode( iface );
1859 TRACE("(%p)->(%p)\n", This, var1);
1860 return return_null_var(var1);
1863 static HRESULT WINAPI unknode_put_dataType(
1864 IXMLDOMNode *iface,
1865 BSTR p)
1867 unknode *This = unknode_from_IXMLDOMNode( iface );
1869 FIXME("(%p)->(%s)\n", This, debugstr_w(p));
1871 if(!p)
1872 return E_INVALIDARG;
1874 return E_FAIL;
1877 static HRESULT WINAPI unknode_get_xml(
1878 IXMLDOMNode *iface,
1879 BSTR* p)
1881 unknode *This = unknode_from_IXMLDOMNode( iface );
1883 FIXME("(%p)->(%p)\n", This, p);
1885 return node_get_xml(&This->node, FALSE, p);
1888 static HRESULT WINAPI unknode_transformNode(
1889 IXMLDOMNode *iface,
1890 IXMLDOMNode* domNode, BSTR* p)
1892 unknode *This = unknode_from_IXMLDOMNode( iface );
1893 return node_transform_node(&This->node, domNode, p);
1896 static HRESULT WINAPI unknode_selectNodes(
1897 IXMLDOMNode *iface,
1898 BSTR p, IXMLDOMNodeList** outList)
1900 unknode *This = unknode_from_IXMLDOMNode( iface );
1901 return node_select_nodes(&This->node, p, outList);
1904 static HRESULT WINAPI unknode_selectSingleNode(
1905 IXMLDOMNode *iface,
1906 BSTR p, IXMLDOMNode** outNode)
1908 unknode *This = unknode_from_IXMLDOMNode( iface );
1909 return node_select_singlenode(&This->node, p, outNode);
1912 static HRESULT WINAPI unknode_get_parsed(
1913 IXMLDOMNode *iface,
1914 VARIANT_BOOL* isParsed)
1916 unknode *This = unknode_from_IXMLDOMNode( iface );
1917 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1918 *isParsed = VARIANT_TRUE;
1919 return S_OK;
1922 static HRESULT WINAPI unknode_get_namespaceURI(
1923 IXMLDOMNode *iface,
1924 BSTR* p)
1926 unknode *This = unknode_from_IXMLDOMNode( iface );
1927 TRACE("(%p)->(%p)\n", This, p);
1928 return node_get_namespaceURI(&This->node, p);
1931 static HRESULT WINAPI unknode_get_prefix(
1932 IXMLDOMNode *iface,
1933 BSTR* p)
1935 unknode *This = unknode_from_IXMLDOMNode( iface );
1936 return node_get_prefix(&This->node, p);
1939 static HRESULT WINAPI unknode_get_baseName(
1940 IXMLDOMNode *iface,
1941 BSTR* p)
1943 unknode *This = unknode_from_IXMLDOMNode( iface );
1944 return node_get_base_name(&This->node, p);
1947 static HRESULT WINAPI unknode_transformNodeToObject(
1948 IXMLDOMNode *iface,
1949 IXMLDOMNode* domNode, VARIANT var1)
1951 unknode *This = unknode_from_IXMLDOMNode( iface );
1952 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1953 return E_NOTIMPL;
1956 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1958 unknode_QueryInterface,
1959 unknode_AddRef,
1960 unknode_Release,
1961 unknode_GetTypeInfoCount,
1962 unknode_GetTypeInfo,
1963 unknode_GetIDsOfNames,
1964 unknode_Invoke,
1965 unknode_get_nodeName,
1966 unknode_get_nodeValue,
1967 unknode_put_nodeValue,
1968 unknode_get_nodeType,
1969 unknode_get_parentNode,
1970 unknode_get_childNodes,
1971 unknode_get_firstChild,
1972 unknode_get_lastChild,
1973 unknode_get_previousSibling,
1974 unknode_get_nextSibling,
1975 unknode_get_attributes,
1976 unknode_insertBefore,
1977 unknode_replaceChild,
1978 unknode_removeChild,
1979 unknode_appendChild,
1980 unknode_hasChildNodes,
1981 unknode_get_ownerDocument,
1982 unknode_cloneNode,
1983 unknode_get_nodeTypeString,
1984 unknode_get_text,
1985 unknode_put_text,
1986 unknode_get_specified,
1987 unknode_get_definition,
1988 unknode_get_nodeTypedValue,
1989 unknode_put_nodeTypedValue,
1990 unknode_get_dataType,
1991 unknode_put_dataType,
1992 unknode_get_xml,
1993 unknode_transformNode,
1994 unknode_selectNodes,
1995 unknode_selectSingleNode,
1996 unknode_get_parsed,
1997 unknode_get_namespaceURI,
1998 unknode_get_prefix,
1999 unknode_get_baseName,
2000 unknode_transformNodeToObject
2003 IXMLDOMNode *create_node( xmlNodePtr node )
2005 IUnknown *pUnk;
2006 IXMLDOMNode *ret;
2007 HRESULT hr;
2009 if ( !node )
2010 return NULL;
2012 TRACE("type %d\n", node->type);
2013 switch(node->type)
2015 case XML_ELEMENT_NODE:
2016 pUnk = create_element( node );
2017 break;
2018 case XML_ATTRIBUTE_NODE:
2019 pUnk = create_attribute( node );
2020 break;
2021 case XML_TEXT_NODE:
2022 pUnk = create_text( node );
2023 break;
2024 case XML_CDATA_SECTION_NODE:
2025 pUnk = create_cdata( node );
2026 break;
2027 case XML_ENTITY_REF_NODE:
2028 pUnk = create_doc_entity_ref( node );
2029 break;
2030 case XML_PI_NODE:
2031 pUnk = create_pi( node );
2032 break;
2033 case XML_COMMENT_NODE:
2034 pUnk = create_comment( node );
2035 break;
2036 case XML_DOCUMENT_NODE:
2037 pUnk = create_domdoc( node );
2038 break;
2039 case XML_DOCUMENT_FRAG_NODE:
2040 pUnk = create_doc_fragment( node );
2041 break;
2042 case XML_DTD_NODE:
2043 case XML_DOCUMENT_TYPE_NODE:
2044 pUnk = create_doc_type( node );
2045 break;
2046 case XML_ENTITY_NODE:
2047 case XML_NOTATION_NODE: {
2048 unknode *new_node;
2050 FIXME("only creating basic node for type %d\n", node->type);
2052 new_node = heap_alloc(sizeof(unknode));
2053 if(!new_node)
2054 return NULL;
2056 new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl;
2057 new_node->ref = 1;
2058 init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL);
2059 pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface;
2060 break;
2062 default:
2063 ERR("Called for unsupported node type %d\n", node->type);
2064 return NULL;
2067 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
2068 IUnknown_Release(pUnk);
2069 if(FAILED(hr)) return NULL;
2070 return ret;
2072 #endif