Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- Fixes https://bugs.winehq.org/show_bug.cgi?id=42468
On September 8, Nikolay agreed to sign off on this patch if Wine Staging accepted it and there were no reported problems for two months.[1] On September 17, Wine Staging accepted the patch.[2] On September 20, Wine Staging 2.17 was released, which included the patch.[3] It has now been two months and there have been no reported problems.
[1] https://www.winehq.org/pipermail/wine-devel/2017-September/118879.html [2] https://github.com/wine-compholio/wine-staging/commit/63a8a664c9a49361ecb675... [3] https://wine-staging.com/news/2017-09-20-release-2.17.html --- dlls/msxml3/tests/domdoc.c | 153 +++++++++++++++++++++++++++++++++++++++------ dlls/msxml3/text.c | 34 +++++++--- 2 files changed, 161 insertions(+), 26 deletions(-)
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index 9a607e3d3c..f6df417471 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -12101,34 +12101,148 @@ static void test_put_data(void) type++; }
- /* \r\n sequence is never escaped */ + IXMLDOMDocument_Release(doc); + free_bstrs(); +} + +static void test_newline_normalization(void) +{ + const struct msxmlsupported_data_t *table = domdoc_support_data; + IXMLDOMDocument *doc; + IXMLDOMText *text; + IXMLDOMNode *node; + VARIANT v; + VARIANT_BOOL b; + BSTR s; + HRESULT hr; + LONG length; + V_VT(&v) = VT_I2; V_I2(&v) = NODE_TEXT;
- hr = IXMLDOMDocument_createNode(doc, v, _bstr_("name"), NULL, &node); - ok(hr == S_OK, "got 0x%08x\n", hr); + while (table->clsid) + { + if (!is_clsid_supported(table->clsid, &IID_IXMLDOMDocument)) + { + table++; + continue; + }
- IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)&text); + hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&doc); + ok(hr == S_OK, "got 0x%08x\n", hr);
- hr = IXMLDOMText_put_data(text, _bstr_("\r\n")); - ok(hr == S_OK, "got 0x%08x\n", hr); + hr = IXMLDOMDocument_createNode(doc, v, _bstr_("name"), NULL, &node); + ok(hr == S_OK, "got 0x%08x\n", hr);
- hr = IXMLDOMText_get_data(text, &get_data); - ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine - ok(!lstrcmpW(get_data, _bstr_("\n")), "got %s\n", wine_dbgstr_w(get_data)); - SysFreeString(get_data); + IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)&text);
- hr = IXMLDOMText_get_xml(text, &get_data); - ok(hr == S_OK, "got 0x%08x\n", hr); - ok(!lstrcmpW(get_data, _bstr_("\r\n")), "got %s\n", wine_dbgstr_w(get_data)); - SysFreeString(get_data); + /* \r\n is normalized to \n and back to \r\n */
- IXMLDOMText_Release(text); - IXMLDOMNode_Release(node); + hr = IXMLDOMText_put_data(text, _bstr_("\r\n")); + ok(hr == S_OK, "got 0x%08x\n", hr);
- IXMLDOMDocument_Release(doc); - free_bstrs(); + hr = IXMLDOMText_get_data(text, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("\n")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + hr = IXMLDOMText_get_length(text, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(length == 1, "got %d, expected 1\n", length); + + hr = IXMLDOMText_get_xml(text, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("\r\n")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + /* \r\r\n is normalized to \n\n and back to \r\n\r\n */ + + hr = IXMLDOMText_put_data(text, _bstr_("\r\r\n")); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IXMLDOMText_get_data(text, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("\n\n")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + hr = IXMLDOMText_get_length(text, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(length == 2, "got %d, expected 2\n", length); + + hr = IXMLDOMText_get_xml(text, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("\r\n\r\n")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + /* the same normalizations are applied when loading a document as a whole */ + + hr = IXMLDOMDocument_loadXML(doc, _bstr_("<?xml version=\"1.0\"?><root>foo\n\r\n\r\r\nbar</root>"), &b); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IXMLDOMDocument_get_text(doc, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("foo\n\n\n\nbar")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + hr = IXMLDOMDocument_get_xml(doc, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("<?xml version=\"1.0\"?>\r\n<root>foo\r\n\r\n\r\n\r\nbar</root>\r\n")), + "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + /* even if xml:space="preserve" */ + + hr = IXMLDOMDocument_loadXML(doc, _bstr_("<?xml version=\"1.0\"?>" + "<root xml:space="preserve">foo\n\r\n\r\r\nbar</root>"), &b); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IXMLDOMDocument_get_text(doc, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("foo\n\n\n\nbar")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + hr = IXMLDOMDocument_get_xml(doc, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("<?xml version=\"1.0\"?>\r\n" + "<root xml:space="preserve">foo\r\n\r\n\r\n\r\nbar</root>\r\n")), + "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + /* or preserveWhiteSpace is set */ + + hr = IXMLDOMDocument_put_preserveWhiteSpace(doc, VARIANT_TRUE); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IXMLDOMDocument_loadXML(doc, _bstr_("<?xml version=\"1.0\"?><root>foo\n\r\n\r\r\nbar</root>"), &b); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IXMLDOMDocument_get_text(doc, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!lstrcmpW(s, _bstr_("foo\n\n\n\nbar")), "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + hr = IXMLDOMDocument_get_xml(doc, &s); + ok(hr == S_OK, "got 0x%08x\n", hr); + if (IsEqualGUID(table->clsid, &CLSID_DOMDocument60)) + { + /* DOMDocument60 does the newline normalization but does not insert line breaks around the root node */ +todo_wine + ok(!lstrcmpW(s, _bstr_("<?xml version=\"1.0\"?><root>foo\r\n\r\n\r\n\r\nbar</root>")), + "got %s\n", wine_dbgstr_w(s)); + } + else + { + ok(!lstrcmpW(s, _bstr_("<?xml version=\"1.0\"?>\r\n<root>foo\r\n\r\n\r\n\r\nbar</root>\r\n")), + "got %s\n", wine_dbgstr_w(s)); + } + SysFreeString(s); + + IXMLDOMText_Release(text); + IXMLDOMNode_Release(node); + IXMLDOMDocument_Release(doc); + free_bstrs(); + table++; + } }
static void test_putref_schemas(void) @@ -12712,6 +12826,7 @@ START_TEST(domdoc) test_nodeValue(); test_get_namespaces(); test_put_data(); + test_newline_normalization(); test_putref_schemas(); test_namedmap_newenum(); test_xmlns_attribute(); diff --git a/dlls/msxml3/text.c b/dlls/msxml3/text.c index 3a12d4bf62..abd89dbd6b 100644 --- a/dlls/msxml3/text.c +++ b/dlls/msxml3/text.c @@ -522,7 +522,7 @@ static HRESULT WINAPI domtext_get_xml(
TRACE("(%p)->(%p)\n", This, p);
- return node_get_xml(&This->node, FALSE, p); + return node_get_xml(&This->node, TRUE, p); }
static HRESULT WINAPI domtext_transformNode( @@ -616,15 +616,35 @@ static HRESULT WINAPI domtext_put_data( BSTR data) { domtext *This = impl_from_IXMLDOMText( iface ); - static const WCHAR rnW[] = {'\r','\n',0}; + BSTR normalized_data = NULL; + HRESULT hr; + size_t i, j;
TRACE("(%p)->(%s)\n", This, debugstr_w(data));
- if (data && !strcmpW(rnW, data)) - This->node.node->name = xmlStringTextNoenc; - else - domtext_reset_noenc(This); - return node_set_content(&This->node, data); + if (data) + { + /* normalize line endings */ + normalized_data = SysAllocStringLen(NULL, SysStringLen(data)); + if (!normalized_data) return E_OUTOFMEMORY; + for (i = 0, j = 0; data[i]; i++) + { + if (data[i] == '\r') + { + if (data[i + 1] == '\n') i++; /* change \r\n to just \n */ + normalized_data[j++] = '\n'; /* change \r by itself to \n */ + } + else + normalized_data[j++] = data[i]; + } + normalized_data[j] = 0; + } + + domtext_reset_noenc(This); + hr = node_set_content(&This->node, normalized_data); + + SysFreeString(normalized_data); + return hr; }
static HRESULT WINAPI domtext_get_length(