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 test suite 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 "parser.h" |
30 | |
31 | #if QT_DEPRECATED_SINCE(5, 15) |
32 | |
33 | #include <qxml.h> |
34 | #include <qregularexpression.h> |
35 | |
36 | QT_WARNING_PUSH |
37 | QT_WARNING_DISABLE_DEPRECATED |
38 | class ContentHandler : public QXmlDefaultHandler |
39 | { |
40 | public: |
41 | ContentHandler(); |
42 | |
43 | // QXmlContentHandler methods |
44 | bool startDocument(); |
45 | bool endDocument(); |
46 | bool startElement(const QString &namespaceURI, |
47 | const QString &localName, |
48 | const QString &qName, |
49 | const QXmlAttributes &atts); |
50 | bool endElement(const QString &namespaceURI, |
51 | const QString &localName, |
52 | const QString &qName); |
53 | bool characters(const QString &ch); |
54 | void setDocumentLocator(QXmlLocator *locator); |
55 | bool startPrefixMapping(const QString &prefix, const QString &uri); |
56 | bool endPrefixMapping(const QString &prefix); |
57 | bool ignorableWhitespace(const QString &ch); |
58 | bool processingInstruction(const QString &target, const QString &data); |
59 | bool skippedEntity(const QString &name); |
60 | |
61 | // QXmlErrorHandler methods |
62 | bool warning(const QXmlParseException &exception); |
63 | bool error(const QXmlParseException &exception); |
64 | bool fatalError(const QXmlParseException &exception); |
65 | |
66 | // QXmlDTDHandler methods |
67 | bool notationDecl(const QString &name, const QString &publicId, |
68 | const QString &systemId); |
69 | bool unparsedEntityDecl(const QString &name, |
70 | const QString &publicId, |
71 | const QString &systemId, |
72 | const QString ¬ationName); |
73 | |
74 | // QXmlEntityResolver methods |
75 | bool resolveEntity(const QString &publicId, |
76 | const QString &systemId, |
77 | QXmlInputSource *&); |
78 | |
79 | // QXmlLexicalHandler methods |
80 | bool startDTD (const QString &name, const QString &publicId, const QString &systemId); |
81 | bool endDTD(); |
82 | bool startEntity(const QString &name); |
83 | bool endEntity(const QString &name); |
84 | bool startCDATA(); |
85 | bool endCDATA(); |
86 | bool comment(const QString &ch); |
87 | |
88 | // QXmlDeclHandler methods |
89 | bool attributeDecl(const QString &eName, const QString &aName, const QString &type, const QString &valueDefault, const QString &value); |
90 | bool internalEntityDecl(const QString &name, const QString &value); |
91 | bool externalEntityDecl(const QString &name, const QString &publicId, const QString &systemId); |
92 | |
93 | |
94 | const QString &result() const { return m_result; } |
95 | const QString &errorMsg() const { return m_error_msg; } |
96 | |
97 | private: |
98 | QString nestPrefix() const { return QString().fill(c: ' ', size: 3*m_nest); } |
99 | QString formatAttributes(const QXmlAttributes & atts); |
100 | QString escapeStr(const QString &s); |
101 | |
102 | unsigned m_nest; |
103 | QString m_result, m_error_msg; |
104 | }; |
105 | |
106 | ContentHandler::ContentHandler() |
107 | { |
108 | m_nest = 0; |
109 | } |
110 | |
111 | |
112 | bool ContentHandler::startDocument() |
113 | { |
114 | m_result += nestPrefix(); |
115 | m_result += "startDocument()\n" ; |
116 | ++m_nest; |
117 | return true; |
118 | } |
119 | |
120 | bool ContentHandler::endDocument() |
121 | { |
122 | --m_nest; |
123 | m_result += nestPrefix(); |
124 | m_result += "endDocument()\n" ; |
125 | return true; |
126 | } |
127 | |
128 | bool ContentHandler::startElement(const QString &namespaceURI, |
129 | const QString &localName, |
130 | const QString &qName, |
131 | const QXmlAttributes &atts) |
132 | { |
133 | m_result += nestPrefix(); |
134 | m_result += "startElement(namespaceURI=\"" + escapeStr(s: namespaceURI) |
135 | + "\", localName=\"" + escapeStr(s: localName) |
136 | + "\", qName=\"" + escapeStr(s: qName) |
137 | + "\", atts=[" + formatAttributes(atts) + "])\n" ; |
138 | ++m_nest; |
139 | return true; |
140 | } |
141 | |
142 | QString ContentHandler::escapeStr(const QString &s) |
143 | { |
144 | QString result = s; |
145 | result.replace(re: QRegularExpression("\"" ), after: "\\\"" ); |
146 | result.replace(re: QRegularExpression("\\" ), after: "\\\\" ); |
147 | result.replace(re: QRegularExpression("\n" ), after: "\\n" ); |
148 | result.replace(re: QRegularExpression("\r" ), after: "\\r" ); |
149 | result.replace(re: QRegularExpression("\t" ), after: "\\t" ); |
150 | return result; |
151 | } |
152 | |
153 | QString ContentHandler::formatAttributes(const QXmlAttributes &atts) |
154 | { |
155 | QString result; |
156 | for (int i = 0, cnt = atts.count(); i < cnt; ++i) { |
157 | if (i != 0) result += ", " ; |
158 | result += "{localName=\"" + escapeStr(s: atts.localName(index: i)) |
159 | + "\", qName=\"" + escapeStr(s: atts.qName(index: i)) |
160 | + "\", uri=\"" + escapeStr(s: atts.uri(index: i)) |
161 | + "\", type=\"" + escapeStr(s: atts.type(index: i)) |
162 | + "\", value=\"" + escapeStr(s: atts.value(index: i)) + "\"}" ; |
163 | } |
164 | return result; |
165 | } |
166 | |
167 | bool ContentHandler::endElement(const QString &namespaceURI, |
168 | const QString &localName, |
169 | const QString &qName) |
170 | { |
171 | --m_nest; |
172 | m_result += nestPrefix(); |
173 | m_result += "endElement(namespaceURI=\"" + escapeStr(s: namespaceURI) |
174 | + "\", localName=\"" + escapeStr(s: localName) |
175 | + "\", qName=\"" + escapeStr(s: qName) + "\")\n" ; |
176 | return true; |
177 | } |
178 | |
179 | bool ContentHandler::characters(const QString &ch) |
180 | { |
181 | m_result += nestPrefix(); |
182 | m_result += "characters(ch=\"" + escapeStr(s: ch) + "\")\n" ; |
183 | return true; |
184 | } |
185 | |
186 | void ContentHandler::setDocumentLocator(QXmlLocator *locator) |
187 | { |
188 | m_result += nestPrefix(); |
189 | m_result += "setDocumentLocator(locator={columnNumber=" |
190 | + QString::number(locator->columnNumber()) |
191 | + ", lineNumber=" + QString::number(locator->lineNumber()) |
192 | + "})\n" ; |
193 | } |
194 | |
195 | bool ContentHandler::startPrefixMapping (const QString &prefix, const QString & uri) |
196 | { |
197 | m_result += nestPrefix(); |
198 | m_result += "startPrefixMapping(prefix=\"" + escapeStr(s: prefix) |
199 | + "\", uri=\"" + escapeStr(s: uri) + "\")\n" ; |
200 | ++m_nest; |
201 | return true; |
202 | } |
203 | |
204 | bool ContentHandler::endPrefixMapping(const QString &prefix) |
205 | { |
206 | --m_nest; |
207 | m_result += nestPrefix(); |
208 | m_result += "endPrefixMapping(prefix=\"" + escapeStr(s: prefix) + "\")\n" ; |
209 | return true; |
210 | } |
211 | |
212 | bool ContentHandler::ignorableWhitespace(const QString & ch) |
213 | { |
214 | m_result += nestPrefix(); |
215 | m_result += "ignorableWhitespace(ch=\"" + escapeStr(s: ch) + "\")\n" ; |
216 | return true; |
217 | } |
218 | |
219 | bool ContentHandler::processingInstruction(const QString &target, const QString &data) |
220 | { |
221 | m_result += nestPrefix(); |
222 | m_result += "processingInstruction(target=\"" + escapeStr(s: target) |
223 | + "\", data=\"" + escapeStr(s: data) + "\")\n" ; |
224 | return true; |
225 | } |
226 | |
227 | bool ContentHandler::skippedEntity (const QString & name) |
228 | { |
229 | m_result += nestPrefix(); |
230 | m_result += "skippedEntity(name=\"" + escapeStr(s: name) + "\")\n" ; |
231 | return true; |
232 | } |
233 | |
234 | bool ContentHandler::warning(const QXmlParseException & exception) |
235 | { |
236 | m_error_msg = QString("Warning %1:%2: %3" ) |
237 | .arg(a: exception.columnNumber()) |
238 | .arg(a: exception.lineNumber()) |
239 | .arg(a: exception.message()); |
240 | m_result += nestPrefix(); |
241 | m_result += "warning(exception={columnNumber=" |
242 | + QString::number(exception.columnNumber()) |
243 | + ", lineNumber=" |
244 | + QString::number(exception.lineNumber()) |
245 | + ", publicId=\"" + escapeStr(s: exception.publicId()) |
246 | + "\", systemId=\"" + escapeStr(s: exception.systemId()) |
247 | + "\", message=\"" + escapeStr(s: exception.message()) |
248 | + "\"})\n" ; |
249 | return true; |
250 | } |
251 | |
252 | bool ContentHandler::error(const QXmlParseException & exception) |
253 | { |
254 | m_error_msg = QString("Error %1:%2: %3" ) |
255 | .arg(a: exception.columnNumber()) |
256 | .arg(a: exception.lineNumber()) |
257 | .arg(a: exception.message()); |
258 | m_result += nestPrefix(); |
259 | m_result += "error(exception={columnNumber=" |
260 | + QString::number(exception.columnNumber()) |
261 | + ", lineNumber=" |
262 | + QString::number(exception.lineNumber()) |
263 | + ", publicId=\"" + escapeStr(s: exception.publicId()) |
264 | + "\", systemId=\"" + escapeStr(s: exception.systemId()) |
265 | + "\", message=\"" + escapeStr(s: exception.message()) |
266 | + "\"})\n" ; |
267 | return true; |
268 | } |
269 | |
270 | bool ContentHandler::fatalError(const QXmlParseException & exception) |
271 | { |
272 | m_error_msg = QString("Fatal error %1:%2: %3" ) |
273 | .arg(a: exception.columnNumber()) |
274 | .arg(a: exception.lineNumber()) |
275 | .arg(a: exception.message()); |
276 | m_result += nestPrefix(); |
277 | m_result += "fatalError(exception={columnNumber=" |
278 | + QString::number(exception.columnNumber()) |
279 | + ", lineNumber=" |
280 | + QString::number(exception.lineNumber()) |
281 | + ", publicId=\"" + escapeStr(s: exception.publicId()) |
282 | + "\", systemId=\"" + escapeStr(s: exception.systemId()) |
283 | + "\", message=\"" + escapeStr(s: exception.message()) |
284 | + "\"})\n" ; |
285 | return true; |
286 | } |
287 | |
288 | bool ContentHandler::notationDecl(const QString &name, |
289 | const QString &publicId, |
290 | const QString &systemId ) |
291 | { |
292 | m_result += nestPrefix(); |
293 | m_result += "notationDecl(name=\"" + escapeStr(s: name) + "\", publicId=\"" |
294 | + escapeStr(s: publicId) + "\", systemId=\"" |
295 | + escapeStr(s: systemId) + "\")\n" ; |
296 | return true; |
297 | } |
298 | |
299 | bool ContentHandler::unparsedEntityDecl(const QString &name, |
300 | const QString &publicId, |
301 | const QString &systemId, |
302 | const QString ¬ationName ) |
303 | { |
304 | m_result += nestPrefix(); |
305 | m_result += "unparsedEntityDecl(name=\"" + escapeStr(s: name) |
306 | + "\", publicId=\"" + escapeStr(s: publicId) |
307 | + "\", systemId=\"" + escapeStr(s: systemId) |
308 | + "\", notationName=\"" + escapeStr(s: notationName) |
309 | + "\")\n" ; |
310 | return true; |
311 | } |
312 | |
313 | bool ContentHandler::resolveEntity(const QString &publicId, |
314 | const QString &systemId, |
315 | QXmlInputSource *&) |
316 | { |
317 | m_result += nestPrefix(); |
318 | m_result += "resolveEntity(publicId=\"" + escapeStr(s: publicId) |
319 | + "\", systemId=\"" + escapeStr(s: systemId) |
320 | + "\", ret={})\n" ; |
321 | return true; |
322 | } |
323 | |
324 | bool ContentHandler::startDTD ( const QString & name, const QString & publicId, const QString & systemId ) |
325 | { |
326 | m_result += nestPrefix(); |
327 | m_result += "startDTD(name=\"" + escapeStr(s: name) |
328 | + "\", publicId=\"" + escapeStr(s: publicId) |
329 | + "\", systemId=\"" + escapeStr(s: systemId) + "\")\n" ; |
330 | ++m_nest; |
331 | return true; |
332 | } |
333 | |
334 | bool ContentHandler::endDTD () |
335 | { |
336 | --m_nest; |
337 | m_result += nestPrefix(); |
338 | m_result += "endDTD()\n" ; |
339 | return true; |
340 | } |
341 | |
342 | bool ContentHandler::startEntity ( const QString & name ) |
343 | { |
344 | m_result += nestPrefix(); |
345 | m_result += "startEntity(name=\"" + escapeStr(s: name) + "\")\n" ; |
346 | ++m_nest; |
347 | return true; |
348 | } |
349 | |
350 | bool ContentHandler::endEntity ( const QString & name ) |
351 | { |
352 | --m_nest; |
353 | m_result += nestPrefix(); |
354 | m_result += "endEntity(name=\"" + escapeStr(s: name) + "\")\n" ; |
355 | return true; |
356 | } |
357 | |
358 | bool ContentHandler::startCDATA () |
359 | { |
360 | m_result += nestPrefix(); |
361 | m_result += "startCDATA()\n" ; |
362 | ++m_nest; |
363 | return true; |
364 | } |
365 | |
366 | bool ContentHandler::endCDATA () |
367 | { |
368 | --m_nest; |
369 | m_result += nestPrefix(); |
370 | m_result += "endCDATA()\n" ; |
371 | return true; |
372 | } |
373 | |
374 | bool ContentHandler::comment ( const QString & ch ) |
375 | { |
376 | m_result += nestPrefix(); |
377 | m_result += "comment(ch=\"" + escapeStr(s: ch) + "\")\n" ; |
378 | return true; |
379 | } |
380 | |
381 | bool ContentHandler::attributeDecl(const QString &eName, |
382 | const QString &aName, |
383 | const QString &type, |
384 | const QString &valueDefault, |
385 | const QString &value) |
386 | { |
387 | m_result += nestPrefix(); |
388 | m_result += "attributeDecl(eName=\"" + escapeStr(s: eName) + "\", aName=\"" |
389 | + escapeStr(s: aName) + "\", type=\"" + escapeStr(s: type) |
390 | + "\", valueDefault=\"" + escapeStr(s: valueDefault) |
391 | + "\", value=\"" + escapeStr(s: value) + "\")\n" ; |
392 | return true; |
393 | } |
394 | |
395 | bool ContentHandler::internalEntityDecl(const QString &name, |
396 | const QString &value) |
397 | { |
398 | m_result += nestPrefix(); |
399 | m_result += "internatlEntityDecl(name=\"" + escapeStr(s: name) |
400 | + "\", value=\"" + escapeStr(s: value) + "\")\n" ; |
401 | return true; |
402 | } |
403 | |
404 | bool ContentHandler::externalEntityDecl(const QString &name, |
405 | const QString &publicId, |
406 | const QString &systemId) |
407 | { |
408 | m_result += nestPrefix(); |
409 | m_result += "externalEntityDecl(name=\"" + escapeStr(s: name) |
410 | + "\", publicId=\"" + escapeStr(s: publicId) |
411 | + "\", systemId=\"" + escapeStr(s: systemId) + "\")\n" ; |
412 | return true; |
413 | } |
414 | |
415 | Parser::Parser() |
416 | { |
417 | handler = new ContentHandler; |
418 | setContentHandler(handler); |
419 | setDTDHandler(handler); |
420 | setDeclHandler(handler); |
421 | setEntityResolver(handler); |
422 | setErrorHandler(handler); |
423 | setLexicalHandler(handler); |
424 | } |
425 | |
426 | Parser::~Parser() |
427 | { |
428 | delete handler; |
429 | } |
430 | |
431 | bool Parser::parseFile(QFile *file) |
432 | { |
433 | QXmlInputSource source(file); |
434 | return parse(input: source); |
435 | } |
436 | |
437 | QString Parser::result() const |
438 | { |
439 | return handler->result(); |
440 | } |
441 | |
442 | QString Parser::errorMsg() const |
443 | { |
444 | return handler->errorMsg(); |
445 | } |
446 | |
447 | QT_WARNING_POP |
448 | #endif // QT_DEPRECATED_SINCE(5, 15) |
449 | |