xmllite/writer: Improve namespaces handling in WriteStartElement().

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2018-09-11 13:17:06 +03:00 committed by Alexandre Julliard
parent 8eb054f328
commit a86e2a4a3f
2 changed files with 112 additions and 92 deletions

View File

@ -841,6 +841,46 @@ static void test_bom(void)
IXmlWriter_Release(writer);
}
static HRESULT write_start_element(IXmlWriter *writer, const char *prefix, const char *local,
const char *uri)
{
WCHAR *prefixW, *localW, *uriW;
HRESULT hr;
prefixW = strdupAtoW(prefix);
localW = strdupAtoW(local);
uriW = strdupAtoW(uri);
hr = IXmlWriter_WriteStartElement(writer, prefixW, localW, uriW);
heap_free(prefixW);
heap_free(localW);
heap_free(uriW);
return hr;
}
static HRESULT write_element_string(IXmlWriter *writer, const char *prefix, const char *local,
const char *uri, const char *value)
{
WCHAR *prefixW, *localW, *uriW, *valueW;
HRESULT hr;
prefixW = strdupAtoW(prefix);
localW = strdupAtoW(local);
uriW = strdupAtoW(uri);
valueW = strdupAtoW(value);
hr = IXmlWriter_WriteElementString(writer, prefixW, localW, uriW, valueW);
heap_free(prefixW);
heap_free(localW);
heap_free(uriW);
heap_free(valueW);
return hr;
}
static void test_WriteStartElement(void)
{
static const struct
@ -856,24 +896,22 @@ static void test_WriteStartElement(void)
}
start_element_tests[] =
{
{ "prefix", "local", "uri", "<prefix:local xmlns:prefix=\"uri\" />", "<prefix:local", S_OK, 1 },
{ NULL, "local", "uri", "<local xmlns=\"uri\" />", "<local", S_OK, 1 },
{ "", "local", "uri", "<local xmlns=\"uri\" />", "<local", S_OK, 1 },
{ "", "local", "uri", "<local xmlns=\"uri\" />", "<local", S_OK, 1 },
{ "prefix", "local", "uri", "<prefix:local xmlns:prefix=\"uri\" />", "<prefix:local" },
{ NULL, "local", "uri", "<local xmlns=\"uri\" />", "<local" },
{ "", "local", "uri", "<local xmlns=\"uri\" />", "<local" },
{ "", "local", "uri", "<local xmlns=\"uri\" />", "<local" },
{ "prefix", NULL, NULL, NULL, NULL, E_INVALIDARG },
{ NULL, NULL, "uri", NULL, NULL, E_INVALIDARG },
{ NULL, NULL, NULL, NULL, NULL, E_INVALIDARG },
{ NULL, "prefix:local", "uri", NULL, NULL, WC_E_NAMECHARACTER, 1, 1 },
{ "pre:fix", "local", "uri", NULL, NULL, WC_E_NAMECHARACTER, 1, 1 },
{ NULL, ":local", "uri", NULL, NULL, WC_E_NAMECHARACTER, 1, 1 },
{ ":", "local", "uri", NULL, NULL, WC_E_NAMECHARACTER, 1, 1 },
{ NULL, "prefix:local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
{ "pre:fix", "local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
{ NULL, ":local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
{ ":", "local", "uri", NULL, NULL, WC_E_NAMECHARACTER },
{ NULL, "local", "http://www.w3.org/2000/xmlns/", NULL, NULL, WR_E_XMLNSPREFIXDECLARATION },
{ "prefix", "local", "http://www.w3.org/2000/xmlns/", NULL, NULL, WR_E_XMLNSURIDECLARATION },
};
static const WCHAR valueW[] = {'v','a','l','u','e',0};
static const WCHAR aW[] = {'a',0};
static const WCHAR bW[] = {'b',0};
IXmlWriter *writer;
IStream *stream;
unsigned int i;
@ -882,12 +920,12 @@ static void test_WriteStartElement(void)
hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
hr = write_start_element(writer, NULL, "a", NULL);
ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
stream = writer_set_output(writer);
hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
hr = write_start_element(writer, NULL, "a", NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
@ -914,33 +952,45 @@ static void test_WriteStartElement(void)
hr = CreateXmlWriter(&IID_IXmlWriter, (void**)&writer, NULL);
ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW);
hr = write_element_string(writer, NULL, "b", NULL, "value");
ok(hr == E_UNEXPECTED, "got 0x%08x\n", hr);
stream = writer_set_output(writer);
hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = write_start_element(writer, "prefix", "a", "uri");
ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = write_element_string(writer, NULL, "b", NULL, "value");
ok(hr == S_OK, "Failed to write element string, hr %#x.\n", hr);
hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = write_element_string(writer, NULL, "c", NULL, NULL);
ok(hr == S_OK, "Failed to write element string, hr %#x.\n", hr);
hr = write_start_element(writer, NULL, "d", "uri");
ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
hr = write_start_element(writer, "", "e", "uri");
ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
hr = write_start_element(writer, "prefix2", "f", "uri");
ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr);
hr = IXmlWriter_Flush(writer);
ok(hr == S_OK, "got 0x%08x\n", hr);
CHECK_OUTPUT(stream,
"<a><b>value</b><b />");
"<prefix:a xmlns:prefix=\"uri\">"
"<b>value</b>"
"<c />"
"<prefix:d>"
"<e xmlns=\"uri\">"
"<prefix2:f");
IStream_Release(stream);
/* WriteStartElement */
for (i = 0; i < ARRAY_SIZE(start_element_tests); ++i)
{
WCHAR *prefixW, *localW, *uriW;
stream = writer_set_output(writer);
writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration);
@ -948,12 +998,8 @@ static void test_WriteStartElement(void)
hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
ok(hr == S_OK, "Failed to start document, hr %#x.\n", hr);
prefixW = strdupAtoW(start_element_tests[i].prefix);
localW = strdupAtoW(start_element_tests[i].local);
uriW = strdupAtoW(start_element_tests[i].uri);
hr = IXmlWriter_WriteStartElement(writer, prefixW, localW, uriW);
todo_wine_if(i >= 11)
hr = write_start_element(writer, start_element_tests[i].prefix, start_element_tests[i].local,
start_element_tests[i].uri);
ok(hr == start_element_tests[i].hr, "%u: unexpected hr %#x.\n", i, hr);
if (SUCCEEDED(start_element_tests[i].hr))
@ -972,56 +1018,12 @@ static void test_WriteStartElement(void)
check_output(stream, start_element_tests[i].output, start_element_tests[i].todo, __LINE__);
}
heap_free(prefixW);
heap_free(localW);
heap_free(uriW);
IStream_Release(stream);
}
IXmlWriter_Release(writer);
}
static HRESULT write_element_string(IXmlWriter *writer, const char *prefix, const char *local,
const char *uri, const char *value)
{
WCHAR *prefixW, *localW, *uriW, *valueW;
HRESULT hr;
prefixW = strdupAtoW(prefix);
localW = strdupAtoW(local);
uriW = strdupAtoW(uri);
valueW = strdupAtoW(value);
hr = IXmlWriter_WriteElementString(writer, prefixW, localW, uriW, valueW);
heap_free(prefixW);
heap_free(localW);
heap_free(uriW);
heap_free(valueW);
return hr;
}
static HRESULT write_start_element(IXmlWriter *writer, const char *prefix, const char *local,
const char *uri)
{
WCHAR *prefixW, *localW, *uriW;
HRESULT hr;
prefixW = strdupAtoW(prefix);
localW = strdupAtoW(local);
uriW = strdupAtoW(uri);
hr = IXmlWriter_WriteStartElement(writer, prefixW, localW, uriW);
heap_free(prefixW);
heap_free(localW);
heap_free(uriW);
return hr;
}
static void test_WriteElementString(void)
{
static const struct
@ -1164,10 +1166,8 @@ static void test_WriteElementString(void)
IXmlWriter_Release(writer);
}
static void test_writeendelement(void)
static void test_WriteEndElement(void)
{
static const WCHAR aW[] = {'a',0};
static const WCHAR bW[] = {'b',0};
IXmlWriter *writer;
IStream *stream;
HRESULT hr;
@ -1177,10 +1177,10 @@ static void test_writeendelement(void)
stream = writer_set_output(writer);
hr = IXmlWriter_WriteStartElement(writer, NULL, aW, NULL);
hr = write_start_element(writer, NULL, "a", NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IXmlWriter_WriteStartElement(writer, NULL, bW, NULL);
hr = write_start_element(writer, NULL, "b", NULL);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IXmlWriter_WriteEndElement(writer);
@ -1892,7 +1892,7 @@ START_TEST(writer)
test_writestartdocument();
test_WriteStartElement();
test_WriteElementString();
test_writeendelement();
test_WriteEndElement();
test_flush();
test_omitxmldeclaration();
test_bom();

View File

@ -497,15 +497,9 @@ static HRESULT write_xmldecl(xmlwriter *writer, XmlStandalone standalone)
return S_OK;
}
static HRESULT writer_close_starttag(xmlwriter *writer)
static void writer_output_ns(xmlwriter *writer, struct element *element)
{
struct element *element;
struct ns *ns;
HRESULT hr;
if (!writer->starttagopen) return S_OK;
element = LIST_ENTRY(list_head(&writer->elements), struct element, entry);
LIST_FOR_EACH_ENTRY(ns, &element->ns, struct ns, entry)
{
@ -513,7 +507,15 @@ static HRESULT writer_close_starttag(xmlwriter *writer)
write_output_buffer(writer->output, eqW, ARRAY_SIZE(eqW));
write_output_buffer_quoted(writer->output, ns->uri, -1);
}
}
static HRESULT writer_close_starttag(xmlwriter *writer)
{
HRESULT hr;
if (!writer->starttagopen) return S_OK;
writer_output_ns(writer, LIST_ENTRY(list_head(&writer->elements), struct element, entry));
hr = write_output_buffer(writer->output, gtW, ARRAY_SIZE(gtW));
writer->starttagopen = FALSE;
return hr;
@ -967,6 +969,8 @@ static struct ns *writer_find_ns(xmlwriter *writer, const WCHAR *prefix, const W
}
else if (!strcmpW(uri, ns->uri))
{
if (prefix && !*prefix)
return NULL;
if (!prefix || !strcmpW(prefix, ns->prefix))
return ns;
}
@ -1114,11 +1118,13 @@ static HRESULT WINAPI xmlwriter_WriteEndElement(IXmlWriter *iface)
if (This->starttagopen)
{
writer_output_ns(This, element);
write_output_buffer(This->output, closetagW, ARRAY_SIZE(closetagW));
This->starttagopen = FALSE;
}
else {
/* write full end tag */
else
{
/* Write full end tag. */
write_node_indent(This);
write_output_buffer(This->output, closeelementW, ARRAY_SIZE(closeelementW));
write_output_buffer(This->output, element->qname, element->len);
@ -1402,6 +1408,7 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
xmlwriter *This = impl_from_IXmlWriter(iface);
int prefix_len, local_len;
struct element *element;
struct ns *ns;
HRESULT hr;
TRACE("(%p)->(%s %s %s)\n", This, wine_dbgstr_w(prefix), wine_dbgstr_w(local_name), wine_dbgstr_w(uri));
@ -1417,6 +1424,9 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
return MX_E_ENCODING;
case XmlWriterState_DocClosed:
return WR_E_INVALIDACTION;
case XmlWriterState_ElemStarted:
writer_close_starttag(This);
break;
default:
;
}
@ -1428,9 +1438,16 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
if (FAILED(hr = is_valid_ncname(local_name, &local_len)))
return hr;
/* close pending element */
if (This->starttagopen)
write_output_buffer(This->output, gtW, ARRAY_SIZE(gtW));
if (uri && !strcmpW(uri, xmlnsuriW))
{
if (!prefix)
return WR_E_XMLNSPREFIXDECLARATION;
if (!is_empty_string(prefix))
return WR_E_XMLNSURIDECLARATION;
}
ns = writer_find_ns(This, prefix, uri);
element = alloc_element(This, prefix, local_name);
if (!element)
@ -1444,11 +1461,14 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre
writer_push_element(This, element);
if (prefix_len && uri)
if (!ns && uri)
writer_push_ns(This, prefix, prefix_len, uri);
write_output_buffer(This->output, ltW, ARRAY_SIZE(ltW));
write_output_qname(This->output, prefix, prefix_len, local_name, local_len);
if (ns)
write_output_qname(This->output, ns->prefix, ns->prefix_len, local_name, local_len);
else
write_output_qname(This->output, prefix, prefix_len, local_name, local_len);
writer_inc_indent(This);
return S_OK;