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
34 #include "msxml_private.h"
37 # include <libxml/HTMLtree.h>
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
46 static const WCHAR szBinBase64[] = {'b','i','n','.','b','a','s','e','6','4',0};
47 static const WCHAR szString[] = {'s','t','r','i','n','g',0};
48 static const WCHAR szNumber[] = {'n','u','m','b','e','r',0};
49 static const WCHAR szInt[] = {'I','n','t',0};
50 static const WCHAR szFixed[] = {'F','i','x','e','d','.','1','4','.','4',0};
51 static const WCHAR szBoolean[] = {'B','o','o','l','e','a','n',0};
52 static const WCHAR szDateTime[] = {'d','a','t','e','T','i','m','e',0};
53 static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
54 static const WCHAR szDate[] = {'D','a','t','e',0};
55 static const WCHAR szTime[] = {'T','i','m','e',0};
56 static const WCHAR szTimeTZ[] = {'T','i','m','e','.','t','z',0};
57 static const WCHAR szI1[] = {'i','1',0};
58 static const WCHAR szI2[] = {'i','2',0};
59 static const WCHAR szI4[] = {'i','4',0};
60 static const WCHAR szIU1[] = {'u','i','1',0};
61 static const WCHAR szIU2[] = {'u','i','2',0};
62 static const WCHAR szIU4[] = {'u','i','4',0};
63 static const WCHAR szR4[] = {'r','4',0};
64 static const WCHAR szR8[] = {'r','8',0};
65 static const WCHAR szFloat[] = {'f','l','o','a','t',0};
66 static const WCHAR szUUID[] = {'u','u','i','d',0};
67 static const WCHAR szBinHex[] = {'b','i','n','.','h','e','x',0};
69 static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}};
71 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
77 This = get_node_obj( iface );
78 if ( !This || !This->node )
80 if ( type && This->node->type != type )
85 BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv)
87 if(IsEqualGUID(&IID_xmlnode, riid)) {
88 TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv);
93 if(This->dispex.outer)
94 return dispex_query_interface(&This->dispex, riid, ppv);
99 xmlnode *get_node_obj(IXMLDOMNode *node)
104 hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj);
105 return SUCCEEDED(hres) ? obj : NULL;
108 static inline xmlnode *impl_from_IXMLDOMNode( IXMLDOMNode *iface )
110 return (xmlnode *)((char*)iface - FIELD_OFFSET(xmlnode, lpVtbl));
113 HRESULT node_get_nodeName(xmlnode *This, BSTR *name)
118 *name = bstr_from_xmlChar(This->node->name);
125 HRESULT node_get_content(xmlnode *This, VARIANT *value)
132 content = xmlNodeGetContent(This->node);
133 V_VT(value) = VT_BSTR;
134 V_BSTR(value) = bstr_from_xmlChar( content );
137 TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value)));
141 HRESULT node_set_content(xmlnode *This, LPCWSTR value)
145 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
146 str = xmlChar_from_wchar(value);
148 return E_OUTOFMEMORY;
150 xmlNodeSetContent(This->node, str);
155 static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value)
157 xmlChar *str, *escaped;
159 TRACE("(%p)->(%s)\n", This, debugstr_w(value));
160 str = xmlChar_from_wchar(value);
162 return E_OUTOFMEMORY;
164 escaped = xmlEncodeSpecialChars(NULL, str);
168 return E_OUTOFMEMORY;
171 xmlNodeSetContent(This->node, escaped);
179 HRESULT node_put_value(xmlnode *This, VARIANT *value)
181 VARIANT string_value;
184 VariantInit(&string_value);
185 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
187 WARN("Couldn't convert to VT_BSTR\n");
191 hr = node_set_content(This, V_BSTR(&string_value));
192 VariantClear(&string_value);
197 HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value)
199 VARIANT string_value;
202 VariantInit(&string_value);
203 hr = VariantChangeType(&string_value, value, 0, VT_BSTR);
205 WARN("Couldn't convert to VT_BSTR\n");
209 hr = node_set_content_escaped(This, V_BSTR(&string_value));
210 VariantClear(&string_value);
215 static HRESULT get_node(
221 TRACE("(%p)->(%s %p %p)\n", This, name, node, out );
226 /* if we don't have a doc, use our parent. */
227 if(node && !node->doc && node->parent)
228 node->doc = node->parent->doc;
230 *out = create_node( node );
236 HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent)
238 return get_node( This, "parent", This->node->parent, parent );
241 HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret)
246 *ret = create_children_nodelist(This->node);
248 return E_OUTOFMEMORY;
253 HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret)
255 return get_node(This, "firstChild", This->node->children, ret);
258 HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret)
260 return get_node(This, "lastChild", This->node->last, ret);
263 HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret)
265 return get_node(This, "previous", This->node->prev, ret);
268 HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret)
270 return get_node(This, "next", This->node->next, ret);
273 HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child,
276 xmlNodePtr before_node, new_child_node;
277 IXMLDOMNode *before = NULL;
284 node_obj = get_node_obj(new_child);
286 FIXME("newChild is not our node implementation\n");
290 switch(V_VT(ref_child))
298 hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (LPVOID)&before);
299 if(FAILED(hr)) return hr;
303 FIXME("refChild var type %x\n", V_VT(ref_child));
307 new_child_node = node_obj->node;
308 TRACE("new_child_node %p This->node %p\n", new_child_node, This->node);
310 if(!new_child_node->parent)
311 if(xmldoc_remove_orphan(new_child_node->doc, new_child_node) != S_OK)
312 WARN("%p is not an orphan of %p\n", new_child_node, new_child_node->doc);
316 node_obj = get_node_obj(before);
317 IXMLDOMNode_Release(before);
319 FIXME("before node is not our node implementation\n");
323 before_node = node_obj->node;
324 xmlAddPrevSibling(before_node, new_child_node);
328 xmlAddChild(This->node, new_child_node);
332 IXMLDOMNode_AddRef(new_child);
340 HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild,
343 xmlnode *old_child, *new_child;
344 xmlDocPtr leaving_doc;
345 xmlNode *my_ancestor;
347 /* Do not believe any documentation telling that newChild == NULL
348 means removal. It does certainly *not* apply to msxml3! */
349 if(!newChild || !oldChild)
355 old_child = get_node_obj(oldChild);
357 FIXME("oldChild is not our node implementation\n");
361 if(old_child->node->parent != This->node)
363 WARN("childNode %p is not a child of %p\n", oldChild, This);
367 new_child = get_node_obj(newChild);
369 FIXME("newChild is not our node implementation\n");
373 my_ancestor = This->node;
376 if(my_ancestor == new_child->node)
378 WARN("tried to create loop\n");
381 my_ancestor = my_ancestor->parent;
384 if(!new_child->node->parent)
385 if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK)
386 WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc);
388 leaving_doc = new_child->node->doc;
389 xmldoc_add_ref(old_child->node->doc);
390 xmlReplaceNode(old_child->node, new_child->node);
391 xmldoc_release(leaving_doc);
393 xmldoc_add_orphan(old_child->node->doc, old_child->node);
397 IXMLDOMNode_AddRef(oldChild);
404 static HRESULT WINAPI xmlnode_removeChild(
406 IXMLDOMNode* childNode,
407 IXMLDOMNode** oldChild)
409 xmlnode *This = impl_from_IXMLDOMNode( iface );
412 TRACE("(%p)->(%p %p)\n", This, childNode, oldChild);
414 if(!childNode) return E_INVALIDARG;
419 child_node = get_node_obj(childNode);
421 FIXME("childNode is not our node implementation\n");
425 if(child_node->node->parent != This->node)
427 WARN("childNode %p is not a child of %p\n", childNode, iface);
431 xmlUnlinkNode(child_node->node);
435 IXMLDOMNode_AddRef(childNode);
436 *oldChild = childNode;
442 static HRESULT WINAPI xmlnode_appendChild(
444 IXMLDOMNode* newChild,
445 IXMLDOMNode** outNewChild)
447 xmlnode *This = impl_from_IXMLDOMNode( iface );
452 TRACE("(%p)->(%p %p)\n", This, newChild, outNewChild);
454 hr = IXMLDOMNode_get_nodeType(newChild, &type);
455 if(FAILED(hr) || type == NODE_ATTRIBUTE) {
456 if(outNewChild) *outNewChild = NULL;
461 return IXMLDOMNode_insertBefore(This->iface, newChild, var, outNewChild);
464 static HRESULT WINAPI xmlnode_hasChildNodes(
466 VARIANT_BOOL* hasChild)
468 xmlnode *This = impl_from_IXMLDOMNode( iface );
470 TRACE("(%p)->(%p)\n", This, hasChild);
474 if (!This->node->children)
476 *hasChild = VARIANT_FALSE;
480 *hasChild = VARIANT_TRUE;
484 static HRESULT WINAPI xmlnode_get_ownerDocument(
486 IXMLDOMDocument** DOMDocument)
488 xmlnode *This = impl_from_IXMLDOMNode( iface );
490 TRACE("(%p)->(%p)\n", This, DOMDocument);
492 return DOMDocument_create_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)DOMDocument);
495 HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode)
500 if(!cloneNode) return E_INVALIDARG;
502 clone = xmlCopyNode(This->node, deep ? 1 : 2);
505 clone->doc = This->node->doc;
506 xmldoc_add_orphan(clone->doc, clone);
508 node = create_node(clone);
511 ERR("Copy failed\n");
519 ERR("Copy failed\n");
526 static inline xmlChar* trim_whitespace(xmlChar* str)
534 while (*ret && isspace(*ret))
536 len = xmlStrlen(ret);
537 while (isspace(ret[len-1]))
540 ret = xmlStrndup(ret, len);
545 static xmlChar* do_get_text(xmlNodePtr node)
549 BOOL preserving = is_preserving_whitespace(node);
553 str = xmlNodeGetContent(node);
557 xmlElementType prev_type = XML_TEXT_NODE;
559 str = xmlStrdup(BAD_CAST "");
560 for (child = node->children; child != NULL; child = child->next)
564 case XML_ELEMENT_NODE:
565 tmp = do_get_text(child);
568 case XML_CDATA_SECTION_NODE:
569 case XML_ENTITY_REF_NODE:
570 case XML_ENTITY_NODE:
571 tmp = xmlNodeGetContent(child);
582 if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE)
583 str = xmlStrcat(str, BAD_CAST " ");
584 str = xmlStrcat(str, tmp);
585 prev_type = child->type;
594 case XML_ELEMENT_NODE:
596 case XML_ENTITY_REF_NODE:
597 case XML_ENTITY_NODE:
598 case XML_DOCUMENT_NODE:
599 case XML_DOCUMENT_FRAG_NODE:
601 str = trim_whitespace(str);
610 static HRESULT WINAPI xmlnode_get_text(
614 xmlnode *This = impl_from_IXMLDOMNode( iface );
618 TRACE("(%p, type %d)->(%p)\n", This, This->node->type, text);
623 pContent = do_get_text((xmlNodePtr)This->node);
626 str = bstr_from_xmlChar(pContent);
630 /* Always return a string. */
631 if (!str) str = SysAllocStringLen( NULL, 0 );
633 TRACE("%p %s\n", This, debugstr_w(str) );
639 HRESULT node_put_text(xmlnode *This, BSTR text)
643 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
645 str = xmlChar_from_wchar(text);
647 /* Escape the string. */
648 str2 = xmlEncodeEntitiesReentrant(This->node->doc, str);
651 xmlNodeSetContent(This->node, str2);
657 static inline BYTE hex_to_byte(xmlChar c)
659 if(c <= '9') return c-'0';
660 if(c <= 'F') return c-'A'+10;
664 static inline BYTE base64_to_byte(xmlChar c)
666 if(c == '+') return 62;
667 if(c == '/') return 63;
668 if(c <= '9') return c-'0'+52;
669 if(c <= 'Z') return c-'A';
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_ELEMENT_NODE ||
855 This->node->type == XML_TEXT_NODE ||
856 This->node->type == XML_ENTITY_REF_NODE)
857 hres = IXMLDOMNode_get_dataType(This->iface, &type);
859 if(hres != S_OK && This->node->type != XML_ELEMENT_NODE)
860 return IXMLDOMNode_get_nodeValue(This->iface, typedValue);
862 content = xmlNodeGetContent(This->node);
863 hres = VARIANT_from_xmlChar(content, typedValue,
864 hres==S_OK ? V_BSTR(&type) : NULL);
871 static HRESULT WINAPI xmlnode_put_nodeTypedValue(
875 xmlnode *This = impl_from_IXMLDOMNode( iface );
880 static HRESULT WINAPI xmlnode_put_dataType(
884 xmlnode *This = impl_from_IXMLDOMNode( iface );
887 TRACE("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
889 if(dataTypeName == NULL)
892 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
893 This applies to changing types (string->bool) or setting a new one
895 FIXME("Need to Validate the data before allowing a type to be set.\n");
897 /* Check all supported types. */
898 if(lstrcmpiW(dataTypeName,szString) == 0 ||
899 lstrcmpiW(dataTypeName,szNumber) == 0 ||
900 lstrcmpiW(dataTypeName,szUUID) == 0 ||
901 lstrcmpiW(dataTypeName,szInt) == 0 ||
902 lstrcmpiW(dataTypeName,szI4) == 0 ||
903 lstrcmpiW(dataTypeName,szFixed) == 0 ||
904 lstrcmpiW(dataTypeName,szBoolean) == 0 ||
905 lstrcmpiW(dataTypeName,szDateTime) == 0 ||
906 lstrcmpiW(dataTypeName,szDateTimeTZ) == 0 ||
907 lstrcmpiW(dataTypeName,szDate) == 0 ||
908 lstrcmpiW(dataTypeName,szTime) == 0 ||
909 lstrcmpiW(dataTypeName,szTimeTZ) == 0 ||
910 lstrcmpiW(dataTypeName,szI1) == 0 ||
911 lstrcmpiW(dataTypeName,szI2) == 0 ||
912 lstrcmpiW(dataTypeName,szIU1) == 0 ||
913 lstrcmpiW(dataTypeName,szIU2) == 0 ||
914 lstrcmpiW(dataTypeName,szIU4) == 0 ||
915 lstrcmpiW(dataTypeName,szR4) == 0 ||
916 lstrcmpiW(dataTypeName,szR8) == 0 ||
917 lstrcmpiW(dataTypeName,szFloat) == 0 ||
918 lstrcmpiW(dataTypeName,szBinHex) == 0 ||
919 lstrcmpiW(dataTypeName,szBinBase64) == 0)
921 xmlChar* str = xmlChar_from_wchar(dataTypeName);
924 if (!str) return E_OUTOFMEMORY;
926 attr = xmlHasNsProp(This->node, (const xmlChar*)"dt",
927 (const xmlChar*)"urn:schemas-microsoft-com:datatypes");
930 attr = xmlSetNsProp(This->node, attr->ns, (const xmlChar*)"dt", str);
935 xmlNsPtr ns = xmlNewNs(This->node, (const xmlChar*)"urn:schemas-microsoft-com:datatypes", (const xmlChar*)"dt");
938 attr = xmlNewNsProp(This->node, ns, (const xmlChar*)"dt", str);
941 xmlAddChild(This->node, (xmlNodePtr)attr);
945 ERR("Failed to create Attribute\n");
948 ERR("Failed to create Namespace\n");
956 BSTR EnsureCorrectEOL(BSTR sInput)
963 nLen = SysStringLen(sInput);
964 /* Count line endings */
965 for(i=0; i < nLen; i++)
967 if(sInput[i] == '\n')
971 TRACE("len=%d, num=%d\n", nLen, nNum);
973 /* Add linefeed as needed */
977 sNew = SysAllocStringLen(NULL, nLen + nNum+1);
978 for(i=0; i < nLen; i++)
980 if(sInput[i] == '\n')
982 sNew[i+nPlace] = '\r';
985 sNew[i+nPlace] = sInput[i];
988 SysFreeString(sInput);
995 TRACE("len %d\n", SysStringLen(sNew));
1000 /* Removes encoding information and last character (nullbyte) */
1001 static BSTR EnsureNoEncoding(BSTR sInput)
1003 static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='};
1008 while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding)))
1013 SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1);
1018 pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2;
1019 while(*pEnd != '\"') pEnd++;
1022 sNew = SysAllocStringLen(NULL,
1023 pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1);
1024 memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR));
1025 memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR));
1027 SysFreeString(sInput);
1032 * We are trying to replicate the same behaviour as msxml by converting
1033 * line endings to \r\n and using indents as \t. The problem is that msxml
1034 * only formats nodes that have a line ending. Using libxml we cannot
1035 * reproduce behaviour exactly.
1038 HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret)
1040 xmlBufferPtr xml_buf;
1045 return E_INVALIDARG;
1049 xml_buf = xmlBufferCreate();
1051 return E_OUTOFMEMORY;
1053 xmldecl = xmldoc_unlink_xmldecl( This->node->doc );
1055 size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1);
1057 const xmlChar *buf_content;
1060 /* Attribute Nodes return a space in front of their name */
1061 buf_content = xmlBufferContent(xml_buf);
1063 content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0));
1065 content = EnsureCorrectEOL(content);
1066 if(ensure_no_encoding)
1067 content = EnsureNoEncoding(content);
1071 *ret = SysAllocStringLen(NULL, 0);
1074 xmlBufferFree(xml_buf);
1075 xmldoc_link_xmldecl( This->node->doc, xmldecl );
1076 return *ret ? S_OK : E_OUTOFMEMORY;
1079 static HRESULT WINAPI xmlnode_transformNode(
1081 IXMLDOMNode* styleSheet,
1084 #ifdef SONAME_LIBXSLT
1085 xmlnode *This = impl_from_IXMLDOMNode( iface );
1086 xmlnode *pStyleSheet = NULL;
1087 xsltStylesheetPtr xsltSS = NULL;
1088 xmlDocPtr result = NULL;
1090 TRACE("(%p)->(%p %p)\n", This, styleSheet, xmlString);
1092 if (!libxslt_handle)
1094 if(!styleSheet || !xmlString)
1095 return E_INVALIDARG;
1099 pStyleSheet = get_node_obj(styleSheet);
1101 FIXME("styleSheet is not our xmlnode implementation\n");
1105 xsltSS = pxsltParseStylesheetDoc( pStyleSheet->node->doc);
1108 result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL);
1111 const xmlChar *pContent;
1113 if(result->type == XML_HTML_DOCUMENT_NODE)
1115 xmlOutputBufferPtr pOutput = xmlAllocOutputBuffer(NULL);
1118 htmlDocContentDumpOutput(pOutput, result->doc, NULL);
1119 pContent = xmlBufferContent(pOutput->buffer);
1120 *xmlString = bstr_from_xmlChar(pContent);
1121 xmlOutputBufferClose(pOutput);
1126 xmlBufferPtr pXmlBuf;
1129 pXmlBuf = xmlBufferCreate();
1132 nSize = xmlNodeDump(pXmlBuf, NULL, (xmlNodePtr)result, 0, 0);
1135 pContent = xmlBufferContent(pXmlBuf);
1136 *xmlString = bstr_from_xmlChar(pContent);
1138 xmlBufferFree(pXmlBuf);
1143 /* libxslt "helpfully" frees the XML document the stylesheet was
1144 generated from, too */
1146 pxsltFreeStylesheet(xsltSS);
1149 if(*xmlString == NULL)
1150 *xmlString = SysAllocStringLen(NULL, 0);
1154 FIXME("libxslt headers were not found at compile time\n");
1159 static HRESULT WINAPI xmlnode_selectNodes(
1162 IXMLDOMNodeList** resultList)
1164 xmlnode *This = impl_from_IXMLDOMNode( iface );
1166 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultList );
1168 if (!queryString || !resultList) return E_INVALIDARG;
1170 return queryresult_create( This->node, queryString, resultList );
1173 static HRESULT WINAPI xmlnode_selectSingleNode(
1176 IXMLDOMNode** resultNode)
1178 xmlnode *This = impl_from_IXMLDOMNode( iface );
1179 IXMLDOMNodeList *list;
1182 TRACE("(%p)->(%s %p)\n", This, debugstr_w(queryString), resultNode );
1184 r = IXMLDOMNode_selectNodes(This->iface, queryString, &list);
1187 r = IXMLDOMNodeList_nextNode(list, resultNode);
1188 IXMLDOMNodeList_Release(list);
1193 static HRESULT WINAPI xmlnode_get_namespaceURI(
1197 xmlnode *This = impl_from_IXMLDOMNode( iface );
1200 TRACE("(%p)->(%p)\n", This, namespaceURI );
1203 return E_INVALIDARG;
1205 *namespaceURI = NULL;
1207 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1209 if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href );
1213 TRACE("uri: %s\n", debugstr_w(*namespaceURI));
1215 return *namespaceURI ? S_OK : S_FALSE;
1218 HRESULT node_get_prefix(xmlnode *This, BSTR *prefix)
1222 if (!prefix) return E_INVALIDARG;
1226 if ((ns = xmlGetNsList(This->node->doc, This->node)))
1228 if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix );
1232 TRACE("prefix: %s\n", debugstr_w(*prefix));
1234 return *prefix ? S_OK : S_FALSE;
1237 HRESULT node_get_base_name(xmlnode *This, BSTR *name)
1239 if (!name) return E_INVALIDARG;
1241 *name = bstr_from_xmlChar(This->node->name);
1242 if (!*name) return E_OUTOFMEMORY;
1244 TRACE("returning %s\n", debugstr_w(*name));
1249 static HRESULT WINAPI xmlnode_transformNodeToObject(
1251 IXMLDOMNode* stylesheet,
1252 VARIANT outputObject)
1254 xmlnode *This = impl_from_IXMLDOMNode( iface );
1255 FIXME("(%p)->(%p)\n", This, stylesheet);
1259 static const struct IXMLDOMNodeVtbl xmlnode_vtbl =
1281 xmlnode_removeChild,
1282 xmlnode_appendChild,
1283 xmlnode_hasChildNodes,
1284 xmlnode_get_ownerDocument,
1291 xmlnode_get_nodeTypedValue,
1292 xmlnode_put_nodeTypedValue,
1294 xmlnode_put_dataType,
1296 xmlnode_transformNode,
1297 xmlnode_selectNodes,
1298 xmlnode_selectSingleNode,
1300 xmlnode_get_namespaceURI,
1303 xmlnode_transformNodeToObject,
1306 void destroy_xmlnode(xmlnode *This)
1309 xmldoc_release(This->node->doc);
1312 void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data)
1315 xmldoc_add_ref( node->doc );
1317 This->lpVtbl = &xmlnode_vtbl;
1319 This->iface = node_iface;
1322 init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data);
1324 This->dispex.outer = NULL;
1329 const IXMLDOMNodeVtbl *lpVtbl;
1333 static inline unknode *impl_from_unkIXMLDOMNode(IXMLDOMNode *iface)
1335 return (unknode *)((char*)iface - FIELD_OFFSET(unknode, lpVtbl));
1338 static HRESULT WINAPI unknode_QueryInterface(
1343 unknode *This = impl_from_unkIXMLDOMNode( iface );
1345 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1347 if (IsEqualGUID(riid, &IID_IUnknown)) {
1349 }else if (IsEqualGUID( riid, &IID_IDispatch) ||
1350 IsEqualGUID( riid, &IID_IXMLDOMNode)) {
1351 *ppvObject = &This->lpVtbl;
1352 }else if(node_query_interface(&This->node, riid, ppvObject)) {
1353 return *ppvObject ? S_OK : E_NOINTERFACE;
1355 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1357 return E_NOINTERFACE;
1360 IUnknown_AddRef((IUnknown*)*ppvObject);
1364 static ULONG WINAPI unknode_AddRef(
1365 IXMLDOMNode *iface )
1367 unknode *This = impl_from_unkIXMLDOMNode( iface );
1369 return InterlockedIncrement(&This->ref);
1372 static ULONG WINAPI unknode_Release(
1373 IXMLDOMNode *iface )
1375 unknode *This = impl_from_unkIXMLDOMNode( iface );
1378 ref = InterlockedDecrement( &This->ref );
1380 destroy_xmlnode(&This->node);
1387 static HRESULT WINAPI unknode_GetTypeInfoCount(
1391 unknode *This = impl_from_unkIXMLDOMNode( iface );
1393 TRACE("(%p)->(%p)\n", This, pctinfo);
1400 static HRESULT WINAPI unknode_GetTypeInfo(
1404 ITypeInfo** ppTInfo )
1406 unknode *This = impl_from_unkIXMLDOMNode( iface );
1409 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1411 hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo);
1416 static HRESULT WINAPI unknode_GetIDsOfNames(
1419 LPOLESTR* rgszNames,
1424 unknode *This = impl_from_unkIXMLDOMNode( iface );
1426 ITypeInfo *typeinfo;
1429 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1432 if(!rgszNames || cNames == 0 || !rgDispId)
1433 return E_INVALIDARG;
1435 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1438 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1439 ITypeInfo_Release(typeinfo);
1445 static HRESULT WINAPI unknode_Invoke(
1447 DISPID dispIdMember,
1451 DISPPARAMS* pDispParams,
1452 VARIANT* pVarResult,
1453 EXCEPINFO* pExcepInfo,
1456 unknode *This = impl_from_unkIXMLDOMNode( iface );
1457 ITypeInfo *typeinfo;
1460 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1461 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1463 hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo);
1466 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1467 pVarResult, pExcepInfo, puArgErr);
1468 ITypeInfo_Release(typeinfo);
1474 static HRESULT WINAPI unknode_get_nodeName(
1478 unknode *This = impl_from_unkIXMLDOMNode( iface );
1480 FIXME("(%p)->(%p)\n", This, p);
1482 return node_get_nodeName(&This->node, p);
1485 static HRESULT WINAPI unknode_get_nodeValue(
1489 unknode *This = impl_from_unkIXMLDOMNode( iface );
1491 FIXME("(%p)->(%p)\n", This, value);
1494 return E_INVALIDARG;
1496 V_VT(value) = VT_NULL;
1500 static HRESULT WINAPI unknode_put_nodeValue(
1504 unknode *This = impl_from_unkIXMLDOMNode( iface );
1505 FIXME("(%p)->(v%d)\n", This, V_VT(&value));
1509 static HRESULT WINAPI unknode_get_nodeType(
1511 DOMNodeType* domNodeType )
1513 unknode *This = impl_from_unkIXMLDOMNode( iface );
1515 FIXME("(%p)->(%p)\n", This, domNodeType);
1517 *domNodeType = This->node.node->type;
1521 static HRESULT WINAPI unknode_get_parentNode(
1523 IXMLDOMNode** parent )
1525 unknode *This = impl_from_unkIXMLDOMNode( iface );
1526 FIXME("(%p)->(%p)\n", This, parent);
1527 if (!parent) return E_INVALIDARG;
1532 static HRESULT WINAPI unknode_get_childNodes(
1534 IXMLDOMNodeList** outList)
1536 unknode *This = impl_from_unkIXMLDOMNode( iface );
1538 TRACE("(%p)->(%p)\n", This, outList);
1540 return node_get_child_nodes(&This->node, outList);
1543 static HRESULT WINAPI unknode_get_firstChild(
1545 IXMLDOMNode** domNode)
1547 unknode *This = impl_from_unkIXMLDOMNode( iface );
1549 TRACE("(%p)->(%p)\n", This, domNode);
1551 return node_get_first_child(&This->node, domNode);
1554 static HRESULT WINAPI unknode_get_lastChild(
1556 IXMLDOMNode** domNode)
1558 unknode *This = impl_from_unkIXMLDOMNode( iface );
1560 TRACE("(%p)->(%p)\n", This, domNode);
1562 return node_get_last_child(&This->node, domNode);
1565 static HRESULT WINAPI unknode_get_previousSibling(
1567 IXMLDOMNode** domNode)
1569 unknode *This = impl_from_unkIXMLDOMNode( iface );
1571 TRACE("(%p)->(%p)\n", This, domNode);
1573 return node_get_previous_sibling(&This->node, domNode);
1576 static HRESULT WINAPI unknode_get_nextSibling(
1578 IXMLDOMNode** domNode)
1580 unknode *This = impl_from_unkIXMLDOMNode( iface );
1582 TRACE("(%p)->(%p)\n", This, domNode);
1584 return node_get_next_sibling(&This->node, domNode);
1587 static HRESULT WINAPI unknode_get_attributes(
1589 IXMLDOMNamedNodeMap** attributeMap)
1591 unknode *This = impl_from_unkIXMLDOMNode( iface );
1593 FIXME("(%p)->(%p)\n", This, attributeMap);
1595 return return_null_ptr((void**)attributeMap);
1598 static HRESULT WINAPI unknode_insertBefore(
1600 IXMLDOMNode* newNode, VARIANT refChild,
1601 IXMLDOMNode** outOldNode)
1603 unknode *This = impl_from_unkIXMLDOMNode( iface );
1605 FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode);
1607 return node_insert_before(&This->node, newNode, &refChild, outOldNode);
1610 static HRESULT WINAPI unknode_replaceChild(
1612 IXMLDOMNode* newNode,
1613 IXMLDOMNode* oldNode,
1614 IXMLDOMNode** outOldNode)
1616 unknode *This = impl_from_unkIXMLDOMNode( iface );
1618 FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
1620 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
1623 static HRESULT WINAPI unknode_removeChild(
1625 IXMLDOMNode* domNode, IXMLDOMNode** oldNode)
1627 unknode *This = impl_from_unkIXMLDOMNode( iface );
1628 return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), domNode, oldNode );
1631 static HRESULT WINAPI unknode_appendChild(
1633 IXMLDOMNode* newNode, IXMLDOMNode** outNewNode)
1635 unknode *This = impl_from_unkIXMLDOMNode( iface );
1636 return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newNode, outNewNode );
1639 static HRESULT WINAPI unknode_hasChildNodes(
1641 VARIANT_BOOL* pbool)
1643 unknode *This = impl_from_unkIXMLDOMNode( iface );
1644 return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), pbool );
1647 static HRESULT WINAPI unknode_get_ownerDocument(
1649 IXMLDOMDocument** domDocument)
1651 unknode *This = impl_from_unkIXMLDOMNode( iface );
1652 return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), domDocument );
1655 static HRESULT WINAPI unknode_cloneNode(
1657 VARIANT_BOOL pbool, IXMLDOMNode** outNode)
1659 unknode *This = impl_from_unkIXMLDOMNode( iface );
1660 return IXMLDOMNode_cloneNode( IXMLDOMNode_from_impl(&This->node), pbool, outNode );
1663 static HRESULT WINAPI unknode_get_nodeTypeString(
1667 unknode *This = impl_from_unkIXMLDOMNode( iface );
1669 FIXME("(%p)->(%p)\n", This, p);
1671 return node_get_nodeName(&This->node, p);
1674 static HRESULT WINAPI unknode_get_text(
1678 unknode *This = impl_from_unkIXMLDOMNode( iface );
1679 return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), p );
1682 static HRESULT WINAPI unknode_put_text(
1686 unknode *This = impl_from_unkIXMLDOMNode( iface );
1687 return IXMLDOMNode_put_text( IXMLDOMNode_from_impl(&This->node), p );
1690 static HRESULT WINAPI unknode_get_specified(
1692 VARIANT_BOOL* isSpecified)
1694 unknode *This = impl_from_unkIXMLDOMNode( iface );
1695 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1696 *isSpecified = VARIANT_TRUE;
1700 static HRESULT WINAPI unknode_get_definition(
1702 IXMLDOMNode** definitionNode)
1704 unknode *This = impl_from_unkIXMLDOMNode( iface );
1705 FIXME("(%p)->(%p)\n", This, definitionNode);
1709 static HRESULT WINAPI unknode_get_nodeTypedValue(
1713 unknode *This = impl_from_unkIXMLDOMNode( iface );
1714 return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1717 static HRESULT WINAPI unknode_put_nodeTypedValue(
1721 unknode *This = impl_from_unkIXMLDOMNode( iface );
1722 return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), var1 );
1725 static HRESULT WINAPI unknode_get_dataType(
1729 unknode *This = impl_from_unkIXMLDOMNode( iface );
1730 return IXMLDOMNode_get_dataType( IXMLDOMNode_from_impl(&This->node), var1 );
1733 static HRESULT WINAPI unknode_put_dataType(
1737 unknode *This = impl_from_unkIXMLDOMNode( iface );
1738 return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), p );
1741 static HRESULT WINAPI unknode_get_xml(
1745 unknode *This = impl_from_unkIXMLDOMNode( iface );
1747 FIXME("(%p)->(%p)\n", This, p);
1749 return node_get_xml(&This->node, FALSE, FALSE, p);
1752 static HRESULT WINAPI unknode_transformNode(
1754 IXMLDOMNode* domNode, BSTR* p)
1756 unknode *This = impl_from_unkIXMLDOMNode( iface );
1757 return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), domNode, p );
1760 static HRESULT WINAPI unknode_selectNodes(
1762 BSTR p, IXMLDOMNodeList** outList)
1764 unknode *This = impl_from_unkIXMLDOMNode( iface );
1765 return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), p, outList );
1768 static HRESULT WINAPI unknode_selectSingleNode(
1770 BSTR p, IXMLDOMNode** outNode)
1772 unknode *This = impl_from_unkIXMLDOMNode( iface );
1773 return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), p, outNode );
1776 static HRESULT WINAPI unknode_get_parsed(
1778 VARIANT_BOOL* isParsed)
1780 unknode *This = impl_from_unkIXMLDOMNode( iface );
1781 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1782 *isParsed = VARIANT_TRUE;
1786 static HRESULT WINAPI unknode_get_namespaceURI(
1790 unknode *This = impl_from_unkIXMLDOMNode( iface );
1791 return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), p );
1794 static HRESULT WINAPI unknode_get_prefix(
1798 unknode *This = impl_from_unkIXMLDOMNode( iface );
1799 return IXMLDOMNode_get_prefix( IXMLDOMNode_from_impl(&This->node), p );
1802 static HRESULT WINAPI unknode_get_baseName(
1806 unknode *This = impl_from_unkIXMLDOMNode( iface );
1807 return IXMLDOMNode_get_baseName( IXMLDOMNode_from_impl(&This->node), p );
1810 static HRESULT WINAPI unknode_transformNodeToObject(
1812 IXMLDOMNode* domNode, VARIANT var1)
1814 unknode *This = impl_from_unkIXMLDOMNode( iface );
1815 return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), domNode, var1 );
1818 static const struct IXMLDOMNodeVtbl unknode_vtbl =
1820 unknode_QueryInterface,
1823 unknode_GetTypeInfoCount,
1824 unknode_GetTypeInfo,
1825 unknode_GetIDsOfNames,
1827 unknode_get_nodeName,
1828 unknode_get_nodeValue,
1829 unknode_put_nodeValue,
1830 unknode_get_nodeType,
1831 unknode_get_parentNode,
1832 unknode_get_childNodes,
1833 unknode_get_firstChild,
1834 unknode_get_lastChild,
1835 unknode_get_previousSibling,
1836 unknode_get_nextSibling,
1837 unknode_get_attributes,
1838 unknode_insertBefore,
1839 unknode_replaceChild,
1840 unknode_removeChild,
1841 unknode_appendChild,
1842 unknode_hasChildNodes,
1843 unknode_get_ownerDocument,
1845 unknode_get_nodeTypeString,
1848 unknode_get_specified,
1849 unknode_get_definition,
1850 unknode_get_nodeTypedValue,
1851 unknode_put_nodeTypedValue,
1852 unknode_get_dataType,
1853 unknode_put_dataType,
1855 unknode_transformNode,
1856 unknode_selectNodes,
1857 unknode_selectSingleNode,
1859 unknode_get_namespaceURI,
1861 unknode_get_baseName,
1862 unknode_transformNodeToObject
1865 IXMLDOMNode *create_node( xmlNodePtr node )
1874 TRACE("type %d\n", node->type);
1877 case XML_ELEMENT_NODE:
1878 pUnk = create_element( node );
1880 case XML_ATTRIBUTE_NODE:
1881 pUnk = create_attribute( node );
1884 pUnk = create_text( node );
1886 case XML_CDATA_SECTION_NODE:
1887 pUnk = create_cdata( node );
1889 case XML_ENTITY_REF_NODE:
1890 pUnk = create_doc_entity_ref( node );
1893 pUnk = create_pi( node );
1895 case XML_COMMENT_NODE:
1896 pUnk = create_comment( node );
1898 case XML_DOCUMENT_NODE:
1899 pUnk = create_domdoc( node );
1901 case XML_DOCUMENT_FRAG_NODE:
1902 pUnk = create_doc_fragment( node );
1905 pUnk = create_doc_type( node );
1910 FIXME("only creating basic node for type %d\n", node->type);
1912 new_node = heap_alloc(sizeof(unknode));
1916 new_node->lpVtbl = &unknode_vtbl;
1918 init_xmlnode(&new_node->node, node, (IXMLDOMNode*)&new_node->lpVtbl, NULL);
1919 pUnk = (IUnknown*)&new_node->lpVtbl;
1923 hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
1924 IUnknown_Release(pUnk);
1925 if(FAILED(hr)) return NULL;