Module: wine Branch: master Commit: b3d85d41d99fbe9518db35761c7e7560d6cdd61b URL: http://source.winehq.org/git/wine.git/?a=commit;h=b3d85d41d99fbe9518db35761c...
Author: Nikolay Sivov nsivov@codeweavers.com Date: Sat Jul 27 18:27:27 2013 +0400
msxml3: Implement output indentation for writer.
---
dlls/msxml3/mxwriter.c | 62 +++++++++++++++++++++++++++++++++++++++-- dlls/msxml3/tests/saxreader.c | 62 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 5 deletions(-)
diff --git a/dlls/msxml3/mxwriter.c b/dlls/msxml3/mxwriter.c index d62e6a3..558582d 100644 --- a/dlls/msxml3/mxwriter.c +++ b/dlls/msxml3/mxwriter.c @@ -1,7 +1,7 @@ /* * MXWriter implementation * - * Copyright 2011-2012 Nikolay Sivov for CodeWeavers + * Copyright 2011-2013 Nikolay Sivov for CodeWeavers * Copyright 2011 Thomas Mullaly * * This library is free software; you can redistribute it and/or @@ -43,6 +43,7 @@ static const WCHAR emptyW[] = {0}; static const WCHAR spaceW[] = {' '}; static const WCHAR quotW[] = {'"'}; static const WCHAR closetagW[] = {'>','\r','\n'}; +static const WCHAR crlfW[] = {'\r','\n'};
/* should be ordered as encoding names are sorted */ typedef enum @@ -146,6 +147,10 @@ typedef struct BOOL prop_changed; BOOL cdata;
+ BOOL text; /* last node was text node, so we shouldn't indent next node */ + BOOL newline; /* newline was already added as a part of previous call */ + UINT indent; /* indentation level for next node */ + BSTR version;
BSTR encoding; /* exact property value */ @@ -454,14 +459,13 @@ static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len) return ret; }
-static void write_prolog_buffer(const mxwriter *This) +static void write_prolog_buffer(mxwriter *This) { static const WCHAR versionW[] = {'<','?','x','m','l',' ','v','e','r','s','i','o','n','='}; static const WCHAR encodingW[] = {' ','e','n','c','o','d','i','n','g','=','"'}; static const WCHAR standaloneW[] = {' ','s','t','a','n','d','a','l','o','n','e','=','"'}; static const WCHAR yesW[] = {'y','e','s','"','?','>'}; static const WCHAR noW[] = {'n','o','"','?','>'}; - static const WCHAR crlfW[] = {'\r','\n'};
/* version */ write_output_buffer(This->buffer, versionW, sizeof(versionW)/sizeof(WCHAR)); @@ -483,6 +487,7 @@ static void write_prolog_buffer(const mxwriter *This) write_output_buffer(This->buffer, noW, sizeof(noW)/sizeof(WCHAR));
write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR)); + This->newline = TRUE; }
/* Attempts to the write data from the mxwriter's buffer to @@ -536,6 +541,41 @@ static void close_element_starttag(const mxwriter *This) write_output_buffer(This->buffer, gtW, 1); }
+static void write_node_indent(mxwriter *This) +{ + static const WCHAR tabW[] = {'\t'}; + int indent = This->indent; + + if (!This->props[MXWriter_Indent] || This->text) + { + This->text = FALSE; + return; + } + + /* This is to workaround PI output logic that always puts newline chars, + document prolog PI does that too. */ + if (!This->newline) + write_output_buffer(This->buffer, crlfW, sizeof(crlfW)/sizeof(WCHAR)); + while (indent--) + write_output_buffer(This->buffer, tabW, 1); + + This->newline = FALSE; + This->text = FALSE; +} + +static inline void writer_inc_indent(mxwriter *This) +{ + This->indent++; +} + +static inline void writer_dec_indent(mxwriter *This) +{ + if (This->indent) This->indent--; + /* depth is decreased only when element is closed, meaning it's not a text node + at this point */ + This->text = FALSE; +} + static void set_element_name(mxwriter *This, const WCHAR *name, int len) { SysFreeString(This->element); @@ -1082,8 +1122,11 @@ static HRESULT WINAPI SAXContentHandler_startElement( set_element_name(This, QName ? QName : emptyW, QName ? nQName : 0);
+ write_node_indent(This); + write_output_buffer(This->buffer, ltW, 1); write_output_buffer(This->buffer, QName, nQName); + writer_inc_indent(This);
if (attr) { @@ -1147,6 +1190,8 @@ static HRESULT WINAPI SAXContentHandler_endElement( (nQName == -1 && This->class_version == MSXML6)) return E_INVALIDARG;
+ writer_dec_indent(This); + if (This->element) { static const WCHAR closeW[] = {'/','>'}; @@ -1157,6 +1202,7 @@ static HRESULT WINAPI SAXContentHandler_endElement( static const WCHAR closetagW[] = {'<','/'}; static const WCHAR gtW[] = {'>'};
+ write_node_indent(This); write_output_buffer(This->buffer, closetagW, 2); write_output_buffer(This->buffer, QName, nQName); write_output_buffer(This->buffer, gtW, 1); @@ -1181,6 +1227,9 @@ static HRESULT WINAPI SAXContentHandler_characters( close_element_starttag(This); set_element_name(This, NULL, 0);
+ if (!This->cdata) + This->text = TRUE; + if (nchars) { if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE) @@ -1230,6 +1279,7 @@ static HRESULT WINAPI SAXContentHandler_processingInstruction(
if (!target) return E_INVALIDARG;
+ write_node_indent(This); write_output_buffer(This->buffer, openpiW, sizeof(openpiW)/sizeof(WCHAR));
if (*target) @@ -1242,6 +1292,7 @@ static HRESULT WINAPI SAXContentHandler_processingInstruction( }
write_output_buffer(This->buffer, closepiW, sizeof(closepiW)/sizeof(WCHAR)); + This->newline = TRUE;
return S_OK; } @@ -1381,6 +1432,7 @@ static HRESULT WINAPI SAXLexicalHandler_startCDATA(ISAXLexicalHandler *iface)
TRACE("(%p)\n", This);
+ write_node_indent(This); write_output_buffer(This->buffer, scdataW, sizeof(scdataW)/sizeof(WCHAR)); This->cdata = TRUE;
@@ -1411,6 +1463,7 @@ static HRESULT WINAPI SAXLexicalHandler_comment(ISAXLexicalHandler *iface, const if (!chars) return E_INVALIDARG;
close_element_starttag(This); + write_node_indent(This);
write_output_buffer(This->buffer, copenW, sizeof(copenW)/sizeof(WCHAR)); if (nchars) @@ -1609,6 +1662,9 @@ HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
This->element = NULL; This->cdata = FALSE; + This->indent = 0; + This->text = FALSE; + This->newline = FALSE;
This->dest = NULL; This->dest_written = 0; diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c index dec62bb..1eff7f6 100644 --- a/dlls/msxml3/tests/saxreader.c +++ b/dlls/msxml3/tests/saxreader.c @@ -35,6 +35,8 @@
#include "wine/test.h"
+static const WCHAR emptyW[] = {0}; + #define EXPECT_HR(hr,hr_exp) \ ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
@@ -2890,7 +2892,6 @@ static void test_mxwriter_default_properties(const struct mxwriter_props_t *tabl static void test_mxwriter_properties(void) { static const WCHAR utf16W[] = {'U','T','F','-','1','6',0}; - static const WCHAR emptyW[] = {0}; static const WCHAR testW[] = {'t','e','s','t',0}; ISAXContentHandler *content; IMXWriter *writer; @@ -3041,7 +3042,6 @@ static void test_mxwriter_properties(void)
static void test_mxwriter_flush(void) { - static const WCHAR emptyW[] = {0}; ISAXContentHandler *content; IMXWriter *writer; LARGE_INTEGER pos; @@ -5245,6 +5245,63 @@ static void test_mxattr_localname(void) } }
+static void test_mxwriter_indent(void) +{ + ISAXContentHandler *content; + IMXWriter *writer; + VARIANT dest; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IMXWriter, (void**)&writer); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + hr = IMXWriter_put_indent(writer, VARIANT_TRUE); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_startDocument(content); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1, NULL); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_characters(content, _bstr_(""), 0); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1, NULL); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_startElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1, NULL); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("c"), -1); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("b"), -1); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_endElement(content, emptyW, 0, emptyW, 0, _bstr_("a"), -1); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ISAXContentHandler_endDocument(content); + ok(hr == S_OK, "got %08x\n", hr); + + V_VT(&dest) = VT_EMPTY; + hr = IMXWriter_get_output(writer, &dest); + ok(hr == S_OK, "got %08x\n", hr); + ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest)); + ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n<a><b>\r\n\t\t<c/>\r\n\t</b>\r\n</a>"), V_BSTR(&dest)), + "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest))); + VariantClear(&dest); + + ISAXContentHandler_Release(content); + IMXWriter_Release(writer); + + free_bstrs(); +} + START_TEST(saxreader) { ISAXXMLReader *reader; @@ -5292,6 +5349,7 @@ START_TEST(saxreader) test_mxwriter_stream(); test_mxwriter_encoding(); test_mxwriter_dispex(); + test_mxwriter_indent(); } else win_skip("MXXMLWriter not supported\n");