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,