From 49a57bcabaddc801733d7ebd5163c78b4efd7aa6 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 3 Aug 2017 11:00:31 +0300 Subject: [PATCH] xmllite/writer: Improve handling of the output with invalid encoding. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/xmllite/reader.c | 4 +- dlls/xmllite/tests/writer.c | 117 +++++++++++++++++++++++++++++++++++- dlls/xmllite/writer.c | 85 +++++++++++++++++++------- 3 files changed, 181 insertions(+), 25 deletions(-) diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c index ac0fe33f9ff..495d4e3cb4d 100644 --- a/dlls/xmllite/reader.c +++ b/dlls/xmllite/reader.c @@ -156,7 +156,7 @@ struct xml_encoding_data static const struct xml_encoding_data xml_encoding_map[] = { { usasciiW, XmlEncoding_USASCII, 20127 }, - { utf16W, XmlEncoding_UTF16, ~0 }, + { utf16W, XmlEncoding_UTF16, 1200 }, { utf8W, XmlEncoding_UTF8, CP_UTF8 }, }; @@ -1084,7 +1084,7 @@ static HRESULT reader_more(xmlreader *reader) prev_len = dest->written / sizeof(WCHAR); /* just copy for UTF-16 case */ - if (cp == ~0) + if (cp == 1200) { readerinput_grow(readerinput, len); memcpy(dest->data + dest->written, src->data + src->cur, len); diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index 8ef2e709793..1add717b8e4 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -31,6 +31,8 @@ #include "initguid.h" DEFINE_GUID(IID_IXmlWriterOutput, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a); +static const WCHAR aW[] = {'a',0}; + #define EXPECT_REF(obj, ref) _expect_ref((IUnknown *)obj, ref, __LINE__) static void _expect_ref(IUnknown *obj, ULONG ref, int line) { @@ -292,11 +294,92 @@ static void test_writer_create(void) IXmlWriter_Release(writer); } +static void test_invalid_output_encoding(IXmlWriter *writer, IUnknown *output) +{ + HRESULT hr; + + hr = IXmlWriter_SetOutput(writer, output); + ok(hr == S_OK, "Failed to set output, hr %#x.\n", hr); + + /* TODO: WriteAttributes */ + + hr = IXmlWriter_WriteAttributeString(writer, NULL, aW, NULL, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteCData(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteCharEntity(writer, 0x100); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteChars(writer, aW, 1); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteComment(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + /* TODO: WriteDocType */ + + hr = IXmlWriter_WriteElementString(writer, NULL, aW, NULL, NULL); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteEndDocument(writer); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteEndElement(writer); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteEntityRef(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteFullEndElement(writer); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteName(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteNmToken(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + /* TODO: WriteNode */ + /* TODO: WriteNodeShallow */ + + hr = IXmlWriter_WriteProcessingInstruction(writer, aW, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteQualifiedName(writer, aW, NULL); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteRaw(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteRawChars(writer, aW, 1); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + hr = IXmlWriter_WriteString(writer, aW); + ok(hr == MX_E_ENCODING, "Unexpected hr %#x.\n", hr); + + /* TODO: WriteSurrogateCharEntity */ + /* ًُُTODO: WriteWhitespace */ + + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#x.\n", hr); +} + static void test_writeroutput(void) { static const WCHAR utf16W[] = {'u','t','f','-','1','6',0}; static const WCHAR usasciiW[] = {'u','s','-','a','s','c','i','i',0}; + static const WCHAR dummyW[] = {'d','u','m','m','y',0}; IXmlWriterOutput *output; + IXmlWriter *writer; + IStream *stream; IUnknown *unk; HRESULT hr; @@ -339,6 +422,39 @@ todo_wine hr = CreateXmlWriterOutputWithEncodingName(&testoutput, NULL, usasciiW, &output); ok(hr == S_OK, "got %08x\n", hr); IUnknown_Release(output); + + /* Create output with meaningless code page value. */ + hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL); + ok(hr == S_OK, "Failed to create writer, hr %#x.\n", hr); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + output = NULL; + hr = CreateXmlWriterOutputWithEncodingCodePage((IUnknown *)stream, NULL, ~0u, &output); + ok(hr == S_OK, "Failed to create writer output, hr %#x.\n", hr); + + test_invalid_output_encoding(writer, output); + CHECK_OUTPUT(stream, ""); + + IStream_Release(stream); + IUnknown_Release(output); + + /* Same, with invalid encoding name. */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + output = NULL; + hr = CreateXmlWriterOutputWithEncodingName((IUnknown *)stream, NULL, dummyW, &output); + ok(hr == S_OK, "got %08x\n", hr); + + test_invalid_output_encoding(writer, output); + CHECK_OUTPUT(stream, ""); + + IStream_Release(stream); + IUnknown_Release(output); + + IXmlWriter_Release(writer); } static void test_writestartdocument(void) @@ -547,7 +663,6 @@ static void test_bom(void) static const WCHAR versionW[] = {'v','e','r','s','i','o','n','=','"','1','.','0','"',0}; static const WCHAR utf16W[] = {'u','t','f','-','1','6',0}; static const WCHAR xmlW[] = {'x','m','l',0}; - static const WCHAR aW[] = {'a',0}; IXmlWriterOutput *output; unsigned char *ptr; IXmlWriter *writer; diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index 9e993387986..9bf7e632115 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -57,13 +57,14 @@ struct output_buffer typedef enum { - XmlWriterState_Initial, /* output is not set yet */ - XmlWriterState_Ready, /* SetOutput() was called, ready to start */ - XmlWriterState_PIDocStarted, /* document was started with manually added 'xml' PI */ - XmlWriterState_DocStarted, /* document was started with WriteStartDocument() */ - XmlWriterState_ElemStarted, /* writing element */ - XmlWriterState_Content, /* content is accepted at this point */ - XmlWriterState_DocClosed /* WriteEndDocument was called */ + XmlWriterState_Initial, /* output is not set yet */ + XmlWriterState_Ready, /* SetOutput() was called, ready to start */ + XmlWriterState_InvalidEncoding, /* SetOutput() was called, but output had invalid encoding */ + XmlWriterState_PIDocStarted, /* document was started with manually added 'xml' PI */ + XmlWriterState_DocStarted, /* document was started with WriteStartDocument() */ + XmlWriterState_ElemStarted, /* writing element */ + XmlWriterState_Content, /* content is accepted at this point */ + XmlWriterState_DocClosed /* WriteEndDocument was called */ } XmlWriterState; typedef struct @@ -208,11 +209,11 @@ static HRESULT init_output_buffer(xmlwriteroutput *output) { struct output_buffer *buffer = &output->buffer; const int initial_len = 0x2000; + UINT cp = ~0u; HRESULT hr; - UINT cp; - hr = get_code_page(output->encoding, &cp); - if (FAILED(hr)) return hr; + if (FAILED(hr = get_code_page(output->encoding, &cp))) + WARN("Failed to get code page for specified encoding.\n"); buffer->data = writeroutput_alloc(output, initial_len); if (!buffer->data) return E_OUTOFMEMORY; @@ -256,16 +257,8 @@ static HRESULT write_output_buffer(xmlwriteroutput *output, const WCHAR *data, i HRESULT hr; char *ptr; - if (buffer->codepage != ~0) { - length = WideCharToMultiByte(buffer->codepage, 0, data, len, NULL, 0, NULL, NULL); - hr = grow_output_buffer(output, length); - if (FAILED(hr)) return hr; - ptr = buffer->data + buffer->written; - length = WideCharToMultiByte(buffer->codepage, 0, data, len, ptr, length, NULL, NULL); - buffer->written += len == -1 ? length-1 : length; - } - else { - /* WCHAR data just copied */ + if (buffer->codepage == 1200) { + /* For UTF-16 encoding just copy. */ length = len == -1 ? strlenW(data) : len; if (length) { length *= sizeof(WCHAR); @@ -281,6 +274,14 @@ static HRESULT write_output_buffer(xmlwriteroutput *output, const WCHAR *data, i *(WCHAR*)ptr = 0; } } + else { + length = WideCharToMultiByte(buffer->codepage, 0, data, len, NULL, 0, NULL, NULL); + hr = grow_output_buffer(output, length); + if (FAILED(hr)) return hr; + ptr = buffer->data + buffer->written; + length = WideCharToMultiByte(buffer->codepage, 0, data, len, ptr, length, NULL, NULL); + buffer->written += len == -1 ? length-1 : length; + } return S_OK; } @@ -546,7 +547,6 @@ static HRESULT WINAPI xmlwriter_SetOutput(IXmlWriter *iface, IUnknown *output) writeroutput, writeroutput->lpVtbl); IUnknown_Release(writeroutput); return E_FAIL; - } } @@ -557,7 +557,10 @@ static HRESULT WINAPI xmlwriter_SetOutput(IXmlWriter *iface, IUnknown *output) This->output = impl_from_IXmlWriterOutput(writeroutput); } - This->state = XmlWriterState_Ready; + if (This->output->encoding == XmlEncoding_Unknown) + This->state = XmlWriterState_InvalidEncoding; + else + This->state = XmlWriterState_Ready; return writeroutput_query_for_stream(This->output); } @@ -643,6 +646,8 @@ static HRESULT WINAPI xmlwriter_WriteAttributeString(IXmlWriter *iface, LPCWSTR case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -690,6 +695,8 @@ static HRESULT WINAPI xmlwriter_WriteCData(IXmlWriter *iface, LPCWSTR data) case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -731,6 +738,8 @@ static HRESULT WINAPI xmlwriter_WriteCharEntity(IXmlWriter *iface, WCHAR ch) { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_ElemStarted: writer_close_starttag(This); break; @@ -756,6 +765,8 @@ static HRESULT WINAPI xmlwriter_WriteChars(IXmlWriter *iface, const WCHAR *pwch, { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_DocClosed: return WR_E_INVALIDACTION; default: @@ -778,6 +789,8 @@ static HRESULT WINAPI xmlwriter_WriteComment(IXmlWriter *iface, LPCWSTR comment) { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_ElemStarted: writer_close_starttag(This); break; @@ -835,6 +848,8 @@ static HRESULT WINAPI xmlwriter_WriteElementString(IXmlWriter *iface, LPCWSTR pr { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_ElemStarted: writer_close_starttag(This); break; @@ -879,6 +894,8 @@ static HRESULT WINAPI xmlwriter_WriteEndDocument(IXmlWriter *iface) case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -906,6 +923,8 @@ static HRESULT WINAPI xmlwriter_WriteEndElement(IXmlWriter *iface) case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -942,6 +961,8 @@ static HRESULT WINAPI xmlwriter_WriteEntityRef(IXmlWriter *iface, LPCWSTR pwszNa { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_DocClosed: return WR_E_INVALIDACTION; default: @@ -966,6 +987,8 @@ static HRESULT WINAPI xmlwriter_WriteFullEndElement(IXmlWriter *iface) case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -1005,6 +1028,8 @@ static HRESULT WINAPI xmlwriter_WriteName(IXmlWriter *iface, LPCWSTR pwszName) case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -1026,6 +1051,8 @@ static HRESULT WINAPI xmlwriter_WriteNmToken(IXmlWriter *iface, LPCWSTR pwszNmTo case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; } @@ -1066,6 +1093,8 @@ static HRESULT WINAPI xmlwriter_WriteProcessingInstruction(IXmlWriter *iface, LP { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_DocStarted: if (!strcmpW(name, xmlW)) return WR_E_INVALIDACTION; @@ -1102,6 +1131,8 @@ static HRESULT WINAPI xmlwriter_WriteQualifiedName(IXmlWriter *iface, LPCWSTR pw { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_DocClosed: return WR_E_INVALIDACTION; default: @@ -1130,6 +1161,8 @@ static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data) case XmlWriterState_DocStarted: case XmlWriterState_PIDocStarted: break; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; @@ -1149,6 +1182,8 @@ static HRESULT WINAPI xmlwriter_WriteRawChars(IXmlWriter *iface, const WCHAR *p { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_DocClosed: return WR_E_INVALIDACTION; default: @@ -1173,6 +1208,8 @@ static HRESULT WINAPI xmlwriter_WriteStartDocument(IXmlWriter *iface, XmlStandal return S_OK; case XmlWriterState_Ready: break; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; @@ -1195,6 +1232,8 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre { case XmlWriterState_Initial: return E_UNEXPECTED; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; case XmlWriterState_DocClosed: return WR_E_INVALIDACTION; default: @@ -1271,6 +1310,8 @@ static HRESULT WINAPI xmlwriter_WriteString(IXmlWriter *iface, const WCHAR *stri case XmlWriterState_DocClosed: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; default: ; }