Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/xmllite/tests/writer.c | 127 +++++++++++++++++++------ dlls/xmllite/writer.c | 184 ++++++++++++++++++++++++++++++++---- 2 files changed, 264 insertions(+), 47 deletions(-)
diff --git a/dlls/xmllite/tests/writer.c b/dlls/xmllite/tests/writer.c index cf43f30f6b..9331899a19 100644 --- a/dlls/xmllite/tests/writer.c +++ b/dlls/xmllite/tests/writer.c @@ -982,6 +982,46 @@ static void test_WriteStartElement(void) 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 @@ -996,13 +1036,18 @@ static void test_WriteElementString(void) } element_string_tests[] = { - { "prefix", "local", "uri", "value", "<prefix:local xmlns:prefix="uri">value</prefix:local>", S_OK, 1 }, - { NULL, "local", "uri", "value", "<local xmlns="uri">value</local>", S_OK, 1 }, - { "", "local", "uri", "value", "<local xmlns="uri">value</local>", S_OK, 1 }, - { "prefix", "local", "uri", NULL, "<prefix:local xmlns:prefix="uri" />", S_OK, 1 }, - { NULL, "local", "uri", NULL, "<local xmlns="uri" />", S_OK, 1 }, - { "", "local", "uri", NULL, "<local xmlns="uri" />", S_OK, 1 }, + { "prefix", "local", "uri", "value", "<prefix:local xmlns:prefix="uri">value</prefix:local>" }, + { NULL, "local", "uri", "value", "<local xmlns="uri">value</local>" }, + { "", "local", "uri", "value", "<local xmlns="uri">value</local>" }, + { "prefix", "local", "uri", NULL, "<prefix:local xmlns:prefix="uri" />" }, + { NULL, "local", "uri", NULL, "<local xmlns="uri" />" }, + { "", "local", "uri", NULL, "<local xmlns="uri" />" }, { NULL, "local", NULL, NULL, "<local />" }, + { "prefix", "local", "uri", "", "<prefix:local xmlns:prefix="uri"></prefix:local>" }, + { NULL, "local", "uri", "", "<local xmlns="uri"></local>" }, + { "", "local", "uri", "", "<local xmlns="uri"></local>" }, + { NULL, "local", NULL, "", "<local></local>" }, + { "", "local", "http://www.w3.org/2000/xmlns/", NULL, "<local xmlns="http://www.w3.org/2000/xmlns/%5C" />" },
{ "prefix", NULL, NULL, "value", NULL, E_INVALIDARG }, { NULL, NULL, "uri", "value", NULL, E_INVALIDARG }, @@ -1010,12 +1055,11 @@ static void test_WriteElementString(void) { NULL, "prefix:local", "uri", "value", NULL, WC_E_NAMECHARACTER }, { NULL, ":local", "uri", "value", NULL, WC_E_NAMECHARACTER }, { ":", "local", "uri", "value", NULL, WC_E_NAMECHARACTER }, + { "prefix", "local", NULL, "value", NULL, WR_E_NSPREFIXWITHEMPTYNSURI }, + { "prefix", "local", "", "value", NULL, WR_E_NSPREFIXWITHEMPTYNSURI }, { NULL, "local", "http://www.w3.org/2000/xmlns/", "value", NULL, WR_E_XMLNSPREFIXDECLARATION }, { "prefix", "local", "http://www.w3.org/2000/xmlns/", "value", 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; @@ -1024,32 +1068,69 @@ static void test_WriteElementString(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); + hr = write_start_element(writer, NULL, "a", NULL); ok(hr == S_OK, "got 0x%08x\n", hr);
- hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, valueW); + hr = write_element_string(writer, NULL, "b", NULL, "value"); ok(hr == S_OK, "got 0x%08x\n", hr);
- hr = IXmlWriter_WriteElementString(writer, NULL, bW, NULL, NULL); + hr = write_element_string(writer, NULL, "b", NULL, NULL); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = write_element_string(writer, "prefix", "b", "uri", NULL); ok(hr == S_OK, "got 0x%08x\n", hr);
+ hr = write_start_element(writer, "prefix", "c", "uri"); + ok(hr == S_OK, "Failed to start element, hr %#x.\n", hr); + + hr = write_element_string(writer, "prefix", "d", NULL, NULL); + ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, "prefix2", "d", "uri", NULL); + ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, NULL, "e", "uri", NULL); + ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, "prefix", "f", "uri2", NULL); + ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, NULL, "g", "uri3", NULL); + ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, "prefix", "h", NULL, NULL); + ok(hr == S_OK, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, "prefix_i", "i", NULL, NULL); + ok(hr == WR_E_NSPREFIXWITHEMPTYNSURI, "Failed to write element, hr %#x.\n", hr); + + hr = write_element_string(writer, "", "j", "uri", NULL); + ok(hr == S_OK, "Failed to write 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 />"); + "<a><b>value</b><b />" + "<prefix:b xmlns:prefix="uri" />" + "<prefix:c xmlns:prefix="uri">" + "<prefix:d />" + "<prefix2:d xmlns:prefix2="uri" />" + "<prefix:e />" + "<prefix:f xmlns:prefix="uri2" />" + "<g xmlns="uri3" />" + "<prefix:h />" + "<j xmlns="uri" />");
IStream_Release(stream);
for (i = 0; i < ARRAY_SIZE(element_string_tests); ++i) { - WCHAR *prefixW, *localW, *uriW, *valueW; - stream = writer_set_output(writer);
writer_set_property(writer, XmlWriterProperty_OmitXmlDeclaration); @@ -1057,13 +1138,8 @@ static void test_WriteElementString(void) hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit); ok(hr == S_OK, "Failed to start document, hr %#x.\n", hr);
- prefixW = strdupAtoW(element_string_tests[i].prefix); - localW = strdupAtoW(element_string_tests[i].local); - uriW = strdupAtoW(element_string_tests[i].uri); - valueW = strdupAtoW(element_string_tests[i].value); - - hr = IXmlWriter_WriteElementString(writer, prefixW, localW, uriW, valueW); - todo_wine_if(i >= 13) + hr = write_element_string(writer, element_string_tests[i].prefix, element_string_tests[i].local, + element_string_tests[i].uri, element_string_tests[i].value); ok(hr == element_string_tests[i].hr, "%u: unexpected hr %#x.\n", i, hr);
if (SUCCEEDED(element_string_tests[i].hr)) @@ -1082,11 +1158,6 @@ static void test_WriteElementString(void) check_output(stream, element_string_tests[i].output, element_string_tests[i].todo, __LINE__); }
- heap_free(prefixW); - heap_free(localW); - heap_free(uriW); - heap_free(valueW); - IStream_Release(stream); }
diff --git a/dlls/xmllite/writer.c b/dlls/xmllite/writer.c index f9e8c666b2..e8935cd508 100644 --- a/dlls/xmllite/writer.c +++ b/dlls/xmllite/writer.c @@ -46,6 +46,9 @@ static const WCHAR ltW[] = {'<'}; static const WCHAR gtW[] = {'>'}; static const WCHAR spaceW[] = {' '}; static const WCHAR quoteW[] = {'"'}; +static const WCHAR eqW[] = {'='}; +static const WCHAR xmlnsW[] = {' ','x','m','l','n','s'}; +static const WCHAR xmlnsuriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0};
struct output_buffer { @@ -81,11 +84,20 @@ typedef struct
static const struct IUnknownVtbl xmlwriteroutputvtbl;
+struct ns +{ + struct list entry; + WCHAR *prefix; + int prefix_len; + WCHAR *uri; +}; + struct element { struct list entry; WCHAR *qname; unsigned int len; /* qname length in chars */ + struct list ns; };
typedef struct _xmlwriter @@ -149,12 +161,12 @@ static inline void *writeroutput_realloc(xmlwriteroutput *output, void *mem, siz }
/* writer memory allocation functions */ -static inline void *writer_alloc(xmlwriter *writer, size_t len) +static inline void *writer_alloc(const xmlwriter *writer, size_t len) { return m_alloc(writer->imalloc, len); }
-static inline void writer_free(xmlwriter *writer, void *mem) +static inline void writer_free(const xmlwriter *writer, void *mem) { m_free(writer->imalloc, mem); } @@ -180,17 +192,39 @@ static struct element *alloc_element(xmlwriter *writer, const WCHAR *prefix, con else ret->qname[0] = 0; strcatW(ret->qname, local); + list_init(&ret->ns);
return ret; }
-static void free_element(xmlwriter *writer, struct element *element) +static void writer_free_element(xmlwriter *writer, struct element *element) { + struct ns *ns, *ns2; + + LIST_FOR_EACH_ENTRY_SAFE(ns, ns2, &element->ns, struct ns, entry) + { + list_remove(&ns->entry); + writer_free(writer, ns->prefix); + writer_free(writer, ns->uri); + writer_free(writer, ns); + } + writer_free(writer, element->qname); writer_free(writer, element); }
-static void push_element(xmlwriter *writer, struct element *element) +static void writer_free_element_stack(xmlwriter *writer) +{ + struct element *element, *element2; + + LIST_FOR_EACH_ENTRY_SAFE(element, element2, &writer->elements, struct element, entry) + { + list_remove(&element->entry); + writer_free_element(writer, element); + } +} + +static void writer_push_element(xmlwriter *writer, struct element *element) { list_add_head(&writer->elements, &element->entry); } @@ -205,6 +239,46 @@ static struct element *pop_element(xmlwriter *writer) return element; }
+static WCHAR *writer_strndupW(const xmlwriter *writer, const WCHAR *str, int len) +{ + size_t size; + WCHAR *ret; + + if (!str) + return NULL; + + if (len == -1) + len = strlenW(str); + + size = (len + 1) * sizeof(WCHAR); + ret = writer_alloc(writer, size); + memcpy(ret, str, size); + return ret; +} + +static WCHAR *writer_strdupW(const xmlwriter *writer, const WCHAR *str) +{ + return writer_strndupW(writer, str, -1); +} + +static void writer_push_ns(xmlwriter *writer, const WCHAR *prefix, int prefix_len, const WCHAR *uri) +{ + struct element *element; + struct ns *ns; + + element = LIST_ENTRY(list_head(&writer->elements), struct element, entry); + if (!element) + return; + + if ((ns = writer_alloc(writer, sizeof(*ns)))) + { + ns->prefix = writer_strndupW(writer, prefix, prefix_len); + ns->prefix_len = prefix_len; + ns->uri = writer_strdupW(writer, uri); + list_add_tail(&element->ns, &ns->entry); + } +} + static HRESULT init_output_buffer(xmlwriteroutput *output) { struct output_buffer *buffer = &output->buffer; @@ -298,13 +372,15 @@ static HRESULT write_output_buffer_quoted(xmlwriteroutput *output, const WCHAR * static HRESULT write_output_qname(xmlwriteroutput *output, const WCHAR *prefix, int prefix_len, const WCHAR *local_name, int local_len) { + static const WCHAR colW[] = {':'}; + assert(prefix_len >= 0 && local_len >= 0);
- if (prefix_len) { - static const WCHAR colW[] = {':'}; + if (prefix_len) write_output_buffer(output, prefix, prefix_len); + + if (prefix_len && local_len) write_output_buffer(output, colW, ARRAY_SIZE(colW)); - }
write_output_buffer(output, local_name, local_len);
@@ -423,9 +499,21 @@ static HRESULT write_xmldecl(xmlwriter *writer, XmlStandalone standalone)
static HRESULT writer_close_starttag(xmlwriter *writer) { + 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) + { + write_output_qname(writer->output, xmlnsW, ARRAY_SIZE(xmlnsW), ns->prefix, ns->prefix_len); + write_output_buffer(writer->output, eqW, ARRAY_SIZE(eqW)); + write_output_buffer_quoted(writer->output, ns->uri, -1); + } + hr = write_output_buffer(writer->output, gtW, ARRAY_SIZE(gtW)); writer->starttagopen = FALSE; return hr; @@ -498,17 +586,12 @@ static ULONG WINAPI xmlwriter_Release(IXmlWriter *iface) TRACE("(%p)->(%u)\n", This, ref);
if (ref == 0) { - struct element *element, *element2; IMalloc *imalloc = This->imalloc;
writeroutput_flush_stream(This->output); if (This->output) IUnknown_Release(&This->output->IXmlWriterOutput_iface);
- /* element stack */ - LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, struct element, entry) { - list_remove(&element->entry); - free_element(This, element); - } + writer_free_element_stack(This);
writer_free(This, This); if (imalloc) IMalloc_Release(imalloc); @@ -532,6 +615,7 @@ static HRESULT WINAPI xmlwriter_SetOutput(IXmlWriter *iface, IUnknown *output) This->output = NULL; This->bomwritten = FALSE; This->indent_level = 0; + writer_free_element_stack(This); }
/* just reset current output */ @@ -635,7 +719,6 @@ static HRESULT WINAPI xmlwriter_WriteAttributes(IXmlWriter *iface, IXmlReader *p static HRESULT WINAPI xmlwriter_WriteAttributeString(IXmlWriter *iface, LPCWSTR ns_prefix, LPCWSTR local_name, LPCWSTR ns_uri, LPCWSTR value) { - static const WCHAR eqW[] = {'=','"'}; xmlwriter *This = impl_from_IXmlWriter(iface);
TRACE("%p %s %s %s %s\n", This, debugstr_w(ns_prefix), debugstr_w(local_name), @@ -664,8 +747,7 @@ static HRESULT WINAPI xmlwriter_WriteAttributeString(IXmlWriter *iface, LPCWSTR write_output_buffer(This->output, spaceW, ARRAY_SIZE(spaceW)); write_output_buffer(This->output, local_name, -1); write_output_buffer(This->output, eqW, ARRAY_SIZE(eqW)); - write_output_buffer(This->output, value, -1); - write_output_buffer(This->output, quoteW, ARRAY_SIZE(quoteW)); + write_output_buffer_quoted(This->output, value, -1);
return S_OK; } @@ -860,11 +942,46 @@ static HRESULT is_valid_ncname(const WCHAR *str, int *out) return S_OK; }
+static BOOL is_empty_string(const WCHAR *str) +{ + return !str || !*str; +} + +static struct ns *writer_find_ns(xmlwriter *writer, const WCHAR *prefix, const WCHAR *uri) +{ + struct element *element; + struct ns *ns; + + if (is_empty_string(prefix) && is_empty_string(uri)) + return NULL; + + LIST_FOR_EACH_ENTRY(element, &writer->elements, struct element, entry) + { + LIST_FOR_EACH_ENTRY(ns, &element->ns, struct ns, entry) + { + if (!uri) + { + if (!ns->prefix) continue; + if (!strcmpW(ns->prefix, prefix)) + return ns; + } + else if (!strcmpW(uri, ns->uri)) + { + if (!prefix || !strcmpW(prefix, ns->prefix)) + return ns; + } + } + } + + return NULL; +} + static HRESULT WINAPI xmlwriter_WriteElementString(IXmlWriter *iface, LPCWSTR prefix, LPCWSTR local_name, LPCWSTR uri, LPCWSTR value) { xmlwriter *This = impl_from_IXmlWriter(iface); int prefix_len, local_len; + struct ns *ns; HRESULT hr;
TRACE("(%p)->(%s %s %s %s)\n", This, wine_dbgstr_w(prefix), wine_dbgstr_w(local_name), @@ -895,10 +1012,34 @@ static HRESULT WINAPI xmlwriter_WriteElementString(IXmlWriter *iface, LPCWSTR pr if (FAILED(hr = is_valid_ncname(local_name, &local_len))) return hr;
+ ns = writer_find_ns(This, prefix, uri); + if (!ns && !is_empty_string(prefix) && is_empty_string(uri)) + return WR_E_NSPREFIXWITHEMPTYNSURI; + + if (uri && !strcmpW(uri, xmlnsuriW)) + { + if (!prefix) + return WR_E_XMLNSPREFIXDECLARATION; + + if (!is_empty_string(prefix)) + return WR_E_XMLNSURIDECLARATION; + } + write_encoding_bom(This); write_node_indent(This); + 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); + + if (!ns && (prefix_len || !is_empty_string(uri))) + { + write_output_qname(This->output, xmlnsW, ARRAY_SIZE(xmlnsW), prefix, prefix_len); + write_output_buffer(This->output, eqW, ARRAY_SIZE(eqW)); + write_output_buffer_quoted(This->output, uri, -1); + }
if (value) { @@ -1025,6 +1166,9 @@ static HRESULT WINAPI xmlwriter_WriteFullEndElement(IXmlWriter *iface) return WR_E_INVALIDACTION; case XmlWriterState_InvalidEncoding: return MX_E_ENCODING; + case XmlWriterState_ElemStarted: + writer_close_starttag(This); + break; default: ; } @@ -1033,7 +1177,6 @@ static HRESULT WINAPI xmlwriter_WriteFullEndElement(IXmlWriter *iface) if (!element) return WR_E_INVALIDACTION;
- writer_close_starttag(This); writer_dec_indent(This);
/* don't force full end tag to the next line */ @@ -1299,7 +1442,10 @@ static HRESULT WINAPI xmlwriter_WriteStartElement(IXmlWriter *iface, LPCWSTR pre This->state = XmlWriterState_ElemStarted; This->starttagopen = TRUE;
- push_element(This, element); + writer_push_element(This, element); + + if (prefix_len && 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);
Signed-off-by: Nikolay Sivov nsivov@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;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index 2c2ef7c516..66cc49a16e 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -831,6 +831,8 @@ HRESULT opc_package_create(IOpcFactory *factory, IOpcPackage **out)
static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlWriter *writer) { + static const WCHAR uriW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','o','p','e','n','x','m','l','f','o','r','m','a','t','s','.','o','r','g','/', + 'p','a','c','k','a','g','e','/','2','0','0','6','/','c','o','n','t','e','n','t','-','t','y','p','e','s',0}; static const WCHAR contenttypesW[] = {'[','C','o','n','t','e','n','t','_','T','y','p','e','s',']','.','x','m','l',0}; static const WCHAR typesW[] = {'T','y','p','e','s',0}; IStream *content; @@ -843,7 +845,7 @@ static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlW
hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit); if (SUCCEEDED(hr)) - hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, NULL); + hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, uriW); if (SUCCEEDED(hr)) hr = IXmlWriter_WriteEndDocument(writer); if (SUCCEEDED(hr))