From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/reader.c | 16 ++++++++-------- dlls/xmllite/tests/reader.c | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c index 118b7bd5ea2..6e5e08734bc 100644 --- a/dlls/xmllite/reader.c +++ b/dlls/xmllite/reader.c @@ -1296,13 +1296,13 @@ static HRESULT reader_parse_encname(xmlreader *reader, strval *val) }
/* [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) */ -static HRESULT reader_parse_encdecl(xmlreader *reader) +static HRESULT reader_parse_encdecl(xmlreader *reader, BOOL *spaces) { struct reader_position position; strval name, val; HRESULT hr;
- if (!reader_skipspaces(reader)) return S_FALSE; + if (!(*spaces = reader_skipspaces(reader))) return S_FALSE;
position = reader->position; if (reader_cmp(reader, L"encoding")) return S_FALSE; @@ -1328,19 +1328,20 @@ static HRESULT reader_parse_encdecl(xmlreader *reader)
/* skip "'"|'"' */ reader_skipn(reader, 1); + *spaces = FALSE;
return reader_add_attr(reader, NULL, &name, NULL, &val, &position, 0); }
/* [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) */ -static HRESULT reader_parse_sddecl(xmlreader *reader) +static HRESULT reader_parse_sddecl(xmlreader *reader, BOOL spaces) { struct reader_position position; strval name, val; UINT start; HRESULT hr;
- if (!reader_skipspaces(reader)) return S_FALSE; + if (!spaces && !reader_skipspaces(reader)) return S_FALSE;
position = reader->position; if (reader_cmp(reader, L"standalone")) return S_FALSE; @@ -1377,6 +1378,7 @@ static HRESULT reader_parse_sddecl(xmlreader *reader) static HRESULT reader_parse_xmldecl(xmlreader *reader) { struct reader_position position; + BOOL spaces; HRESULT hr;
if (reader_cmp(reader, L"<?xml ")) @@ -1389,12 +1391,10 @@ static HRESULT reader_parse_xmldecl(xmlreader *reader) if (FAILED(hr)) return hr;
- hr = reader_parse_encdecl(reader); - if (FAILED(hr)) + if (FAILED(hr = reader_parse_encdecl(reader, &spaces))) return hr;
- hr = reader_parse_sddecl(reader); - if (FAILED(hr)) + if (FAILED(hr = reader_parse_sddecl(reader, spaces))) return hr;
reader_skipspaces(reader); diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c index 2ea781ce992..8bb30f730a4 100644 --- a/dlls/xmllite/tests/reader.c +++ b/dlls/xmllite/tests/reader.c @@ -1019,6 +1019,27 @@ todo_wine { TEST_READER_STATE(reader, XmlReadState_Error);
IStream_Release(stream); + + /* No encoding attribute. */ + set_input_string(reader, "<?xml version=\"1.0\" standalone=\"yes\"?><a/>"); + hr = IXmlReader_Read(reader, &type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type); + + /* Just version attribute, no spaces. */ + set_input_string(reader, "<?xml version=\"1.0\"?><a/>"); + hr = IXmlReader_Read(reader, &type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(type == XmlNodeType_XmlDeclaration, "got %d\n", type); + + set_input_string(reader, "<?xml version=\"1.0\"encoding=\"UTF-8\"?><a/>"); + hr = IXmlReader_Read(reader, &type); + ok(hr == WC_E_XMLDECL, "Unexpected hr %#lx.\n", hr); + + set_input_string(reader, "<?xml version=\"1.0\"standalone=\"yes\"?><a/>"); + hr = IXmlReader_Read(reader, &type); + ok(hr == WC_E_XMLDECL, "Unexpected hr %#lx.\n", hr); + IXmlReader_Release(reader); }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/reader.c | 5 ---- dlls/xmllite/tests/writer.c | 51 ++++++++++++++++++++++++++++------ dlls/xmllite/writer.c | 31 ++++++++++++++++++--- dlls/xmllite/xmllite_private.h | 5 ++++ 4 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c index 6e5e08734bc..d747e36e623 100644 --- a/dlls/xmllite/reader.c +++ b/dlls/xmllite/reader.c @@ -1159,11 +1159,6 @@ static void reader_skipn(xmlreader *reader, int n) } }
-static inline BOOL is_wchar_space(WCHAR ch) -{ - return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; -} - /* [3] S ::= (#x20 | #x9 | #xD | #xA)+ */ static int reader_skipspaces(xmlreader *reader) { diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index 3e1c362664e..a000bde6d80 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -148,28 +148,30 @@ static void check_writer_state(IXmlWriter *writer, HRESULT exp_hr) /* FIXME: add WriteNodeShallow */
hr = IXmlWriter_WriteProcessingInstruction(writer, L"a", L"a"); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
hr = IXmlWriter_WriteQualifiedName(writer, L"a", NULL); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
hr = IXmlWriter_WriteRaw(writer, L"a"); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
hr = IXmlWriter_WriteRawChars(writer, L"a", 1); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
hr = IXmlWriter_WriteStartElement(writer, NULL, L"a", NULL); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
hr = IXmlWriter_WriteString(writer, L"a"); - ok(hr == exp_hr, "Unexpected hr %#lx., expected %#lx.\n", hr, exp_hr); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr);
/* FIXME: add WriteSurrogateCharEntity */ - /* FIXME: add WriteWhitespace */ + + hr = IXmlWriter_WriteWhitespace(writer, L" "); + ok(hr == exp_hr, "Unexpected hr %#lx, expected %#lx.\n", hr, exp_hr); }
static IStream *writer_set_output(IXmlWriter *writer) @@ -388,7 +390,9 @@ static void test_invalid_output_encoding(IXmlWriter *writer, IUnknown *output) ok(hr == MX_E_ENCODING, "Unexpected hr %#lx.\n", hr);
/* TODO: WriteSurrogateCharEntity */ - /* TODO: WriteWhitespace */ + + hr = IXmlWriter_WriteWhitespace(writer, L" "); + ok(hr == MX_E_ENCODING, "Unexpected hr %#lx.\n", hr);
hr = IXmlWriter_Flush(writer); ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); @@ -2063,6 +2067,34 @@ static void test_WriteDocType(void) IXmlWriter_Release(writer); }
+static void test_WriteWhitespace(void) +{ + IXmlWriter *writer; + IStream *stream; + HRESULT hr; + + hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + stream = writer_set_output(writer); + + hr = IXmlWriter_WriteWhitespace(writer, L" "); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteWhitespace(writer, L"ab"); + ok(hr == WR_E_NONWHITESPACE, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteStartElement(writer, NULL, L"w", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteWhitespace(writer, L"\t"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, " <w>\t"); + IStream_Release(stream); + + IXmlWriter_Release(writer); +} + START_TEST(writer) { test_writer_create(); @@ -2085,4 +2117,5 @@ START_TEST(writer) test_WriteCharEntity(); test_WriteString(); test_WriteDocType(); + test_WriteWhitespace(); } diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index 6f455ffcb19..0a3717d426e 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -1752,13 +1752,36 @@ static HRESULT WINAPI xmlwriter_WriteSurrogateCharEntity(IXmlWriter *iface, WCHA return E_NOTIMPL; }
-static HRESULT WINAPI xmlwriter_WriteWhitespace(IXmlWriter *iface, LPCWSTR pwszWhitespace) +static HRESULT WINAPI xmlwriter_WriteWhitespace(IXmlWriter *iface, LPCWSTR text) { - xmlwriter *This = impl_from_IXmlWriter(iface); + xmlwriter *writer = impl_from_IXmlWriter(iface); + size_t length = 0;
- FIXME("%p %s\n", This, wine_dbgstr_w(pwszWhitespace)); + TRACE("%p, %s.\n", iface, wine_dbgstr_w(text));
- return E_NOTIMPL; + switch (writer->state) + { + case XmlWriterState_Initial: + return E_UNEXPECTED; + case XmlWriterState_ElemStarted: + writer_close_starttag(writer); + break; + case XmlWriterState_InvalidEncoding: + return MX_E_ENCODING; + case XmlWriterState_Ready: + break; + default: + return WR_E_INVALIDACTION; + } + + while (text[length]) + { + if (!is_wchar_space(text[length])) return WR_E_NONWHITESPACE; + length++; + } + + write_output_buffer(writer->output, text, length); + return S_OK; }
static HRESULT WINAPI xmlwriter_Flush(IXmlWriter *iface) diff --git a/dlls/xmllite/xmllite_private.h b/dlls/xmllite/xmllite_private.h index 03653bbe371..bd53fca575f 100644 --- a/dlls/xmllite/xmllite_private.h +++ b/dlls/xmllite/xmllite_private.h @@ -63,4 +63,9 @@ BOOL is_pubchar(WCHAR ch) DECLSPEC_HIDDEN; BOOL is_namestartchar(WCHAR ch) DECLSPEC_HIDDEN; BOOL is_namechar(WCHAR ch) DECLSPEC_HIDDEN;
+static inline BOOL is_wchar_space(WCHAR ch) +{ + return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; +} + #endif /* __XMLLITE_PRIVATE__ */
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 26 +++++++++++++++++++++++++- dlls/xmllite/writer.c | 20 ++++++++++---------- 2 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index a000bde6d80..c76f3708fca 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -1736,9 +1736,33 @@ static void test_WriteFullEndElement(void) "<a>\r\n" " <a></a>\r\n" "</a>"); + IStream_Release(stream);
- IXmlWriter_Release(writer); + /* Empty strings for prefix and uri. */ + stream = writer_set_output(writer); + + hr = IXmlWriter_SetProperty(writer, XmlWriterProperty_Indent, FALSE); + ok(hr == S_OK, "Failed to set property, hr %#lx.\n", hr); + + hr = IXmlWriter_WriteStartElement(writer, L"", L"a", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteStartElement(writer, NULL, L"b", L""); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteStartElement(writer, L"", L"c", L""); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteFullEndElement(writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteFullEndElement(writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteFullEndElement(writer); + 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, "<a><b><c></c></b></a>"); IStream_Release(stream); + + IXmlWriter_Release(writer); }
static void test_WriteCharEntity(void) diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index 0a3717d426e..2ec1a3b12da 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -168,6 +168,11 @@ static inline void writer_free(const xmlwriter *writer, void *mem) m_free(writer->imalloc, mem); }
+static BOOL is_empty_string(const WCHAR *str) +{ + return !str || !*str; +} + static struct element *alloc_element(xmlwriter *writer, const WCHAR *prefix, const WCHAR *local) { struct element *ret; @@ -176,7 +181,7 @@ static struct element *alloc_element(xmlwriter *writer, const WCHAR *prefix, con ret = writer_alloc(writer, sizeof(*ret)); if (!ret) return ret;
- len = prefix ? lstrlenW(prefix) + 1 /* ':' */ : 0; + len = is_empty_string(prefix) ? 0 : lstrlenW(prefix) + 1 /* ':' */; len += lstrlenW(local);
ret->qname = writer_alloc(writer, (len + 1)*sizeof(WCHAR)); @@ -188,13 +193,13 @@ static struct element *alloc_element(xmlwriter *writer, const WCHAR *prefix, con }
ret->len = len; - if (prefix) + if (is_empty_string(prefix)) + ret->qname[0] = 0; + else { lstrcpyW(ret->qname, prefix); lstrcatW(ret->qname, L":"); } - else - ret->qname[0] = 0; lstrcatW(ret->qname, local); list_init(&ret->ns);
@@ -288,11 +293,6 @@ static struct ns *writer_push_ns(xmlwriter *writer, const WCHAR *prefix, int pre return ns; }
-static BOOL is_empty_string(const WCHAR *str) -{ - return !str || !*str; -} - static struct ns *writer_find_ns_current(const xmlwriter *writer, const WCHAR *prefix, const WCHAR *uri) { struct element *element; @@ -1676,7 +1676,7 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
writer_push_element(This, element);
- if (!ns && uri) + if (!ns && !is_empty_string(uri)) writer_push_ns(This, prefix, prefix_len, uri);
write_output_buffer_char(This->output, '<');
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 16 ++++++++++++++-- dlls/xmllite/writer.c | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index c76f3708fca..72ca7309355 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -1320,11 +1320,23 @@ static void test_WriteRaw(void)
hr = IXmlWriter_Flush(writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>a<:a<:<!--a<:-->a<:<a>a</a>"); + IStream_Release(stream);
- IXmlWriter_Release(writer); + /* With open element. */ + stream = writer_set_output(writer); + + hr = IXmlWriter_WriteStartElement(writer, NULL, L"w", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteRaw(writer, L"text"); + 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, "<w>text"); IStream_Release(stream); + + IXmlWriter_Release(writer); }
static void test_writer_state(void) diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index 2ec1a3b12da..99dfff3c918 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -1563,6 +1563,9 @@ static HRESULT WINAPI xmlwriter_WriteRaw(IXmlWriter *iface, LPCWSTR data) break; case XmlWriterState_InvalidEncoding: return MX_E_ENCODING; + case XmlWriterState_ElemStarted: + writer_close_starttag(This); + break; default: This->state = XmlWriterState_DocClosed; return WR_E_INVALIDACTION;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 25 +++++++++++++++++++++++++ dlls/xmllite/writer.c | 2 ++ 2 files changed, 27 insertions(+)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index 72ca7309355..f01f6194a4d 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -2131,6 +2131,30 @@ static void test_WriteWhitespace(void) IXmlWriter_Release(writer); }
+static void test_WriteProcessingInstruction(void) +{ + IXmlWriter *writer; + IStream *stream; + HRESULT hr; + + hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + stream = writer_set_output(writer); + + hr = IXmlWriter_WriteStartElement(writer, NULL, L"w", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteProcessingInstruction(writer, L"pi", L"content"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, "<w><?pi content?>"); + IStream_Release(stream); + + IXmlWriter_Release(writer); +} + START_TEST(writer) { test_writer_create(); @@ -2154,4 +2178,5 @@ START_TEST(writer) test_WriteString(); test_WriteDocType(); test_WriteWhitespace(); + test_WriteProcessingInstruction(); } diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index 99dfff3c918..1df4c1dc922 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -1500,6 +1500,8 @@ static HRESULT WINAPI xmlwriter_WriteProcessingInstruction(IXmlWriter *iface, LP return WR_E_INVALIDACTION; break; case XmlWriterState_ElemStarted: + writer_close_starttag(This); + break; case XmlWriterState_DocClosed: return WR_E_INVALIDACTION; default:
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 105 ++++++++++++++++++++++++++++++++++++ dlls/xmllite/writer.c | 50 +++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index f01f6194a4d..c65916d44e4 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -32,6 +32,41 @@ #include "initguid.h" DEFINE_GUID(IID_IXmlWriterOutput, 0xc1131708, 0x0f59, 0x477f, 0x93, 0x59, 0x7d, 0x33, 0x24, 0x51, 0xbc, 0x1a);
+static IStream *create_stream_on_data(const void *data, unsigned int size) +{ + IStream *stream = NULL; + HGLOBAL hglobal; + void *ptr; + HRESULT hr; + + hglobal = GlobalAlloc(GHND, size); + ptr = GlobalLock(hglobal); + + memcpy(ptr, data, size); + + hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(stream != NULL, "Expected non-NULL stream\n"); + + GlobalUnlock(hglobal); + + return stream; +} + +#define reader_set_input(a, b) _reader_set_input(__LINE__, a, b) +static void _reader_set_input(unsigned line, IXmlReader *reader, const char *xml) +{ + IStream *stream; + HRESULT hr; + + stream = create_stream_on_data(xml, strlen(xml)); + + hr = IXmlReader_SetInput(reader, (IUnknown *)stream); + ok_(__FILE__,line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IStream_Release(stream); +} + #define EXPECT_REF(obj, ref) _expect_ref((IUnknown *)obj, ref, __LINE__) static void _expect_ref(IUnknown *obj, ULONG ref, int line) { @@ -2155,6 +2190,75 @@ static void test_WriteProcessingInstruction(void) IXmlWriter_Release(writer); }
+static void test_WriteAttributes(void) +{ + XmlNodeType node_type; + IXmlWriter *writer; + IXmlReader *reader; + const WCHAR *name; + IStream *stream; + HRESULT hr; + + hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* No attributes. */ + reader_set_input(reader, "<a/>"); + stream = writer_set_output(writer); + hr = IXmlWriter_WriteAttributes(writer, reader, FALSE); + ok(hr == E_UNEXPECTED, "Unexpected hr %#lx.\n", hr); + hr = IXmlReader_Read(reader, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteAttributes(writer, reader, FALSE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, ""); + IStream_Release(stream); + + /* Position on element with attributes. */ + reader_set_input(reader, "<a attr1='b' attr2='c' attr3='d' />"); + stream = writer_set_output(writer); + hr = IXmlReader_Read(reader, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteStartElement(writer, NULL, L"w", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteAttributes(writer, reader, FALSE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_Element, "Unexpected node type %d.\n", node_type); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_OUTPUT(stream, "<w attr1="b" attr2="c" attr3="d""); + IStream_Release(stream); + + /* Position on second attribute. */ + hr = IXmlReader_MoveToAttributeByName(reader, L"attr2", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + stream = writer_set_output(writer); + hr = IXmlWriter_WriteStartElement(writer, NULL, L"w", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteAttributes(writer, reader, FALSE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_Attribute, "Unexpected node type %d.\n", node_type); + hr = IXmlReader_GetLocalName(reader, &name, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!wcscmp(name, L"attr3"), "Unexpected node %s.\n", debugstr_w(name)); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_OUTPUT(stream, "<w attr2="c" attr3="d""); + IStream_Release(stream); + + IXmlWriter_Release(writer); + IXmlReader_Release(reader); +} + START_TEST(writer) { test_writer_create(); @@ -2179,4 +2283,5 @@ START_TEST(writer) test_WriteDocType(); test_WriteWhitespace(); test_WriteProcessingInstruction(); + test_WriteAttributes(); } diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index 1df4c1dc922..e9a2e387126 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -845,14 +845,54 @@ static HRESULT WINAPI xmlwriter_SetProperty(IXmlWriter *iface, UINT property, LO return S_OK; }
-static HRESULT WINAPI xmlwriter_WriteAttributes(IXmlWriter *iface, IXmlReader *pReader, - BOOL fWriteDefaultAttributes) +static HRESULT writer_write_attribute(IXmlWriter *writer, IXmlReader *reader, BOOL write_default_attributes) { - xmlwriter *This = impl_from_IXmlWriter(iface); + const WCHAR *prefix, *local, *uri, *value; + HRESULT hr;
- FIXME("%p %p %d\n", This, pReader, fWriteDefaultAttributes); + if (IXmlReader_IsDefault(reader) && !write_default_attributes) + return S_OK;
- return E_NOTIMPL; + if (FAILED(hr = IXmlReader_GetPrefix(reader, &prefix, NULL))) return hr; + if (FAILED(hr = IXmlReader_GetLocalName(reader, &local, NULL))) return hr; + if (FAILED(hr = IXmlReader_GetNamespaceUri(reader, &uri, NULL))) return hr; + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + return IXmlWriter_WriteAttributeString(writer, prefix, local, uri, value); +} + +static HRESULT WINAPI xmlwriter_WriteAttributes(IXmlWriter *iface, IXmlReader *reader, BOOL write_default_attributes) +{ + XmlNodeType node_type; + HRESULT hr = S_OK; + + TRACE("%p, %p, %d.\n", iface, reader, write_default_attributes); + + if (FAILED(hr = IXmlReader_GetNodeType(reader, &node_type))) return hr; + + switch (node_type) + { + case XmlNodeType_Element: + case XmlNodeType_XmlDeclaration: + case XmlNodeType_Attribute: + if (node_type != XmlNodeType_Attribute) + { + if (FAILED(hr = IXmlReader_MoveToFirstAttribute(reader))) return hr; + if (hr == S_FALSE) return S_OK; + } + if (FAILED(hr = writer_write_attribute(iface, reader, write_default_attributes))) return hr; + while (IXmlReader_MoveToNextAttribute(reader) == S_OK) + { + if (FAILED(hr = writer_write_attribute(iface, reader, write_default_attributes))) break; + } + if (node_type != XmlNodeType_Attribute && SUCCEEDED(hr)) + hr = IXmlReader_MoveToElement(reader); + break; + default: + WARN("Unexpected node type %d.\n", node_type); + return E_UNEXPECTED; + } + + return hr; }
static void write_output_attribute(xmlwriter *writer, const WCHAR *prefix, int prefix_len,
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 150 ++++++++++++++++++++++++++++++++++++ dlls/xmllite/writer.c | 98 +++++++++++++++++++++-- 2 files changed, 243 insertions(+), 5 deletions(-)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index c65916d44e4..6d05a65d2f2 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -2259,6 +2259,155 @@ static void test_WriteAttributes(void) IXmlReader_Release(reader); }
+static void test_WriteNode(void) +{ + static const struct + { + const char *input; + const char *output; + XmlNodeType node_type; + } + write_node_tests[] = + { + { "<r><!-- comment --></r>", "<w><!-- comment -->", XmlNodeType_Comment }, + { "<r>text</r>", "<w>text", XmlNodeType_Text }, + { "<r> </r>", "<w> ", XmlNodeType_Whitespace }, + { "<r><![CDATA[ cdata ]]></r>", "<w><![CDATA[ cdata ]]>", XmlNodeType_CDATA }, + { "<r><?pi pidata ?></r>", "<w><?pi pidata ?>", XmlNodeType_ProcessingInstruction }, + { "<r><e1><e2 attr1='a'/></e1></r>", "<w><e1><e2 attr1="a" /></e1>", XmlNodeType_Element }, + { "<r><e1/></r>", "<w><e1 />", XmlNodeType_Element }, + { "<r></r>", "<w></w>", XmlNodeType_EndElement }, + }; + XmlNodeType node_type; + IXmlWriter *writer; + IXmlReader *reader; + const WCHAR *name; + IStream *stream; + unsigned int i; + HRESULT hr; + + hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(write_node_tests); ++i) + { + winetest_push_context("Test %s", debugstr_a(write_node_tests[i].input)); + + stream = writer_set_output(writer); + reader_set_input(reader, write_node_tests[i].input); + + /* Skip top level element. */ + hr = IXmlReader_Read(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IXmlReader_Read(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == write_node_tests[i].node_type, "Unexpected node type %d.\n", node_type); + + /* Always write a root node to give a valid context for following nodes. */ + hr = IXmlWriter_WriteStartElement(writer, NULL, L"w", NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlWriter_WriteNode(writer, reader, FALSE); + ok(SUCCEEDED(hr), "Failed to write a node, hr %#lx.\n", hr); + + if (hr == S_OK) + { + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_EndElement, "Unexpected node type on return %d.\n", node_type); + hr = IXmlReader_GetLocalName(reader, &name, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!wcscmp(name, L"r"), "Unexpected node name %s.\n", debugstr_w(name)); + } + + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + + CHECK_OUTPUT(stream, write_node_tests[i].output); + + IStream_Release(stream); + + winetest_pop_context(); + } + + /* Current node is an attribute. */ + reader_set_input(reader, "<a attr='b' ></a>"); + hr = IXmlReader_Read(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_Element, "Unexpected node type on return %d.\n", node_type); + hr = IXmlReader_MoveToFirstAttribute(reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + stream = writer_set_output(writer); + hr = IXmlWriter_WriteNode(writer, reader, FALSE); + ok(hr == S_OK, "Failed to write a node, hr %#lx.\n", hr); + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_EndElement, "Unexpected node type on return %d.\n", node_type); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, ""); + IStream_Release(stream); + + /* Xml declaration node. */ + reader_set_input(reader, "<?xml version=\"1.0\" ?><a/>"); + hr = IXmlReader_Read(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_XmlDeclaration, "Unexpected node type on return %d.\n", node_type); + + stream = writer_set_output(writer); + hr = IXmlWriter_WriteNode(writer, reader, FALSE); + ok(hr == S_OK, "Failed to write a node, hr %#lx.\n", hr); + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_Element, "Unexpected node type on return %d.\n", node_type); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + IStream_Release(stream); + + /* With standalone attribute. */ + reader_set_input(reader, "<?xml version=\"1.0\" standalone=\'yes\'?><a/>"); + hr = IXmlReader_Read(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_XmlDeclaration, "Unexpected node type on return %d.\n", node_type); + + stream = writer_set_output(writer); + hr = IXmlWriter_WriteNode(writer, reader, FALSE); + ok(hr == S_OK, "Failed to write a node, hr %#lx.\n", hr); + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_Element, "Unexpected node type on return %d.\n", node_type); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"); + IStream_Release(stream); + + /* Initial state. */ + reader_set_input(reader, "<?xml version=\"1.0\" ?><a><b/></a>"); + hr = IXmlReader_GetNodeType(reader, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_None, "Unexpected node type on return %d.\n", node_type); + stream = writer_set_output(writer); + hr = IXmlWriter_WriteNode(writer, reader, FALSE); + ok(hr == S_FALSE, "Failed to write a node, hr %#lx.\n", hr); + node_type = XmlNodeType_Element; + hr = IXmlReader_GetNodeType(reader, &node_type); + todo_wine + ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr); + ok(node_type == XmlNodeType_None, "Unexpected node type on return %d.\n", node_type); + hr = IXmlWriter_Flush(writer); + ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr); + CHECK_OUTPUT(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><a><b /></a>"); + IStream_Release(stream); + + IXmlReader_Release(reader); + IXmlWriter_Release(writer); +} + START_TEST(writer) { test_writer_create(); @@ -2284,4 +2433,5 @@ START_TEST(writer) test_WriteWhitespace(); test_WriteProcessingInstruction(); test_WriteAttributes(); + test_WriteNode(); } diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index e9a2e387126..95e56bfd864 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -1502,14 +1502,102 @@ static HRESULT WINAPI xmlwriter_WriteNmToken(IXmlWriter *iface, LPCWSTR pwszNmTo return E_NOTIMPL; }
-static HRESULT WINAPI xmlwriter_WriteNode(IXmlWriter *iface, IXmlReader *pReader, - BOOL fWriteDefaultAttributes) +static HRESULT writer_write_node(IXmlWriter *writer, IXmlReader *reader, BOOL write_default_attributes) { - xmlwriter *This = impl_from_IXmlWriter(iface); + XmlStandalone standalone = XmlStandalone_Omit; + const WCHAR *name, *value, *prefix, *uri; + unsigned int start_depth = 0, depth; + XmlNodeType node_type; + HRESULT hr;
- FIXME("%p %p %d\n", This, pReader, fWriteDefaultAttributes); + if (FAILED(hr = IXmlReader_GetNodeType(reader, &node_type))) return hr;
- return E_NOTIMPL; + switch (node_type) + { + case XmlNodeType_None: + while ((hr = IXmlReader_Read(reader, NULL)) == S_OK) + { + if (FAILED(hr = writer_write_node(writer, reader, write_default_attributes))) return hr; + } + break; + case XmlNodeType_Element: + if (FAILED(hr = IXmlReader_GetPrefix(reader, &prefix, NULL))) return hr; + if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL))) return hr; + if (FAILED(hr = IXmlReader_GetNamespaceUri(reader, &uri, NULL))) return hr; + if (FAILED(hr = IXmlWriter_WriteStartElement(writer, prefix, name, uri))) return hr; + if (FAILED(hr = IXmlWriter_WriteAttributes(writer, reader, write_default_attributes))) return hr; + if (IXmlReader_IsEmptyElement(reader)) + { + hr = IXmlWriter_WriteEndElement(writer); + } + else + { + if (FAILED(hr = IXmlReader_MoveToElement(reader))) return hr; + if (FAILED(hr = IXmlReader_GetDepth(reader, &start_depth))) return hr; + while ((hr = IXmlReader_Read(reader, &node_type)) == S_OK) + { + if (FAILED(hr = writer_write_node(writer, reader, write_default_attributes))) return hr; + if (FAILED(hr = IXmlReader_MoveToElement(reader))) return hr; + + depth = 0; + if (FAILED(hr = IXmlReader_GetDepth(reader, &depth))) return hr; + if (node_type == XmlNodeType_EndElement && (start_depth == depth - 1)) break; + } + } + break; + case XmlNodeType_Attribute: + break; + case XmlNodeType_Text: + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + hr = IXmlWriter_WriteRaw(writer, value); + break; + case XmlNodeType_CDATA: + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + hr = IXmlWriter_WriteCData(writer, value); + break; + case XmlNodeType_ProcessingInstruction: + if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL))) return hr; + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + hr = IXmlWriter_WriteProcessingInstruction(writer, name, value); + break; + case XmlNodeType_Comment: + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + hr = IXmlWriter_WriteComment(writer, value); + break; + case XmlNodeType_Whitespace: + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + hr = IXmlWriter_WriteWhitespace(writer, value); + break; + case XmlNodeType_EndElement: + hr = IXmlWriter_WriteFullEndElement(writer); + break; + case XmlNodeType_XmlDeclaration: + if (FAILED(hr = IXmlReader_MoveToAttributeByName(reader, L"standalone", NULL))) return hr; + if (hr == S_OK) + { + if (FAILED(hr = IXmlReader_GetValue(reader, &value, NULL))) return hr; + standalone = !wcscmp(value, L"yes") ? XmlStandalone_Yes : XmlStandalone_No; + } + hr = IXmlWriter_WriteStartDocument(writer, standalone); + break; + default: + WARN("Unknown node type %d.\n", node_type); + return E_UNEXPECTED; + } + + return hr; +} + +static HRESULT WINAPI xmlwriter_WriteNode(IXmlWriter *iface, IXmlReader *reader, BOOL write_default_attributes) +{ + HRESULT hr; + + TRACE("%p, %p, %d.\n", iface, reader, write_default_attributes); + + if (SUCCEEDED(hr = writer_write_node(iface, reader, write_default_attributes))) + hr = IXmlReader_Read(reader, NULL); + + return hr; }
static HRESULT WINAPI xmlwriter_WriteNodeShallow(IXmlWriter *iface, IXmlReader *pReader,
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index 6d05a65d2f2..59950ae22fd 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -861,6 +861,8 @@ static void test_WriteStartElement(void) { NULL, L"local", L"uri", "<local xmlns="uri" />", "<local" }, { L"", L"local", L"uri", "<local xmlns="uri" />", "<local" }, { L"", L"local", L"uri", "<local xmlns="uri" />", "<local" }, + { NULL, L"local", NULL, "<local />", "<local" }, + { NULL, L"local", L"", "<local />", "<local" },
{ L"prefix", NULL, NULL, NULL, NULL, E_INVALIDARG }, { NULL, NULL, L"uri", NULL, NULL, E_INVALIDARG },
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/reader.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/dlls/xmllite/tests/reader.c b/dlls/xmllite/tests/reader.c index 8bb30f730a4..6c784826232 100644 --- a/dlls/xmllite/tests/reader.c +++ b/dlls/xmllite/tests/reader.c @@ -1833,16 +1833,15 @@ static void test_isemptyelement(void) { struct test_entry_empty *test = empty_element_tests; IXmlReader *reader; + XmlNodeType type; HRESULT hr; + BOOL ret;
hr = CreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
while (test->xml) { - XmlNodeType type; - BOOL ret; - set_input_string(reader, test->xml);
type = XmlNodeType_None; @@ -1856,6 +1855,23 @@ static void test_isemptyelement(void) test++; }
+ /* Move to an attribute of an empty element. */ + set_input_string(reader, "<a attr1='b' />"); + + hr = IXmlReader_Read(reader, &type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(type == XmlNodeType_Element, "Unexpected node type %d.\n", type); + ret = IXmlReader_IsEmptyElement(reader); + ok(ret, "Unexpected empty flag %d.\n", ret); + + hr = IXmlReader_MoveToFirstAttribute(reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IXmlReader_GetNodeType(reader, &type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(type == XmlNodeType_Attribute, "Unexpected node type %d.\n", type); + ret = IXmlReader_IsEmptyElement(reader); + ok(!ret, "Unexpected empty flag %d.\n", ret); + IXmlReader_Release(reader); }