From: Alex Henrie Subject: [PATCH resend2] msxml3: Remove CRs in domtext_put_data and add them in domtext_get_xml Message-Id: <20180220071044.18522-1-alexhenrie24@gmail.com> Date: Tue, 20 Feb 2018 00:10:44 -0700 Signed-off-by: Alex Henrie --- Fixes https://bugs.winehq.org/show_bug.cgi?id=42468 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 7aeafa5e75..23c17ea978 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -12143,34 +12143,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_("foo\n\r\n\r\r\nbar"), &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_("\r\nfoo\r\n\r\n\r\n\r\nbar\r\n")), + "got %s\n", wine_dbgstr_w(s)); + SysFreeString(s); + + /* even if xml:space="preserve" */ + + hr = IXMLDOMDocument_loadXML(doc, _bstr_("" + "foo\n\r\n\r\r\nbar"), &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_("\r\n" + "foo\r\n\r\n\r\n\r\nbar\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_("foo\n\r\n\r\r\nbar"), &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_("foo\r\n\r\n\r\n\r\nbar")), + "got %s\n", wine_dbgstr_w(s)); + } + else + { + ok(!lstrcmpW(s, _bstr_("\r\nfoo\r\n\r\n\r\n\r\nbar\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) @@ -12754,6 +12868,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( -- 2.16.2