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
176public:
182
191
192
199
201 {
202 qsizetype pos = tagStackStringStorageSize;
203 if (pos != tagStackStringStorage.size())
204 tagStackStringStorage.resize(pos);
205 s.visit([&](auto s) { tagStackStringStorage.append(s); });
206 qsizetype sz = (tagStackStringStorage.size() - pos);
207 tagStackStringStorageSize += sz;
208 return XmlStringRef(&tagStackStringStorage, pos, sz);
209 }
210
212
213
214 inline Tag tagStack_pop() {
215 Tag tag = tagStack.pop();
216 tagStackStringStorageSize = tag.tagStackStringStorageSize;
217 namespaceDeclarations.resize(tag.namespaceDeclarationsSize);
218 tagsDone = tagStack.isEmpty();
219 return tag;
220 }
221 inline Tag &tagStack_push() {
222 Tag &tag = tagStack.push();
223 tag.tagStackStringStorageSize = tagStackStringStorageSize;
224 tag.namespaceDeclarationsSize = namespaceDeclarations.size();
225 return tag;
226 }
227};
228
229#if QT_CONFIG(xmlstreamreader)
230class QXmlStreamEntityResolver;
231class QXmlStreamReaderPrivate : public QXmlStreamGrammar, public QXmlStreamPrivateTagStack
232{
233 QXmlStreamReader *q_ptr;
234 Q_DECLARE_PUBLIC(QXmlStreamReader)
235public:
236 QXmlStreamReaderPrivate(QXmlStreamReader *q);
237 ~QXmlStreamReaderPrivate();
238 void init();
239
240 struct BufferAndEncoding
241 {
242 QByteArray buffer;
243 // System means that we didn't specify the encoding
244 QStringDecoder::Encoding encoding;
245
246 BufferAndEncoding()
247 : buffer(), encoding(QStringDecoder::System)
248 {}
249 BufferAndEncoding(const QByteArray &b, QStringDecoder::Encoding e)
250 : buffer(b), encoding(e)
251 {}
252 };
253 QList<BufferAndEncoding> dataInfo;
254 QStringDecoder chunkDecoder;
255 void appendDataWithEncoding(const QByteArray &data, QStringDecoder::Encoding enc);
256 void addData(const QByteArray &data, QStringDecoder::Encoding enc);
257
258 QByteArray rawReadBuffer;
259 uchar firstByte;
260 qint64 nbytesread;
261 QString readBuffer;
262 qsizetype readBufferPos;
263 QXmlStreamSimpleStack<uint> putStack;
264 struct Entity {
265 Entity() = default;
266 Entity(const QString &name, const QString &value)
267 : name(name), value(value), external(false), unparsed(false), literal(false),
268 hasBeenParsed(false), isCurrentlyReferenced(false){}
269 static inline Entity createLiteral(QLatin1StringView name, QLatin1StringView value)
270 { Entity result(name, value); result.literal = result.hasBeenParsed = true; return result; }
271 QString name, value;
272 uint external : 1;
273 uint unparsed : 1;
274 uint literal : 1;
275 uint hasBeenParsed : 1;
276 uint isCurrentlyReferenced : 1;
277 };
278 // these hash tables use a QStringView as a key to avoid creating QStrings
279 // just for lookup. The keys are usually views into Entity::name and thus
280 // are guaranteed to have the same lifetime as the referenced data:
281 QHash<QStringView, Entity> entityHash;
282 QHash<QStringView, Entity> parameterEntityHash;
283 struct QEntityReference
284 {
285 QHash<QStringView, Entity> *hash;
286 QStringView name;
287 };
288 QXmlStreamSimpleStack<QEntityReference> entityReferenceStack;
289 int entityExpansionLimit = 4096;
290 int entityLength = 0;
291 inline bool referenceEntity(QHash<QStringView, Entity> *hash, Entity &entity)
292 {
293 Q_ASSERT(hash);
294 if (entity.isCurrentlyReferenced) {
295 raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected."));
296 return false;
297 }
298 // entityLength represents the amount of additional characters the
299 // entity expands into (can be negative for e.g. &amp;). It's used to
300 // avoid DoS attacks through recursive entity expansions
301 entityLength += entity.value.size() - entity.name.size() - 2;
302 if (entityLength > entityExpansionLimit) {
303 raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit."));
304 return false;
305 }
306 entity.isCurrentlyReferenced = true;
307 entityReferenceStack.push() = { hash, entity.name };
308 injectToken(ENTITY_DONE);
309 return true;
310 }
311
312
313 QIODevice *device;
314 bool deleteDevice;
315 QStringDecoder decoder;
316 bool atEnd;
317
318 enum class XmlContext
319 {
320 Prolog,
321 Body,
322 };
323
324 XmlContext currentContext = XmlContext::Prolog;
325 bool foundDTD = false;
326 bool isValidToken(QXmlStreamReader::TokenType type);
327 void checkToken();
328
329 /*!
330 \sa setType()
331 */
332 QXmlStreamReader::TokenType type;
333 QXmlStreamReader::Error error;
334 QString errorString;
335 QString unresolvedEntity;
336
337 qint64 lineNumber, lastLineStart, characterOffset;
338
339
340 void write(const QString &);
341 void write(const char *);
342
343
344 QXmlStreamAttributes attributes;
345 XmlStringRef namespaceForPrefix(QStringView prefix);
346 void resolveTag();
347 void resolvePublicNamespaces();
348 void resolveDtd();
349 uint resolveCharRef(int symbolIndex);
350 bool checkStartDocument();
351 void startDocument();
352 void parseError();
353 void checkPublicLiteral(QStringView publicId);
354
355 bool scanDtd;
356 XmlStringRef lastAttributeValue;
357 bool lastAttributeIsCData;
358 struct DtdAttribute {
359 XmlStringRef tagName;
360 XmlStringRef attributeQualifiedName;
361 XmlStringRef attributePrefix;
362 XmlStringRef attributeName;
363 XmlStringRef defaultValue;
364 bool isCDATA;
365 bool isNamespaceAttribute;
366 };
367 QXmlStreamSimpleStack<DtdAttribute> dtdAttributes;
368 struct NotationDeclaration {
369 XmlStringRef name;
370 XmlStringRef publicId;
371 XmlStringRef systemId;
372 };
373 QXmlStreamSimpleStack<NotationDeclaration> notationDeclarations;
374 QXmlStreamNotationDeclarations publicNotationDeclarations;
375 QXmlStreamNamespaceDeclarations publicNamespaceDeclarations;
376
377 struct EntityDeclaration {
378 XmlStringRef name;
379 XmlStringRef notationName;
380 XmlStringRef publicId;
381 XmlStringRef systemId;
382 XmlStringRef value;
383 bool parameter;
384 bool external;
385 inline void clear() {
386 name.clear();
387 notationName.clear();
388 publicId.clear();
389 systemId.clear();
390 value.clear();
391 parameter = external = false;
392 }
393 };
394 QXmlStreamSimpleStack<EntityDeclaration> entityDeclarations;
395 QXmlStreamEntityDeclarations publicEntityDeclarations;
396
397 XmlStringRef text;
398
399 XmlStringRef prefix, namespaceUri, qualifiedName, name;
400 XmlStringRef processingInstructionTarget, processingInstructionData;
401 XmlStringRef dtdName, dtdPublicId, dtdSystemId;
402 XmlStringRef documentVersion, documentEncoding;
403 uint isEmptyElement : 1;
404 uint isWhitespace : 1;
405 uint isCDATA : 1;
406 uint standalone : 1;
407 uint hasCheckedStartDocument : 1;
408 uint normalizeLiterals : 1;
409 uint hasSeenTag : 1;
410 uint inParseEntity : 1;
411 uint referenceToUnparsedEntityDetected : 1;
412 uint referenceToParameterEntityDetected : 1;
413 uint hasExternalDtdSubset : 1;
414 uint lockEncoding : 1;
415 uint namespaceProcessing : 1;
416 uint hasStandalone : 1; // TODO: expose in public API
417
418 int resumeReduction;
419 void resume(int rule);
420
421 inline bool entitiesMustBeDeclared() const {
422 return (!inParseEntity
423 && (standalone
424 || (!referenceToUnparsedEntityDetected
425 && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25
426 && !hasExternalDtdSubset)));
427 }
428
429 // qlalr parser
430 int tos;
431 int stack_size;
432 struct Value {
433 qsizetype pos; // offset into textBuffer
434 qsizetype len; // length incl. prefix (if any)
435 qint16 prefix; // prefix of a name (as in "prefix:name") limited to 4k in fastScanName()
436 ushort c;
437 };
438
439 Value *sym_stack;
440 int *state_stack;
441 inline void reallocateStack();
442 inline Value &sym(int index) const
443 { return sym_stack[tos + index - 1]; }
444 QString textBuffer;
445 inline void clearTextBuffer() {
446 if (!scanDtd) {
447 textBuffer.resize(0);
448 textBuffer.reserve(256);
449 }
450 }
451 struct Attribute {
452 Value key;
453 Value value;
454 };
455 QXmlStreamSimpleStack<Attribute> attributeStack;
456
457 inline XmlStringRef symString(int index) {
458 const Value &symbol = sym(index);
459 return XmlStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);
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 const Value &symbol = sym(index);
468 return XmlStringRef(&textBuffer, symbol.pos, symbol.len);
469 }
470 inline XmlStringRef symString(int index, int offset) {
471 const Value &symbol = sym(index);
472 return XmlStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset);
473 }
474 inline XmlStringRef symPrefix(int index) {
475 const Value &symbol = sym(index);
476 if (symbol.prefix)
477 return XmlStringRef(&textBuffer, symbol.pos, symbol.prefix - 1);
478 return XmlStringRef();
479 }
480 inline XmlStringRef symString(const Value &symbol) {
481 return XmlStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);
482 }
483 inline XmlStringRef symName(const Value &symbol) {
484 return XmlStringRef(&textBuffer, symbol.pos, symbol.len);
485 }
486 inline XmlStringRef symPrefix(const Value &symbol) {
487 if (symbol.prefix)
488 return XmlStringRef(&textBuffer, symbol.pos, symbol.prefix - 1);
489 return XmlStringRef();
490 }
491
492 inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; }
493
494
495 short token;
496 uint token_char;
497
498 uint filterCarriageReturn();
499 inline uint getChar();
500 inline uint peekChar();
501 inline void putChar(uint c) { putStack.push() = c; }
502 inline void putChar(QChar c) { putStack.push() = c.unicode(); }
503 void putString(QStringView s, qsizetype from = 0);
504 void putStringLiteral(QStringView s);
505 void putReplacement(QStringView s);
506 void putReplacementInAttributeValue(QStringView s);
507 uint getChar_helper();
508
509 bool scanUntil(const char *str, short tokenToInject = -1);
510 bool scanString(const char *str, short tokenToInject, bool requireSpace = true);
511 inline void injectToken(ushort tokenToInject) {
512 putChar(int(tokenToInject) << 16);
513 }
514
515 QString resolveUndeclaredEntity(const QString &name);
516 void parseEntity(const QString &value);
517 std::unique_ptr<QXmlStreamReaderPrivate> entityParser;
518
519 bool scanAfterLangleBang();
520 bool scanPublicOrSystem();
521 bool scanNData();
522 bool scanAfterDefaultDecl();
523 bool scanAttType();
524
525
526 // scan optimization functions. Not strictly necessary but LALR is
527 // not very well suited for scanning fast
528 qsizetype fastScanLiteralContent();
529 qsizetype fastScanSpace();
530 qsizetype fastScanContentCharList();
531 std::optional<qsizetype> fastScanName(Value *val = nullptr);
532 inline qsizetype fastScanNMTOKEN();
533
534
535 bool parse();
536 inline void consumeRule(int);
537
538 void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
539 void raiseWellFormedError(const QString &message);
540 void raiseNamePrefixTooLongError();
541
542 QXmlStreamEntityResolver *entityResolver;
543
544private:
545 /*! \internal
546 Never assign to variable type directly. Instead use this function.
547
548 This prevents errors from being ignored.
549 */
550 inline void setType(const QXmlStreamReader::TokenType t)
551 {
552 if (type != QXmlStreamReader::Invalid)
553 type = t;
554 }
555};
556#endif // feature xmlstreamreader
557
558QT_END_NAMESPACE
559
560#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