msxml3: Implement output indentation for writer.
This commit is contained in:
parent
95d01f1751
commit
b3d85d41d9
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue