Commit 5016f7ba authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

msxml3: Properly escape character data in text nodes.

parent cdac8cb1
......@@ -68,6 +68,12 @@ typedef enum
MXWriter_LastProp
} mxwriter_prop;
typedef enum
{
EscapeValue,
EscapeText
} escape_mode;
typedef struct
{
char *data;
......@@ -94,6 +100,7 @@ typedef struct
VARIANT_BOOL props[MXWriter_LastProp];
BOOL prop_changed;
BOOL cdata;
BSTR version;
......@@ -275,7 +282,7 @@ static void close_output_buffer(mxwriter *This)
'"' -> """
'>' -> ">"
*/
static WCHAR *get_escaped_string(const WCHAR *str, int *len)
static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len)
{
static const WCHAR ltW[] = {'&','l','t',';'};
static const WCHAR ampW[] = {'&','a','m','p',';'};
......@@ -311,14 +318,18 @@ static WCHAR *get_escaped_string(const WCHAR *str, int *len)
memcpy(ptr, ampW, sizeof(ampW));
ptr += sizeof(ampW)/sizeof(WCHAR);
break;
case '"':
memcpy(ptr, equotW, sizeof(equotW));
ptr += sizeof(equotW)/sizeof(WCHAR);
break;
case '>':
memcpy(ptr, gtW, sizeof(gtW));
ptr += sizeof(gtW)/sizeof(WCHAR);
break;
case '"':
if (mode == EscapeValue)
{
memcpy(ptr, equotW, sizeof(equotW));
ptr += sizeof(equotW)/sizeof(WCHAR);
break;
}
/* fallthrough for text mode */
default:
*ptr++ = *str;
break;
......@@ -429,6 +440,7 @@ static inline HRESULT flush_output_buffer(mxwriter *This)
{
close_element_starttag(This);
set_element_name(This, NULL, 0);
This->cdata = FALSE;
return write_data_to_stream(This);
}
......@@ -978,7 +990,7 @@ static HRESULT WINAPI SAXContentHandler_startElement(
hr = ISAXAttributes_getValue(attr, i, &str, &len);
if (FAILED(hr)) return hr;
escaped = get_escaped_string(str, &len);
escaped = get_escaped_string(str, EscapeValue, &len);
write_output_buffer_quoted(This->buffer, escaped, len);
heap_free(escaped);
}
......@@ -1040,7 +1052,19 @@ static HRESULT WINAPI SAXContentHandler_characters(
set_element_name(This, NULL, 0);
if (nchars)
write_output_buffer(This->buffer, chars, nchars);
{
if (This->cdata)
write_output_buffer(This->buffer, chars, nchars);
else
{
int len = nchars;
WCHAR *escaped;
escaped = get_escaped_string(chars, EscapeText, &len);
write_output_buffer(This->buffer, escaped, len);
heap_free(escaped);
}
}
return S_OK;
}
......@@ -1203,6 +1227,7 @@ static HRESULT WINAPI SAXLexicalHandler_startCDATA(ISAXLexicalHandler *iface)
TRACE("(%p)\n", This);
write_output_buffer(This->buffer, scdataW, sizeof(scdataW)/sizeof(WCHAR));
This->cdata = TRUE;
return S_OK;
}
......@@ -1215,6 +1240,7 @@ static HRESULT WINAPI SAXLexicalHandler_endCDATA(ISAXLexicalHandler *iface)
TRACE("(%p)\n", This);
write_output_buffer(This->buffer, ecdataW, sizeof(ecdataW)/sizeof(WCHAR));
This->cdata = FALSE;
return S_OK;
}
......@@ -1296,6 +1322,7 @@ HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
This->xml_enc = XmlEncoding_UTF16;
This->element = NULL;
This->cdata = FALSE;
This->dest = NULL;
This->dest_written = 0;
......
......@@ -2439,13 +2439,29 @@ static void test_mxwriter_startendelement(void)
free_bstrs();
}
struct writer_characters_t {
const GUID *clsid;
const char *data;
const char *output;
};
static const struct writer_characters_t writer_characters[] = {
{ &CLSID_MXXMLWriter, "< > & \"", "&lt; &gt; &amp; \"" },
{ &CLSID_MXXMLWriter30, "< > & \"", "&lt; &gt; &amp; \"" },
{ &CLSID_MXXMLWriter40, "< > & \"", "&lt; &gt; &amp; \"" },
{ &CLSID_MXXMLWriter60, "< > & \"", "&lt; &gt; &amp; \"" },
{ NULL }
};
static void test_mxwriter_characters(void)
{
static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
const struct writer_characters_t *table = writer_characters;
ISAXContentHandler *content;
IMXWriter *writer;
VARIANT dest;
HRESULT hr;
int i = 0;
hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
&IID_IMXWriter, (void**)&writer);
......@@ -2515,6 +2531,54 @@ static void test_mxwriter_characters(void)
ISAXContentHandler_Release(content);
IMXWriter_Release(writer);
/* batch tests */
while (table->clsid)
{
ISAXContentHandler *content;
IMXWriter *writer;
HRESULT hr;
if (!is_clsid_supported(table->clsid, mxwriter_support_data))
{
table++;
i++;
continue;
}
hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IMXWriter, (void**)&writer);
EXPECT_HR(hr, S_OK);
hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
EXPECT_HR(hr, S_OK);
hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
EXPECT_HR(hr, S_OK);
hr = ISAXContentHandler_startDocument(content);
EXPECT_HR(hr, S_OK);
hr = ISAXContentHandler_characters(content, _bstr_(table->data), strlen(table->data));
EXPECT_HR(hr, S_OK);
/* test output */
if (hr == S_OK)
{
VARIANT dest;
V_VT(&dest) = VT_EMPTY;
hr = IMXWriter_get_output(writer, &dest);
EXPECT_HR(hr, S_OK);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
"test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
VariantClear(&dest);
}
table++;
i++;
}
free_bstrs();
}
......@@ -2975,6 +3039,10 @@ static void test_mxwriter_cdata(void)
hr = ISAXLexicalHandler_startCDATA(lexical);
EXPECT_HR(hr, S_OK);
/* all these are escaped for text nodes */
hr = ISAXContentHandler_characters(content, _bstr_("< > & \""), 7);
EXPECT_HR(hr, S_OK);
hr = ISAXLexicalHandler_endCDATA(lexical);
EXPECT_HR(hr, S_OK);
......@@ -2982,7 +3050,7 @@ static void test_mxwriter_cdata(void)
hr = IMXWriter_get_output(writer, &dest);
EXPECT_HR(hr, S_OK);
ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
ok(!lstrcmpW(_bstr_("<![CDATA[<![CDATA[< > & \"]]>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
VariantClear(&dest);
ISAXContentHandler_Release(content);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment