Nikolay Sivov : msxml3: Implement output indentation for writer.
Alexandre Julliard
julliard at winehq.org
Mon Jul 29 14:01:18 CDT 2013
Module: wine
Branch: master
Commit: b3d85d41d99fbe9518db35761c7e7560d6cdd61b
URL: http://source.winehq.org/git/wine.git/?a=commit;h=b3d85d41d99fbe9518db35761c7e7560d6cdd61b
Author: Nikolay Sivov <nsivov at 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");
More information about the wine-cvs
mailing list