diff --git a/reactos/dll/win32/msxml3/CMakeLists.txt b/reactos/dll/win32/msxml3/CMakeLists.txt index a9d6ab9e62a..b4e72a50705 100644 --- a/reactos/dll/win32/msxml3/CMakeLists.txt +++ b/reactos/dll/win32/msxml3/CMakeLists.txt @@ -1,7 +1,4 @@ -remove_definitions(-D_WIN32_WINNT=0x502) -add_definitions(-D_WIN32_WINNT=0x601) - add_definitions( -D__WINESRC__ -D_WINE @@ -13,9 +10,7 @@ if(MSVC) endif() include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine) - spec2def(msxml3.dll msxml3.spec ADD_IMPORTLIB) - add_typelib(msxml3_v1.idl) list(APPEND SOURCE @@ -56,24 +51,17 @@ list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/msxml3_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/msxml3.def) +list(APPEND msxml3_rc_deps + ${CMAKE_CURRENT_SOURCE_DIR}/msxml3.manifest + ${CMAKE_CURRENT_SOURCE_DIR}/msxml3_v1.rgs + ${CMAKE_CURRENT_SOURCE_DIR}/xmlparser.rgs + ${CMAKE_CURRENT_BINARY_DIR}/msxml3_v1.tlb) + +set_source_files_properties(version.rc PROPERTIES OBJECT_DEPENDS "${msxml3_rc_deps}") add_library(msxml3 SHARED ${SOURCE} version.rc) - -if(NOT MSVC) - # FIXME: http://www.cmake.org/Bug/view.php?id=12998 - #allow_warnings(msxml3) - set_source_files_properties(${SOURCE} PROPERTIES COMPILE_FLAGS "-Wno-error") -endif() - add_idl_headers(xmlparser_idlheader xmlparser.idl) -add_dependencies(msxml3 xmlparser_idlheader) - set_module_type(msxml3 win32dll) -set_source_files_properties(version.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/msxml3_v1.tlb) -target_link_libraries(msxml3 libxml2 uuid wine wineldr) - -add_importlibs(msxml3 urlmon wininet ws2_32 comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 msvcrt kernel32 ntdll) - -# msxml3_v1.tlb needs stdole2.tlb -add_dependencies(msxml3 stdole2) - +target_link_libraries(msxml3 libxml2 uuid wine) +add_importlibs(msxml3 urlmon ws2_32 shlwapi oleaut32 ole32 user32 msvcrt kernel32 ntdll) +add_dependencies(msxml3 xmlparser_idlheader stdole2) # msxml3_v1.tlb needs stdole2.tlb add_cd_file(TARGET msxml3 DESTINATION reactos/system32 FOR all) diff --git a/reactos/dll/win32/msxml3/attribute.c b/reactos/dll/win32/msxml3/attribute.c index 6bd7a5809d1..b74e7183d9f 100644 --- a/reactos/dll/win32/msxml3/attribute.c +++ b/reactos/dll/win32/msxml3/attribute.c @@ -46,6 +46,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml); #ifdef HAVE_LIBXML2 +static const xmlChar xmlns[] = "xmlns"; + typedef struct _domattr { xmlnode node; @@ -56,7 +58,7 @@ typedef struct _domattr static const tid_t domattr_se_tids[] = { IXMLDOMNode_tid, IXMLDOMAttribute_tid, - 0 + NULL_tid }; static inline domattr *impl_from_IXMLDOMAttribute( IXMLDOMAttribute *iface ) @@ -545,8 +547,29 @@ static HRESULT WINAPI domattr_get_namespaceURI( BSTR* p) { domattr *This = impl_from_IXMLDOMAttribute( iface ); + xmlNsPtr ns = This->node.node->ns; + TRACE("(%p)->(%p)\n", This, p); - return node_get_namespaceURI(&This->node, p); + + if (!p) + return E_INVALIDARG; + + *p = NULL; + + if (ns) + { + /* special case for default namespace definition */ + if (xmlStrEqual(This->node.node->name, xmlns)) + *p = bstr_from_xmlChar(xmlns); + else if (xmlStrEqual(ns->prefix, xmlns)) + *p = SysAllocStringLen(NULL, 0); + else if (ns->href) + *p = bstr_from_xmlChar(ns->href); + } + + TRACE("uri: %s\n", debugstr_w(*p)); + + return *p ? S_OK : S_FALSE; } static HRESULT WINAPI domattr_get_prefix( @@ -554,8 +577,26 @@ static HRESULT WINAPI domattr_get_prefix( BSTR* prefix) { domattr *This = impl_from_IXMLDOMAttribute( iface ); + xmlNsPtr ns = This->node.node->ns; + TRACE("(%p)->(%p)\n", This, prefix); - return node_get_prefix( &This->node, prefix ); + + if (!prefix) return E_INVALIDARG; + + *prefix = NULL; + + if (ns) + { + /* special case for default namespace definition */ + if (xmlStrEqual(This->node.node->name, xmlns)) + *prefix = bstr_from_xmlChar(xmlns); + else if (ns->prefix) + *prefix = bstr_from_xmlChar(ns->prefix); + } + + TRACE("prefix: %s\n", debugstr_w(*prefix)); + + return *prefix ? S_OK : S_FALSE; } static HRESULT WINAPI domattr_get_baseName( diff --git a/reactos/dll/win32/msxml3/cdata.c b/reactos/dll/win32/msxml3/cdata.c index cbf72cb58a2..b8d099f4347 100644 --- a/reactos/dll/win32/msxml3/cdata.c +++ b/reactos/dll/win32/msxml3/cdata.c @@ -55,7 +55,7 @@ typedef struct static const tid_t domcdata_se_tids[] = { IXMLDOMNode_tid, IXMLDOMCDATASection_tid, - 0 + NULL_tid }; static inline domcdata *impl_from_IXMLDOMCDATASection( IXMLDOMCDATASection *iface ) @@ -336,7 +336,7 @@ static HRESULT WINAPI domcdata_hasChildNodes( { domcdata *This = impl_from_IXMLDOMCDATASection( iface ); TRACE("(%p)->(%p)\n", This, ret); - return node_has_childnodes(&This->node, ret); + return return_var_false(ret); } static HRESULT WINAPI domcdata_get_ownerDocument( diff --git a/reactos/dll/win32/msxml3/comment.c b/reactos/dll/win32/msxml3/comment.c index da99fc8e483..77440a5f0f4 100644 --- a/reactos/dll/win32/msxml3/comment.c +++ b/reactos/dll/win32/msxml3/comment.c @@ -55,7 +55,7 @@ typedef struct _domcomment static const tid_t domcomment_se_tids[] = { IXMLDOMNode_tid, IXMLDOMComment_tid, - 0 + NULL_tid }; static inline domcomment *impl_from_IXMLDOMComment( IXMLDOMComment *iface ) @@ -335,7 +335,7 @@ static HRESULT WINAPI domcomment_hasChildNodes( { domcomment *This = impl_from_IXMLDOMComment( iface ); TRACE("(%p)->(%p)\n", This, ret); - return node_has_childnodes(&This->node, ret); + return return_var_false(ret); } static HRESULT WINAPI domcomment_get_ownerDocument( diff --git a/reactos/dll/win32/msxml3/docfrag.c b/reactos/dll/win32/msxml3/docfrag.c index 35cb5e3cdbf..0e9d0a1f2f0 100644 --- a/reactos/dll/win32/msxml3/docfrag.c +++ b/reactos/dll/win32/msxml3/docfrag.c @@ -55,7 +55,7 @@ typedef struct _domfrag static const tid_t domfrag_se_tids[] = { IXMLDOMNode_tid, IXMLDOMDocumentFragment_tid, - 0 + NULL_tid }; static inline domfrag *impl_from_IXMLDOMDocumentFragment( IXMLDOMDocumentFragment *iface ) diff --git a/reactos/dll/win32/msxml3/domdoc.c b/reactos/dll/win32/msxml3/domdoc.c index 9828482f5c0..03937d953b2 100644 --- a/reactos/dll/win32/msxml3/domdoc.c +++ b/reactos/dll/win32/msxml3/domdoc.c @@ -419,10 +419,26 @@ static void sax_characters(void *ctx, const xmlChar *ch, int len) if (ctxt->node) { - /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */ + xmlChar cur = *(ctxt->input->cur); + + /* Characters are reported with multiple calls, for example each charref is reported with a separate + call and then parser appends it to a single text node or creates a new node if not created. + It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be + space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces, + or whole node if it has nothing but space chars, so to detect leading space node->last is checked that + contains text node pointer if already created, trailing spaces are detected directly looking at parser input + for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last + chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not + a text node it's safe to ignore. + + Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */ + if (!This->properties->preserving && !is_preserving_whitespace(ctxt->node) && - strn_isspace(ch, len)) + strn_isspace(ch, len) && + (!ctxt->node->last || + ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE)) + ))) return; } @@ -852,7 +868,7 @@ static const tid_t domdoc_se_tids[] = { IXMLDOMDocument_tid, IXMLDOMDocument2_tid, IXMLDOMDocument3_tid, - 0 + NULL_tid }; static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject ) @@ -1921,9 +1937,6 @@ static HRESULT WINAPI domdoc_createNode( hr = get_node_type(Type, &node_type); if(FAILED(hr)) return hr; - if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT) - FIXME("nodes with namespaces currently not supported.\n"); - TRACE("node_type %d\n", node_type); /* exit earlier for types that need name */ @@ -1966,8 +1979,26 @@ static HRESULT WINAPI domdoc_createNode( break; } case NODE_ATTRIBUTE: - xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL); + { + xmlChar *local, *prefix; + + local = xmlSplitQName2(xml_name, &prefix); + + xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL); + + if (local || (href && *href)) + { + /* we need a floating namespace here, it can't be created linked to attribute from + a start */ + xmlNsPtr ns = xmlNewNs(NULL, href, prefix); + xmlSetNs(xmlnode, ns); + } + + xmlFree(local); + xmlFree(prefix); + break; + } case NODE_TEXT: xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL); break; @@ -2984,7 +3015,7 @@ static HRESULT WINAPI domdoc_setProperty( lstrcmpiW(p, PropertyResolveExternalsW) == 0) { /* Ignore */ - FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value)); + FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value)); return S_OK; } diff --git a/reactos/dll/win32/msxml3/element.c b/reactos/dll/win32/msxml3/element.c index 1cdc0f84b8b..d507b77ee49 100644 --- a/reactos/dll/win32/msxml3/element.c +++ b/reactos/dll/win32/msxml3/element.c @@ -61,7 +61,7 @@ static const struct nodemap_funcs domelem_attr_map; static const tid_t domelem_se_tids[] = { IXMLDOMNode_tid, IXMLDOMElement_tid, - 0 + NULL_tid }; static inline domelem *impl_from_IXMLDOMElement( IXMLDOMElement *iface ) diff --git a/reactos/dll/win32/msxml3/entityref.c b/reactos/dll/win32/msxml3/entityref.c index e28166ff466..57a6d3aedf0 100644 --- a/reactos/dll/win32/msxml3/entityref.c +++ b/reactos/dll/win32/msxml3/entityref.c @@ -55,7 +55,7 @@ typedef struct _entityref static const tid_t domentityref_se_tids[] = { IXMLDOMNode_tid, IXMLDOMEntityReference_tid, - 0 + NULL_tid }; static inline entityref *impl_from_IXMLDOMEntityReference( IXMLDOMEntityReference *iface ) diff --git a/reactos/dll/win32/msxml3/httprequest.c b/reactos/dll/win32/msxml3/httprequest.c index 4179368839f..5dbb4cb64f0 100644 --- a/reactos/dll/win32/msxml3/httprequest.c +++ b/reactos/dll/win32/msxml3/httprequest.c @@ -622,8 +622,27 @@ static HRESULT WINAPI Authenticate_Authenticate(IAuthenticate *iface, HWND *hwnd, LPWSTR *username, LPWSTR *password) { BindStatusCallback *This = impl_from_IAuthenticate(iface); - FIXME("(%p)->(%p %p %p)\n", This, hwnd, username, password); - return E_NOTIMPL; + httprequest *request = This->request; + + TRACE("(%p)->(%p %p %p)\n", This, hwnd, username, password); + + if (request->user && *request->user) + { + if (hwnd) *hwnd = NULL; + *username = CoTaskMemAlloc(SysStringByteLen(request->user)+sizeof(WCHAR)); + *password = CoTaskMemAlloc(SysStringByteLen(request->password)+sizeof(WCHAR)); + if (!*username || !*password) + { + CoTaskMemFree(*username); + CoTaskMemFree(*password); + return E_OUTOFMEMORY; + } + + memcpy(*username, request->user, SysStringByteLen(request->user)+sizeof(WCHAR)); + memcpy(*password, request->password, SysStringByteLen(request->password)+sizeof(WCHAR)); + } + + return S_OK; } static const IAuthenticateVtbl AuthenticateVtbl = { @@ -706,7 +725,7 @@ static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback * heap_free(bsc); return hr; } - if ((hr = SafeArrayGetUBound(sa, 1, &size) != S_OK)) + if ((hr = SafeArrayGetUBound(sa, 1, &size)) != S_OK) { SafeArrayUnaccessData(sa); heap_free(bsc); @@ -720,27 +739,31 @@ static HRESULT BindStatusCallback_create(httprequest* This, BindStatusCallback * /* fall through */ case VT_EMPTY: case VT_ERROR: + case VT_NULL: ptr = NULL; size = 0; break; } - bsc->body = GlobalAlloc(GMEM_FIXED, size); - if (!bsc->body) + if (size) { - if (V_VT(body) == VT_BSTR) - heap_free(ptr); - else if (V_VT(body) == (VT_ARRAY|VT_UI1)) - SafeArrayUnaccessData(sa); + bsc->body = GlobalAlloc(GMEM_FIXED, size); + if (!bsc->body) + { + if (V_VT(body) == VT_BSTR) + heap_free(ptr); + else if (V_VT(body) == (VT_ARRAY|VT_UI1)) + SafeArrayUnaccessData(sa); - heap_free(bsc); - return E_OUTOFMEMORY; + heap_free(bsc); + return E_OUTOFMEMORY; + } + + send_data = GlobalLock(bsc->body); + memcpy(send_data, ptr, size); + GlobalUnlock(bsc->body); } - send_data = GlobalLock(bsc->body); - memcpy(send_data, ptr, size); - GlobalUnlock(bsc->body); - if (V_VT(body) == VT_BSTR) heap_free(ptr); else if (V_VT(body) == (VT_ARRAY|VT_UI1)) @@ -885,12 +908,6 @@ static HRESULT httprequest_open(httprequest *This, BSTR method, BSTR url, return hr; } - This->uri = uri; - - VariantInit(&is_async); - hr = VariantChangeType(&is_async, &async, 0, VT_BOOL); - This->async = hr == S_OK && V_BOOL(&is_async); - VariantInit(&str); hr = VariantChangeType(&str, &user, 0, VT_BSTR); if (hr == S_OK) @@ -901,6 +918,38 @@ static HRESULT httprequest_open(httprequest *This, BSTR method, BSTR url, if (hr == S_OK) This->password = V_BSTR(&str); + /* add authentication info */ + if (This->user && *This->user) + { + IUriBuilder *builder; + + hr = CreateIUriBuilder(uri, 0, 0, &builder); + if (hr == S_OK) + { + IUri *full_uri; + + IUriBuilder_SetUserName(builder, This->user); + IUriBuilder_SetPassword(builder, This->password); + hr = IUriBuilder_CreateUri(builder, -1, 0, 0, &full_uri); + if (hr == S_OK) + { + IUri_Release(uri); + uri = full_uri; + } + else + WARN("failed to create modified uri, 0x%08x\n", hr); + IUriBuilder_Release(builder); + } + else + WARN("IUriBuilder creation failed, 0x%08x\n", hr); + } + + This->uri = uri; + + VariantInit(&is_async); + hr = VariantChangeType(&is_async, &async, 0, VT_BOOL); + This->async = hr == S_OK && V_BOOL(&is_async); + httprequest_setreadystate(This, READYSTATE_LOADING); return S_OK; diff --git a/reactos/dll/win32/msxml3/main.c b/reactos/dll/win32/msxml3/main.c index 4f18378876a..25ff33e5cbb 100644 --- a/reactos/dll/win32/msxml3/main.c +++ b/reactos/dll/win32/msxml3/main.c @@ -212,7 +212,7 @@ static void init_libxslt(void) #endif } -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID reserved) { MSXML_hInstance = hInstDLL; @@ -243,7 +243,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) { pxsltCleanupGlobals(); wine_dlclose(libxslt_handle, NULL, 0); - libxslt_handle = NULL; } #endif #ifdef HAVE_LIBXML2 diff --git a/reactos/dll/win32/msxml3/msxml_private.h b/reactos/dll/win32/msxml3/msxml_private.h index dc5250bb132..9f11add0b04 100644 --- a/reactos/dll/win32/msxml3/msxml_private.h +++ b/reactos/dll/win32/msxml3/msxml_private.h @@ -475,6 +475,15 @@ static inline HRESULT return_null_bstr(BSTR *p) return S_FALSE; } +static inline HRESULT return_var_false(VARIANT_BOOL *p) +{ + if(!p) + return E_INVALIDARG; + + *p = VARIANT_FALSE; + return S_FALSE; +} + extern IXMLDOMParseError *create_parseError( LONG code, BSTR url, BSTR reason, BSTR srcText, LONG line, LONG linepos, LONG filepos ) DECLSPEC_HIDDEN; extern HRESULT DOMDocument_create(MSXML_VERSION, IUnknown*, void**) DECLSPEC_HIDDEN; diff --git a/reactos/dll/win32/msxml3/mxwriter.c b/reactos/dll/win32/msxml3/mxwriter.c index e60a6074069..324fd8dd653 100644 --- a/reactos/dll/win32/msxml3/mxwriter.c +++ b/reactos/dll/win32/msxml3/mxwriter.c @@ -1,7 +1,7 @@ /* * MXWriter implementation * - * Copyright 2011-2012 Nikolay Sivov for CodeWeavers + * Copyright 2011-2013 Nikolay Sivov for CodeWeavers * Copyright 2011 Thomas Mullaly * * This library is free software; you can redistribute it and/or @@ -46,6 +46,8 @@ static const WCHAR emptyW[] = {0}; static const WCHAR spaceW[] = {' '}; static const WCHAR quotW[] = {'\"'}; static const WCHAR closetagW[] = {'>','\r','\n'}; +static const WCHAR crlfW[] = {'\r','\n'}; +static const WCHAR entityW[] = {'<','!','E','N','T','I','T','Y',' '}; /* should be ordered as encoding names are sorted */ typedef enum @@ -149,6 +151,10 @@ typedef struct BOOL prop_changed; BOOL cdata; + BOOL text; /* last node was text node, so we shouldn't indent next node */ + BOOL newline; /* newline was already added as a part of previous call */ + UINT indent; /* indentation level for next node */ + BSTR version; BSTR encoding; /* exact property value */ @@ -457,14 +463,13 @@ static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len) return ret; } -static void write_prolog_buffer(const mxwriter *This) +static void write_prolog_buffer(mxwriter *This) { static const WCHAR versionW[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','='}; static const WCHAR encodingW[] = {' ','e','n','c','o','d','i','n','g','=','\"'}; static const WCHAR standaloneW[] = {' ','s','t','a','n','d','a','l','o','n','e','=','\"'}; static const WCHAR yesW[] = {'y','e','s','\"','?','>'}; static const WCHAR noW[] = {'n','o','\"','?','>'}; - static const WCHAR crlfW[] = {'\r','\n'}; /* version */ write_output_buffer(This->buffer, versionW, sizeof(versionW)/sizeof(WCHAR)); @@ -486,6 +491,7 @@ static void write_prolog_buffer(const mxwriter *This) write_output_buffer(This->buffer, noW, sizeof(noW)/sizeof(WCHAR)); write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR)); + This->newline = TRUE; } /* Attempts to the write data from the mxwriter's buffer to @@ -539,6 +545,41 @@ static void close_element_starttag(const mxwriter *This) write_output_buffer(This->buffer, gtW, 1); } +static void write_node_indent(mxwriter *This) +{ + static const WCHAR tabW[] = {'\t'}; + int indent = This->indent; + + if (!This->props[MXWriter_Indent] || This->text) + { + This->text = FALSE; + return; + } + + /* This is to workaround PI output logic that always puts newline chars, + document prolog PI does that too. */ + if (!This->newline) + write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR)); + while (indent--) + write_output_buffer(This->buffer, tabW, 1); + + This->newline = FALSE; + This->text = FALSE; +} + +static inline void writer_inc_indent(mxwriter *This) +{ + This->indent++; +} + +static inline void writer_dec_indent(mxwriter *This) +{ + if (This->indent) This->indent--; + /* depth is decreased only when element is closed, meaning it's not a text node + at this point */ + This->text = FALSE; +} + static void set_element_name(mxwriter *This, const WCHAR *name, int len) { SysFreeString(This->element); @@ -1085,8 +1126,11 @@ static HRESULT WINAPI SAXContentHandler_startElement( set_element_name(This, QName ? QName : emptyW, QName ? nQName : 0); + write_node_indent(This); + write_output_buffer(This->buffer, ltW, 1); write_output_buffer(This->buffer, QName, nQName); + writer_inc_indent(This); if (attr) { @@ -1150,6 +1194,8 @@ static HRESULT WINAPI SAXContentHandler_endElement( (nQName == -1 && This->class_version == MSXML6)) return E_INVALIDARG; + writer_dec_indent(This); + if (This->element) { static const WCHAR closeW[] = {'/','>'}; @@ -1160,6 +1206,7 @@ static HRESULT WINAPI SAXContentHandler_endElement( static const WCHAR closetagW[] = {'<','/'}; static const WCHAR gtW[] = {'>'}; + write_node_indent(This); write_output_buffer(This->buffer, closetagW, 2); write_output_buffer(This->buffer, QName, nQName); write_output_buffer(This->buffer, gtW, 1); @@ -1184,6 +1231,9 @@ static HRESULT WINAPI SAXContentHandler_characters( close_element_starttag(This); set_element_name(This, NULL, 0); + if (!This->cdata) + This->text = TRUE; + if (nchars) { if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE) @@ -1233,6 +1283,7 @@ static HRESULT WINAPI SAXContentHandler_processingInstruction( if (!target) return E_INVALIDARG; + write_node_indent(This); write_output_buffer(This->buffer, openpiW, sizeof(openpiW)/sizeof(WCHAR)); if (*target) @@ -1245,6 +1296,7 @@ static HRESULT WINAPI SAXContentHandler_processingInstruction( } write_output_buffer(This->buffer, closepiW, sizeof(closepiW)/sizeof(WCHAR)); + This->newline = TRUE; return S_OK; } @@ -1384,6 +1436,7 @@ static HRESULT WINAPI SAXLexicalHandler_startCDATA(ISAXLexicalHandler *iface) TRACE("(%p)\n", This); + write_node_indent(This); write_output_buffer(This->buffer, scdataW, sizeof(scdataW)/sizeof(WCHAR)); This->cdata = TRUE; @@ -1414,6 +1467,7 @@ static HRESULT WINAPI SAXLexicalHandler_comment(ISAXLexicalHandler *iface, const if (!chars) return E_INVALIDARG; close_element_starttag(This); + write_node_indent(This); write_output_buffer(This->buffer, copenW, sizeof(copenW)/sizeof(WCHAR)); if (nchars) @@ -1526,7 +1580,6 @@ static HRESULT WINAPI SAXDeclHandler_internalEntityDecl(ISAXDeclHandler *iface, const WCHAR *name, int n_name, const WCHAR *value, int n_value) { mxwriter *This = impl_from_ISAXDeclHandler( iface ); - static const WCHAR entityW[] = {'<','!','E','N','T','I','T','Y',' '}; TRACE("(%p)->(%s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name, debugstr_wn(value, n_value), n_value); @@ -1551,10 +1604,39 @@ static HRESULT WINAPI SAXDeclHandler_externalEntityDecl(ISAXDeclHandler *iface, const WCHAR *name, int n_name, const WCHAR *publicId, int n_publicId, const WCHAR *systemId, int n_systemId) { + static const WCHAR publicW[] = {'P','U','B','L','I','C',' '}; + static const WCHAR systemW[] = {'S','Y','S','T','E','M',' '}; mxwriter *This = impl_from_ISAXDeclHandler( iface ); - FIXME("(%p)->(%s:%d %s:%d %s:%d): stub\n", This, debugstr_wn(name, n_name), n_name, + + TRACE("(%p)->(%s:%d %s:%d %s:%d)\n", This, debugstr_wn(name, n_name), n_name, debugstr_wn(publicId, n_publicId), n_publicId, debugstr_wn(systemId, n_systemId), n_systemId); - return E_NOTIMPL; + + if (!name) return E_INVALIDARG; + if (publicId && !systemId) return E_INVALIDARG; + if (!publicId && !systemId) return E_INVALIDARG; + + write_output_buffer(This->buffer, entityW, sizeof(entityW)/sizeof(WCHAR)); + if (n_name) { + write_output_buffer(This->buffer, name, n_name); + write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR)); + } + + if (publicId) + { + write_output_buffer(This->buffer, publicW, sizeof(publicW)/sizeof(WCHAR)); + write_output_buffer_quoted(This->buffer, publicId, n_publicId); + write_output_buffer(This->buffer, spaceW, sizeof(spaceW)/sizeof(WCHAR)); + write_output_buffer_quoted(This->buffer, systemId, n_systemId); + } + else + { + write_output_buffer(This->buffer, systemW, sizeof(systemW)/sizeof(WCHAR)); + write_output_buffer_quoted(This->buffer, systemId, n_systemId); + } + + write_output_buffer(This->buffer, closetagW, sizeof(closetagW)/sizeof(WCHAR)); + + return S_OK; } static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = { @@ -1612,6 +1694,9 @@ HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj) This->element = NULL; This->cdata = FALSE; + This->indent = 0; + This->text = FALSE; + This->newline = FALSE; This->dest = NULL; This->dest_written = 0; @@ -1806,11 +1891,32 @@ static HRESULT WINAPI MXAttributes_clear(IMXAttributes *iface) return S_OK; } +static mxattribute *get_attribute_byindex(mxattributes *attrs, int index) +{ + if (index < 0 || index >= attrs->length) return NULL; + return &attrs->attr[index]; +} + static HRESULT WINAPI MXAttributes_removeAttribute(IMXAttributes *iface, int index) { mxattributes *This = impl_from_IMXAttributes( iface ); - FIXME("(%p)->(%d): stub\n", This, index); - return E_NOTIMPL; + mxattribute *dst; + + TRACE("(%p)->(%d)\n", This, index); + + if (!(dst = get_attribute_byindex(This, index))) return E_INVALIDARG; + + /* no need to remove last attribute, just make it inaccessible */ + if (index + 1 == This->length) + { + This->length--; + return S_OK; + } + + memmove(dst, dst + 1, (This->length-index-1)*sizeof(*dst)); + This->length--; + + return S_OK; } static HRESULT WINAPI MXAttributes_setAttribute(IMXAttributes *iface, int index, @@ -1833,29 +1939,61 @@ static HRESULT WINAPI MXAttributes_setLocalName(IMXAttributes *iface, int index, BSTR localName) { mxattributes *This = impl_from_IMXAttributes( iface ); - FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(localName)); - return E_NOTIMPL; + mxattribute *attr; + + TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(localName)); + + if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG; + + SysFreeString(attr->local); + attr->local = SysAllocString(localName); + + return S_OK; } static HRESULT WINAPI MXAttributes_setQName(IMXAttributes *iface, int index, BSTR QName) { mxattributes *This = impl_from_IMXAttributes( iface ); - FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(QName)); - return E_NOTIMPL; + mxattribute *attr; + + TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(QName)); + + if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG; + + SysFreeString(attr->qname); + attr->qname = SysAllocString(QName); + + return S_OK; } static HRESULT WINAPI MXAttributes_setURI(IMXAttributes *iface, int index, BSTR uri) { mxattributes *This = impl_from_IMXAttributes( iface ); - FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(uri)); - return E_NOTIMPL; + mxattribute *attr; + + TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(uri)); + + if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG; + + SysFreeString(attr->uri); + attr->uri = SysAllocString(uri); + + return S_OK; } static HRESULT WINAPI MXAttributes_setValue(IMXAttributes *iface, int index, BSTR value) { mxattributes *This = impl_from_IMXAttributes( iface ); - FIXME("(%p)->(%d %s): stub\n", This, index, debugstr_w(value)); - return E_NOTIMPL; + mxattribute *attr; + + TRACE("(%p)->(%d %s)\n", This, index, debugstr_w(value)); + + if (!(attr = get_attribute_byindex(This, index))) return E_INVALIDARG; + + SysFreeString(attr->value); + attr->value = SysAllocString(value); + + return S_OK; } static const IMXAttributesVtbl MXAttributesVtbl = { diff --git a/reactos/dll/win32/msxml3/node.c b/reactos/dll/win32/msxml3/node.c index f52026e8668..53efb61cc43 100644 --- a/reactos/dll/win32/msxml3/node.c +++ b/reactos/dll/win32/msxml3/node.c @@ -153,7 +153,7 @@ static HRESULT WINAPI SupportErrorInfo_InterfaceSupportsErrorInfo(ISupportErrorI TRACE("(%p)->(%s)\n", This, debugstr_guid(riid)); tid = This->iids; - while (*tid) + while (*tid != NULL_tid) { if (IsEqualGUID(riid, get_riid_from_tid(*tid))) return S_OK; @@ -899,6 +899,50 @@ HRESULT node_get_xml(xmlnode *This, BOOL ensure_eol, BSTR *ret) return *ret ? S_OK : E_OUTOFMEMORY; } +/* duplicates xmlBufferWriteQuotedString() logic */ +static void xml_write_quotedstring(xmlOutputBufferPtr buf, const xmlChar *string) +{ + const xmlChar *cur, *base; + + if (xmlStrchr(string, '\"')) + { + if (xmlStrchr(string, '\'')) + { + xmlOutputBufferWrite(buf, 1, "\""); + base = cur = string; + + while (*cur) + { + if (*cur == '"') + { + if (base != cur) + xmlOutputBufferWrite(buf, cur-base, (const char*)base); + xmlOutputBufferWrite(buf, 6, """); + cur++; + base = cur; + } + else + cur++; + } + if (base != cur) + xmlOutputBufferWrite(buf, cur-base, (const char*)base); + xmlOutputBufferWrite(buf, 1, "\""); + } + else + { + xmlOutputBufferWrite(buf, 1, "\'"); + xmlOutputBufferWriteString(buf, (const char*)string); + xmlOutputBufferWrite(buf, 1, "\'"); + } + } + else + { + xmlOutputBufferWrite(buf, 1, "\""); + xmlOutputBufferWriteString(buf, (const char*)string); + xmlOutputBufferWrite(buf, 1, "\""); + } +} + static void htmldtd_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc) { xmlDtdPtr cur = doc->intSubset; @@ -908,17 +952,17 @@ static void htmldtd_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc) if (cur->ExternalID) { xmlOutputBufferWriteString(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf->buffer, cur->ExternalID); + xml_write_quotedstring(buf, cur->ExternalID); if (cur->SystemID) { xmlOutputBufferWriteString(buf, " "); - xmlBufferWriteQuotedString(buf->buffer, cur->SystemID); + xml_write_quotedstring(buf, cur->SystemID); } } else if (cur->SystemID) { xmlOutputBufferWriteString(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf->buffer, cur->SystemID); + xml_write_quotedstring(buf, cur->SystemID); } xmlOutputBufferWriteString(buf, ">\n"); } @@ -946,6 +990,15 @@ static void htmldoc_dumpcontent(xmlOutputBufferPtr buf, xmlDocPtr doc) doc->type = type; } +static const xmlChar *get_output_buffer_content(xmlOutputBufferPtr output) +{ +#ifdef LIBXML2_NEW_BUFFER + return xmlOutputBufferGetContent(output); +#else + return xmlBufferContent(output->buffer); +#endif +} + HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p) { #ifdef SONAME_LIBXSLT @@ -974,7 +1027,7 @@ HRESULT node_transform_node(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR * if (output) { htmldoc_dumpcontent(output, result->doc); - content = xmlBufferContent(output->buffer); + content = get_output_buffer_content(output); *p = bstr_from_xmlChar(content); xmlOutputBufferClose(output); } diff --git a/reactos/dll/win32/msxml3/pi.c b/reactos/dll/win32/msxml3/pi.c index 73a318c4bf0..e846e32be6c 100644 --- a/reactos/dll/win32/msxml3/pi.c +++ b/reactos/dll/win32/msxml3/pi.c @@ -57,7 +57,7 @@ static const struct nodemap_funcs dom_pi_attr_map; static const tid_t dompi_se_tids[] = { IXMLDOMNode_tid, IXMLDOMProcessingInstruction_tid, - 0 + NULL_tid }; static inline dom_pi *impl_from_IXMLDOMProcessingInstruction( IXMLDOMProcessingInstruction *iface ) diff --git a/reactos/dll/win32/msxml3/saxreader.c b/reactos/dll/win32/msxml3/saxreader.c index 9fb17120423..241f681a59c 100644 --- a/reactos/dll/win32/msxml3/saxreader.c +++ b/reactos/dll/win32/msxml3/saxreader.c @@ -1268,6 +1268,49 @@ static const struct ISAXAttributesVtbl isaxattributes_vtbl = isaxattributes_getValueFromQName }; +/* Libxml2 escapes '&' back to char reference '&' in attribute value, + so when document has escaped value with '&' it's parsed to '&' and then + escaped to '&'. This function takes care of ampersands only. */ +static BSTR saxreader_get_unescaped_value(const xmlChar *buf, int len) +{ + static const WCHAR ampescW[] = {'&','#','3','8',';',0}; + WCHAR *dest, *ptrW, *str; + DWORD str_len; + BSTR bstr; + + if (!buf) + return NULL; + + str_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0); + if (len != -1) str_len++; + + str = heap_alloc(str_len*sizeof(WCHAR)); + if (!str) return NULL; + + MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, str, str_len); + if (len != -1) str[str_len-1] = 0; + + ptrW = str; + while ((dest = strstrW(ptrW, ampescW))) + { + WCHAR *src; + + /* leave first '&' from a reference as a value */ + src = dest + (sizeof(ampescW)/sizeof(WCHAR) - 1); + dest++; + + /* move together with null terminator */ + memmove(dest, src, (strlenW(src) + 1)*sizeof(WCHAR)); + + ptrW++; + } + + bstr = SysAllocString(str); + heap_free(str); + + return bstr; +} + static HRESULT SAXAttributes_populate(saxlocator *locator, int nb_namespaces, const xmlChar **xmlNamespaces, int nb_attributes, const xmlChar **xmlAttributes) @@ -1320,8 +1363,7 @@ static HRESULT SAXAttributes_populate(saxlocator *locator, attrs[i].szURI = find_element_uri(locator, xmlAttributes[i*5+2]); attrs[i].szLocalname = bstr_from_xmlChar(xmlAttributes[i*5]); - attrs[i].szValue = bstr_from_xmlCharN(xmlAttributes[i*5+3], - xmlAttributes[i*5+4]-xmlAttributes[i*5+3]); + attrs[i].szValue = saxreader_get_unescaped_value(xmlAttributes[i*5+3], xmlAttributes[i*5+4]-xmlAttributes[i*5+3]); attrs[i].szQName = QName_from_xmlChar(xmlAttributes[i*5+1], xmlAttributes[i*5]); } diff --git a/reactos/dll/win32/msxml3/text.c b/reactos/dll/win32/msxml3/text.c index efc79e547e1..68a40085f3a 100644 --- a/reactos/dll/win32/msxml3/text.c +++ b/reactos/dll/win32/msxml3/text.c @@ -333,7 +333,7 @@ static HRESULT WINAPI domtext_hasChildNodes( { domtext *This = impl_from_IXMLDOMText( iface ); TRACE("(%p)->(%p)\n", This, ret); - return node_has_childnodes(&This->node, ret); + return return_var_false(ret); } static HRESULT WINAPI domtext_get_ownerDocument( diff --git a/reactos/dll/win32/msxml3/version.rc b/reactos/dll/win32/msxml3/version.rc index 497bdaf98e0..c6e46c693b2 100644 --- a/reactos/dll/win32/msxml3/version.rc +++ b/reactos/dll/win32/msxml3/version.rc @@ -22,7 +22,7 @@ #define WINE_PRODUCTVERSION_STR "8.90.1101.0" #define WINE_EXTRAVALUES VALUE "OLESelfRegister","" -#include "wine/wine_common_ver.rc" +#include /* @makedep: msxml3.manifest */ WINE_MANIFEST 24 msxml3.manifest diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 32df320ed16..0ae78b1294a 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -132,7 +132,7 @@ reactos/dll/win32/msvfw32 # Synced to Wine-1.7.1 reactos/dll/win32/msvidc32 # Synced to Wine-1.7.1 reactos/dll/win32/msxml # Synced to Wine-1.5.19 reactos/dll/win32/msxml2 # Synced to Wine-1.5.19 -reactos/dll/win32/msxml3 # Synced to Wine-1.5.26 +reactos/dll/win32/msxml3 # Synced to Wine-1.7.1 reactos/dll/win32/msxml4 # Synced to Wine-1.5.19 reactos/dll/win32/msxml6 # Synced to Wine-1.5.19 reactos/dll/win32/nddeapi # Synced to Wine-1.5.19