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
33 #include "msxml_private.h"
36 # include <libxml/HTMLtree.h>
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
45 static const WCHAR szBinBase64[] = {'b','i','n','.','b','a','s','e','6','4',0};
46 static const WCHAR szString[] = {'s','t','r','i','n','g',0};
47 static const WCHAR szNumber[] = {'n','u','m','b','e','r',0};
48 static const WCHAR szInt[] = {'I','n','t',0};
49 static const WCHAR szFixed[] = {'F','i','x','e','d','.','1','4','.','4',0};
50 static const WCHAR szBoolean[] = {'B','o','o','l','e','a','n',0};
51 static const WCHAR szDateTime[] = {'d','a','t','e','T','i','m','e',0};
52 static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
53 static const WCHAR szDate[] = {'D','a','t','e',0};
54 static const WCHAR szTime[] = {'T','i','m','e',0};
55 static const WCHAR szTimeTZ[] = {'T','i','m','e','.','t','z',0};
56 static const WCHAR szI1[] = {'i','1',0};
57 static const WCHAR szI2[] = {'i','2',0};
58 static const WCHAR szI4[] = {'i','4',0};
59 static const WCHAR szIU1[] = {'u','i','1',0};
60 static const WCHAR szIU2[] = {'u','i','2',0};
61 static const WCHAR szIU4[] = {'u','i','4',0};
62 static const WCHAR szR4[] = {'r','4',0};
63 static const WCHAR szR8[] = {'r','8',0};
64 static const WCHAR szFloat[] = {'f','l','o','a','t',0};
65 static const WCHAR szUUID[] = {'u','u','i','d',0};
66 static const WCHAR szBinHex[] = {'b','i','n','.','h','e','x',0};
68 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
70 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
76 This = get_node_obj( iface );
77 if ( !This || !This->node )
79 if ( type && This->node->type != type )
84 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
86 if(IsEqualGUID(&IID_xmlnode, riid)) {
87 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
92 if(This->dispex.outer)
93 return dispex_query_interface(&This->dispex, riid, ppv);
98 xmlnode *get_node_obj(IXMLDOMNode *node)
103 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
104 return SUCCEEDED(hres) ? obj : NULL;
107 static inline xmlnode *impl_from_IXMLDOMNode( IXMLDOMNode *iface )
109 return (xmlnode *)((char*)iface - FIELD_OFFSET(xmlnode, lpVtbl));
112 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
117 *name = bstr_from_xmlChar(This->node->name);
124 HRESULT node_get_content(xmlnode *This, VARIANT *value)
131 content = xmlNodeGetContent(This->node);
132 V_VT(value) = VT_BSTR;
133 V_BSTR(value) = bstr_from_xmlChar( content );
136 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
140 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
144 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
145 str = xmlChar_from_wchar(value);
147 return E_OUTOFMEMORY;
149 xmlNodeSetContent(This->node, str);
154 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
156 xmlChar *str, *escaped;
158 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
159 str = xmlChar_from_wchar(value);
161 return E_OUTOFMEMORY;
163 escaped = xmlEncodeSpecialChars(NULL, str);
167 return E_OUTOFMEMORY;
170 xmlNodeSetContent(This->node, escaped);
178 HRESULT node_put_value(xmlnode *This, VARIANT *value)
180 VARIANT string_value;
183 VariantInit(&string_value);
184 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
186 WARN("Couldn't convert to VT_BSTR\n");
190 hr = node_set_content(This, V_BSTR(&string_value));
191 VariantClear(&string_value);
196 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
198 VARIANT string_value;
201 VariantInit(&string_value);
202 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
204 WARN("Couldn't convert to VT_BSTR\n");
208 hr = node_set_content_escaped(This, V_BSTR(&string_value));
209 VariantClear(&string_value);
214 static HRESULT get_node(
220 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
225 /* if we don't have a doc, use our parent. */
226 if(node && !node->doc && node->parent)
227 node->doc = node->parent->doc;
229 *out = create_node( node );
235 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
237 return get_node( This, "parent", This->node->parent, parent );
240 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
245 *ret = create_children_nodelist(This->node);
247 return E_OUTOFMEMORY;
252 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
254 return get_node(This, "firstChild", This->node->children, ret);
257 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
259 return get_node(This, "lastChild", This->node->last, ret);
262 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
264 return get_node(This, "previous", This->node->prev, ret);
267 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
269 return get_node(This, "next", This->node->next, ret);
272 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
275 xmlNodePtr before_node, new_child_node;
276 IXMLDOMNode *before = NULL;
283 node_obj = get_node_obj(new_child);
285 FIXME("newChild is not our node implementation\n");
289 switch(V_VT(ref_child))
297 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (LPVOID)&before);
298 if(FAILED(hr)) return hr;
302 FIXME("refChild var type %x\n", V_VT(ref_child));
306 new_child_node = node_obj->node;
307 TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
309 if(!new_child_node->parent)
310 if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
311 WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
315 node_obj = get_node_obj(before);
316 IXMLDOMNode_Release(before);
318 FIXME("before node is not our node implementation\n");
322 before_node = node_obj->node;
323 xmlAddPrevSibling(before_node, new_child_node);
327 xmlAddChild(This->node, new_child_node);
331 IXMLDOMNode_AddRef(new_child);
339 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
342 xmlnode *old_child, *new_child;
343 xmlDocPtr leaving_doc;
344 xmlNode *my_ancestor;
346 /* Do not believe any documentation telling that newChild == NULL
347 means removal. It does certainly *not* apply to msxml3! */
348 if(!newChild || !oldChild)
354 old_child = get_node_obj(oldChild);
356 FIXME("oldChild is not our node implementation\n");
360 if(old_child->node->parent != This->node)
362 WARN("childNode %p is not a child of %p\n", oldChild, This);
366 new_child = get_node_obj(newChild);
368 FIXME("newChild is not our node implementation\n");
372 my_ancestor = This->node;
375 if(my_ancestor == new_child->node)
377 WARN("tried to create loop\n");
380 my_ancestor = my_ancestor->parent;
383 if(!new_child->node->parent)
384 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
385 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
387 leaving_doc = new_child->node->doc;
388 xmldoc_add_ref(old_child->node->doc);
389 xmlReplaceNode(old_child->node, new_child->node);
390 xmldoc_release(leaving_doc);
392 xmldoc_add_orphan(old_child->node->doc, old_child->node);
396 IXMLDOMNode_AddRef(oldChild);
403 static HRESULT WINAPI xmlnode_removeChild(
405 IXMLDOMNode* childNode,
406 IXMLDOMNode** oldChild)
408 xmlnode *This = impl_from_IXMLDOMNode( iface );
411 TRACE("(%p)->(%p %p)\n", This, childNode, oldChild);
413 if(!childNode) return E_INVALIDARG;
418 child_node = get_node_obj(childNode);
420 FIXME("childNode is not our node implementation\n");
424 if(child_node->node->parent != This->node)
426 WARN("childNode %p is not a child of %p\n", childNode, iface);
430 xmlUnlinkNode(child_node->node);
434 IXMLDOMNode_AddRef(childNode);
435 *oldChild = childNode;
441 static HRESULT WINAPI xmlnode_appendChild(
443 IXMLDOMNode* newChild,
444 IXMLDOMNode** outNewChild)
446 xmlnode *This = impl_from_IXMLDOMNode( iface );
451 TRACE("(%p)->(%p %p)\n", This, newChild, outNewChild);
453 hr = IXMLDOMNode_get_nodeType(newChild, &type);
454 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
455 if(outNewChild) *outNewChild = NULL;
460 return IXMLDOMNode_insertBefore(This->iface, newChild, var, outNewChild);
463 static HRESULT WINAPI xmlnode_hasChildNodes(
465 VARIANT_BOOL* hasChild)
467 xmlnode *This = impl_from_IXMLDOMNode( iface );
469 TRACE("(%p)->(%p)\n", This, hasChild);
473 if (!This->node->children)
475 *hasChild = VARIANT_FALSE;
479 *hasChild = VARIANT_TRUE;
483 static HRESULT WINAPI xmlnode_get_ownerDocument(
485 IXMLDOMDocument** DOMDocument)
487 xmlnode *This = impl_from_IXMLDOMNode( iface );
489 TRACE("(%p)->(%p)\n", This, DOMDocument);
491 return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)DOMDocument);
494 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
499 if(!cloneNode) return E_INVALIDARG;
501 clone = xmlCopyNode(This->node, deep ? 1 : 2);
504 clone->doc = This->node->doc;
505 xmldoc_add_orphan(clone->doc, clone);
507 node = create_node(clone);
510 ERR("Copy failed\n");
518 ERR("Copy failed\n");
525 static inline xmlChar* trim_whitespace(xmlChar* str)
533 while (*ret && isspace(*ret))
535 len = xmlStrlen(ret);
536 while (isspace(ret[len-1]))
539 ret = xmlStrndup(ret, len);
544 static xmlChar* do_get_text(xmlNodePtr node)
548 BOOL preserving = is_preserving_whitespace(node);
552 str = xmlNodeGetContent(node);
556 xmlElementType prev_type = XML_TEXT_NODE;
558 str = xmlStrdup(BAD_CAST "");
559 for (child = node->children; child != NULL; child = child->next)
563 case XML_ELEMENT_NODE:
564 tmp = do_get_text(child);
567 case XML_CDATA_SECTION_NODE:
568 case XML_ENTITY_REF_NODE:
569 case XML_ENTITY_NODE:
570 tmp = xmlNodeGetContent(child);
581 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
582 str = xmlStrcat(str, BAD_CAST " ");
583 str = xmlStrcat(str, tmp);
584 prev_type = child->type;
593 case XML_ELEMENT_NODE:
595 case XML_ENTITY_REF_NODE:
596 case XML_ENTITY_NODE:
597 case XML_DOCUMENT_NODE:
598 case XML_DOCUMENT_FRAG_NODE:
600 str = trim_whitespace(str);
609 static HRESULT WINAPI xmlnode_get_text(
613 xmlnode *This = impl_from_IXMLDOMNode( iface );
617 TRACE("(%p, type %d)->(%p)\n", This, This->node->type, text);
622 pContent = do_get_text((xmlNodePtr)This->node);
625 str = bstr_from_xmlChar(pContent);
629 /* Always return a string. */
630 if (!str) str = SysAllocStringLen( NULL, 0 );
632 TRACE("%p %s\n", This, debugstr_w(str) );
638 HRESULT node_put_text(xmlnode *This, BSTR text)
642 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
644 str = xmlChar_from_wchar(text);
646 /* Escape the string. */
647 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
650 xmlNodeSetContent(This->node, str2);
656 static inline BYTE hex_to_byte(xmlChar c)
658 if(c <= '9') return c-'0';
659 if(c <= 'F') return c-'A'+10;
663 static inline BYTE base64_to_byte(xmlChar c)
665 if(c == '+') return 62;
666 if(c == '/') return 63;
667 if(c <= '9') return c-'0'+52;
668 if(c <= 'Z') return c-'A';
672 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
674 if(!type || !lstrcmpiW(type, szString) ||
675 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
678 V_BSTR(v) = bstr_from_xmlChar(str);
681 return E_OUTOFMEMORY;
683 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
684 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
685 !lstrcmpiW(type, szTimeTZ))
695 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
697 V_VT(&src) = VT_BSTR;
698 V_BSTR(&src) = bstr_from_xmlChar(str);
701 return E_OUTOFMEMORY;
704 e = p + SysStringLen(V_BSTR(&src));
706 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
709 st.wMonth = atoiW(p+5);
710 st.wDay = atoiW(p+8);
716 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
719 st.wMinute = atoiW(p+3);
720 st.wSecond = atoiW(p+6);
726 while(isdigitW(*p)) p++;
730 SystemTimeToVariantTime(&st, &date);
734 if(*p == '+') /* parse timezone offset (+hh:mm) */
735 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
736 else if(*p == '-') /* parse timezone offset (-hh:mm) */
737 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
741 else if(!lstrcmpiW(type, szBinHex))
746 len = xmlStrlen(str)/2;
750 V_VT(v) = (VT_ARRAY|VT_UI1);
751 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
754 return E_OUTOFMEMORY;
757 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
758 + hex_to_byte(str[2*i+1]);
760 else if(!lstrcmpiW(type, szBinBase64))
765 len = xmlStrlen(str);
766 if(str[len-2] == '=') i = 2;
767 else if(str[len-1] == '=') i = 1;
771 sab.cElements = len/4*3-i;
773 V_VT(v) = (VT_ARRAY|VT_UI1);
774 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
777 return E_OUTOFMEMORY;
779 for(i=0; i<len/4; i++)
781 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
782 + (base64_to_byte(str[4*i+1])>>4);
783 if(3*i+1 < sab.cElements)
784 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
785 + (base64_to_byte(str[4*i+2])>>2);
786 if(3*i+2 < sab.cElements)
787 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
788 + base64_to_byte(str[4*i+3]);
796 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
798 else if(!lstrcmpiW(type, szFixed))
800 else if(!lstrcmpiW(type, szBoolean))
802 else if(!lstrcmpiW(type, szI1))
804 else if(!lstrcmpiW(type, szI2))
806 else if(!lstrcmpiW(type, szIU1))
808 else if(!lstrcmpiW(type, szIU2))
810 else if(!lstrcmpiW(type, szIU4))
812 else if(!lstrcmpiW(type, szR4))
814 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
818 FIXME("Type handling not yet implemented\n");
822 V_VT(&src) = VT_BSTR;
823 V_BSTR(&src) = bstr_from_xmlChar(str);
826 return E_OUTOFMEMORY;
828 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
829 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
837 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
841 xmlnode *This = impl_from_IXMLDOMNode( iface );
844 HRESULT hres = S_FALSE;
846 TRACE("(%p)->(%p)\n", This, typedValue);
851 V_VT(typedValue) = VT_NULL;
853 if(This->node->type == XML_ELEMENT_NODE ||
854 This->node->type == XML_TEXT_NODE ||
855 This->node->type == XML_ENTITY_REF_NODE)
856 hres = IXMLDOMNode_get_dataType(This->iface, &type);
858 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
859 return IXMLDOMNode_get_nodeValue(This->iface, typedValue);
861 content = xmlNodeGetContent(This->node);
862 hres = VARIANT_from_xmlChar(content, typedValue,
863 hres==S_OK ? V_BSTR(&type) : NULL);
870 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
874 xmlnode *This = impl_from_IXMLDOMNode( iface );
879 static HRESULT WINAPI xmlnode_put_dataType(
883 xmlnode *This = impl_from_IXMLDOMNode( iface );
886 TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
888 if(dataTypeName == NULL)
891 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
892 This applies to changing types (string->bool) or setting a new one
894 FIXME("Need to Validate the data before allowing a type to be set.\n");
896 /* Check all supported types. */
897 if(lstrcmpiW(dataTypeName,szString) == 0 ||
898 lstrcmpiW(dataTypeName,szNumber) == 0 ||
899 lstrcmpiW(dataTypeName,szUUID) == 0 ||
900 lstrcmpiW(dataTypeName,szInt) == 0 ||
901 lstrcmpiW(dataTypeName,szI4) == 0 ||
902 lstrcmpiW(dataTypeName,szFixed) == 0 ||
903 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
904 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
905 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
906 lstrcmpiW(dataTypeName,szDate) == 0 ||
907 lstrcmpiW(dataTypeName,szTime) == 0 ||
908 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
909 lstrcmpiW(dataTypeName,szI1) == 0 ||
910 lstrcmpiW(dataTypeName,szI2) == 0 ||
911 lstrcmpiW(dataTypeName,szIU1) == 0 ||
912 lstrcmpiW(dataTypeName,szIU2) == 0 ||
913 lstrcmpiW(dataTypeName,szIU4) == 0 ||
914 lstrcmpiW(dataTypeName,szR4) == 0 ||
915 lstrcmpiW(dataTypeName,szR8) == 0 ||
916 lstrcmpiW(dataTypeName,szFloat) == 0 ||
917 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
918 lstrcmpiW(dataTypeName,szBinBase64) == 0)
920 xmlChar* str = xmlChar_from_wchar(dataTypeName);
923 if (!str) return E_OUTOFMEMORY;
925 attr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
926 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
929 attr = xmlSetNsProp(This->node, attr->ns, (const xmlChar*)"dt", str);
934 xmlNsPtr ns = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
937 attr = xmlNewNsProp(This->node, ns, (const xmlChar*)"dt", str);
940 xmlAddChild(This->node, (xmlNodePtr)attr);
944 ERR("Failed to create Attribute\n");
947 ERR("Failed to create Namespace\n");
955 BSTR EnsureCorrectEOL(BSTR sInput)
962 nLen = SysStringLen(sInput);
963 /* Count line endings */
964 for(i=0; i < nLen; i++)
966 if(sInput[i] == '\n')
970 TRACE("len=%d, num=%d\n", nLen, nNum);
972 /* Add linefeed as needed */
976 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
977 for(i=0; i < nLen; i++)
979 if(sInput[i] == '\n')
981 sNew[i+nPlace] = '\r';
984 sNew[i+nPlace] = sInput[i];
987 SysFreeString(sInput);
994 TRACE("len %d\n", SysStringLen(sNew));
999 /* Removes encoding information and last character (nullbyte) */
1000 static BSTR EnsureNoEncoding(BSTR sInput)
1002 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1007 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1012 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1017 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1018 while(*pEnd != '\"') pEnd++;
1021 sNew = SysAllocStringLen(NULL,
1022 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1023 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1024 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1026 SysFreeString(sInput);
1031 * We are trying to replicate the same behaviour as msxml by converting
1032 * line endings to \r\n and using indents as \t. The problem is that msxml
1033 * only formats nodes that have a line ending. Using libxml we cannot
1034 * reproduce behaviour exactly.
1037 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
1039 xmlBufferPtr xml_buf;
1044 return E_INVALIDARG;
1048 xml_buf = xmlBufferCreate();
1050 return E_OUTOFMEMORY;
1052 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
1054 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
1056 const xmlChar *buf_content;
1059 /* Attribute Nodes return a space in front of their name */
1060 buf_content = xmlBufferContent(xml_buf);
1062 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
1064 content = EnsureCorrectEOL(content);
1065 if(ensure_no_encoding)
1066 content = EnsureNoEncoding(content);
1070 *ret = SysAllocStringLen(NULL, 0);
1073 xmlBufferFree(xml_buf);
1074 xmldoc_link_xmldecl( This->node->doc, xmldecl );
1075 return *ret ? S_OK : E_OUTOFMEMORY;
1078 static HRESULT WINAPI xmlnode_transformNode(
1080 IXMLDOMNode* styleSheet,
1083 #ifdef SONAME_LIBXSLT
1084 xmlnode *This = impl_from_IXMLDOMNode( iface );
1085 xmlnode *pStyleSheet = NULL;
1086 xsltStylesheetPtr xsltSS = NULL;
1087 xmlDocPtr result = NULL;
1089 TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1091 if (!libxslt_handle)
1093 if(!styleSheet || !xmlString)
1094 return E_INVALIDARG;
1098 pStyleSheet = get_node_obj(styleSheet);
1100 FIXME("styleSheet is not our xmlnode implementation\n");
1104 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1107 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1110 const xmlChar *pContent;
1112 if(result->type == XML_HTML_DOCUMENT_NODE)
1114 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1117 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1118 pContent = xmlBufferContent(pOutput->buffer);
1119 *xmlString = bstr_from_xmlChar(pContent);
1120 xmlOutputBufferClose(pOutput);
1125 xmlBufferPtr pXmlBuf;
1128 pXmlBuf = xmlBufferCreate();
1131 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1134 pContent = xmlBufferContent(pXmlBuf);
1135 *xmlString = bstr_from_xmlChar(pContent);
1137 xmlBufferFree(pXmlBuf);
1142 /* libxslt "helpfully" frees the XML document the stylesheet was
1143 generated from, too */
1145 pxsltFreeStylesheet(xsltSS);
1148 if(*xmlString == NULL)
1149 *xmlString = SysAllocStringLen(NULL, 0);
1153 FIXME("libxslt headers were not found at compile time\n");
1158 static HRESULT WINAPI xmlnode_selectNodes(
1161 IXMLDOMNodeList** resultList)
1163 xmlnode *This = impl_from_IXMLDOMNode( iface );
1165 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1167 if (!queryString || !resultList) return E_INVALIDARG;
1169 return queryresult_create( This->node, queryString, resultList );
1172 static HRESULT WINAPI xmlnode_selectSingleNode(
1175 IXMLDOMNode** resultNode)
1177 xmlnode *This = impl_from_IXMLDOMNode( iface );
1178 IXMLDOMNodeList *list;
1181 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1183 r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1186 r = IXMLDOMNodeList_nextNode(list, resultNode);
1187 IXMLDOMNodeList_Release(list);
1192 static HRESULT WINAPI xmlnode_get_namespaceURI(
1196 xmlnode *This = impl_from_IXMLDOMNode( iface );
1199 TRACE("(%p)->(%p)\n", This, namespaceURI );
1202 return E_INVALIDARG;
1204 *namespaceURI = NULL;
1206 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1208 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1212 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1214 return *namespaceURI ? S_OK : S_FALSE;
1217 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1221 if (!prefix) return E_INVALIDARG;
1225 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1227 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1231 TRACE("prefix: %s\n", debugstr_w(*prefix));
1233 return *prefix ? S_OK : S_FALSE;
1236 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1238 if (!name) return E_INVALIDARG;
1240 *name = bstr_from_xmlChar(This->node->name);
1241 if (!*name) return E_OUTOFMEMORY;
1243 TRACE("returning %s\n", debugstr_w(*name));
1248 static HRESULT WINAPI xmlnode_transformNodeToObject(
1250 IXMLDOMNode* stylesheet,
1251 VARIANT outputObject)
1253 xmlnode *This = impl_from_IXMLDOMNode( iface );
1254 FIXME("(%p)->(%p)\n", This, stylesheet);
1258 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1280 xmlnode_removeChild,
1281 xmlnode_appendChild,
1282 xmlnode_hasChildNodes,
1283 xmlnode_get_ownerDocument,
1290 xmlnode_get_nodeTypedValue,
1291 xmlnode_put_nodeTypedValue,
1293 xmlnode_put_dataType,
1295 xmlnode_transformNode,
1296 xmlnode_selectNodes,
1297 xmlnode_selectSingleNode,
1299 xmlnode_get_namespaceURI,
1302 xmlnode_transformNodeToObject,
1305 void destroy_xmlnode(xmlnode *This)
1308 xmldoc_release(This->node->doc);
1311 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1314 xmldoc_add_ref( node->doc );
1316 This->lpVtbl = &xmlnode_vtbl;
1318 This->iface = node_iface;
1321 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1323 This->dispex.outer = NULL;
1328 const IXMLDOMNodeVtbl *lpVtbl;
1332 static inline unknode *impl_from_unkIXMLDOMNode(IXMLDOMNode *iface)
1334 return (unknode *)((char*)iface - FIELD_OFFSET(unknode, lpVtbl));
1337 static HRESULT WINAPI unknode_QueryInterface(
1342 unknode *This = impl_from_unkIXMLDOMNode( iface );
1344 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1346 if (IsEqualGUID(riid, &IID_IUnknown)) {
1348 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1349 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1350 *ppvObject = &This->lpVtbl;
1351 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1352 return *ppvObject ? S_OK : E_NOINTERFACE;
1354 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1356 return E_NOINTERFACE;
1359 IUnknown_AddRef((IUnknown*)*ppvObject);
1363 static ULONG WINAPI unknode_AddRef(
1364 IXMLDOMNode *iface )
1366 unknode *This = impl_from_unkIXMLDOMNode( iface );
1368 return InterlockedIncrement(&This->ref);
1371 static ULONG WINAPI unknode_Release(
1372 IXMLDOMNode *iface )
1374 unknode *This = impl_from_unkIXMLDOMNode( iface );
1377 ref = InterlockedDecrement( &This->ref );
1379 destroy_xmlnode(&This->node);
1386 static HRESULT WINAPI unknode_GetTypeInfoCount(
1390 unknode *This = impl_from_unkIXMLDOMNode( iface );
1392 TRACE("(%p)->(%p)\n", This, pctinfo);
1399 static HRESULT WINAPI unknode_GetTypeInfo(
1403 ITypeInfo** ppTInfo )
1405 unknode *This = impl_from_unkIXMLDOMNode( iface );
1408 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1410 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1415 static HRESULT WINAPI unknode_GetIDsOfNames(
1418 LPOLESTR* rgszNames,
1423 unknode *This = impl_from_unkIXMLDOMNode( iface );
1425 ITypeInfo *typeinfo;
1428 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1431 if(!rgszNames || cNames == 0 || !rgDispId)
1432 return E_INVALIDARG;
1434 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1437 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1438 ITypeInfo_Release(typeinfo);
1444 static HRESULT WINAPI unknode_Invoke(
1446 DISPID dispIdMember,
1450 DISPPARAMS* pDispParams,
1451 VARIANT* pVarResult,
1452 EXCEPINFO* pExcepInfo,
1455 unknode *This = impl_from_unkIXMLDOMNode( iface );
1456 ITypeInfo *typeinfo;
1459 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1460 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1462 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1465 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1466 pVarResult, pExcepInfo, puArgErr);
1467 ITypeInfo_Release(typeinfo);
1473 static HRESULT WINAPI unknode_get_nodeName(
1477 unknode *This = impl_from_unkIXMLDOMNode( iface );
1479 FIXME("(%p)->(%p)\n", This, p);
1481 return node_get_nodeName(&This->node, p);
1484 static HRESULT WINAPI unknode_get_nodeValue(
1488 unknode *This = impl_from_unkIXMLDOMNode( iface );
1490 FIXME("(%p)->(%p)\n", This, value);
1493 return E_INVALIDARG;
1495 V_VT(value) = VT_NULL;
1499 static HRESULT WINAPI unknode_put_nodeValue(
1503 unknode *This = impl_from_unkIXMLDOMNode( iface );
1504 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1508 static HRESULT WINAPI unknode_get_nodeType(
1510 DOMNodeType* domNodeType )
1512 unknode *This = impl_from_unkIXMLDOMNode( iface );
1514 FIXME("(%p)->(%p)\n", This, domNodeType);
1516 *domNodeType = This->node.node->type;
1520 static HRESULT WINAPI unknode_get_parentNode(
1522 IXMLDOMNode** parent )
1524 unknode *This = impl_from_unkIXMLDOMNode( iface );
1525 FIXME("(%p)->(%p)\n", This, parent);
1526 if (!parent) return E_INVALIDARG;
1531 static HRESULT WINAPI unknode_get_childNodes(
1533 IXMLDOMNodeList** outList)
1535 unknode *This = impl_from_unkIXMLDOMNode( iface );
1537 TRACE("(%p)->(%p)\n", This, outList);
1539 return node_get_child_nodes(&This->node, outList);
1542 static HRESULT WINAPI unknode_get_firstChild(
1544 IXMLDOMNode** domNode)
1546 unknode *This = impl_from_unkIXMLDOMNode( iface );
1548 TRACE("(%p)->(%p)\n", This, domNode);
1550 return node_get_first_child(&This->node, domNode);
1553 static HRESULT WINAPI unknode_get_lastChild(
1555 IXMLDOMNode** domNode)
1557 unknode *This = impl_from_unkIXMLDOMNode( iface );
1559 TRACE("(%p)->(%p)\n", This, domNode);
1561 return node_get_last_child(&This->node, domNode);
1564 static HRESULT WINAPI unknode_get_previousSibling(
1566 IXMLDOMNode** domNode)
1568 unknode *This = impl_from_unkIXMLDOMNode( iface );
1570 TRACE("(%p)->(%p)\n", This, domNode);
1572 return node_get_previous_sibling(&This->node, domNode);
1575 static HRESULT WINAPI unknode_get_nextSibling(
1577 IXMLDOMNode** domNode)
1579 unknode *This = impl_from_unkIXMLDOMNode( iface );
1581 TRACE("(%p)->(%p)\n", This, domNode);
1583 return node_get_next_sibling(&This->node, domNode);
1586 static HRESULT WINAPI unknode_get_attributes(
1588 IXMLDOMNamedNodeMap** attributeMap)
1590 unknode *This = impl_from_unkIXMLDOMNode( iface );
1592 FIXME("(%p)->(%p)\n", This, attributeMap);
1594 return return_null_ptr((void**)attributeMap);
1597 static HRESULT WINAPI unknode_insertBefore(
1599 IXMLDOMNode* newNode, VARIANT refChild,
1600 IXMLDOMNode** outOldNode)
1602 unknode *This = impl_from_unkIXMLDOMNode( iface );
1604 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1606 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1609 static HRESULT WINAPI unknode_replaceChild(
1611 IXMLDOMNode* newNode,
1612 IXMLDOMNode* oldNode,
1613 IXMLDOMNode** outOldNode)
1615 unknode *This = impl_from_unkIXMLDOMNode( iface );
1617 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1619 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1622 static HRESULT WINAPI unknode_removeChild(
1624 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1626 unknode *This = impl_from_unkIXMLDOMNode( iface );
1627 return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), domNode, oldNode );
1630 static HRESULT WINAPI unknode_appendChild(
1632 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1634 unknode *This = impl_from_unkIXMLDOMNode( iface );
1635 return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newNode, outNewNode );
1638 static HRESULT WINAPI unknode_hasChildNodes(
1640 VARIANT_BOOL* pbool)
1642 unknode *This = impl_from_unkIXMLDOMNode( iface );
1643 return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), pbool );
1646 static HRESULT WINAPI unknode_get_ownerDocument(
1648 IXMLDOMDocument** domDocument)
1650 unknode *This = impl_from_unkIXMLDOMNode( iface );
1651 return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), domDocument );
1654 static HRESULT WINAPI unknode_cloneNode(
1656 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1658 unknode *This = impl_from_unkIXMLDOMNode( iface );
1659 return IXMLDOMNode_cloneNode( IXMLDOMNode_from_impl(&This->node), pbool, outNode );
1662 static HRESULT WINAPI unknode_get_nodeTypeString(
1666 unknode *This = impl_from_unkIXMLDOMNode( iface );
1668 FIXME("(%p)->(%p)\n", This, p);
1670 return node_get_nodeName(&This->node, p);
1673 static HRESULT WINAPI unknode_get_text(
1677 unknode *This = impl_from_unkIXMLDOMNode( iface );
1678 return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), p );
1681 static HRESULT WINAPI unknode_put_text(
1685 unknode *This = impl_from_unkIXMLDOMNode( iface );
1686 return IXMLDOMNode_put_text( IXMLDOMNode_from_impl(&This->node), p );
1689 static HRESULT WINAPI unknode_get_specified(
1691 VARIANT_BOOL* isSpecified)
1693 unknode *This = impl_from_unkIXMLDOMNode( iface );
1694 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1695 *isSpecified = VARIANT_TRUE;
1699 static HRESULT WINAPI unknode_get_definition(
1701 IXMLDOMNode** definitionNode)
1703 unknode *This = impl_from_unkIXMLDOMNode( iface );
1704 FIXME("(%p)->(%p)\n", This, definitionNode);
1708 static HRESULT WINAPI unknode_get_nodeTypedValue(
1712 unknode *This = impl_from_unkIXMLDOMNode( iface );
1713 return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1716 static HRESULT WINAPI unknode_put_nodeTypedValue(
1720 unknode *This = impl_from_unkIXMLDOMNode( iface );
1721 return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1724 static HRESULT WINAPI unknode_get_dataType(
1728 unknode *This = impl_from_unkIXMLDOMNode( iface );
1729 return IXMLDOMNode_get_dataType( IXMLDOMNode_from_impl(&This->node), var1 );
1732 static HRESULT WINAPI unknode_put_dataType(
1736 unknode *This = impl_from_unkIXMLDOMNode( iface );
1737 return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), p );
1740 static HRESULT WINAPI unknode_get_xml(
1744 unknode *This = impl_from_unkIXMLDOMNode( iface );
1746 FIXME("(%p)->(%p)\n", This, p);
1748 return node_get_xml(&This->node, FALSE, FALSE, p);
1751 static HRESULT WINAPI unknode_transformNode(
1753 IXMLDOMNode* domNode, BSTR* p)
1755 unknode *This = impl_from_unkIXMLDOMNode( iface );
1756 return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), domNode, p );
1759 static HRESULT WINAPI unknode_selectNodes(
1761 BSTR p, IXMLDOMNodeList** outList)
1763 unknode *This = impl_from_unkIXMLDOMNode( iface );
1764 return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), p, outList );
1767 static HRESULT WINAPI unknode_selectSingleNode(
1769 BSTR p, IXMLDOMNode** outNode)
1771 unknode *This = impl_from_unkIXMLDOMNode( iface );
1772 return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), p, outNode );
1775 static HRESULT WINAPI unknode_get_parsed(
1777 VARIANT_BOOL* isParsed)
1779 unknode *This = impl_from_unkIXMLDOMNode( iface );
1780 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1781 *isParsed = VARIANT_TRUE;
1785 static HRESULT WINAPI unknode_get_namespaceURI(
1789 unknode *This = impl_from_unkIXMLDOMNode( iface );
1790 return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), p );
1793 static HRESULT WINAPI unknode_get_prefix(
1797 unknode *This = impl_from_unkIXMLDOMNode( iface );
1798 return IXMLDOMNode_get_prefix( IXMLDOMNode_from_impl(&This->node), p );
1801 static HRESULT WINAPI unknode_get_baseName(
1805 unknode *This = impl_from_unkIXMLDOMNode( iface );
1806 return IXMLDOMNode_get_baseName( IXMLDOMNode_from_impl(&This->node), p );
1809 static HRESULT WINAPI unknode_transformNodeToObject(
1811 IXMLDOMNode* domNode, VARIANT var1)
1813 unknode *This = impl_from_unkIXMLDOMNode( iface );
1814 return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), domNode, var1 );
1817 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1819 unknode_QueryInterface,
1822 unknode_GetTypeInfoCount,
1823 unknode_GetTypeInfo,
1824 unknode_GetIDsOfNames,
1826 unknode_get_nodeName,
1827 unknode_get_nodeValue,
1828 unknode_put_nodeValue,
1829 unknode_get_nodeType,
1830 unknode_get_parentNode,
1831 unknode_get_childNodes,
1832 unknode_get_firstChild,
1833 unknode_get_lastChild,
1834 unknode_get_previousSibling,
1835 unknode_get_nextSibling,
1836 unknode_get_attributes,
1837 unknode_insertBefore,
1838 unknode_replaceChild,
1839 unknode_removeChild,
1840 unknode_appendChild,
1841 unknode_hasChildNodes,
1842 unknode_get_ownerDocument,
1844 unknode_get_nodeTypeString,
1847 unknode_get_specified,
1848 unknode_get_definition,
1849 unknode_get_nodeTypedValue,
1850 unknode_put_nodeTypedValue,
1851 unknode_get_dataType,
1852 unknode_put_dataType,
1854 unknode_transformNode,
1855 unknode_selectNodes,
1856 unknode_selectSingleNode,
1858 unknode_get_namespaceURI,
1860 unknode_get_baseName,
1861 unknode_transformNodeToObject
1864 IXMLDOMNode *create_node( xmlNodePtr node )
1873 TRACE("type %d\n", node->type);
1876 case XML_ELEMENT_NODE:
1877 pUnk = create_element( node );
1879 case XML_ATTRIBUTE_NODE:
1880 pUnk = create_attribute( node );
1883 pUnk = create_text( node );
1885 case XML_CDATA_SECTION_NODE:
1886 pUnk = create_cdata( node );
1888 case XML_ENTITY_REF_NODE:
1889 pUnk = create_doc_entity_ref( node );
1892 pUnk = create_pi( node );
1894 case XML_COMMENT_NODE:
1895 pUnk = create_comment( node );
1897 case XML_DOCUMENT_NODE:
1898 pUnk = create_domdoc( node );
1900 case XML_DOCUMENT_FRAG_NODE:
1901 pUnk = create_doc_fragment( node );
1904 pUnk = create_doc_type( node );
1909 FIXME("only creating basic node for type %d\n", node->type);
1911 new_node = heap_alloc(sizeof(unknode));
1915 new_node->lpVtbl = &unknode_vtbl;
1917 init_xmlnode(&new_node->node, node, (IXMLDOMNode*)&new_node->lpVtbl, NULL);
1918 pUnk = (IUnknown*)&new_node->lpVtbl;
1922 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1923 IUnknown_Release(pUnk);
1924 if(FAILED(hr)) return NULL;