msxml3: Implement output indentation for writer.

This commit is contained in:
Nikolay Sivov 2013-07-27 18:27:27 +04:00 committed by Alexandre Julliard
parent 95d01f1751
commit b3d85d41d9
2 changed files with 119 additions and 5 deletions

View file

@ -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;

View file

@ -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");