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 /* TODO: phasing this version out */
673 static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type)
675 if(!type || !lstrcmpiW(type, szString) ||
676 !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID))
679 V_BSTR(v) = bstr_from_xmlChar(str);
682 return E_OUTOFMEMORY;
684 else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) ||
685 !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) ||
686 !lstrcmpiW(type, szTimeTZ))
696 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
698 V_VT(&src) = VT_BSTR;
699 V_BSTR(&src) = bstr_from_xmlChar(str);
702 return E_OUTOFMEMORY;
705 e = p + SysStringLen(V_BSTR(&src));
707 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
710 st.wMonth = atoiW(p+5);
711 st.wDay = atoiW(p+8);
717 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
720 st.wMinute = atoiW(p+3);
721 st.wSecond = atoiW(p+6);
727 while(isdigitW(*p)) p++;
731 SystemTimeToVariantTime(&st, &date);
735 if(*p == '+') /* parse timezone offset (+hh:mm) */
736 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
737 else if(*p == '-') /* parse timezone offset (-hh:mm) */
738 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
742 else if(!lstrcmpiW(type, szBinHex))
747 len = xmlStrlen(str)/2;
751 V_VT(v) = (VT_ARRAY|VT_UI1);
752 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
755 return E_OUTOFMEMORY;
758 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
759 + hex_to_byte(str[2*i+1]);
761 else if(!lstrcmpiW(type, szBinBase64))
766 len = xmlStrlen(str);
767 if(str[len-2] == '=') i = 2;
768 else if(str[len-1] == '=') i = 1;
772 sab.cElements = len/4*3-i;
774 V_VT(v) = (VT_ARRAY|VT_UI1);
775 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
778 return E_OUTOFMEMORY;
780 for(i=0; i<len/4; i++)
782 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
783 + (base64_to_byte(str[4*i+1])>>4);
784 if(3*i+1 < sab.cElements)
785 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
786 + (base64_to_byte(str[4*i+2])>>2);
787 if(3*i+2 < sab.cElements)
788 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
789 + base64_to_byte(str[4*i+3]);
797 if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4))
799 else if(!lstrcmpiW(type, szFixed))
801 else if(!lstrcmpiW(type, szBoolean))
803 else if(!lstrcmpiW(type, szI1))
805 else if(!lstrcmpiW(type, szI2))
807 else if(!lstrcmpiW(type, szIU1))
809 else if(!lstrcmpiW(type, szIU2))
811 else if(!lstrcmpiW(type, szIU4))
813 else if(!lstrcmpiW(type, szR4))
815 else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat))
819 FIXME("Type handling not yet implemented\n");
823 V_VT(&src) = VT_BSTR;
824 V_BSTR(&src) = bstr_from_xmlChar(str);
827 return E_OUTOFMEMORY;
829 hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID(
830 LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
838 static HRESULT WINAPI xmlnode_get_nodeTypedValue(
842 xmlnode *This = impl_from_IXMLDOMNode( iface );
845 HRESULT hres = S_FALSE;
847 TRACE("(%p)->(%p)\n", This, typedValue);
852 V_VT(typedValue) = VT_NULL;
854 if (This->node->type == XML_TEXT_NODE || This->node->type == XML_ENTITY_REF_NODE)
857 hres = IXMLDOMNode_get_dataType(This->iface, &type);
860 return IXMLDOMNode_get_nodeValue(This->iface, typedValue);
862 content = xmlNodeGetContent(This->node);
863 hres = VARIANT_from_xmlChar(content, typedValue, hres==S_OK ? V_BSTR(&type) : NULL);
869 FIXME("need to handle node type %i\n", This->node->type);
875 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
879 xmlnode *This = impl_from_IXMLDOMNode( iface );
884 static HRESULT WINAPI xmlnode_put_dataType(
888 xmlnode *This = impl_from_IXMLDOMNode( iface );
891 TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
893 if(dataTypeName == NULL)
896 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
897 This applies to changing types (string->bool) or setting a new one
899 FIXME("Need to Validate the data before allowing a type to be set.\n");
901 /* Check all supported types. */
902 if(lstrcmpiW(dataTypeName,szString) == 0 ||
903 lstrcmpiW(dataTypeName,szNumber) == 0 ||
904 lstrcmpiW(dataTypeName,szUUID) == 0 ||
905 lstrcmpiW(dataTypeName,szInt) == 0 ||
906 lstrcmpiW(dataTypeName,szI4) == 0 ||
907 lstrcmpiW(dataTypeName,szFixed) == 0 ||
908 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
909 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
910 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
911 lstrcmpiW(dataTypeName,szDate) == 0 ||
912 lstrcmpiW(dataTypeName,szTime) == 0 ||
913 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
914 lstrcmpiW(dataTypeName,szI1) == 0 ||
915 lstrcmpiW(dataTypeName,szI2) == 0 ||
916 lstrcmpiW(dataTypeName,szIU1) == 0 ||
917 lstrcmpiW(dataTypeName,szIU2) == 0 ||
918 lstrcmpiW(dataTypeName,szIU4) == 0 ||
919 lstrcmpiW(dataTypeName,szR4) == 0 ||
920 lstrcmpiW(dataTypeName,szR8) == 0 ||
921 lstrcmpiW(dataTypeName,szFloat) == 0 ||
922 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
923 lstrcmpiW(dataTypeName,szBinBase64) == 0)
925 xmlChar* str = xmlChar_from_wchar(dataTypeName);
928 if (!str) return E_OUTOFMEMORY;
930 attr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
931 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
934 attr = xmlSetNsProp(This->node, attr->ns, (const xmlChar*)"dt", str);
939 xmlNsPtr ns = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
942 attr = xmlNewNsProp(This->node, ns, (const xmlChar*)"dt", str);
945 xmlAddChild(This->node, (xmlNodePtr)attr);
949 ERR("Failed to create Attribute\n");
952 ERR("Failed to create Namespace\n");
960 BSTR EnsureCorrectEOL(BSTR sInput)
967 nLen = SysStringLen(sInput);
968 /* Count line endings */
969 for(i=0; i < nLen; i++)
971 if(sInput[i] == '\n')
975 TRACE("len=%d, num=%d\n", nLen, nNum);
977 /* Add linefeed as needed */
981 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
982 for(i=0; i < nLen; i++)
984 if(sInput[i] == '\n')
986 sNew[i+nPlace] = '\r';
989 sNew[i+nPlace] = sInput[i];
992 SysFreeString(sInput);
999 TRACE("len %d\n", SysStringLen(sNew));
1004 /* Removes encoding information and last character (nullbyte) */
1005 static BSTR EnsureNoEncoding(BSTR sInput)
1007 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1012 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1017 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1022 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1023 while(*pEnd != '\"') pEnd++;
1026 sNew = SysAllocStringLen(NULL,
1027 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1028 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1029 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1031 SysFreeString(sInput);
1036 * We are trying to replicate the same behaviour as msxml by converting
1037 * line endings to \r\n and using indents as \t. The problem is that msxml
1038 * only formats nodes that have a line ending. Using libxml we cannot
1039 * reproduce behaviour exactly.
1042 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
1044 xmlBufferPtr xml_buf;
1049 return E_INVALIDARG;
1053 xml_buf = xmlBufferCreate();
1055 return E_OUTOFMEMORY;
1057 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
1059 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
1061 const xmlChar *buf_content;
1064 /* Attribute Nodes return a space in front of their name */
1065 buf_content = xmlBufferContent(xml_buf);
1067 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
1069 content = EnsureCorrectEOL(content);
1070 if(ensure_no_encoding)
1071 content = EnsureNoEncoding(content);
1075 *ret = SysAllocStringLen(NULL, 0);
1078 xmlBufferFree(xml_buf);
1079 xmldoc_link_xmldecl( This->node->doc, xmldecl );
1080 return *ret ? S_OK : E_OUTOFMEMORY;
1083 static HRESULT WINAPI xmlnode_transformNode(
1085 IXMLDOMNode* styleSheet,
1088 #ifdef SONAME_LIBXSLT
1089 xmlnode *This = impl_from_IXMLDOMNode( iface );
1090 xmlnode *pStyleSheet = NULL;
1091 xsltStylesheetPtr xsltSS = NULL;
1092 xmlDocPtr result = NULL;
1094 TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1096 if (!libxslt_handle)
1098 if(!styleSheet || !xmlString)
1099 return E_INVALIDARG;
1103 pStyleSheet = get_node_obj(styleSheet);
1105 FIXME("styleSheet is not our xmlnode implementation\n");
1109 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1112 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1115 const xmlChar *pContent;
1117 if(result->type == XML_HTML_DOCUMENT_NODE)
1119 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1122 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1123 pContent = xmlBufferContent(pOutput->buffer);
1124 *xmlString = bstr_from_xmlChar(pContent);
1125 xmlOutputBufferClose(pOutput);
1130 xmlBufferPtr pXmlBuf;
1133 pXmlBuf = xmlBufferCreate();
1136 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1139 pContent = xmlBufferContent(pXmlBuf);
1140 *xmlString = bstr_from_xmlChar(pContent);
1142 xmlBufferFree(pXmlBuf);
1147 /* libxslt "helpfully" frees the XML document the stylesheet was
1148 generated from, too */
1150 pxsltFreeStylesheet(xsltSS);
1153 if(*xmlString == NULL)
1154 *xmlString = SysAllocStringLen(NULL, 0);
1158 FIXME("libxslt headers were not found at compile time\n");
1163 static HRESULT WINAPI xmlnode_selectNodes(
1166 IXMLDOMNodeList** resultList)
1168 xmlnode *This = impl_from_IXMLDOMNode( iface );
1170 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1172 if (!queryString || !resultList) return E_INVALIDARG;
1174 return queryresult_create( This->node, queryString, resultList );
1177 static HRESULT WINAPI xmlnode_selectSingleNode(
1180 IXMLDOMNode** resultNode)
1182 xmlnode *This = impl_from_IXMLDOMNode( iface );
1183 IXMLDOMNodeList *list;
1186 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1188 r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1191 r = IXMLDOMNodeList_nextNode(list, resultNode);
1192 IXMLDOMNodeList_Release(list);
1197 static HRESULT WINAPI xmlnode_get_namespaceURI(
1201 xmlnode *This = impl_from_IXMLDOMNode( iface );
1204 TRACE("(%p)->(%p)\n", This, namespaceURI );
1207 return E_INVALIDARG;
1209 *namespaceURI = NULL;
1211 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1213 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1217 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1219 return *namespaceURI ? S_OK : S_FALSE;
1222 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1226 if (!prefix) return E_INVALIDARG;
1230 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1232 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1236 TRACE("prefix: %s\n", debugstr_w(*prefix));
1238 return *prefix ? S_OK : S_FALSE;
1241 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1243 if (!name) return E_INVALIDARG;
1245 *name = bstr_from_xmlChar(This->node->name);
1246 if (!*name) return E_OUTOFMEMORY;
1248 TRACE("returning %s\n", debugstr_w(*name));
1253 static HRESULT WINAPI xmlnode_transformNodeToObject(
1255 IXMLDOMNode* stylesheet,
1256 VARIANT outputObject)
1258 xmlnode *This = impl_from_IXMLDOMNode( iface );
1259 FIXME("(%p)->(%p)\n", This, stylesheet);
1263 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1285 xmlnode_removeChild,
1286 xmlnode_appendChild,
1287 xmlnode_hasChildNodes,
1288 xmlnode_get_ownerDocument,
1295 xmlnode_get_nodeTypedValue,
1296 xmlnode_put_nodeTypedValue,
1298 xmlnode_put_dataType,
1300 xmlnode_transformNode,
1301 xmlnode_selectNodes,
1302 xmlnode_selectSingleNode,
1304 xmlnode_get_namespaceURI,
1307 xmlnode_transformNodeToObject,
1310 void destroy_xmlnode(xmlnode *This)
1313 xmldoc_release(This->node->doc);
1316 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1319 xmldoc_add_ref( node->doc );
1321 This->lpVtbl = &xmlnode_vtbl;
1323 This->iface = node_iface;
1326 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1328 This->dispex.outer = NULL;
1333 const IXMLDOMNodeVtbl *lpVtbl;
1337 static inline unknode *impl_from_unkIXMLDOMNode(IXMLDOMNode *iface)
1339 return (unknode *)((char*)iface - FIELD_OFFSET(unknode, lpVtbl));
1342 static HRESULT WINAPI unknode_QueryInterface(
1347 unknode *This = impl_from_unkIXMLDOMNode( iface );
1349 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1351 if (IsEqualGUID(riid, &IID_IUnknown)) {
1353 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1354 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1355 *ppvObject = &This->lpVtbl;
1356 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1357 return *ppvObject ? S_OK : E_NOINTERFACE;
1359 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1361 return E_NOINTERFACE;
1364 IUnknown_AddRef((IUnknown*)*ppvObject);
1368 static ULONG WINAPI unknode_AddRef(
1369 IXMLDOMNode *iface )
1371 unknode *This = impl_from_unkIXMLDOMNode( iface );
1373 return InterlockedIncrement(&This->ref);
1376 static ULONG WINAPI unknode_Release(
1377 IXMLDOMNode *iface )
1379 unknode *This = impl_from_unkIXMLDOMNode( iface );
1382 ref = InterlockedDecrement( &This->ref );
1384 destroy_xmlnode(&This->node);
1391 static HRESULT WINAPI unknode_GetTypeInfoCount(
1395 unknode *This = impl_from_unkIXMLDOMNode( iface );
1397 TRACE("(%p)->(%p)\n", This, pctinfo);
1404 static HRESULT WINAPI unknode_GetTypeInfo(
1408 ITypeInfo** ppTInfo )
1410 unknode *This = impl_from_unkIXMLDOMNode( iface );
1413 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1415 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1420 static HRESULT WINAPI unknode_GetIDsOfNames(
1423 LPOLESTR* rgszNames,
1428 unknode *This = impl_from_unkIXMLDOMNode( iface );
1430 ITypeInfo *typeinfo;
1433 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1436 if(!rgszNames || cNames == 0 || !rgDispId)
1437 return E_INVALIDARG;
1439 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1442 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1443 ITypeInfo_Release(typeinfo);
1449 static HRESULT WINAPI unknode_Invoke(
1451 DISPID dispIdMember,
1455 DISPPARAMS* pDispParams,
1456 VARIANT* pVarResult,
1457 EXCEPINFO* pExcepInfo,
1460 unknode *This = impl_from_unkIXMLDOMNode( iface );
1461 ITypeInfo *typeinfo;
1464 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1465 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1467 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1470 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1471 pVarResult, pExcepInfo, puArgErr);
1472 ITypeInfo_Release(typeinfo);
1478 static HRESULT WINAPI unknode_get_nodeName(
1482 unknode *This = impl_from_unkIXMLDOMNode( iface );
1484 FIXME("(%p)->(%p)\n", This, p);
1486 return node_get_nodeName(&This->node, p);
1489 static HRESULT WINAPI unknode_get_nodeValue(
1493 unknode *This = impl_from_unkIXMLDOMNode( iface );
1495 FIXME("(%p)->(%p)\n", This, value);
1498 return E_INVALIDARG;
1500 V_VT(value) = VT_NULL;
1504 static HRESULT WINAPI unknode_put_nodeValue(
1508 unknode *This = impl_from_unkIXMLDOMNode( iface );
1509 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1513 static HRESULT WINAPI unknode_get_nodeType(
1515 DOMNodeType* domNodeType )
1517 unknode *This = impl_from_unkIXMLDOMNode( iface );
1519 FIXME("(%p)->(%p)\n", This, domNodeType);
1521 *domNodeType = This->node.node->type;
1525 static HRESULT WINAPI unknode_get_parentNode(
1527 IXMLDOMNode** parent )
1529 unknode *This = impl_from_unkIXMLDOMNode( iface );
1530 FIXME("(%p)->(%p)\n", This, parent);
1531 if (!parent) return E_INVALIDARG;
1536 static HRESULT WINAPI unknode_get_childNodes(
1538 IXMLDOMNodeList** outList)
1540 unknode *This = impl_from_unkIXMLDOMNode( iface );
1542 TRACE("(%p)->(%p)\n", This, outList);
1544 return node_get_child_nodes(&This->node, outList);
1547 static HRESULT WINAPI unknode_get_firstChild(
1549 IXMLDOMNode** domNode)
1551 unknode *This = impl_from_unkIXMLDOMNode( iface );
1553 TRACE("(%p)->(%p)\n", This, domNode);
1555 return node_get_first_child(&This->node, domNode);
1558 static HRESULT WINAPI unknode_get_lastChild(
1560 IXMLDOMNode** domNode)
1562 unknode *This = impl_from_unkIXMLDOMNode( iface );
1564 TRACE("(%p)->(%p)\n", This, domNode);
1566 return node_get_last_child(&This->node, domNode);
1569 static HRESULT WINAPI unknode_get_previousSibling(
1571 IXMLDOMNode** domNode)
1573 unknode *This = impl_from_unkIXMLDOMNode( iface );
1575 TRACE("(%p)->(%p)\n", This, domNode);
1577 return node_get_previous_sibling(&This->node, domNode);
1580 static HRESULT WINAPI unknode_get_nextSibling(
1582 IXMLDOMNode** domNode)
1584 unknode *This = impl_from_unkIXMLDOMNode( iface );
1586 TRACE("(%p)->(%p)\n", This, domNode);
1588 return node_get_next_sibling(&This->node, domNode);
1591 static HRESULT WINAPI unknode_get_attributes(
1593 IXMLDOMNamedNodeMap** attributeMap)
1595 unknode *This = impl_from_unkIXMLDOMNode( iface );
1597 FIXME("(%p)->(%p)\n", This, attributeMap);
1599 return return_null_ptr((void**)attributeMap);
1602 static HRESULT WINAPI unknode_insertBefore(
1604 IXMLDOMNode* newNode, VARIANT refChild,
1605 IXMLDOMNode** outOldNode)
1607 unknode *This = impl_from_unkIXMLDOMNode( iface );
1609 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1611 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1614 static HRESULT WINAPI unknode_replaceChild(
1616 IXMLDOMNode* newNode,
1617 IXMLDOMNode* oldNode,
1618 IXMLDOMNode** outOldNode)
1620 unknode *This = impl_from_unkIXMLDOMNode( iface );
1622 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1624 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1627 static HRESULT WINAPI unknode_removeChild(
1629 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1631 unknode *This = impl_from_unkIXMLDOMNode( iface );
1632 return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), domNode, oldNode );
1635 static HRESULT WINAPI unknode_appendChild(
1637 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1639 unknode *This = impl_from_unkIXMLDOMNode( iface );
1640 return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newNode, outNewNode );
1643 static HRESULT WINAPI unknode_hasChildNodes(
1645 VARIANT_BOOL* pbool)
1647 unknode *This = impl_from_unkIXMLDOMNode( iface );
1648 return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), pbool );
1651 static HRESULT WINAPI unknode_get_ownerDocument(
1653 IXMLDOMDocument** domDocument)
1655 unknode *This = impl_from_unkIXMLDOMNode( iface );
1656 return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), domDocument );
1659 static HRESULT WINAPI unknode_cloneNode(
1661 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1663 unknode *This = impl_from_unkIXMLDOMNode( iface );
1664 return IXMLDOMNode_cloneNode( IXMLDOMNode_from_impl(&This->node), pbool, outNode );
1667 static HRESULT WINAPI unknode_get_nodeTypeString(
1671 unknode *This = impl_from_unkIXMLDOMNode( iface );
1673 FIXME("(%p)->(%p)\n", This, p);
1675 return node_get_nodeName(&This->node, p);
1678 static HRESULT WINAPI unknode_get_text(
1682 unknode *This = impl_from_unkIXMLDOMNode( iface );
1683 return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), p );
1686 static HRESULT WINAPI unknode_put_text(
1690 unknode *This = impl_from_unkIXMLDOMNode( iface );
1691 return IXMLDOMNode_put_text( IXMLDOMNode_from_impl(&This->node), p );
1694 static HRESULT WINAPI unknode_get_specified(
1696 VARIANT_BOOL* isSpecified)
1698 unknode *This = impl_from_unkIXMLDOMNode( iface );
1699 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1700 *isSpecified = VARIANT_TRUE;
1704 static HRESULT WINAPI unknode_get_definition(
1706 IXMLDOMNode** definitionNode)
1708 unknode *This = impl_from_unkIXMLDOMNode( iface );
1709 FIXME("(%p)->(%p)\n", This, definitionNode);
1713 static HRESULT WINAPI unknode_get_nodeTypedValue(
1717 unknode *This = impl_from_unkIXMLDOMNode( iface );
1718 return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1721 static HRESULT WINAPI unknode_put_nodeTypedValue(
1725 unknode *This = impl_from_unkIXMLDOMNode( iface );
1726 return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1729 static HRESULT WINAPI unknode_get_dataType(
1733 unknode *This = impl_from_unkIXMLDOMNode( iface );
1734 return IXMLDOMNode_get_dataType( IXMLDOMNode_from_impl(&This->node), var1 );
1737 static HRESULT WINAPI unknode_put_dataType(
1741 unknode *This = impl_from_unkIXMLDOMNode( iface );
1742 return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), p );
1745 static HRESULT WINAPI unknode_get_xml(
1749 unknode *This = impl_from_unkIXMLDOMNode( iface );
1751 FIXME("(%p)->(%p)\n", This, p);
1753 return node_get_xml(&This->node, FALSE, FALSE, p);
1756 static HRESULT WINAPI unknode_transformNode(
1758 IXMLDOMNode* domNode, BSTR* p)
1760 unknode *This = impl_from_unkIXMLDOMNode( iface );
1761 return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), domNode, p );
1764 static HRESULT WINAPI unknode_selectNodes(
1766 BSTR p, IXMLDOMNodeList** outList)
1768 unknode *This = impl_from_unkIXMLDOMNode( iface );
1769 return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), p, outList );
1772 static HRESULT WINAPI unknode_selectSingleNode(
1774 BSTR p, IXMLDOMNode** outNode)
1776 unknode *This = impl_from_unkIXMLDOMNode( iface );
1777 return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), p, outNode );
1780 static HRESULT WINAPI unknode_get_parsed(
1782 VARIANT_BOOL* isParsed)
1784 unknode *This = impl_from_unkIXMLDOMNode( iface );
1785 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1786 *isParsed = VARIANT_TRUE;
1790 static HRESULT WINAPI unknode_get_namespaceURI(
1794 unknode *This = impl_from_unkIXMLDOMNode( iface );
1795 return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), p );
1798 static HRESULT WINAPI unknode_get_prefix(
1802 unknode *This = impl_from_unkIXMLDOMNode( iface );
1803 return IXMLDOMNode_get_prefix( IXMLDOMNode_from_impl(&This->node), p );
1806 static HRESULT WINAPI unknode_get_baseName(
1810 unknode *This = impl_from_unkIXMLDOMNode( iface );
1811 return IXMLDOMNode_get_baseName( IXMLDOMNode_from_impl(&This->node), p );
1814 static HRESULT WINAPI unknode_transformNodeToObject(
1816 IXMLDOMNode* domNode, VARIANT var1)
1818 unknode *This = impl_from_unkIXMLDOMNode( iface );
1819 return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), domNode, var1 );
1822 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1824 unknode_QueryInterface,
1827 unknode_GetTypeInfoCount,
1828 unknode_GetTypeInfo,
1829 unknode_GetIDsOfNames,
1831 unknode_get_nodeName,
1832 unknode_get_nodeValue,
1833 unknode_put_nodeValue,
1834 unknode_get_nodeType,
1835 unknode_get_parentNode,
1836 unknode_get_childNodes,
1837 unknode_get_firstChild,
1838 unknode_get_lastChild,
1839 unknode_get_previousSibling,
1840 unknode_get_nextSibling,
1841 unknode_get_attributes,
1842 unknode_insertBefore,
1843 unknode_replaceChild,
1844 unknode_removeChild,
1845 unknode_appendChild,
1846 unknode_hasChildNodes,
1847 unknode_get_ownerDocument,
1849 unknode_get_nodeTypeString,
1852 unknode_get_specified,
1853 unknode_get_definition,
1854 unknode_get_nodeTypedValue,
1855 unknode_put_nodeTypedValue,
1856 unknode_get_dataType,
1857 unknode_put_dataType,
1859 unknode_transformNode,
1860 unknode_selectNodes,
1861 unknode_selectSingleNode,
1863 unknode_get_namespaceURI,
1865 unknode_get_baseName,
1866 unknode_transformNodeToObject
1869 IXMLDOMNode *create_node( xmlNodePtr node )
1878 TRACE("type %d\n", node->type);
1881 case XML_ELEMENT_NODE:
1882 pUnk = create_element( node );
1884 case XML_ATTRIBUTE_NODE:
1885 pUnk = create_attribute( node );
1888 pUnk = create_text( node );
1890 case XML_CDATA_SECTION_NODE:
1891 pUnk = create_cdata( node );
1893 case XML_ENTITY_REF_NODE:
1894 pUnk = create_doc_entity_ref( node );
1897 pUnk = create_pi( node );
1899 case XML_COMMENT_NODE:
1900 pUnk = create_comment( node );
1902 case XML_DOCUMENT_NODE:
1903 pUnk = create_domdoc( node );
1905 case XML_DOCUMENT_FRAG_NODE:
1906 pUnk = create_doc_fragment( node );
1909 pUnk = create_doc_type( node );
1914 FIXME("only creating basic node for type %d\n", node->type);
1916 new_node = heap_alloc(sizeof(unknode));
1920 new_node->lpVtbl = &unknode_vtbl;
1922 init_xmlnode(&new_node->node, node, (IXMLDOMNode*)&new_node->lpVtbl, NULL);
1923 pUnk = (IUnknown*)&new_node->lpVtbl;
1927 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1928 IUnknown_Release(pUnk);
1929 if(FAILED(hr)) return NULL;