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) ...@@ -1466,16 +1466,6 @@ static HRESULT reader_parse_comment(xmlreader *reader)
return S_OK; 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] | [-'()+,./:=?;!*#@$_%] */ /* [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] */
BOOL is_pubchar(WCHAR ch) BOOL is_pubchar(WCHAR ch)
{ {
......
...@@ -1335,6 +1335,8 @@ static void test_WriteCData(void) ...@@ -1335,6 +1335,8 @@ static void test_WriteCData(void)
static void test_WriteRaw(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<:"; static const WCHAR rawW[] = L"a<:";
IXmlWriter *writer; IXmlWriter *writer;
IStream *stream; IStream *stream;
...@@ -1351,6 +1353,15 @@ static void test_WriteRaw(void) ...@@ -1351,6 +1353,15 @@ static void test_WriteRaw(void)
stream = writer_set_output(writer); 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); hr = IXmlWriter_WriteRaw(writer, NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
...@@ -1885,6 +1896,7 @@ static void test_WriteCharEntity(void) ...@@ -1885,6 +1896,7 @@ static void test_WriteCharEntity(void)
static void test_WriteString(void) static void test_WriteString(void)
{ {
static const WCHAR surrogates[] = {0xd800, 0xdc00, 'x', 'y', '\0'};
IXmlWriter *writer; IXmlWriter *writer;
IStream *stream; IStream *stream;
HRESULT hr; HRESULT hr;
...@@ -1905,6 +1917,27 @@ static void test_WriteString(void) ...@@ -1905,6 +1917,27 @@ static void test_WriteString(void)
stream = writer_set_output(writer); 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); hr = IXmlWriter_WriteStartElement(writer, NULL, L"b", NULL);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
......
...@@ -1684,9 +1684,30 @@ static HRESULT WINAPI xmlwriter_WriteQualifiedName(IXmlWriter *iface, LPCWSTR pw ...@@ -1684,9 +1684,30 @@ static HRESULT WINAPI xmlwriter_WriteQualifiedName(IXmlWriter *iface, LPCWSTR pw
return E_NOTIMPL; 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) static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data)
{ {
xmlwriter *This = impl_from_IXmlWriter(iface); xmlwriter *This = impl_from_IXmlWriter(iface);
unsigned int count;
HRESULT hr = S_OK;
TRACE("%p %s\n", This, debugstr_w(data)); TRACE("%p %s\n", This, debugstr_w(data));
...@@ -1713,8 +1734,15 @@ static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data) ...@@ -1713,8 +1734,15 @@ static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data)
return WR_E_INVALIDACTION; return WR_E_INVALIDACTION;
} }
write_output_buffer(This->output, data, -1); while (*data)
return S_OK; {
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) 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 ...@@ -1834,27 +1862,56 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
return S_OK; 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 '<': case '<':
write_output_buffer(writer->output, L"&lt;", 4); hr = write_output_buffer(writer->output, L"&lt;", 4);
break; break;
case '&': case '&':
write_output_buffer(writer->output, L"&amp;", 5); hr = write_output_buffer(writer->output, L"&amp;", 5);
break; break;
case '>': case '>':
write_output_buffer(writer->output, L"&gt;", 4); hr = write_output_buffer(writer->output, L"&gt;", 4);
break; break;
default: default:
write_output_buffer(writer->output, string, 1); hr = write_output_buffer(writer->output, string, count);
} }
string++; 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)
{
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 += count;
length -= count;
}
}
return hr;
} }
static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *string) static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *string)
...@@ -1884,8 +1941,7 @@ static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *stri ...@@ -1884,8 +1941,7 @@ static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *stri
} }
This->textnode = 1; This->textnode = 1;
write_escaped_string(This, string); return write_escaped_string(This, string, ~0u);
return S_OK;
} }
static HRESULT WINAPI xmlwriter_WriteSurrogateCharEntity(IXmlWriter *iface, WCHAR wchLow, WCHAR wchHigh) static HRESULT WINAPI xmlwriter_WriteSurrogateCharEntity(IXmlWriter *iface, WCHAR wchLow, WCHAR wchHigh)
......
...@@ -63,6 +63,17 @@ BOOL is_pubchar(WCHAR ch) DECLSPEC_HIDDEN; ...@@ -63,6 +63,17 @@ BOOL is_pubchar(WCHAR ch) DECLSPEC_HIDDEN;
BOOL is_namestartchar(WCHAR ch) DECLSPEC_HIDDEN; BOOL is_namestartchar(WCHAR ch) DECLSPEC_HIDDEN;
BOOL is_namechar(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) static inline BOOL is_wchar_space(WCHAR ch)
{ {
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; 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