[PATCH 2/3] xmllite/writer: Improve namespaces handling in WriteStartElement().

Nikolay Sivov nsivov at codeweavers.com
Tue Sep 11 05:17:06 CDT 2018


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/xmllite/tests/writer.c | 156 ++++++++++++++++++------------------
 dlls/xmllite/writer.c       |  48 +++++++----
 2 files changed, 112 insertions(+), 92 deletions(-)

diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c
index 9331899a19..87cdaabce1 100644
--- a/dlls/xmllite/tests/writer.c
+++ b/dlls/xmllite/tests/writer.c
@@ -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();
diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c
index e8935cd508..31c11d9340 100644
--- a/dlls/xmllite/writer.c
+++ b/dlls/xmllite/writer.c
@@ -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;
-- 
2.18.0




More information about the wine-devel mailing list