QtBase  v6.3.1
xmloutput.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the qmake application of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "xmloutput.h"
30 
32 
34  : xmlFile(file), indent("\t"), currentLevel(0), currentState(Bare), format(NewLine),
35  conversion(type)
36 {
37  tagStack.clear();
38 }
39 
41 {
42  closeAll();
43 }
44 
45 // Settings ------------------------------------------------------------------
46 void XmlOutput::setIndentString(const QString &indentString)
47 {
48  indent = indentString;
49 }
50 
52 {
53  return indent;
54 }
55 
57 {
58  currentLevel = level;
59 }
60 
62 {
63  return currentLevel;
64 }
65 
67 {
68  currentState = state;
69 }
70 
72 {
73  format = newFormat;
74 }
75 
77 {
78  return currentState;
79 }
80 
81 void XmlOutput::updateIndent()
82 {
83  currentIndent.clear();
84  currentIndent.reserve(currentLevel);
85  for (int i = 0; i < currentLevel; ++i)
86  currentIndent.append(indent);
87 }
88 
89 void XmlOutput::increaseIndent()
90 {
91  ++currentLevel;
92  updateIndent();
93 }
94 
95 void XmlOutput::decreaseIndent()
96 {
97  if (currentLevel)
98  --currentLevel;
99  updateIndent();
100  if (!currentLevel)
101  currentState = Bare;
102 }
103 
104 QString XmlOutput::doConversion(const QString &text)
105 {
106  if (!text.count())
107  return QString();
108  else if (conversion == NoConversion)
109  return text;
110 
111  QString output;
112  if (conversion == XMLConversion) {
113 
114  // this is a way to escape characters that shouldn't be converted
115  for (int i=0; i<text.count(); ++i) {
116  const QChar c = text.at(i);
117  if (c == QLatin1Char('&')) {
118  if ( (i + 7) < text.count() &&
119  text.at(i + 1) == QLatin1Char('#') &&
120  text.at(i + 2) == QLatin1Char('x') &&
121  text.at(i + 7) == QLatin1Char(';') ) {
122  output += text.at(i);
123  } else {
124  output += QLatin1String("&amp;");
125  }
126  } else if (c == QLatin1Char('<')) {
127  output += QLatin1String("&lt;");
128  } else if (c == QLatin1Char('>')) {
129  output += QLatin1String("&gt;");
130  } else {
131  if (c.unicode() < 0x20) {
132  output += QString("&#x%1;").arg(c.unicode(), 2, 16, QLatin1Char('0'));
133  } else {
134  output += c;
135  }
136  }
137  }
138  } else {
139  output = text;
140  }
141 
142  if (conversion == XMLConversion) {
143  output.replace('\"', QLatin1String("&quot;"));
144  output.replace('\'', QLatin1String("&apos;"));
145  } else if (conversion == EscapeConversion) {
146  output.replace('\"', QLatin1String("\\\""));
147  output.replace('\'', QLatin1String("\\\'"));
148  }
149  return output;
150 }
151 
152 // Stream functions ----------------------------------------------------------
154 {
155  return operator<<(data(o));
156 }
157 
159 {
160  switch(o.xo_type) {
161  case tNothing:
162  break;
163  case tRaw:
164  addRaw(o.xo_text);
165  break;
166  case tDeclaration:
167  addDeclaration(o.xo_text, o.xo_value);
168  break;
169  case tTag:
170  newTagOpen(o.xo_text);
171  break;
172  case tTagValue:
173  addRaw(QString("\n%1<%2>").arg(currentIndent).arg(o.xo_text));
174  addRaw(doConversion(o.xo_value));
175  addRaw(QString("</%1>").arg(o.xo_text));
176  break;
177  case tValueTag:
178  addRaw(doConversion(o.xo_text));
180  closeTag();
182  break;
183  case tImport:
184  addRaw(QString("\n%1<Import %2=\"%3\" />").arg(currentIndent).arg(o.xo_text).arg(o.xo_value));
185  break;
186  case tCloseTag:
187  if (o.xo_value.count())
188  closeAll();
189  else if (o.xo_text.count())
190  closeTo(o.xo_text);
191  else
192  closeTag();
193  break;
194  case tAttribute:
195  addAttribute(o.xo_text, o.xo_value);
196  break;
197  case tAttributeTag:
198  addAttributeTag(o.xo_text, o.xo_value);
199  break;
200  case tData:
201  {
202  // Special case to be able to close tag in normal
203  // way ("</tag>", not "/>") without using addRaw()..
204  if (!o.xo_text.count()) {
205  closeOpen();
206  break;
207  }
208  QString output = doConversion(o.xo_text);
209  output.replace('\n', "\n" + currentIndent);
210  addRaw(QString("\n%1%2").arg(currentIndent).arg(output));
211  }
212  break;
213  case tComment:
214  {
215  QString output("<!--%1-->");
216  addRaw(output.arg(o.xo_text));
217  }
218  break;
219  case tCDATA:
220  {
221  QString output("<![CDATA[\n%1\n]]>");
222  addRaw(output.arg(o.xo_text));
223  }
224  break;
225  }
226  return *this;
227 }
228 
229 
230 // Output functions ----------------------------------------------------------
231 void XmlOutput::newTag(const QString &tag)
232 {
233  Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
234  newTagOpen(tag);
235  closeOpen();
236 }
237 
238 void XmlOutput::newTagOpen(const QString &tag)
239 {
240  Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
241  closeOpen();
242 
243  if (format == NewLine)
244  xmlFile << Qt::endl << currentIndent;
245  xmlFile << '<' << doConversion(tag);
246  currentState = Attribute;
247  tagStack.append(tag);
248  increaseIndent(); // ---> indent
249 }
250 
251 void XmlOutput::closeOpen()
252 {
253  switch(currentState) {
254  case Bare:
255  case Tag:
256  return;
257  case Attribute:
258  break;
259  }
260  xmlFile << '>';
261  currentState = Tag;
262 }
263 
264 void XmlOutput::closeTag()
265 {
266  switch(currentState) {
267  case Bare:
268  if (tagStack.count())
269  //warn_msg(WarnLogic, "<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
270  qDebug("<Root>: Cannot close tag in Bare state, %d tags on stack", int(tagStack.count()));
271  else
272  //warn_msg(WarnLogic, "<Root>: Cannot close tag, no tags on stack");
273  qDebug("<Root>: Cannot close tag, no tags on stack");
274  return;
275  case Tag:
276  decreaseIndent(); // <--- Pre-decrease indent
277  if (format == NewLine)
278  xmlFile << Qt::endl << currentIndent;
279  xmlFile << "</" << doConversion(tagStack.last()) << '>';
280  tagStack.pop_back();
281  break;
282  case Attribute:
283  xmlFile << " />";
284  tagStack.pop_back();
285  currentState = Tag;
286  decreaseIndent(); // <--- Post-decrease indent
287  break;
288  }
289 }
290 
291 void XmlOutput::closeTo(const QString &tag)
292 {
293  bool cont = true;
294  if (!tagStack.contains(tag) && !tag.isNull()) {
295  //warn_msg(WarnLogic, "<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().latin1(), tag.latin1());
296  qDebug("<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().toLatin1().constData(), tag.toLatin1().constData());
297  return;
298  }
299  int left = tagStack.count();
300  while (left-- && cont) {
301  cont = tagStack.last().compare(tag) != 0;
302  closeTag();
303  }
304 }
305 
306 void XmlOutput::closeAll()
307 {
308  if (!tagStack.count())
309  return;
310  closeTo(QString());
311 }
312 
313 void XmlOutput::addDeclaration(const QString &version, const QString &encoding)
314 {
315  switch(currentState) {
316  case Bare:
317  break;
318  case Tag:
319  case Attribute:
320  //warn_msg(WarnLogic, "<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
321  qDebug("<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
322  return;
323  }
324  QString outData = QString("<?xml version=\"%1\" encoding=\"%2\"?>")
325  .arg(doConversion(version))
326  .arg(doConversion(encoding));
327  addRaw(outData);
328 }
329 
330 void XmlOutput::addRaw(const QString &rawText)
331 {
332  closeOpen();
333  xmlFile << rawText;
334 }
335 
336 void XmlOutput::addAttribute(const QString &attribute, const QString &value)
337 {
338  switch(currentState) {
339  case Bare:
340  case Tag:
341  //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
342  qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
343  (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
344  attribute.toLatin1().constData());
345  return;
346  case Attribute:
347  break;
348  }
349  if (format == NewLine)
350  xmlFile << Qt::endl;
351  xmlFile << currentIndent << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
352 }
353 
354 void XmlOutput::addAttributeTag(const QString &attribute, const QString &value)
355 {
356  switch(currentState) {
357  case Bare:
358  case Tag:
359  //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
360  qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
361  (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
362  attribute.toLatin1().constData());
363  return;
364  case Attribute:
365  break;
366  }
367  xmlFile << " " << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
368 }
369 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
const char * constData() const noexcept
Definition: qbytearray.h:144
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
T & last()
Definition: qlist.h:646
qsizetype count() const noexcept
Definition: qlist.h:415
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
The QString class provides a Unicode character string.
Definition: qstring.h:388
QByteArray toLatin1() const &
Definition: qstring.h:745
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition: qstring.cpp:3450
void reserve(qsizetype size)
Definition: qstring.h:1307
void clear()
Definition: qstring.h:1240
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=QLatin1Char(' ')) const
Definition: qstring.cpp:8318
QString & append(QChar c)
Definition: qstring.cpp:3152
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:62
@ Attribute
Definition: xmloutput.h:52
XMLState state()
Definition: xmloutput.cpp:76
@ tTagValue
Definition: xmloutput.h:59
@ tCloseTag
Definition: xmloutput.h:61
@ tComment
Definition: xmloutput.h:66
@ tAttribute
Definition: xmloutput.h:62
@ tDeclaration
Definition: xmloutput.h:57
@ tAttributeTag
Definition: xmloutput.h:63
@ tNothing
Definition: xmloutput.h:55
@ tValueTag
Definition: xmloutput.h:60
void setState(XMLState state)
Definition: xmloutput.cpp:66
@ NoNewLine
Definition: xmloutput.h:46
void setFormat(XMLFormat newFormat)
Definition: xmloutput.cpp:71
QString indentString()
Definition: xmloutput.cpp:51
void setIndentLevel(int level)
Definition: xmloutput.cpp:56
XmlOutput & operator<<(const QString &o)
Definition: xmloutput.cpp:153
int indentLevel()
Definition: xmloutput.cpp:61
void setIndentString(const QString &indentString)
Definition: xmloutput.cpp:46
XmlOutput(QTextStream &file, ConverstionType type=XMLConversion)
Definition: xmloutput.cpp:33
ConverstionType
Definition: xmloutput.h:40
@ XMLConversion
Definition: xmloutput.h:43
@ EscapeConversion
Definition: xmloutput.h:42
@ NoConversion
Definition: xmloutput.h:41
QString text
[meta data]
else opt state
[0]
QTextStream & endl(QTextStream &stream)
#define QString()
Definition: parse-defines.h:51
EGLOutputLayerEXT EGLint EGLAttrib value
EGLOutputLayerEXT EGLint attribute
@ text
#define qDebug
[1]
Definition: qlogging.h:177
GLenum type
Definition: qopengl.h:270
GLenum GLuint GLint level
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
const GLubyte * c
Definition: qopenglext.h:12701
GLdouble s
[6]
Definition: qopenglext.h:235
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
SSL_CTX int(*) void arg)
QFile file
[0]
file open(QIODevice::ReadOnly)
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154