Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qxmlstream_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5//
6// W A R N I N G
7// -------------
8//
9// This file is not part of the Qt API. It exists for the convenience
10// of other Qt classes. This header file may change from version to
11// version without notice, or even be removed.
12//
13// We mean it.
14//
15
16#include <QtCore/private/qglobal_p.h>
17#include <qstringconverter.h>
18#include <qxmlstream.h>
20#include <QtCore/qhash.h>
21#include <QCoreApplication> // Q_DECLARE_TR_FUNCTIONS
22
23
24#include <memory>
25#include <optional>
26
27#ifndef QXMLSTREAM_P_H
28#define QXMLSTREAM_P_H
29
30QT_BEGIN_NAMESPACE
31
32namespace QtPrivate {
33
35{
36public:
37 const QString *m_string = nullptr;
40
41 constexpr XmlStringRef() = default;
42 constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length)
44 {
45 }
46 XmlStringRef(const QString *string)
47 : XmlStringRef(string, 0, string->size())
48 {
49 }
50
52 if (!m_string)
53 return QXmlString();
55 d.setBegin(d.data() + m_pos);
56 d.size = m_size;
57 return QXmlString(std::move(d));
58 }
59
60 void clear() { m_string = nullptr; m_pos = 0; m_size= 0; }
62 bool isEmpty() const { return m_size == 0; }
63 bool isNull() const { return !m_string; }
64 QString toString() const { return view().toString(); }
65
77
78#define MAKE_MEMBER(name)
79 auto name () const noexcept { return view(). name (); }
80 MAKE_MEMBER(data)
81 MAKE_MEMBER(size)
82 MAKE_MEMBER(empty)
83 MAKE_MEMBER(begin)
84 MAKE_MEMBER(end)
85 MAKE_MEMBER(cbegin)
86 MAKE_MEMBER(cend)
87 MAKE_MEMBER(rbegin)
88 MAKE_MEMBER(rend)
89 MAKE_MEMBER(crbegin)
90 MAKE_MEMBER(crend)
91#undef MAKE_MEMBER
92
93#define MAKE_OP(op)
94 friend auto operator op(const XmlStringRef &lhs, const XmlStringRef &rhs) noexcept { return lhs.view() op rhs.view(); }
95 /*end*/
96 MAKE_OP(==)
97 MAKE_OP(!=)
98 MAKE_OP(<=)
99 MAKE_OP(>=)
100 MAKE_OP(<)
101 MAKE_OP(>)
102#undef MAKE_OP
103#define MAKE_OP(op)
104 friend auto operator op(const XmlStringRef &lhs, QStringView rhs) noexcept { return lhs.view() op rhs; }
105 friend auto operator op(QStringView lhs, const XmlStringRef &rhs) noexcept { return lhs op rhs.view(); }
106 /*end*/
107 MAKE_OP(==)
108 MAKE_OP(!=)
109 MAKE_OP(<=)
110 MAKE_OP(>=)
111 MAKE_OP(<)
112 MAKE_OP(>)
113#undef MAKE_OP
114};
115
116}
117
118using namespace QtPrivate;
119
120template <typename T> class QXmlStreamSimpleStack
121{
123
124 T *data;
125 qsizetype tos, cap;
126public:
128 : data(nullptr), tos(-1), cap(0)
129 {}
131 {
132 if (data) {
133 std::destroy_n(data, size());
134 free(data);
135 }
136 }
137
138 inline void reserve(qsizetype extraCapacity)
139 {
140 if (tos + extraCapacity + 1 > cap) {
141 cap = qMax(tos + extraCapacity + 1, cap << 1 );
142 void *ptr = realloc(static_cast<void *>(data), cap * sizeof(T));
143 Q_CHECK_PTR(ptr);
144 data = reinterpret_cast<T *>(ptr);
145 }
146 }
147
148 inline T &push() { reserve(1); return rawPush(); }
149 inline T &rawPush() { return *new (data + (++tos)) T; }
150 inline const T &top() const { return data[tos]; }
151 inline T &top() { return data[tos]; }
152 inline T pop() { T t = std::move(data[tos]); std::destroy_at(data + tos); --tos; return t; }
153 inline T &operator[](qsizetype index) { return data[index]; }
154 inline const T &at(qsizetype index) const { return data[index]; }
155 inline qsizetype size() const { return tos + 1; }
156 inline void resize(qsizetype s) { tos = s - 1; }
157 inline bool isEmpty() const { return tos < 0; }
158 inline void clear() { tos = -1; }
159
160 using const_iterator = const T*;
161 using iterator = T*;
162 T *begin() { return data; }
163 const T *begin() const { return data; }
164 const T *cbegin() const { return begin(); }
165 T *end() { return data + size(); }
166 const T *end() const { return data + size(); }
167 const T *cend() const { return end(); }
168};
169
174
177public:
183
192
193
200
202 {
203 qsizetype pos = tagStackStringStorageSize;
204 if (pos != tagStackStringStorage.size())
205 tagStackStringStorage.resize(pos);
206 s.visit([&](auto s) { tagStackStringStorage.append(s); });
207 qsizetype sz = (tagStackStringStorage.size() - pos);
208 tagStackStringStorageSize += sz;
209 return XmlStringRef(&tagStackStringStorage, pos, sz);
210 }
211
213
214
215 inline Tag tagStack_pop() {
216 Tag tag = tagStack.pop();
217 tagStackStringStorageSize = tag.tagStackStringStorageSize;
218 namespaceDeclarations.resize(tag.namespaceDeclarationsSize);
219 tagsDone = tagStack.isEmpty();
220 return tag;
221 }
222 inline Tag &tagStack_push() {
223 Tag &tag = tagStack.push();
224 tag.tagStackStringStorageSize = tagStackStringStorageSize;
225 tag.namespaceDeclarationsSize = namespaceDeclarations.size();
226 return tag;
227 }
228};
229
230#if QT_CONFIG(xmlstreamreader)
231class QXmlStreamEntityResolver;
232class QXmlStreamReaderPrivate : public QXmlStreamGrammar, public QXmlStreamPrivateTagStack
233{
234 QXmlStreamReader *q_ptr;
235 Q_DECLARE_PUBLIC(QXmlStreamReader)
236public:
237 QXmlStreamReaderPrivate(QXmlStreamReader *q);
238 ~QXmlStreamReaderPrivate();
239 void init();
240
241 struct BufferAndEncoding
242 {
243 QByteArray buffer;
244 // System means that we didn't specify the encoding
245 QStringDecoder::Encoding encoding;
246
247 BufferAndEncoding()
248 : buffer(), encoding(QStringDecoder::System)
249 {}
250 BufferAndEncoding(const QByteArray &b, QStringDecoder::Encoding e)
251 : buffer(b), encoding(e)
252 {}
253 };
254 QList<BufferAndEncoding> dataInfo;
255 QStringDecoder chunkDecoder;
256 void appendDataWithEncoding(const QByteArray &data, QStringDecoder::Encoding enc);
257 void addData(const QByteArray &data, QStringDecoder::Encoding enc);
258
259 QByteArray rawReadBuffer;
260 uchar firstByte;
261 qint64 nbytesread;
262 QString readBuffer;
263 qsizetype readBufferPos;
264 QXmlStreamSimpleStack<uint> putStack;
265 struct Entity {
266 Entity() = default;
267 Entity(const QString &name, const QString &value)
268 : name(name), value(value), external(false), unparsed(false), literal(false),
269 hasBeenParsed(false), isCurrentlyReferenced(false){}
270 static inline Entity createLiteral(QLatin1StringView name, QLatin1StringView value)
271 { Entity result(name, value); result.literal = result.hasBeenParsed = true; return result; }
272 QString name, value;
273 uint external : 1;
274 uint unparsed : 1;
275 uint literal : 1;
276 uint hasBeenParsed : 1;
277 uint isCurrentlyReferenced : 1;
278 };
279 // these hash tables use a QStringView as a key to avoid creating QStrings
280 // just for lookup. The keys are usually views into Entity::name and thus
281 // are guaranteed to have the same lifetime as the referenced data:
282 QHash<QStringView, Entity> entityHash;
283 QHash<QStringView, Entity> parameterEntityHash;
284 struct QEntityReference
285 {
286 QHash<QStringView, Entity> *hash;
287 QStringView name;
288 };
289 QXmlStreamSimpleStack<QEntityReference> entityReferenceStack;
290 int entityExpansionLimit = 4096;
291 int entityLength = 0;
292 inline bool referenceEntity(QHash<QStringView, Entity> *hash, Entity &entity)
293 {
294 Q_ASSERT(hash);
295 if (entity.isCurrentlyReferenced) {
296 raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected."));
297 return false;
298 }
299 // entityLength represents the amount of additional characters the
300 // entity expands into (can be negative for e.g. &amp;). It's used to
301 // avoid DoS attacks through recursive entity expansions
302 entityLength += entity.value.size() - entity.name.size() - 2;
303 if (entityLength > entityExpansionLimit) {
304 raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit."));
305 return false;
306 }
307 entity.isCurrentlyReferenced = true;
308 entityReferenceStack.push() = { hash, entity.name };
309 injectToken(ENTITY_DONE);
310 return true;
311 }
312
313
314 QIODevice *device;
315 bool deleteDevice;
316 QStringDecoder decoder;
317 bool atEnd;
318
319 enum class XmlContext
320 {
321 Prolog,
322 Body,
323 };
324
325 XmlContext currentContext = XmlContext::Prolog;
326 bool foundDTD = false;
327 bool isValidToken(QXmlStreamReader::TokenType type);
328 void checkToken();
329
330 /*!
331 \sa setType()
332 */
333 QXmlStreamReader::TokenType type;
334 QXmlStreamReader::Error error;
335 QString errorString;
336 QString unresolvedEntity;
337
338 qint64 lineNumber, lastLineStart, characterOffset;
339
340
341 void write(const QString &);
342 void write(const char *);
343
344
345 QXmlStreamAttributes attributes;
346 XmlStringRef namespaceForPrefix(QStringView prefix);
347 void resolveTag();
348 void resolvePublicNamespaces();
349 void resolveDtd();
350 uint resolveCharRef(int symbolIndex);
351 bool checkStartDocument();
352 void startDocument();
353 void parseError();
354 void checkPublicLiteral(QStringView publicId);
355
356 bool scanDtd;
357 XmlStringRef lastAttributeValue;
358 bool lastAttributeIsCData;
359 struct DtdAttribute {
360 XmlStringRef tagName;
361 XmlStringRef attributeQualifiedName;
362 XmlStringRef attributePrefix;
363 XmlStringRef attributeName;
364 XmlStringRef defaultValue;
365 bool isCDATA;
366 bool isNamespaceAttribute;
367 };
368 QXmlStreamSimpleStack<DtdAttribute> dtdAttributes;
369 struct NotationDeclaration {
370 XmlStringRef name;
371 XmlStringRef publicId;
372 XmlStringRef systemId;
373 };
374 QXmlStreamSimpleStack<NotationDeclaration> notationDeclarations;
375 QXmlStreamNotationDeclarations publicNotationDeclarations;
376 QXmlStreamNamespaceDeclarations publicNamespaceDeclarations;
377
378 struct EntityDeclaration {
379 XmlStringRef name;
380 XmlStringRef notationName;
381 XmlStringRef publicId;
382 XmlStringRef systemId;
383 XmlStringRef value;
384 bool parameter;
385 bool external;
386 inline void clear() {
387 name.clear();
388 notationName.clear();
389 publicId.clear();
390 systemId.clear();
391 value.clear();
392 parameter = external = false;
393 }
394 };
395 QXmlStreamSimpleStack<EntityDeclaration> entityDeclarations;
396 QXmlStreamEntityDeclarations publicEntityDeclarations;
397
398 XmlStringRef text;
399
400 XmlStringRef prefix, namespaceUri, qualifiedName, name;
401 XmlStringRef processingInstructionTarget, processingInstructionData;
402 XmlStringRef dtdName, dtdPublicId, dtdSystemId;
403 XmlStringRef documentVersion, documentEncoding;
404 uint isEmptyElement : 1;
405 uint isWhitespace : 1;
406 uint isCDATA : 1;
407 uint standalone : 1;
408 uint hasCheckedStartDocument : 1;
409 uint normalizeLiterals : 1;
410 uint hasSeenTag : 1;
411 uint inParseEntity : 1;
412 uint referenceToUnparsedEntityDetected : 1;
413 uint referenceToParameterEntityDetected : 1;
414 uint hasExternalDtdSubset : 1;
415 uint lockEncoding : 1;
416 uint namespaceProcessing : 1;
417 uint hasStandalone : 1; // TODO: expose in public API
418
419 int resumeReduction;
420 void resume(int rule);
421
422 inline bool entitiesMustBeDeclared() const {
423 return (!inParseEntity
424 && (standalone
425 || (!referenceToUnparsedEntityDetected
426 && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25
427 && !hasExternalDtdSubset)));
428 }
429
430 // qlalr parser
431 int tos;
432 int stack_size;
433 struct Value {
434 qsizetype pos; // offset into textBuffer
435 qsizetype len; // length incl. prefix (if any)
436 qint16 prefix; // prefix of a name (as in "prefix:name") limited to 4k in fastScanName()
437 ushort c;
438 };
439
440 Value *sym_stack;
441 int *state_stack;
442 inline void reallocateStack();
443 inline Value &sym(int index) const
444 { return sym_stack[tos + index - 1]; }
445 QString textBuffer;
446 inline void clearTextBuffer() {
447 if (!scanDtd) {
448 textBuffer.resize(0);
449 textBuffer.reserve(256);
450 }
451 }
452 struct Attribute {
453 Value key;
454 Value value;
455 };
456 QXmlStreamSimpleStack<Attribute> attributeStack;
457
458 inline XmlStringRef symString(int index) {
459 return symString(sym(index));
460 }
461 QStringView symView(int index) const
462 {
463 const Value &symbol = sym(index);
464 return QStringView(textBuffer.data() + symbol.pos, symbol.len).mid(symbol.prefix);
465 }
466 inline XmlStringRef symName(int index) {
467 return symName(sym(index));
468 }
469 inline XmlStringRef symPrefix(int index) {
470 return symPrefix(sym(index));
471 }
472 inline XmlStringRef symString(const Value &symbol) {
473 return XmlStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);
474 }
475 inline XmlStringRef symName(const Value &symbol) {
476 return XmlStringRef(&textBuffer, symbol.pos, symbol.len);
477 }
478 inline XmlStringRef symPrefix(const Value &symbol) {
479 if (symbol.prefix)
480 return XmlStringRef(&textBuffer, symbol.pos, symbol.prefix - 1);
481 return XmlStringRef();
482 }
483
484 inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; }
485
486
487 short token;
488 uint token_char;
489
490 uint filterCarriageReturn();
491 inline uint getChar();
492 inline uint peekChar();
493 inline void putChar(uint c) { putStack.push() = c; }
494 inline void putChar(QChar c) { putStack.push() = c.unicode(); }
495 void putString(QStringView s, qsizetype from = 0);
496 void putStringLiteral(QStringView s);
497 void putReplacement(QStringView s);
498 void putReplacementInAttributeValue(QStringView s);
499 uint getChar_helper();
500
501 bool scanUntil(const char *str, short tokenToInject = -1);
502 bool scanString(const char *str, short tokenToInject, bool requireSpace = true);
503 inline void injectToken(ushort tokenToInject) {
504 putChar(int(tokenToInject) << 16);
505 }
506
507 QString resolveUndeclaredEntity(const QString &name);
508 void parseEntity(const QString &value);
509 std::unique_ptr<QXmlStreamReaderPrivate> entityParser;
510
511 bool scanAfterLangleBang();
512 bool scanPublicOrSystem();
513 bool scanNData();
514 bool scanAfterDefaultDecl();
515 bool scanAttType();
516
517
518 // scan optimization functions. Not strictly necessary but LALR is
519 // not very well suited for scanning fast
520 qsizetype fastScanLiteralContent();
521 qsizetype fastScanSpace();
522 qsizetype fastScanContentCharList();
523 std::optional<qsizetype> fastScanName(Value *val = nullptr);
524 inline qsizetype fastScanNMTOKEN();
525
526
527 bool parse();
528 inline void consumeRule(int);
529
530 void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
531 void raiseWellFormedError(const QString &message);
532 void raiseNamePrefixTooLongError();
533
534 QXmlStreamEntityResolver *entityResolver;
535
536private:
537 /*! \internal
538 Never assign to variable type directly. Instead use this function.
539
540 This prevents errors from being ignored.
541 */
542 inline void setType(const QXmlStreamReader::TokenType t)
543 {
544 if (type != QXmlStreamReader::Invalid)
545 type = t;
546 }
547};
548#endif // feature xmlstreamreader
549
550QT_END_NAMESPACE
551
552#endif // QXMLSTREAM_P_H
qsizetype initialTagStackStringStorageSize
XmlStringRef addToStringStorage(QAnyStringView s)
QXmlStreamSimpleStack< NamespaceDeclaration > namespaceDeclarations
QXmlStreamSimpleStack< Tag > tagStack
void resize(qsizetype s)
const T * cbegin() const
const T & top() const
void reserve(qsizetype extraCapacity)
const T * cend() const
const T * begin() const
const T & at(qsizetype index) const
T & operator[](qsizetype index)
qsizetype size() const
const T * end() const
XmlStringRef(const QString *string)
constexpr XmlStringRef()=default
const QString * m_string
constexpr XmlStringRef(const QString *string, qsizetype pos, qsizetype length)
#define MAKE_MEMBER(name)
#define MAKE_OP(op)
NamespaceDeclaration namespaceDeclaration