From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/msxml3/mxwriter.c | 158 +++++++++++++++++----------------- dlls/msxml3/tests/saxreader.c | 3 - dlls/msxml6/tests/saxreader.c | 1 - 3 files changed, 81 insertions(+), 81 deletions(-) diff --git a/dlls/msxml3/mxwriter.c b/dlls/msxml3/mxwriter.c index ad6419d0a75..f766aa85955 100644 --- a/dlls/msxml3/mxwriter.c +++ b/dlls/msxml3/mxwriter.c @@ -318,7 +318,7 @@ static HRESULT write_output_buffer(mxwriter *writer, const WCHAR *data, int len) ULONG written; int src_len; - if (!len || !*data) + if (!len) return S_OK; src_len = len == -1 ? lstrlenW(data) : len; @@ -477,76 +477,92 @@ static void close_output_buffer(mxwriter *writer) list_init(&writer->buffer.blocks); } -/* Escapes special characters like: +/* + Special characters are escaped: + '<' -> "<" '&' -> "&" '"' -> """ '>' -> ">" - On call 'len' contains a length of 'str' in chars or -1 if it's null terminated. - After a call it's updated with actual new length if it wasn't -1 initially. + Newlines always produce CRLF. + */ -static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len) + +static void write_crlf(mxwriter *writer) { - static const WCHAR ltW[] = {'&','l','t',';'}; - static const WCHAR ampW[] = {'&','a','m','p',';'}; - static const WCHAR equotW[] = {'&','q','u','o','t',';'}; - static const WCHAR gtW[] = {'&','g','t',';'}; + bool use_charref_lf = writer->class_version == MSXML6; - const int default_alloc = 100; - const int grow_thresh = 10; - int p = *len, conv_len; - WCHAR *ptr, *ret; + if (use_charref_lf) + write_output_buffer(writer, L" ", 5); + else + write_output_buffer(writer, L"\r\n", 2); +} - /* default buffer size to something if length is unknown */ - conv_len = max(2**len, default_alloc); - ptr = ret = malloc(conv_len * sizeof(WCHAR)); +static void write_escaped_string(mxwriter *writer, const WCHAR *str, int len, escape_mode mode) +{ + const WCHAR *p = str; - while (p) + while (len-- > 0) { - if (ptr - ret > conv_len - grow_thresh) + if (*p == '<') + write_output_buffer(writer, L"<", 4); + else if (*p == '&') + write_output_buffer(writer, L"&", 5); + else if (*p == '>') + write_output_buffer(writer, L">", 4); + else if (*p == '"' && mode == EscapeValue) + write_output_buffer(writer, L""", 6); + else if (*p == '\n') + write_crlf(writer); + else if (*p == '\r') { - int written = ptr - ret; - conv_len *= 2; - ptr = ret = realloc(ret, conv_len * sizeof(WCHAR)); - ptr += written; - } + if (len > 0 && p[1] == '\n') + { + write_crlf(writer); - switch (*str) - { - case '<': - memcpy(ptr, ltW, sizeof(ltW)); - ptr += ARRAY_SIZE(ltW); - break; - case '&': - memcpy(ptr, ampW, sizeof(ampW)); - ptr += ARRAY_SIZE(ampW); - break; - case '>': - memcpy(ptr, gtW, sizeof(gtW)); - ptr += ARRAY_SIZE(gtW); - break; - case '"': - if (mode == EscapeValue) + ++p; + --len; + } + else { - memcpy(ptr, equotW, sizeof(equotW)); - ptr += ARRAY_SIZE(equotW); - break; + write_crlf(writer); } - /* fallthrough for text mode */ - default: - *ptr++ = *str; - break; } + else + write_output_buffer(writer, p, 1); - str++; - p--; + ++p; } +} + +static void write_string_with_crlf(mxwriter *writer, const WCHAR *str, int len) +{ + const WCHAR *p = str; + + while (len-- > 0) + { + if (*p == '\n') + write_crlf(writer); + else if (*p == '\r') + { + if (len > 0 && p[1] == '\n') + { + write_crlf(writer); - *len = ptr-ret; - *++ptr = 0; + ++p; + --len; + } + else + { + write_crlf(writer); + } + } + else + write_output_buffer(writer, p, 1); - return ret; + ++p; + } } static void write_prolog_buffer(mxwriter *writer) @@ -1254,14 +1270,12 @@ static void mxwriter_write_attribute(mxwriter *writer, const WCHAR *qname, int q write_output_buffer(writer, qname, qname_len); write_output_buffer(writer, eqW, 1); + write_output_buffer(writer, L"\"", 1); if (escape) - { - WCHAR *escaped = get_escaped_string(value, EscapeValue, &value_len); - write_output_buffer_quoted(writer, escaped, value_len); - free(escaped); - } + write_escaped_string(writer, value, value_len, EscapeValue); else - write_output_buffer_quoted(writer, value, value_len); + write_string_with_crlf(writer, value, value_len); + write_output_buffer(writer, L"\"", 1); } static void mxwriter_write_starttag(mxwriter *writer, const WCHAR *qname, int len) @@ -1369,36 +1383,26 @@ static HRESULT WINAPI SAXContentHandler_endElement( return S_OK; } -static HRESULT WINAPI SAXContentHandler_characters( - ISAXContentHandler *iface, - const WCHAR *chars, - int nchars) +static HRESULT WINAPI SAXContentHandler_characters(ISAXContentHandler *iface, const WCHAR *chars, int nchars) { - mxwriter *This = impl_from_ISAXContentHandler( iface ); + mxwriter *writer = impl_from_ISAXContentHandler(iface); - TRACE("(%p)->(%s:%d)\n", This, debugstr_wn(chars, nchars), nchars); + TRACE("%p, %s, %d.\n", iface, debugstr_wn(chars, nchars), nchars); if (!chars) return E_INVALIDARG; - close_element_starttag(This); - set_element_name(This, NULL, 0); + close_element_starttag(writer); + set_element_name(writer, NULL, 0); - if (!This->cdata) - This->text = TRUE; + if (!writer->cdata) + writer->text = TRUE; if (nchars) { - if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE) - write_output_buffer(This, chars, nchars); + if (writer->cdata || writer->props[MXWriter_DisableEscaping] == VARIANT_TRUE) + write_output_buffer(writer, chars, nchars); else - { - int len = nchars; - WCHAR *escaped; - - escaped = get_escaped_string(chars, EscapeText, &len); - write_output_buffer(This, escaped, len); - free(escaped); - } + write_escaped_string(writer, chars, nchars, EscapeText); } return S_OK; diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c index 1337b3faab8..f5f998fbfec 100644 --- a/dlls/msxml3/tests/saxreader.c +++ b/dlls/msxml3/tests/saxreader.c @@ -4089,7 +4089,6 @@ static void test_mxwriter_startendelement_batch(const struct writer_startendelem hr = IMXWriter_get_output(writer, &dest); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); - todo_wine_if((i >= 48 && i <= 53) || (i >= 57 && i <= 59)) ok(!lstrcmpW(table->output, V_BSTR(&dest)), "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), wine_dbgstr_w(table->output)); VariantClear(&dest); @@ -4571,7 +4570,6 @@ static void test_mxwriter_characters(void) hr = IMXWriter_get_output(writer, &dest); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(V_VT(&dest) == VT_BSTR, "Unexpected type %d.\n", V_VT(&dest)); - todo_wine ok(!lstrcmpW(L"ab\r\n\r\ncd", V_BSTR(&dest)), "Unexpected content %s\n", wine_dbgstr_w(V_BSTR(&dest))); VariantClear(&dest); @@ -4586,7 +4584,6 @@ static void test_mxwriter_characters(void) hr = IMXWriter_get_output(writer, &dest); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(V_VT(&dest) == VT_BSTR, "Unexpected type %d.\n", V_VT(&dest)); - todo_wine ok(!lstrcmpW(L"\r\nab\r\nc\r\n", V_BSTR(&dest)), "Unexpected content %s\n", wine_dbgstr_w(V_BSTR(&dest))); VariantClear(&dest); diff --git a/dlls/msxml6/tests/saxreader.c b/dlls/msxml6/tests/saxreader.c index 2b6178a7560..39498f553c3 100644 --- a/dlls/msxml6/tests/saxreader.c +++ b/dlls/msxml6/tests/saxreader.c @@ -1766,7 +1766,6 @@ static void test_mxwriter_startendelement_batch(void) hr = IMXWriter_get_output(writer, &dest); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); - todo_wine_if(i == 16 || i == 17 || i == 19) ok(!lstrcmpW(table->output, V_BSTR(&dest)), "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), wine_dbgstr_w(table->output)); VariantClear(&dest); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10157