Commit 5d1820c4 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

xmllite/writer: Handle surrogate pairs.

parent 97154872
......@@ -1466,16 +1466,6 @@ static HRESULT reader_parse_comment(xmlreader *reader)
return S_OK;
}
/* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
static inline BOOL is_char(WCHAR ch)
{
return (ch == '\t') || (ch == '\r') || (ch == '\n') ||
(ch >= 0x20 && ch <= 0xd7ff) ||
(ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
(ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
(ch >= 0xe000 && ch <= 0xfffd);
}
/* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
BOOL is_pubchar(WCHAR ch)
{
......
......@@ -1335,6 +1335,8 @@ static void test_WriteCData(void)
static void test_WriteRaw(void)
{
static const WCHAR surrogates[] = {0xdc00, 0xd800, '\0'};
static const WCHAR invalid[] = {0x8, '\0'};
static const WCHAR rawW[] = L"a<:";
IXmlWriter *writer;
IStream *stream;
......@@ -1351,6 +1353,15 @@ static void test_WriteRaw(void)
stream = writer_set_output(writer);
hr = IXmlWriter_WriteRaw(writer, surrogates);
ok(hr == WR_E_INVALIDSURROGATEPAIR, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_WriteRaw(writer, L"\uffff");
ok(hr == WC_E_XMLCHARACTER, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_WriteRaw(writer, invalid);
ok(hr == WC_E_XMLCHARACTER, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_WriteRaw(writer, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
......@@ -1885,6 +1896,7 @@ static void test_WriteCharEntity(void)
static void test_WriteString(void)
{
static const WCHAR surrogates[] = {0xd800, 0xdc00, 'x', 'y', '\0'};
IXmlWriter *writer;
IStream *stream;
HRESULT hr;
......@@ -1905,6 +1917,27 @@ static void test_WriteString(void)
stream = writer_set_output(writer);
hr = IXmlWriter_WriteStartElement(writer, NULL, L"sub", NULL);
ok(hr == S_OK, "Unexpected hr #%lx.\n", hr);
hr = IXmlWriter_WriteString(writer, L"\v");
ok(hr == WC_E_XMLCHARACTER, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_WriteString(writer, L"\ufffe");
ok(hr == WC_E_XMLCHARACTER, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_WriteString(writer, surrogates);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_Flush(writer);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_OUTPUT(stream,
"<sub>\U00010000xy");
IStream_Release(stream);
stream = writer_set_output(writer);
hr = IXmlWriter_WriteStartElement(writer, NULL, L"b", NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
......
......@@ -1684,9 +1684,30 @@ static HRESULT WINAPI xmlwriter_WriteQualifiedName(IXmlWriter *iface, LPCWSTR pw
return E_NOTIMPL;
}
static HRESULT writer_get_next_write_count(const WCHAR *str, unsigned int length, unsigned int *count)
{
if (!is_char(*str)) return WC_E_XMLCHARACTER;
if (IS_HIGH_SURROGATE(*str))
{
if (length < 2 || !IS_LOW_SURROGATE(*(str + 1)))
return WR_E_INVALIDSURROGATEPAIR;
*count = 2;
}
else if (IS_LOW_SURROGATE(*str))
return WR_E_INVALIDSURROGATEPAIR;
else
*count = 1;
return S_OK;
}
static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data)
{
xmlwriter *This = impl_from_IXmlWriter(iface);
unsigned int count;
HRESULT hr = S_OK;
TRACE("%p %s\n", This, debugstr_w(data));
......@@ -1713,8 +1734,15 @@ static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data)
return WR_E_INVALIDACTION;
}
write_output_buffer(This->output, data, -1);
return S_OK;
while (*data)
{
if (FAILED(hr = writer_get_next_write_count(data, ~0u, &count))) return hr;
if (FAILED(hr = write_output_buffer(This->output, data, count))) return hr;
data += count;
}
return hr;
}
static HRESULT WINAPI xmlwriter_WriteRawChars(IXmlWriter *iface, const WCHAR *pwch, UINT cwch)
......@@ -1834,27 +1862,56 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
return S_OK;
}
static void write_escaped_string(xmlwriter *writer, const WCHAR *string)
static HRESULT write_escaped_char(xmlwriter *writer, const WCHAR *string, unsigned int count)
{
while (*string)
HRESULT hr;
switch (*string)
{
switch (*string)
case '<':
hr = write_output_buffer(writer->output, L"&lt;", 4);
break;
case '&':
hr = write_output_buffer(writer->output, L"&amp;", 5);
break;
case '>':
hr = write_output_buffer(writer->output, L"&gt;", 4);
break;
default:
hr = write_output_buffer(writer->output, string, count);
}
return hr;
}
static HRESULT write_escaped_string(xmlwriter *writer, const WCHAR *string, unsigned int length)
{
unsigned int count;
HRESULT hr = S_OK;
if (length == ~0u)
{
while (*string)
{
case '<':
write_output_buffer(writer->output, L"&lt;", 4);
break;
case '&':
write_output_buffer(writer->output, L"&amp;", 5);
break;
case '>':
write_output_buffer(writer->output, L"&gt;", 4);
break;
default:
write_output_buffer(writer->output, string, 1);
if (FAILED(hr = writer_get_next_write_count(string, ~0u, &count))) return hr;
if (FAILED(hr = write_escaped_char(writer, string, count))) return hr;
string += count;
}
}
else
{
while (length)
{
if (FAILED(hr = writer_get_next_write_count(string, length, &count))) return hr;
if (FAILED(hr = write_escaped_char(writer, string, count))) return hr;
string++;
string += count;
length -= count;
}
}
return hr;
}
static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *string)
......@@ -1884,8 +1941,7 @@ static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *stri
}
This->textnode = 1;
write_escaped_string(This, string);
return S_OK;
return write_escaped_string(This, string, ~0u);
}
static HRESULT WINAPI xmlwriter_WriteSurrogateCharEntity(IXmlWriter *iface, WCHAR wchLow, WCHAR wchHigh)
......
......@@ -63,6 +63,17 @@ BOOL is_pubchar(WCHAR ch) DECLSPEC_HIDDEN;
BOOL is_namestartchar(WCHAR ch) DECLSPEC_HIDDEN;
BOOL is_namechar(WCHAR ch) DECLSPEC_HIDDEN;
/* [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] */
static inline BOOL is_char(WCHAR ch)
{
return (ch == '\t') || (ch == '\r') || (ch == '\n') ||
(ch >= 0x20 && ch <= 0xd7ff) ||
(ch >= 0xd800 && ch <= 0xdbff) || /* high surrogate */
(ch >= 0xdc00 && ch <= 0xdfff) || /* low surrogate */
(ch >= 0xe000 && ch <= 0xfffd);
}
/* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
static inline BOOL is_wchar_space(WCHAR ch)
{
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
......
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