| /* |
| * Node implementation |
| * |
| * Copyright 2005 Mike McCormack |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| |
| #define COBJMACROS |
| |
| #include <stdarg.h> |
| |
| #ifdef HAVE_LIBXML2 |
| # include <libxml/parser.h> |
| # include <libxml/xmlerror.h> |
| # include <libxml/HTMLtree.h> |
| # ifdef SONAME_LIBXSLT |
| # ifdef HAVE_LIBXSLT_PATTERN_H |
| # include <libxslt/pattern.h> |
| # endif |
| # ifdef HAVE_LIBXSLT_TRANSFORM_H |
| # include <libxslt/transform.h> |
| # endif |
| # include <libxslt/xsltutils.h> |
| # include <libxslt/xsltInternals.h> |
| # endif |
| #endif |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "winnls.h" |
| #include "ole2.h" |
| #include "msxml6.h" |
| |
| #include "msxml_private.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msxml); |
| |
| #ifdef HAVE_LIBXML2 |
| |
| #ifdef SONAME_LIBXSLT |
| extern void* libxslt_handle; |
| # define MAKE_FUNCPTR(f) extern typeof(f) * p##f |
| MAKE_FUNCPTR(xsltApplyStylesheet); |
| MAKE_FUNCPTR(xsltCleanupGlobals); |
| MAKE_FUNCPTR(xsltFreeStylesheet); |
| MAKE_FUNCPTR(xsltParseStylesheetDoc); |
| # undef MAKE_FUNCPTR |
| #endif |
| |
| /* TODO: get rid of these and use the enum */ |
| static const WCHAR szBinBase64[] = {'b','i','n','.','b','a','s','e','6','4',0}; |
| static const WCHAR szString[] = {'s','t','r','i','n','g',0}; |
| static const WCHAR szNumber[] = {'n','u','m','b','e','r',0}; |
| static const WCHAR szInt[] = {'I','n','t',0}; |
| static const WCHAR szFixed[] = {'F','i','x','e','d','.','1','4','.','4',0}; |
| static const WCHAR szBoolean[] = {'B','o','o','l','e','a','n',0}; |
| static const WCHAR szDateTime[] = {'d','a','t','e','T','i','m','e',0}; |
| static const WCHAR szDateTimeTZ[] = {'d','a','t','e','T','i','m','e','.','t','z',0}; |
| static const WCHAR szDate[] = {'D','a','t','e',0}; |
| static const WCHAR szTime[] = {'T','i','m','e',0}; |
| static const WCHAR szTimeTZ[] = {'T','i','m','e','.','t','z',0}; |
| static const WCHAR szI1[] = {'i','1',0}; |
| static const WCHAR szI2[] = {'i','2',0}; |
| static const WCHAR szI4[] = {'i','4',0}; |
| static const WCHAR szIU1[] = {'u','i','1',0}; |
| static const WCHAR szIU2[] = {'u','i','2',0}; |
| static const WCHAR szIU4[] = {'u','i','4',0}; |
| static const WCHAR szR4[] = {'r','4',0}; |
| static const WCHAR szR8[] = {'r','8',0}; |
| static const WCHAR szFloat[] = {'f','l','o','a','t',0}; |
| static const WCHAR szUUID[] = {'u','u','i','d',0}; |
| static const WCHAR szBinHex[] = {'b','i','n','.','h','e','x',0}; |
| |
| static const IID IID_xmlnode = {0x4f2f4ba2,0xb822,0x11df,{0x8b,0x8a,0x68,0x50,0xdf,0xd7,0x20,0x85}}; |
| |
| xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type ) |
| { |
| xmlnode *This; |
| |
| if ( !iface ) |
| return NULL; |
| This = get_node_obj( iface ); |
| if ( !This || !This->node ) |
| return NULL; |
| if ( type && This->node->type != type ) |
| return NULL; |
| return This->node; |
| } |
| |
| BOOL node_query_interface(xmlnode *This, REFIID riid, void **ppv) |
| { |
| if(IsEqualGUID(&IID_xmlnode, riid)) { |
| TRACE("(%p)->(IID_xmlnode %p)\n", This, ppv); |
| *ppv = This; |
| return TRUE; |
| } |
| |
| if(This->dispex.outer) |
| return dispex_query_interface(&This->dispex, riid, ppv); |
| |
| return FALSE; |
| } |
| |
| xmlnode *get_node_obj(IXMLDOMNode *node) |
| { |
| xmlnode *obj = NULL; |
| HRESULT hres; |
| |
| hres = IXMLDOMNode_QueryInterface(node, &IID_xmlnode, (void**)&obj); |
| if (!obj) WARN("node is not our IXMLDOMNode implementation\n"); |
| return SUCCEEDED(hres) ? obj : NULL; |
| } |
| |
| HRESULT node_get_nodeName(xmlnode *This, BSTR *name) |
| { |
| if (!name) |
| return E_INVALIDARG; |
| |
| *name = bstr_from_xmlChar(This->node->name); |
| if (!*name) |
| return S_FALSE; |
| |
| return S_OK; |
| } |
| |
| HRESULT node_get_content(xmlnode *This, VARIANT *value) |
| { |
| xmlChar *content; |
| |
| if(!value) |
| return E_INVALIDARG; |
| |
| content = xmlNodeGetContent(This->node); |
| V_VT(value) = VT_BSTR; |
| V_BSTR(value) = bstr_from_xmlChar( content ); |
| xmlFree(content); |
| |
| TRACE("%p returned %s\n", This, debugstr_w(V_BSTR(value))); |
| return S_OK; |
| } |
| |
| HRESULT node_set_content(xmlnode *This, LPCWSTR value) |
| { |
| xmlChar *str; |
| |
| TRACE("(%p)->(%s)\n", This, debugstr_w(value)); |
| str = xmlChar_from_wchar(value); |
| if(!str) |
| return E_OUTOFMEMORY; |
| |
| xmlNodeSetContent(This->node, str); |
| heap_free(str); |
| return S_OK; |
| } |
| |
| static HRESULT node_set_content_escaped(xmlnode *This, LPCWSTR value) |
| { |
| xmlChar *str, *escaped; |
| |
| TRACE("(%p)->(%s)\n", This, debugstr_w(value)); |
| str = xmlChar_from_wchar(value); |
| if(!str) |
| return E_OUTOFMEMORY; |
| |
| escaped = xmlEncodeSpecialChars(NULL, str); |
| if(!escaped) |
| { |
| heap_free(str); |
| return E_OUTOFMEMORY; |
| } |
| |
| xmlNodeSetContent(This->node, escaped); |
| |
| heap_free(str); |
| xmlFree(escaped); |
| |
| return S_OK; |
| } |
| |
| HRESULT node_put_value(xmlnode *This, VARIANT *value) |
| { |
| VARIANT string_value; |
| HRESULT hr; |
| |
| VariantInit(&string_value); |
| hr = VariantChangeType(&string_value, value, 0, VT_BSTR); |
| if(FAILED(hr)) { |
| WARN("Couldn't convert to VT_BSTR\n"); |
| return hr; |
| } |
| |
| hr = node_set_content(This, V_BSTR(&string_value)); |
| VariantClear(&string_value); |
| |
| return hr; |
| } |
| |
| HRESULT node_put_value_escaped(xmlnode *This, VARIANT *value) |
| { |
| VARIANT string_value; |
| HRESULT hr; |
| |
| VariantInit(&string_value); |
| hr = VariantChangeType(&string_value, value, 0, VT_BSTR); |
| if(FAILED(hr)) { |
| WARN("Couldn't convert to VT_BSTR\n"); |
| return hr; |
| } |
| |
| hr = node_set_content_escaped(This, V_BSTR(&string_value)); |
| VariantClear(&string_value); |
| |
| return hr; |
| } |
| |
| static HRESULT get_node( |
| xmlnode *This, |
| const char *name, |
| xmlNodePtr node, |
| IXMLDOMNode **out ) |
| { |
| TRACE("(%p)->(%s %p %p)\n", This, name, node, out ); |
| |
| if ( !out ) |
| return E_INVALIDARG; |
| |
| /* if we don't have a doc, use our parent. */ |
| if(node && !node->doc && node->parent) |
| node->doc = node->parent->doc; |
| |
| *out = create_node( node ); |
| if (!*out) |
| return S_FALSE; |
| return S_OK; |
| } |
| |
| HRESULT node_get_parent(xmlnode *This, IXMLDOMNode **parent) |
| { |
| return get_node( This, "parent", This->node->parent, parent ); |
| } |
| |
| HRESULT node_get_child_nodes(xmlnode *This, IXMLDOMNodeList **ret) |
| { |
| if(!ret) |
| return E_INVALIDARG; |
| |
| *ret = create_children_nodelist(This->node); |
| if(!*ret) |
| return E_OUTOFMEMORY; |
| |
| return S_OK; |
| } |
| |
| HRESULT node_get_first_child(xmlnode *This, IXMLDOMNode **ret) |
| { |
| return get_node(This, "firstChild", This->node->children, ret); |
| } |
| |
| HRESULT node_get_last_child(xmlnode *This, IXMLDOMNode **ret) |
| { |
| return get_node(This, "lastChild", This->node->last, ret); |
| } |
| |
| HRESULT node_get_previous_sibling(xmlnode *This, IXMLDOMNode **ret) |
| { |
| return get_node(This, "previous", This->node->prev, ret); |
| } |
| |
| HRESULT node_get_next_sibling(xmlnode *This, IXMLDOMNode **ret) |
| { |
| return get_node(This, "next", This->node->next, ret); |
| } |
| |
| HRESULT node_insert_before(xmlnode *This, IXMLDOMNode *new_child, const VARIANT *ref_child, |
| IXMLDOMNode **ret) |
| { |
| IXMLDOMNode *before = NULL; |
| xmlnode *node_obj; |
| xmlDocPtr doc; |
| HRESULT hr; |
| |
| if(!new_child) |
| return E_INVALIDARG; |
| |
| node_obj = get_node_obj(new_child); |
| if(!node_obj) return E_FAIL; |
| |
| switch(V_VT(ref_child)) |
| { |
| case VT_EMPTY: |
| case VT_NULL: |
| break; |
| |
| case VT_UNKNOWN: |
| case VT_DISPATCH: |
| hr = IUnknown_QueryInterface(V_UNKNOWN(ref_child), &IID_IXMLDOMNode, (void**)&before); |
| if(FAILED(hr)) return hr; |
| break; |
| |
| default: |
| FIXME("refChild var type %x\n", V_VT(ref_child)); |
| return E_FAIL; |
| } |
| |
| TRACE("new child %p, This->node %p\n", node_obj->node, This->node); |
| |
| if(!node_obj->node->parent) |
| if(xmldoc_remove_orphan(node_obj->node->doc, node_obj->node) != S_OK) |
| WARN("%p is not an orphan of %p\n", node_obj->node, node_obj->node->doc); |
| |
| if(before) |
| { |
| xmlnode *before_node_obj = get_node_obj(before); |
| IXMLDOMNode_Release(before); |
| if(!before_node_obj) return E_FAIL; |
| |
| /* unlink from current parent first */ |
| if(node_obj->parent) |
| { |
| hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL); |
| if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node); |
| } |
| doc = node_obj->node->doc; |
| xmldoc_add_ref(before_node_obj->node->doc); |
| xmlAddPrevSibling(before_node_obj->node, node_obj->node); |
| xmldoc_release(doc); |
| node_obj->parent = This->parent; |
| } |
| else |
| { |
| /* unlink from current parent first */ |
| if(node_obj->parent) |
| { |
| hr = IXMLDOMNode_removeChild(node_obj->parent, node_obj->iface, NULL); |
| if (hr == S_OK) xmldoc_remove_orphan(node_obj->node->doc, node_obj->node); |
| } |
| doc = node_obj->node->doc; |
| xmldoc_add_ref(This->node->doc); |
| xmlAddChild(This->node, node_obj->node); |
| xmldoc_release(doc); |
| node_obj->parent = This->iface; |
| } |
| |
| if(ret) |
| { |
| IXMLDOMNode_AddRef(new_child); |
| *ret = new_child; |
| } |
| |
| TRACE("ret S_OK\n"); |
| return S_OK; |
| } |
| |
| HRESULT node_replace_child(xmlnode *This, IXMLDOMNode *newChild, IXMLDOMNode *oldChild, |
| IXMLDOMNode **ret) |
| { |
| xmlnode *old_child, *new_child; |
| xmlDocPtr leaving_doc; |
| xmlNode *my_ancestor; |
| |
| /* Do not believe any documentation telling that newChild == NULL |
| means removal. It does certainly *not* apply to msxml3! */ |
| if(!newChild || !oldChild) |
| return E_INVALIDARG; |
| |
| if(ret) |
| *ret = NULL; |
| |
| old_child = get_node_obj(oldChild); |
| if(!old_child) return E_FAIL; |
| |
| if(old_child->node->parent != This->node) |
| { |
| WARN("childNode %p is not a child of %p\n", oldChild, This); |
| return E_INVALIDARG; |
| } |
| |
| new_child = get_node_obj(newChild); |
| if(!new_child) return E_FAIL; |
| |
| my_ancestor = This->node; |
| while(my_ancestor) |
| { |
| if(my_ancestor == new_child->node) |
| { |
| WARN("tried to create loop\n"); |
| return E_FAIL; |
| } |
| my_ancestor = my_ancestor->parent; |
| } |
| |
| if(!new_child->node->parent) |
| if(xmldoc_remove_orphan(new_child->node->doc, new_child->node) != S_OK) |
| WARN("%p is not an orphan of %p\n", new_child->node, new_child->node->doc); |
| |
| leaving_doc = new_child->node->doc; |
| xmldoc_add_ref(old_child->node->doc); |
| xmlReplaceNode(old_child->node, new_child->node); |
| xmldoc_release(leaving_doc); |
| new_child->parent = old_child->parent; |
| old_child->parent = NULL; |
| |
| xmldoc_add_orphan(old_child->node->doc, old_child->node); |
| |
| if(ret) |
| { |
| IXMLDOMNode_AddRef(oldChild); |
| *ret = oldChild; |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT node_remove_child(xmlnode *This, IXMLDOMNode* child, IXMLDOMNode** oldChild) |
| { |
| xmlnode *child_node; |
| |
| if(!child) return E_INVALIDARG; |
| |
| if(oldChild) |
| *oldChild = NULL; |
| |
| child_node = get_node_obj(child); |
| if(!child_node) return E_FAIL; |
| |
| if(child_node->node->parent != This->node) |
| { |
| WARN("childNode %p is not a child of %p\n", child, This); |
| return E_INVALIDARG; |
| } |
| |
| xmlUnlinkNode(child_node->node); |
| child_node->parent = NULL; |
| xmldoc_add_orphan(child_node->node->doc, child_node->node); |
| |
| if(oldChild) |
| { |
| IXMLDOMNode_AddRef(child); |
| *oldChild = child; |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT node_append_child(xmlnode *This, IXMLDOMNode *child, IXMLDOMNode **outChild) |
| { |
| DOMNodeType type; |
| VARIANT var; |
| HRESULT hr; |
| |
| hr = IXMLDOMNode_get_nodeType(child, &type); |
| if(FAILED(hr) || type == NODE_ATTRIBUTE) { |
| if (outChild) *outChild = NULL; |
| return E_FAIL; |
| } |
| |
| VariantInit(&var); |
| return IXMLDOMNode_insertBefore(This->iface, child, var, outChild); |
| } |
| |
| HRESULT node_has_childnodes(const xmlnode *This, VARIANT_BOOL *ret) |
| { |
| if (!ret) return E_INVALIDARG; |
| |
| if (!This->node->children) |
| { |
| *ret = VARIANT_FALSE; |
| return S_FALSE; |
| } |
| |
| *ret = VARIANT_TRUE; |
| return S_OK; |
| } |
| |
| HRESULT node_get_owner_doc(const xmlnode *This, IXMLDOMDocument **doc) |
| { |
| return get_domdoc_from_xmldoc(This->node->doc, (IXMLDOMDocument3**)doc); |
| } |
| |
| HRESULT node_clone(xmlnode *This, VARIANT_BOOL deep, IXMLDOMNode **cloneNode) |
| { |
| IXMLDOMNode *node; |
| xmlNodePtr clone; |
| |
| if(!cloneNode) return E_INVALIDARG; |
| |
| clone = xmlCopyNode(This->node, deep ? 1 : 2); |
| if (clone) |
| { |
| clone->doc = This->node->doc; |
| xmldoc_add_orphan(clone->doc, clone); |
| |
| node = create_node(clone); |
| if (!node) |
| { |
| ERR("Copy failed\n"); |
| xmldoc_remove_orphan(clone->doc, clone); |
| xmlFreeNode(clone); |
| return E_FAIL; |
| } |
| |
| *cloneNode = node; |
| } |
| else |
| { |
| ERR("Copy failed\n"); |
| return E_FAIL; |
| } |
| |
| return S_OK; |
| } |
| |
| static inline xmlChar* trim_whitespace(xmlChar* str) |
| { |
| xmlChar* ret = str; |
| int len; |
| |
| if (!str) |
| return NULL; |
| |
| while (*ret && isspace(*ret)) |
| ++ret; |
| len = xmlStrlen(ret); |
| if (len) |
| while (isspace(ret[len-1])) --len; |
| |
| ret = xmlStrndup(ret, len); |
| xmlFree(str); |
| return ret; |
| } |
| |
| static xmlChar* do_get_text(xmlNodePtr node) |
| { |
| xmlNodePtr child; |
| xmlChar* str; |
| BOOL preserving = is_preserving_whitespace(node); |
| |
| if (!node->children) |
| { |
| str = xmlNodeGetContent(node); |
| } |
| else |
| { |
| xmlElementType prev_type = XML_TEXT_NODE; |
| xmlChar* tmp; |
| str = xmlStrdup(BAD_CAST ""); |
| for (child = node->children; child != NULL; child = child->next) |
| { |
| switch (child->type) |
| { |
| case XML_ELEMENT_NODE: |
| tmp = do_get_text(child); |
| break; |
| case XML_TEXT_NODE: |
| case XML_CDATA_SECTION_NODE: |
| case XML_ENTITY_REF_NODE: |
| case XML_ENTITY_NODE: |
| tmp = xmlNodeGetContent(child); |
| break; |
| default: |
| tmp = NULL; |
| break; |
| } |
| |
| if (tmp) |
| { |
| if (*tmp) |
| { |
| if (prev_type == XML_ELEMENT_NODE && child->type == XML_ELEMENT_NODE) |
| str = xmlStrcat(str, BAD_CAST " "); |
| str = xmlStrcat(str, tmp); |
| prev_type = child->type; |
| } |
| xmlFree(tmp); |
| } |
| } |
| } |
| |
| switch (node->type) |
| { |
| case XML_ELEMENT_NODE: |
| case XML_TEXT_NODE: |
| case XML_ENTITY_REF_NODE: |
| case XML_ENTITY_NODE: |
| case XML_DOCUMENT_NODE: |
| case XML_DOCUMENT_FRAG_NODE: |
| if (!preserving) |
| str = trim_whitespace(str); |
| break; |
| default: |
| break; |
| } |
| |
| return str; |
| } |
| |
| HRESULT node_get_text(const xmlnode *This, BSTR *text) |
| { |
| BSTR str = NULL; |
| xmlChar *content; |
| |
| if (!text) return E_INVALIDARG; |
| |
| content = do_get_text(This->node); |
| if (content) |
| { |
| str = bstr_from_xmlChar(content); |
| xmlFree(content); |
| } |
| |
| /* Always return a string. */ |
| if (!str) str = SysAllocStringLen( NULL, 0 ); |
| |
| TRACE("%p %s\n", This, debugstr_w(str) ); |
| *text = str; |
| |
| return S_OK; |
| } |
| |
| HRESULT node_put_text(xmlnode *This, BSTR text) |
| { |
| xmlChar *str, *str2; |
| |
| TRACE("(%p)->(%s)\n", This, debugstr_w(text)); |
| |
| str = xmlChar_from_wchar(text); |
| |
| /* Escape the string. */ |
| str2 = xmlEncodeEntitiesReentrant(This->node->doc, str); |
| heap_free(str); |
| |
| xmlNodeSetContent(This->node, str2); |
| xmlFree(str2); |
| |
| return S_OK; |
| } |
| |
| static inline BYTE hex_to_byte(xmlChar c) |
| { |
| if(c <= '9') return c-'0'; |
| if(c <= 'F') return c-'A'+10; |
| return c-'a'+10; |
| } |
| |
| static inline BYTE base64_to_byte(xmlChar c) |
| { |
| if(c == '+') return 62; |
| if(c == '/') return 63; |
| if(c <= '9') return c-'0'+52; |
| if(c <= 'Z') return c-'A'; |
| return c-'a'+26; |
| } |
| |
| /* TODO: phasing this version out */ |
| static inline HRESULT VARIANT_from_xmlChar(xmlChar *str, VARIANT *v, BSTR type) |
| { |
| if(!type || !lstrcmpiW(type, szString) || |
| !lstrcmpiW(type, szNumber) || !lstrcmpiW(type, szUUID)) |
| { |
| V_VT(v) = VT_BSTR; |
| V_BSTR(v) = bstr_from_xmlChar(str); |
| |
| if(!V_BSTR(v)) |
| return E_OUTOFMEMORY; |
| } |
| else if(!lstrcmpiW(type, szDateTime) || !lstrcmpiW(type, szDateTimeTZ) || |
| !lstrcmpiW(type, szDate) || !lstrcmpiW(type, szTime) || |
| !lstrcmpiW(type, szTimeTZ)) |
| { |
| VARIANT src; |
| WCHAR *p, *e; |
| SYSTEMTIME st; |
| DOUBLE date = 0.0; |
| |
| st.wYear = 1899; |
| st.wMonth = 12; |
| st.wDay = 30; |
| st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; |
| |
| V_VT(&src) = VT_BSTR; |
| V_BSTR(&src) = bstr_from_xmlChar(str); |
| |
| if(!V_BSTR(&src)) |
| return E_OUTOFMEMORY; |
| |
| p = V_BSTR(&src); |
| e = p + SysStringLen(V_BSTR(&src)); |
| |
| if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */ |
| { |
| st.wYear = atoiW(p); |
| st.wMonth = atoiW(p+5); |
| st.wDay = atoiW(p+8); |
| p += 10; |
| |
| if(*p == 'T') p++; |
| } |
| |
| if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */ |
| { |
| st.wHour = atoiW(p); |
| st.wMinute = atoiW(p+3); |
| st.wSecond = atoiW(p+6); |
| p += 8; |
| |
| if(*p == '.') |
| { |
| p++; |
| while(isdigitW(*p)) p++; |
| } |
| } |
| |
| SystemTimeToVariantTime(&st, &date); |
| V_VT(v) = VT_DATE; |
| V_DATE(v) = date; |
| |
| if(*p == '+') /* parse timezone offset (+hh:mm) */ |
| V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440; |
| else if(*p == '-') /* parse timezone offset (-hh:mm) */ |
| V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440; |
| |
| VariantClear(&src); |
| } |
| else if(!lstrcmpiW(type, szBinHex)) |
| { |
| SAFEARRAYBOUND sab; |
| int i, len; |
| |
| len = xmlStrlen(str)/2; |
| sab.lLbound = 0; |
| sab.cElements = len; |
| |
| V_VT(v) = (VT_ARRAY|VT_UI1); |
| V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab); |
| |
| if(!V_ARRAY(v)) |
| return E_OUTOFMEMORY; |
| |
| for(i=0; i<len; i++) |
| ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4) |
| + hex_to_byte(str[2*i+1]); |
| } |
| else if(!lstrcmpiW(type, szBinBase64)) |
| { |
| SAFEARRAYBOUND sab; |
| int i, len; |
| |
| len = xmlStrlen(str); |
| if(str[len-2] == '=') i = 2; |
| else if(str[len-1] == '=') i = 1; |
| else i = 0; |
| |
| sab.lLbound = 0; |
| sab.cElements = len/4*3-i; |
| |
| V_VT(v) = (VT_ARRAY|VT_UI1); |
| V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab); |
| |
| if(!V_ARRAY(v)) |
| return E_OUTOFMEMORY; |
| |
| for(i=0; i<len/4; i++) |
| { |
| ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2) |
| + (base64_to_byte(str[4*i+1])>>4); |
| if(3*i+1 < sab.cElements) |
| ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4) |
| + (base64_to_byte(str[4*i+2])>>2); |
| if(3*i+2 < sab.cElements) |
| ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6) |
| + base64_to_byte(str[4*i+3]); |
| } |
| } |
| else |
| { |
| VARIANT src; |
| HRESULT hres; |
| |
| if(!lstrcmpiW(type, szInt) || !lstrcmpiW(type, szI4)) |
| V_VT(v) = VT_I4; |
| else if(!lstrcmpiW(type, szFixed)) |
| V_VT(v) = VT_CY; |
| else if(!lstrcmpiW(type, szBoolean)) |
| V_VT(v) = VT_BOOL; |
| else if(!lstrcmpiW(type, szI1)) |
| V_VT(v) = VT_I1; |
| else if(!lstrcmpiW(type, szI2)) |
| V_VT(v) = VT_I2; |
| else if(!lstrcmpiW(type, szIU1)) |
| V_VT(v) = VT_UI1; |
| else if(!lstrcmpiW(type, szIU2)) |
| V_VT(v) = VT_UI2; |
| else if(!lstrcmpiW(type, szIU4)) |
| V_VT(v) = VT_UI4; |
| else if(!lstrcmpiW(type, szR4)) |
| V_VT(v) = VT_R4; |
| else if(!lstrcmpiW(type, szR8) || !lstrcmpiW(type, szFloat)) |
| V_VT(v) = VT_R8; |
| else |
| { |
| FIXME("Type handling not yet implemented\n"); |
| V_VT(v) = VT_BSTR; |
| } |
| |
| V_VT(&src) = VT_BSTR; |
| V_BSTR(&src) = bstr_from_xmlChar(str); |
| |
| if(!V_BSTR(&src)) |
| return E_OUTOFMEMORY; |
| |
| hres = VariantChangeTypeEx(v, &src, MAKELCID(MAKELANGID( |
| LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v)); |
| VariantClear(&src); |
| return hres; |
| } |
| |
| return S_OK; |
| } |
| |
| BSTR EnsureCorrectEOL(BSTR sInput) |
| { |
| int nNum = 0; |
| BSTR sNew; |
| int nLen; |
| int i; |
| |
| nLen = SysStringLen(sInput); |
| /* Count line endings */ |
| for(i=0; i < nLen; i++) |
| { |
| if(sInput[i] == '\n') |
| nNum++; |
| } |
| |
| TRACE("len=%d, num=%d\n", nLen, nNum); |
| |
| /* Add linefeed as needed */ |
| if(nNum > 0) |
| { |
| int nPlace = 0; |
| sNew = SysAllocStringLen(NULL, nLen + nNum+1); |
| for(i=0; i < nLen; i++) |
| { |
| if(sInput[i] == '\n') |
| { |
| sNew[i+nPlace] = '\r'; |
| nPlace++; |
| } |
| sNew[i+nPlace] = sInput[i]; |
| } |
| |
| SysFreeString(sInput); |
| } |
| else |
| { |
| sNew = sInput; |
| } |
| |
| TRACE("len %d\n", SysStringLen(sNew)); |
| |
| return sNew; |
| } |
| |
| /* Removes encoding information and last character (nullbyte) */ |
| static BSTR EnsureNoEncoding(BSTR sInput) |
| { |
| static const WCHAR wszEncoding[] = {'e','n','c','o','d','i','n','g','='}; |
| BSTR sNew; |
| WCHAR *pBeg, *pEnd; |
| |
| pBeg = sInput; |
| while(*pBeg != '\n' && memcmp(pBeg, wszEncoding, sizeof(wszEncoding))) |
| pBeg++; |
| |
| if(*pBeg == '\n') |
| { |
| SysReAllocStringLen(&sInput, sInput, SysStringLen(sInput)-1); |
| return sInput; |
| } |
| pBeg--; |
| |
| pEnd = pBeg + sizeof(wszEncoding)/sizeof(WCHAR) + 2; |
| while(*pEnd != '\"') pEnd++; |
| pEnd++; |
| |
| sNew = SysAllocStringLen(NULL, |
| pBeg-sInput + SysStringLen(sInput)-(pEnd-sInput)-1); |
| memcpy(sNew, sInput, (pBeg-sInput)*sizeof(WCHAR)); |
| memcpy(&sNew[pBeg-sInput], pEnd, (SysStringLen(sInput)-(pEnd-sInput)-1)*sizeof(WCHAR)); |
| |
| SysFreeString(sInput); |
| return sNew; |
| } |
| |
| /* |
| * We are trying to replicate the same behaviour as msxml by converting |
| * line endings to \r\n and using indents as \t. The problem is that msxml |
| * only formats nodes that have a line ending. Using libxml we cannot |
| * reproduce behaviour exactly. |
| * |
| */ |
| HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BOOL ensure_no_encoding, BSTR *ret) |
| { |
| xmlBufferPtr xml_buf; |
| xmlNodePtr xmldecl; |
| int size; |
| |
| if(!ret) |
| return E_INVALIDARG; |
| |
| *ret = NULL; |
| |
| xml_buf = xmlBufferCreate(); |
| if(!xml_buf) |
| return E_OUTOFMEMORY; |
| |
| xmldecl = xmldoc_unlink_xmldecl( This->node->doc ); |
| |
| size = xmlNodeDump(xml_buf, This->node->doc, This->node, 0, 1); |
| if(size > 0) { |
| const xmlChar *buf_content; |
| BSTR content; |
| |
| /* Attribute Nodes return a space in front of their name */ |
| buf_content = xmlBufferContent(xml_buf); |
| |
| content = bstr_from_xmlChar(buf_content + (buf_content[0] == ' ' ? 1 : 0)); |
| if(ensure_eol) |
| content = EnsureCorrectEOL(content); |
| if(ensure_no_encoding) |
| content = EnsureNoEncoding(content); |
| |
| *ret = content; |
| }else { |
| *ret = SysAllocStringLen(NULL, 0); |
| } |
| |
| xmlBufferFree(xml_buf); |
| xmldoc_link_xmldecl( This->node->doc, xmldecl ); |
| return *ret ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p) |
| { |
| #ifdef SONAME_LIBXSLT |
| xsltStylesheetPtr xsltSS; |
| xmlnode *sheet; |
| |
| if (!libxslt_handle) return E_NOTIMPL; |
| if (!stylesheet || !p) return E_INVALIDARG; |
| |
| *p = NULL; |
| |
| sheet = get_node_obj(stylesheet); |
| if(!sheet) return E_FAIL; |
| |
| xsltSS = pxsltParseStylesheetDoc(sheet->node->doc); |
| if(xsltSS) |
| { |
| xmlDocPtr result = pxsltApplyStylesheet(xsltSS, This->node->doc, NULL); |
| if(result) |
| { |
| const xmlChar *content; |
| |
| if(result->type == XML_HTML_DOCUMENT_NODE) |
| { |
| xmlOutputBufferPtr output = xmlAllocOutputBuffer(NULL); |
| if (output) |
| { |
| htmlDocContentDumpOutput(output, result->doc, NULL); |
| content = xmlBufferContent(output->buffer); |
| *p = bstr_from_xmlChar(content); |
| xmlOutputBufferClose(output); |
| } |
| } |
| else |
| { |
| xmlBufferPtr buf = xmlBufferCreate(); |
| if (buf) |
| { |
| int size = xmlNodeDump(buf, NULL, (xmlNodePtr)result, 0, 0); |
| if(size > 0) |
| { |
| content = xmlBufferContent(buf); |
| *p = bstr_from_xmlChar(content); |
| } |
| xmlBufferFree(buf); |
| } |
| } |
| xmlFreeDoc(result); |
| } |
| /* libxslt "helpfully" frees the XML document the stylesheet was |
| generated from, too */ |
| xsltSS->doc = NULL; |
| pxsltFreeStylesheet(xsltSS); |
| } |
| |
| if(!*p) *p = SysAllocStringLen(NULL, 0); |
| |
| return S_OK; |
| #else |
| FIXME("libxslt headers were not found at compile time\n"); |
| return E_NOTIMPL; |
| #endif |
| } |
| |
| HRESULT node_select_nodes(const xmlnode *This, BSTR query, IXMLDOMNodeList **nodes) |
| { |
| xmlChar* str; |
| HRESULT hr; |
| |
| if (!query || !nodes) return E_INVALIDARG; |
| |
| str = xmlChar_from_wchar(query); |
| hr = queryresult_create(This->node, str, nodes); |
| heap_free(str); |
| |
| return hr; |
| } |
| |
| HRESULT node_select_singlenode(const xmlnode *This, BSTR query, IXMLDOMNode **node) |
| { |
| IXMLDOMNodeList *list; |
| HRESULT hr; |
| |
| hr = node_select_nodes(This, query, &list); |
| if (hr == S_OK) |
| { |
| hr = IXMLDOMNodeList_nextNode(list, node); |
| IXMLDOMNodeList_Release(list); |
| } |
| return hr; |
| } |
| |
| HRESULT node_get_namespaceURI(xmlnode *This, BSTR *namespaceURI) |
| { |
| xmlNsPtr *ns; |
| |
| if(!namespaceURI) |
| return E_INVALIDARG; |
| |
| *namespaceURI = NULL; |
| |
| if ((ns = xmlGetNsList(This->node->doc, This->node))) |
| { |
| if (ns[0]->href) *namespaceURI = bstr_from_xmlChar( ns[0]->href ); |
| xmlFree(ns); |
| } |
| |
| TRACE("uri: %s\n", debugstr_w(*namespaceURI)); |
| |
| return *namespaceURI ? S_OK : S_FALSE; |
| } |
| |
| HRESULT node_get_prefix(xmlnode *This, BSTR *prefix) |
| { |
| xmlNsPtr *ns; |
| |
| if (!prefix) return E_INVALIDARG; |
| |
| *prefix = NULL; |
| |
| if ((ns = xmlGetNsList(This->node->doc, This->node))) |
| { |
| if (ns[0]->prefix) *prefix = bstr_from_xmlChar( ns[0]->prefix ); |
| xmlFree(ns); |
| } |
| |
| TRACE("prefix: %s\n", debugstr_w(*prefix)); |
| |
| return *prefix ? S_OK : S_FALSE; |
| } |
| |
| HRESULT node_get_base_name(xmlnode *This, BSTR *name) |
| { |
| if (!name) return E_INVALIDARG; |
| |
| *name = bstr_from_xmlChar(This->node->name); |
| if (!*name) return E_OUTOFMEMORY; |
| |
| TRACE("returning %s\n", debugstr_w(*name)); |
| |
| return S_OK; |
| } |
| |
| void destroy_xmlnode(xmlnode *This) |
| { |
| if(This->node) |
| xmldoc_release(This->node->doc); |
| } |
| |
| void init_xmlnode(xmlnode *This, xmlNodePtr node, IXMLDOMNode *node_iface, dispex_static_data_t *dispex_data) |
| { |
| if(node) |
| xmldoc_add_ref( node->doc ); |
| |
| This->node = node; |
| This->iface = node_iface; |
| This->parent = NULL; |
| |
| if(dispex_data) |
| init_dispex(&This->dispex, (IUnknown*)This->iface, dispex_data); |
| else |
| This->dispex.outer = NULL; |
| } |
| |
| typedef struct { |
| xmlnode node; |
| IXMLDOMNode IXMLDOMNode_iface; |
| LONG ref; |
| } unknode; |
| |
| static inline unknode *unknode_from_IXMLDOMNode(IXMLDOMNode *iface) |
| { |
| return CONTAINING_RECORD(iface, unknode, IXMLDOMNode_iface); |
| } |
| |
| static HRESULT WINAPI unknode_QueryInterface( |
| IXMLDOMNode *iface, |
| REFIID riid, |
| void** ppvObject ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); |
| |
| if (IsEqualGUID(riid, &IID_IUnknown)) { |
| *ppvObject = iface; |
| }else if (IsEqualGUID( riid, &IID_IDispatch) || |
| IsEqualGUID( riid, &IID_IXMLDOMNode)) { |
| *ppvObject = &This->IXMLDOMNode_iface; |
| }else if(node_query_interface(&This->node, riid, ppvObject)) { |
| return *ppvObject ? S_OK : E_NOINTERFACE; |
| }else { |
| FIXME("interface %s not implemented\n", debugstr_guid(riid)); |
| *ppvObject = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppvObject); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI unknode_AddRef( |
| IXMLDOMNode *iface ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| return InterlockedIncrement(&This->ref); |
| } |
| |
| static ULONG WINAPI unknode_Release( |
| IXMLDOMNode *iface ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| LONG ref; |
| |
| ref = InterlockedDecrement( &This->ref ); |
| if(!ref) { |
| destroy_xmlnode(&This->node); |
| heap_free(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI unknode_GetTypeInfoCount( |
| IXMLDOMNode *iface, |
| UINT* pctinfo ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, pctinfo); |
| |
| *pctinfo = 1; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI unknode_GetTypeInfo( |
| IXMLDOMNode *iface, |
| UINT iTInfo, |
| LCID lcid, |
| ITypeInfo** ppTInfo ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| HRESULT hr; |
| |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(IXMLDOMNode_tid, ppTInfo); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI unknode_GetIDsOfNames( |
| IXMLDOMNode *iface, |
| REFIID riid, |
| LPOLESTR* rgszNames, |
| UINT cNames, |
| LCID lcid, |
| DISPID* rgDispId ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, |
| lcid, rgDispId); |
| |
| if(!rgszNames || cNames == 0 || !rgDispId) |
| return E_INVALIDARG; |
| |
| hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI unknode_Invoke( |
| IXMLDOMNode *iface, |
| DISPID dispIdMember, |
| REFIID riid, |
| LCID lcid, |
| WORD wFlags, |
| DISPPARAMS* pDispParams, |
| VARIANT* pVarResult, |
| EXCEPINFO* pExcepInfo, |
| UINT* puArgErr ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| ITypeInfo *typeinfo; |
| HRESULT hr; |
| |
| TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), |
| lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IXMLDOMNode_tid, &typeinfo); |
| if(SUCCEEDED(hr)) |
| { |
| hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNode_iface, dispIdMember, wFlags, pDispParams, |
| pVarResult, pExcepInfo, puArgErr); |
| ITypeInfo_Release(typeinfo); |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI unknode_get_nodeName( |
| IXMLDOMNode *iface, |
| BSTR* p ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p)\n", This, p); |
| |
| return node_get_nodeName(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_get_nodeValue( |
| IXMLDOMNode *iface, |
| VARIANT* value) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p)\n", This, value); |
| |
| if(!value) |
| return E_INVALIDARG; |
| |
| V_VT(value) = VT_NULL; |
| return S_FALSE; |
| } |
| |
| static HRESULT WINAPI unknode_put_nodeValue( |
| IXMLDOMNode *iface, |
| VARIANT value) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(v%d)\n", This, V_VT(&value)); |
| return E_FAIL; |
| } |
| |
| static HRESULT WINAPI unknode_get_nodeType( |
| IXMLDOMNode *iface, |
| DOMNodeType* domNodeType ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p)\n", This, domNodeType); |
| |
| *domNodeType = This->node.node->type; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI unknode_get_parentNode( |
| IXMLDOMNode *iface, |
| IXMLDOMNode** parent ) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%p)\n", This, parent); |
| if (!parent) return E_INVALIDARG; |
| *parent = NULL; |
| return S_FALSE; |
| } |
| |
| static HRESULT WINAPI unknode_get_childNodes( |
| IXMLDOMNode *iface, |
| IXMLDOMNodeList** outList) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, outList); |
| |
| return node_get_child_nodes(&This->node, outList); |
| } |
| |
| static HRESULT WINAPI unknode_get_firstChild( |
| IXMLDOMNode *iface, |
| IXMLDOMNode** domNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, domNode); |
| |
| return node_get_first_child(&This->node, domNode); |
| } |
| |
| static HRESULT WINAPI unknode_get_lastChild( |
| IXMLDOMNode *iface, |
| IXMLDOMNode** domNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, domNode); |
| |
| return node_get_last_child(&This->node, domNode); |
| } |
| |
| static HRESULT WINAPI unknode_get_previousSibling( |
| IXMLDOMNode *iface, |
| IXMLDOMNode** domNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, domNode); |
| |
| return node_get_previous_sibling(&This->node, domNode); |
| } |
| |
| static HRESULT WINAPI unknode_get_nextSibling( |
| IXMLDOMNode *iface, |
| IXMLDOMNode** domNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| TRACE("(%p)->(%p)\n", This, domNode); |
| |
| return node_get_next_sibling(&This->node, domNode); |
| } |
| |
| static HRESULT WINAPI unknode_get_attributes( |
| IXMLDOMNode *iface, |
| IXMLDOMNamedNodeMap** attributeMap) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p)\n", This, attributeMap); |
| |
| return return_null_ptr((void**)attributeMap); |
| } |
| |
| static HRESULT WINAPI unknode_insertBefore( |
| IXMLDOMNode *iface, |
| IXMLDOMNode* newNode, VARIANT refChild, |
| IXMLDOMNode** outOldNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p x%d %p)\n", This, newNode, V_VT(&refChild), outOldNode); |
| |
| return node_insert_before(&This->node, newNode, &refChild, outOldNode); |
| } |
| |
| static HRESULT WINAPI unknode_replaceChild( |
| IXMLDOMNode *iface, |
| IXMLDOMNode* newNode, |
| IXMLDOMNode* oldNode, |
| IXMLDOMNode** outOldNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode); |
| |
| return node_replace_child(&This->node, newNode, oldNode, outOldNode); |
| } |
| |
| static HRESULT WINAPI unknode_removeChild( |
| IXMLDOMNode *iface, |
| IXMLDOMNode* domNode, IXMLDOMNode** oldNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_remove_child(&This->node, domNode, oldNode); |
| } |
| |
| static HRESULT WINAPI unknode_appendChild( |
| IXMLDOMNode *iface, |
| IXMLDOMNode* newNode, IXMLDOMNode** outNewNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_append_child(&This->node, newNode, outNewNode); |
| } |
| |
| static HRESULT WINAPI unknode_hasChildNodes( |
| IXMLDOMNode *iface, |
| VARIANT_BOOL* pbool) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_has_childnodes(&This->node, pbool); |
| } |
| |
| static HRESULT WINAPI unknode_get_ownerDocument( |
| IXMLDOMNode *iface, |
| IXMLDOMDocument** domDocument) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_get_owner_doc(&This->node, domDocument); |
| } |
| |
| static HRESULT WINAPI unknode_cloneNode( |
| IXMLDOMNode *iface, |
| VARIANT_BOOL pbool, IXMLDOMNode** outNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_clone(&This->node, pbool, outNode ); |
| } |
| |
| static HRESULT WINAPI unknode_get_nodeTypeString( |
| IXMLDOMNode *iface, |
| BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p)\n", This, p); |
| |
| return node_get_nodeName(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_get_text( |
| IXMLDOMNode *iface, |
| BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_get_text(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_put_text( |
| IXMLDOMNode *iface, |
| BSTR p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_put_text(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_get_specified( |
| IXMLDOMNode *iface, |
| VARIANT_BOOL* isSpecified) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%p) stub!\n", This, isSpecified); |
| *isSpecified = VARIANT_TRUE; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI unknode_get_definition( |
| IXMLDOMNode *iface, |
| IXMLDOMNode** definitionNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%p)\n", This, definitionNode); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI unknode_get_nodeTypedValue( |
| IXMLDOMNode *iface, |
| VARIANT* var1) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%p)\n", This, var1); |
| return return_null_var(var1); |
| } |
| |
| static HRESULT WINAPI unknode_put_nodeTypedValue( |
| IXMLDOMNode *iface, |
| VARIANT typedValue) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI unknode_get_dataType( |
| IXMLDOMNode *iface, |
| VARIANT* var1) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| TRACE("(%p)->(%p)\n", This, var1); |
| return return_null_var(var1); |
| } |
| |
| static HRESULT WINAPI unknode_put_dataType( |
| IXMLDOMNode *iface, |
| BSTR p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%s)\n", This, debugstr_w(p)); |
| |
| if(!p) |
| return E_INVALIDARG; |
| |
| return E_FAIL; |
| } |
| |
| static HRESULT WINAPI unknode_get_xml( |
| IXMLDOMNode *iface, |
| BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| |
| FIXME("(%p)->(%p)\n", This, p); |
| |
| return node_get_xml(&This->node, FALSE, FALSE, p); |
| } |
| |
| static HRESULT WINAPI unknode_transformNode( |
| IXMLDOMNode *iface, |
| IXMLDOMNode* domNode, BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_transform_node(&This->node, domNode, p); |
| } |
| |
| static HRESULT WINAPI unknode_selectNodes( |
| IXMLDOMNode *iface, |
| BSTR p, IXMLDOMNodeList** outList) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_select_nodes(&This->node, p, outList); |
| } |
| |
| static HRESULT WINAPI unknode_selectSingleNode( |
| IXMLDOMNode *iface, |
| BSTR p, IXMLDOMNode** outNode) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_select_singlenode(&This->node, p, outNode); |
| } |
| |
| static HRESULT WINAPI unknode_get_parsed( |
| IXMLDOMNode *iface, |
| VARIANT_BOOL* isParsed) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%p) stub!\n", This, isParsed); |
| *isParsed = VARIANT_TRUE; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI unknode_get_namespaceURI( |
| IXMLDOMNode *iface, |
| BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| TRACE("(%p)->(%p)\n", This, p); |
| return node_get_namespaceURI(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_get_prefix( |
| IXMLDOMNode *iface, |
| BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_get_prefix(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_get_baseName( |
| IXMLDOMNode *iface, |
| BSTR* p) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| return node_get_base_name(&This->node, p); |
| } |
| |
| static HRESULT WINAPI unknode_transformNodeToObject( |
| IXMLDOMNode *iface, |
| IXMLDOMNode* domNode, VARIANT var1) |
| { |
| unknode *This = unknode_from_IXMLDOMNode( iface ); |
| FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1)); |
| return E_NOTIMPL; |
| } |
| |
| static const struct IXMLDOMNodeVtbl unknode_vtbl = |
| { |
| unknode_QueryInterface, |
| unknode_AddRef, |
| unknode_Release, |
| unknode_GetTypeInfoCount, |
| unknode_GetTypeInfo, |
| unknode_GetIDsOfNames, |
| unknode_Invoke, |
| unknode_get_nodeName, |
| unknode_get_nodeValue, |
| unknode_put_nodeValue, |
| unknode_get_nodeType, |
| unknode_get_parentNode, |
| unknode_get_childNodes, |
| unknode_get_firstChild, |
| unknode_get_lastChild, |
| unknode_get_previousSibling, |
| unknode_get_nextSibling, |
| unknode_get_attributes, |
| unknode_insertBefore, |
| unknode_replaceChild, |
| unknode_removeChild, |
| unknode_appendChild, |
| unknode_hasChildNodes, |
| unknode_get_ownerDocument, |
| unknode_cloneNode, |
| unknode_get_nodeTypeString, |
| unknode_get_text, |
| unknode_put_text, |
| unknode_get_specified, |
| unknode_get_definition, |
| unknode_get_nodeTypedValue, |
| unknode_put_nodeTypedValue, |
| unknode_get_dataType, |
| unknode_put_dataType, |
| unknode_get_xml, |
| unknode_transformNode, |
| unknode_selectNodes, |
| unknode_selectSingleNode, |
| unknode_get_parsed, |
| unknode_get_namespaceURI, |
| unknode_get_prefix, |
| unknode_get_baseName, |
| unknode_transformNodeToObject |
| }; |
| |
| IXMLDOMNode *create_node( xmlNodePtr node ) |
| { |
| IUnknown *pUnk; |
| IXMLDOMNode *ret; |
| HRESULT hr; |
| |
| if ( !node ) |
| return NULL; |
| |
| TRACE("type %d\n", node->type); |
| switch(node->type) |
| { |
| case XML_ELEMENT_NODE: |
| pUnk = create_element( node ); |
| break; |
| case XML_ATTRIBUTE_NODE: |
| pUnk = create_attribute( node ); |
| break; |
| case XML_TEXT_NODE: |
| pUnk = create_text( node ); |
| break; |
| case XML_CDATA_SECTION_NODE: |
| pUnk = create_cdata( node ); |
| break; |
| case XML_ENTITY_REF_NODE: |
| pUnk = create_doc_entity_ref( node ); |
| break; |
| case XML_PI_NODE: |
| pUnk = create_pi( node ); |
| break; |
| case XML_COMMENT_NODE: |
| pUnk = create_comment( node ); |
| break; |
| case XML_DOCUMENT_NODE: |
| pUnk = create_domdoc( node ); |
| break; |
| case XML_DOCUMENT_FRAG_NODE: |
| pUnk = create_doc_fragment( node ); |
| break; |
| case XML_DTD_NODE: |
| pUnk = create_doc_type( node ); |
| break; |
| default: { |
| unknode *new_node; |
| |
| FIXME("only creating basic node for type %d\n", node->type); |
| |
| new_node = heap_alloc(sizeof(unknode)); |
| if(!new_node) |
| return NULL; |
| |
| new_node->IXMLDOMNode_iface.lpVtbl = &unknode_vtbl; |
| new_node->ref = 1; |
| init_xmlnode(&new_node->node, node, &new_node->IXMLDOMNode_iface, NULL); |
| pUnk = (IUnknown*)&new_node->IXMLDOMNode_iface; |
| } |
| } |
| |
| hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret); |
| IUnknown_Release(pUnk); |
| if(FAILED(hr)) return NULL; |
| return ret; |
| } |
| #endif |