1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Test Executor
3 * ------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief XML Writer.
22 *//*--------------------------------------------------------------------*/
23
24#include "xeXMLWriter.hpp"
25
26#include <cstring>
27
28namespace xe
29{
30namespace xml
31{
32
33const Writer::EndElementType Writer::EndElement = Writer::EndElementType();
34
35inline const char* getEscapeEntity (char ch)
36{
37	switch (ch)
38	{
39		case '<':	return "&lt;";
40		case '>':	return "&gt;";
41		case '&':	return "&amp;";
42		case '\'':	return "&apos;";
43		case '"':	return "&quot;";
44		default:	return DE_NULL;
45	}
46}
47
48std::streamsize EscapeStreambuf::xsputn (const char* s, std::streamsize count)
49{
50	std::streamsize	numWritten = 0;
51
52	for (std::streamsize inPos = 0; inPos < count; inPos++)
53	{
54		const char* entity = getEscapeEntity(s[inPos]);
55
56		if (entity)
57		{
58			// Flush data prior to entity.
59			if (inPos > numWritten)
60			{
61				m_dst.write(s + numWritten, inPos-numWritten);
62				if (m_dst.fail())
63					return numWritten;
64			}
65
66			// Flush entity value
67			m_dst.write(entity, (std::streamsize)strlen(entity));
68
69			numWritten = inPos+1;
70		}
71	}
72
73	if (numWritten < count)
74	{
75		m_dst.write(s + numWritten, count-numWritten);
76		if (m_dst.fail())
77			return numWritten;
78	}
79
80	return count;
81}
82
83int EscapeStreambuf::overflow (int ch)
84{
85	if (ch == -1)
86		return -1;
87	else
88	{
89		DE_ASSERT((ch & 0xff) == ch);
90		const char chVal = (char)(deUint8)(ch & 0xff);
91		return xsputn(&chVal, 1) == 1 ? ch : -1;
92	}
93}
94
95Writer::Writer (std::ostream& dst)
96	: m_rawDst	(dst)
97	, m_dataBuf	(dst)
98	, m_dataStr	(&m_dataBuf)
99	, m_state	(STATE_DATA)
100{
101}
102
103Writer::~Writer (void)
104{
105}
106
107Writer& Writer::operator<< (const BeginElement& begin)
108{
109	if (m_state == STATE_ELEMENT)
110		m_rawDst << ">";
111
112	if (m_state == STATE_ELEMENT || m_state == STATE_ELEMENT_END)
113	{
114		m_rawDst << "\n";
115		for (int i = 0; i < (int)m_elementStack.size(); i++)
116			m_rawDst << "  ";
117	}
118
119	m_rawDst << "<" << begin.element;
120
121	m_elementStack.push_back(begin.element);
122	m_state = STATE_ELEMENT;
123
124	return *this;
125}
126
127Writer& Writer::operator<< (const Attribute& attribute)
128{
129	DE_ASSERT(m_state == STATE_ELEMENT);
130
131	// \todo [2012-09-05 pyry] Escape?
132	m_rawDst << " " << attribute.name << "=\"" << attribute.value << "\"";
133
134	return *this;
135}
136
137Writer& Writer::operator<< (const EndElementType&)
138{
139	if (m_state == STATE_ELEMENT)
140		m_rawDst << "/>";
141	else
142	{
143		if (m_state == STATE_ELEMENT_END)
144		{
145			m_rawDst << "\n";
146			for (int i = 0; i < (int)m_elementStack.size()-1; i++)
147				m_rawDst << "  ";
148		}
149
150		m_rawDst << "</" << m_elementStack.back() << ">";
151	}
152
153	m_elementStack.pop_back();
154	m_state = STATE_ELEMENT_END;
155
156	return *this;
157}
158
159} // xml
160} // xe
161