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 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | XmlOutput::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 | |
53 | XmlOutput::~XmlOutput() |
54 | { |
55 | closeAll(); |
56 | } |
57 | |
58 | // Settings ------------------------------------------------------------------ |
59 | void XmlOutput::setIndentString(const QString &indentString) |
60 | { |
61 | indent = indentString; |
62 | } |
63 | |
64 | QString XmlOutput::indentString() |
65 | { |
66 | return indent; |
67 | } |
68 | |
69 | void XmlOutput::setIndentLevel(int level) |
70 | { |
71 | currentLevel = level; |
72 | } |
73 | |
74 | int XmlOutput::indentLevel() |
75 | { |
76 | return currentLevel; |
77 | } |
78 | |
79 | void XmlOutput::setState(XMLState state) |
80 | { |
81 | currentState = state; |
82 | } |
83 | |
84 | void XmlOutput::setFormat(XMLFormat newFormat) |
85 | { |
86 | format = newFormat; |
87 | } |
88 | |
89 | XmlOutput::XMLState XmlOutput::state() |
90 | { |
91 | return currentState; |
92 | } |
93 | |
94 | void XmlOutput::updateIndent() |
95 | { |
96 | currentIndent.clear(); |
97 | for (int i = 0; i < currentLevel; ++i) |
98 | currentIndent.append(indent); |
99 | } |
100 | |
101 | void XmlOutput::increaseIndent() |
102 | { |
103 | ++currentLevel; |
104 | updateIndent(); |
105 | } |
106 | |
107 | void XmlOutput::decreaseIndent() |
108 | { |
109 | if (currentLevel) |
110 | --currentLevel; |
111 | updateIndent(); |
112 | if (!currentLevel) |
113 | currentState = Bare; |
114 | } |
115 | |
116 | QString 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( |
132 | text.at(i + 7) == QLatin1Char( |
133 | output += text.at(i); |
134 | } else { |
135 | output += QLatin1String("&"); |
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( |
141 | } else { |
142 | output += text.at(i); |
143 | } |
144 | } |
145 | } |
146 | } else { |
147 | output = text; |
148 | } |
149 | |
150 | if (conversion == XMLConversion) { |
151 | output.replace("""); |
152 | output.replace("'"); |
153 | } else if (conversion == EscapeConversion) { |
154 | output.replace("\\\""); |
155 | output.replace("\\\'"); |
156 | } |
157 | return output; |
158 | } |
159 | |
160 | // Stream functions ---------------------------------------------------------- |
161 | XmlOutput& XmlOutput::operator<<(const QString& o) |
162 | { |
163 | return operator<<(data(o)); |
164 | } |
165 | |
166 | XmlOutput& 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"+ 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 ---------------------------------------------------------- |
239 | void 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 | |
246 | void 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 << |
254 | currentState = Attribute; |
255 | tagStack.append(tag); |
256 | increaseIndent(); // ---> indent |
257 | } |
258 | |
259 | void 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 | |
272 | void 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 | |
299 | void 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 | |
314 | void XmlOutput::closeAll() |
315 | { |
316 | if (!tagStack.count()) |
317 | return; |
318 | closeTo(QString()); |
319 | } |
320 | |
321 | void 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 | |
338 | void XmlOutput::addRaw(const QString &rawText) |
339 | { |
340 | closeOpen(); |
341 | xmlFile << rawText; |
342 | } |
343 | |
344 | void 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 | |
362 | void 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 | |
378 | QT_END_NAMESPACE |
379 |
Warning: That file was not part of the compilation database. It may have many parsing errors.