Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the qmake application of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "xmloutput.h"
43
44QT_BEGIN_NAMESPACE
45
46XmlOutput::XmlOutput(QTextStream &file, ConverstionType type)
47 : xmlFile(file), indent("\t"), currentLevel(0), currentState(Bare), format(NewLine),
48 conversion(type)
49{
50 tagStack.clear();
51}
52
53XmlOutput::~XmlOutput()
54{
55 closeAll();
56}
57
58// Settings ------------------------------------------------------------------
59void XmlOutput::setIndentString(const QString &indentString)
60{
61 indent = indentString;
62}
63
64QString XmlOutput::indentString()
65{
66 return indent;
67}
68
69void XmlOutput::setIndentLevel(int level)
70{
71 currentLevel = level;
72}
73
74int XmlOutput::indentLevel()
75{
76 return currentLevel;
77}
78
79void XmlOutput::setState(XMLState state)
80{
81 currentState = state;
82}
83
84void XmlOutput::setFormat(XMLFormat newFormat)
85{
86 format = newFormat;
87}
88
89XmlOutput::XMLState XmlOutput::state()
90{
91 return currentState;
92}
93
94void XmlOutput::updateIndent()
95{
96 currentIndent.clear();
97 for (int i = 0; i < currentLevel; ++i)
98 currentIndent.append(indent);
99}
100
101void XmlOutput::increaseIndent()
102{
103 ++currentLevel;
104 updateIndent();
105}
106
107void XmlOutput::decreaseIndent()
108{
109 if (currentLevel)
110 --currentLevel;
111 updateIndent();
112 if (!currentLevel)
113 currentState = Bare;
114}
115
116QString XmlOutput::doConversion(const QString &text)
117{
118 if (!text.count())
119 return QString();
120 else if (conversion == NoConversion)
121 return text;
122
123 QString output;
124 if (conversion == XMLConversion) {
125
126 // this is a way to escape characters that shouldn't be converted
127 for (int i=0; i<text.count(); ++i) {
128 if (text.at(i) == QLatin1Char('&')) {
129 if ( (i + 7) < text.count() &&
130 text.at(i + 1) == QLatin1Char('#') &&
131 text.at(i + 2) == QLatin1Char('x') &&
132 text.at(i + 7) == QLatin1Char(';') ) {
133 output += text.at(i);
134 } else {
135 output += QLatin1String("&amp;");
136 }
137 } else {
138 QChar c = text.at(i);
139 if (c.unicode() < 0x20) {
140 output += QString("&#x%1;").arg(c.unicode(), 2, 16, QLatin1Char('0'));
141 } else {
142 output += text.at(i);
143 }
144 }
145 }
146 } else {
147 output = text;
148 }
149
150 if (conversion == XMLConversion) {
151 output.replace('\"', "&quot;");
152 output.replace('\'', "&apos;");
153 } else if (conversion == EscapeConversion) {
154 output.replace('\"', "\\\"");
155 output.replace('\'', "\\\'");
156 }
157 return output;
158}
159
160// Stream functions ----------------------------------------------------------
161XmlOutput& XmlOutput::operator<<(const QString& o)
162{
163 return operator<<(data(o));
164}
165
166XmlOutput& XmlOutput::operator<<(const xml_output& o)
167{
168 switch(o.xo_type) {
169 case tNothing:
170 break;
171 case tRaw:
172 addRaw(o.xo_text);
173 break;
174 case tDeclaration:
175 addDeclaration(o.xo_text, o.xo_value);
176 break;
177 case tTag:
178 newTagOpen(o.xo_text);
179 break;
180 case tTagValue:
181 addRaw(QString("\n%1<%2>").arg(currentIndent).arg(o.xo_text));
182 addRaw(doConversion(o.xo_value));
183 addRaw(QString("</%1>").arg(o.xo_text));
184 break;
185 case tValueTag:
186 addRaw(QString("%1").arg(doConversion(o.xo_text)));
187 setFormat(NoNewLine);
188 closeTag();
189 setFormat(NewLine);
190 break;
191 case tImport:
192 addRaw(QString("\n%1<Import %2=\"%3\" />").arg(currentIndent).arg(o.xo_text).arg(o.xo_value));
193 break;
194 case tCloseTag:
195 if (o.xo_value.count())
196 closeAll();
197 else if (o.xo_text.count())
198 closeTo(o.xo_text);
199 else
200 closeTag();
201 break;
202 case tAttribute:
203 addAttribute(o.xo_text, o.xo_value);
204 break;
205 case tAttributeTag:
206 addAttributeTag(o.xo_text, o.xo_value);
207 break;
208 case tData:
209 {
210 // Special case to be able to close tag in normal
211 // way ("</tag>", not "/>") without using addRaw()..
212 if (!o.xo_text.count()) {
213 closeOpen();
214 break;
215 }
216 QString output = doConversion(o.xo_text);
217 output.replace('\n', "\n" + currentIndent);
218 addRaw(QString("\n%1%2").arg(currentIndent).arg(output));
219 }
220 break;
221 case tComment:
222 {
223 QString output("<!--%1-->");
224 addRaw(output.arg(o.xo_text));
225 }
226 break;
227 case tCDATA:
228 {
229 QString output("<![CDATA[\n%1\n]]>");
230 addRaw(output.arg(o.xo_text));
231 }
232 break;
233 }
234 return *this;
235}
236
237
238// Output functions ----------------------------------------------------------
239void XmlOutput::newTag(const QString &tag)
240{
241 Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
242 newTagOpen(tag);
243 closeOpen();
244}
245
246void XmlOutput::newTagOpen(const QString &tag)
247{
248 Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
249 closeOpen();
250
251 if (format == NewLine)
252 xmlFile << endl << currentIndent;
253 xmlFile << '<' << doConversion(tag);
254 currentState = Attribute;
255 tagStack.append(tag);
256 increaseIndent(); // ---> indent
257}
258
259void XmlOutput::closeOpen()
260{
261 switch(currentState) {
262 case Bare:
263 case Tag:
264 return;
265 case Attribute:
266 break;
267 }
268 xmlFile << '>';
269 currentState = Tag;
270}
271
272void XmlOutput::closeTag()
273{
274 switch(currentState) {
275 case Bare:
276 if (tagStack.count())
277 //warn_msg(WarnLogic, "<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
278 qDebug("<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
279 else
280 //warn_msg(WarnLogic, "<Root>: Cannot close tag, no tags on stack");
281 qDebug("<Root>: Cannot close tag, no tags on stack");
282 return;
283 case Tag:
284 decreaseIndent(); // <--- Pre-decrease indent
285 if (format == NewLine)
286 xmlFile << endl << currentIndent;
287 xmlFile << "</" << doConversion(tagStack.last()) << '>';
288 tagStack.pop_back();
289 break;
290 case Attribute:
291 xmlFile << " />";
292 tagStack.pop_back();
293 currentState = Tag;
294 decreaseIndent(); // <--- Post-decrease indent
295 break;
296 }
297}
298
299void XmlOutput::closeTo(const QString &tag)
300{
301 bool cont = true;
302 if (!tagStack.contains(tag) && !tag.isNull()) {
303 //warn_msg(WarnLogic, "<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().latin1(), tag.latin1());
304 qDebug("<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().toLatin1().constData(), tag.toLatin1().constData());
305 return;
306 }
307 int left = tagStack.count();
308 while (left-- && cont) {
309 cont = tagStack.last().compare(tag) != 0;
310 closeTag();
311 }
312}
313
314void XmlOutput::closeAll()
315{
316 if (!tagStack.count())
317 return;
318 closeTo(QString());
319}
320
321void XmlOutput::addDeclaration(const QString &version, const QString &encoding)
322{
323 switch(currentState) {
324 case Bare:
325 break;
326 case Tag:
327 case Attribute:
328 //warn_msg(WarnLogic, "<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
329 qDebug("<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
330 return;
331 }
332 QString outData = QString("<?xml version=\"%1\" encoding=\"%2\"?>")
333 .arg(doConversion(version))
334 .arg(doConversion(encoding));
335 addRaw(outData);
336}
337
338void XmlOutput::addRaw(const QString &rawText)
339{
340 closeOpen();
341 xmlFile << rawText;
342}
343
344void XmlOutput::addAttribute(const QString &attribute, const QString &value)
345{
346 switch(currentState) {
347 case Bare:
348 case Tag:
349 //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
350 qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
351 (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
352 attribute.toLatin1().constData());
353 return;
354 case Attribute:
355 break;
356 }
357 if (format == NewLine)
358 xmlFile << endl;
359 xmlFile << currentIndent << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
360}
361
362void XmlOutput::addAttributeTag(const QString &attribute, const QString &value)
363{
364 switch(currentState) {
365 case Bare:
366 case Tag:
367 //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
368 qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
369 (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
370 attribute.toLatin1().constData());
371 return;
372 case Attribute:
373 break;
374 }
375 xmlFile << " " << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
376}
377
378QT_END_NAMESPACE
379

Warning: That file was not part of the compilation database. It may have many parsing errors.