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
qcborvalue_p.h
Go to the documentation of this file.
1// Copyright (C) 2020 Intel Corporation.
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#ifndef QCBORVALUE_P_H
6#define QCBORVALUE_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API.
13// This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include "qcborvalue.h"
20
21#if QT_CONFIG(cborstreamreader)
22# include "qcborstreamreader.h"
23#endif
24
25#include <private/qglobal_p.h>
26#include <private/qstringconverter_p.h>
27
28#include <math.h>
29
30QT_BEGIN_NAMESPACE
31
32namespace QtCbor {
37
38struct Undefined {};
39struct Element
40{
42 IsContainer = 0x0001,
43 HasByteData = 0x0002,
44 StringIsUtf16 = 0x0004,
46 };
47 Q_DECLARE_FLAGS(ValueFlags, ValueFlag)
48
49 union {
52 };
55
56 Element(qint64 v = 0, QCborValue::Type t = QCborValue::Undefined, ValueFlags f = {})
57 : value(v), type(t), flags(f)
58 {}
59
60 Element(QCborContainerPrivate *d, QCborValue::Type t, ValueFlags f = {})
62 {}
63
64 double fpvalue() const
65 {
66 double d;
67 memcpy(&d, &value, sizeof(d));
68 return d;
69 }
70};
71Q_DECLARE_OPERATORS_FOR_FLAGS(Element::ValueFlags)
72static_assert(sizeof(Element) == 16);
73
75{
77
78 const char *byte() const { return reinterpret_cast<const char *>(this + 1); }
79 char *byte() { return reinterpret_cast<char *>(this + 1); }
80 const QChar *utf16() const { return reinterpret_cast<const QChar *>(this + 1); }
81 QChar *utf16() { return reinterpret_cast<QChar *>(this + 1); }
82
83 QByteArray toByteArray() const { return QByteArray(byte(), len); }
84 QString toString() const { return QString(utf16(), len / 2); }
85 QString toUtf8String() const { return QString::fromUtf8(byte(), len); }
86
87 QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), len); }
88 QLatin1StringView asLatin1() const { return {byte(), len}; }
89 QUtf8StringView asUtf8StringView() const { return QUtf8StringView(byte(), len); }
90 QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
91 QString asQStringRaw() const { return QString::fromRawData(utf16(), len / 2); }
92};
94static_assert(std::is_trivially_copyable<ByteData>::value);
95static_assert(std::is_standard_layout<ByteData>::value);
96} // namespace QtCbor
97
99
101{
102 friend class QExplicitlySharedDataPointer<QCborContainerPrivate>;
103 ~QCborContainerPrivate();
104
105public:
111
113
114 union {
116 QCborContainerPrivate *nextToDelete; // only used in d-tor
117 };
120
121 void deref() { if (!ref.deref()) delete this; }
122 void compact();
123 static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
124 static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
125 static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
126
127 static qptrdiff addByteDataImpl(QByteArray &target, QByteArray::size_type &targetUsed,
128 const char *block, qsizetype len)
129 {
130 // This function does not do overflow checking, since the len parameter
131 // is expected to be trusted. There's another version of this function
132 // in decodeStringFromCbor(), which checks.
133
134 qptrdiff offset = target.size();
135
136 // align offset
137 offset += alignof(QtCbor::ByteData) - 1;
138 offset &= ~(alignof(QtCbor::ByteData) - 1);
139
140 qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
141
142 targetUsed += increment;
143 target.resize(offset + increment);
144
145 char *ptr = target.begin() + offset;
146 auto b = new (ptr) QtCbor::ByteData;
147 b->len = len;
148 if (block)
149 memcpy(b->byte(), block, len);
150
151 return offset;
152 }
153
154 qptrdiff addByteData(const char *block, qsizetype len)
155 {
156 return addByteDataImpl(data, usedData, block, len);
157 }
158
160 {
161 if ((e.flags & QtCbor::Element::HasByteData) == 0)
162 return nullptr;
163
164 size_t offset = size_t(e.value);
165 Q_ASSERT((offset % alignof(QtCbor::ByteData)) == 0);
166 Q_ASSERT(offset + sizeof(QtCbor::ByteData) <= size_t(data.size()));
167
168 auto b = reinterpret_cast<const QtCbor::ByteData *>(data.constData() + offset);
169 Q_ASSERT(offset + sizeof(*b) + size_t(b->len) <= size_t(data.size()));
170 return b;
171 }
172 const QtCbor::ByteData *byteData(qsizetype idx) const
173 {
174 return byteData(elements.at(idx));
175 }
176
177 QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
178 {
179 const QtCbor::Element &e = elements.at(idx);
180 if (e.type != type || (e.flags & QtCbor::Element::IsContainer) == 0)
181 return nullptr;
182 return e.container;
183 }
184
185 void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp);
186 void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
187 {
188 if (value.container)
189 return replaceAt_complex(e, value, disp);
190
191 e = { value.value_helper(), value.type() };
192 if (value.isContainer())
193 e.container = nullptr;
194 }
195 void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
196 {
197 QtCbor::Element &e = elements[idx];
198 if (e.flags & QtCbor::Element::IsContainer) {
199 e.container->deref();
200 e.container = nullptr;
201 e.flags = {};
202 } else if (auto b = byteData(e)) {
203 usedData -= b->len + sizeof(QtCbor::ByteData);
204 }
205 replaceAt_internal(e, value, disp);
206 }
207 void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
208 {
209 replaceAt_internal(*elements.insert(idx, {}), value, disp);
210 }
211
213 {
214 elements.append(QtCbor::Element());
215 }
216 void append(qint64 value)
217 {
218 elements.append(QtCbor::Element(value , QCborValue::Integer));
219 }
220 void append(QCborTag tag)
221 {
222 elements.append(QtCbor::Element(qint64(tag), QCborValue::Tag));
223 }
224 void appendByteData(const char *data, qsizetype len, QCborValue::Type type,
225 QtCbor::Element::ValueFlags extraFlags = {})
226 {
227 elements.append(QtCbor::Element(addByteData(data, len), type,
228 QtCbor::Element::HasByteData | extraFlags));
229 }
230 void appendAsciiString(const char *str, qsizetype len)
231 {
232 appendByteData(str, len, QCborValue::String, QtCbor::Element::StringIsAscii);
233 }
234 void appendUtf8String(const char *str, qsizetype len)
235 {
236 appendByteData(str, len, QCborValue::String);
237 }
238 void append(QLatin1StringView s)
239 {
240 if (!QtPrivate::isAscii(s))
241 return appendNonAsciiString(QString(s));
242
243 // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
244 appendByteData(s.latin1(), s.size(), QCborValue::String,
245 QtCbor::Element::StringIsAscii);
246 }
247 void appendAsciiString(QStringView s);
248 void appendNonAsciiString(QStringView s);
249
250 void append(const QString &s)
251 {
252 append(qToStringViewIgnoringNull(s));
253 }
254
255 void append(QStringView s)
256 {
257 if (QtPrivate::isAscii(s))
258 appendAsciiString(s);
259 else
260 appendNonAsciiString(s);
261 }
262 void append(const QCborValue &v)
263 {
264 insertAt(elements.size(), v);
265 }
266 void append(QCborValue &&v)
267 {
268 insertAt(elements.size(), v, MoveContainer);
269 v.container = nullptr;
270 v.t = QCborValue::Undefined;
271 }
272
273 QByteArray byteArrayAt(qsizetype idx) const
274 {
275 const auto &e = elements.at(idx);
276 const auto data = byteData(e);
277 if (!data)
278 return QByteArray();
279 return data->toByteArray();
280 }
281 QString stringAt(qsizetype idx) const
282 {
283 const auto &e = elements.at(idx);
284 const auto data = byteData(e);
285 if (!data)
286 return QString();
287 if (e.flags & QtCbor::Element::StringIsUtf16)
288 return data->toString();
289 if (e.flags & QtCbor::Element::StringIsAscii)
290 return data->asLatin1();
291 return data->toUtf8String();
292 }
293 QAnyStringView anyStringViewAt(qsizetype idx) const
294 {
295 const auto &e = elements.at(idx);
296 const auto data = byteData(e);
297 if (!data)
298 return nullptr;
299 if (e.flags & QtCbor::Element::StringIsUtf16)
300 return data->asStringView();
301 if (e.flags & QtCbor::Element::StringIsAscii)
302 return data->asLatin1();
303 return data->asUtf8StringView();
304 }
305
306 static void resetValue(QCborValue &v)
307 {
308 v.container = nullptr;
309 }
310
311 static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr,
313 {
314 QCborValue result;
315 result.t = type;
316 result.n = n;
317 result.container = d;
318 if (d && disp == CopyContainer)
319 d->ref.ref();
320 return result;
321 }
322
323 QCborValue valueAt(qsizetype idx) const
324 {
325 const auto &e = elements.at(idx);
326
327 if (e.flags & QtCbor::Element::IsContainer) {
328 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
329 // invalid tags can be created due to incomplete parsing
330 return makeValue(QCborValue::Invalid, 0, nullptr);
331 }
332 return makeValue(e.type, -1, e.container);
333 } else if (e.flags & QtCbor::Element::HasByteData) {
334 return makeValue(e.type, idx, const_cast<QCborContainerPrivate *>(this));
335 }
336 return makeValue(e.type, e.value);
337 }
339 QCborValue extractAt(qsizetype idx)
340 {
341 QtCbor::Element e;
342 qSwap(e, elements[idx]);
343
344 if (e.flags & QtCbor::Element::IsContainer) {
345 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
346 // invalid tags can be created due to incomplete parsing
347 e.container->deref();
348 return makeValue(QCborValue::Invalid, 0, nullptr);
349 }
350 return makeValue(e.type, -1, e.container, MoveContainer);
351 } else if (e.flags & QtCbor::Element::HasByteData) {
352 return extractAt_complex(e);
353 }
354 return makeValue(e.type, e.value);
355 }
356
357 static QtCbor::Element elementFromValue(const QCborValue &value)
358 {
359 if (value.n >= 0 && value.container)
360 return value.container->elements.at(value.n);
361
362 QtCbor::Element e;
363 e.value = value.n;
364 e.type = value.t;
365 if (value.container) {
366 e.container = value.container;
368 }
369 return e;
370 }
371
372 static int compareUtf8(const QtCbor::ByteData *b, QLatin1StringView s)
373 {
374 return QUtf8::compareUtf8(QByteArrayView(b->byte(), b->len), s);
375 }
376
377 static int compareUtf8(const QtCbor::ByteData *b, QStringView s)
378 {
379 return QUtf8::compareUtf8(QByteArrayView(b->byte(), b->len), s);
380 }
381
382 template<typename String>
383 int stringCompareElement(const QtCbor::Element &e, String s, QtCbor::Comparison mode) const
384 {
385 if (e.type != QCborValue::String)
386 return int(e.type) - int(QCborValue::String);
387
388 const QtCbor::ByteData *b = byteData(e);
389 if (!b)
390 return s.isEmpty() ? 0 : -1;
391
392 if (e.flags & QtCbor::Element::StringIsUtf16) {
394 return b->asStringView() == s ? 0 : 1;
395 return b->asStringView().compare(s);
396 }
397 return compareUtf8(b, s);
398 }
399
400 template<typename String>
401 bool stringEqualsElement(const QtCbor::Element &e, String s) const
402 {
403 return stringCompareElement(e, s, QtCbor::Comparison::ForEquality) == 0;
404 }
405
406 template<typename String>
407 bool stringEqualsElement(qsizetype idx, String s) const
408 {
409 return stringEqualsElement(elements.at(idx), s);
410 }
411
413 const QCborContainerPrivate *c2, QtCbor::Element e2,
414 QtCbor::Comparison mode) noexcept;
415 int compareElement(qsizetype idx, const QCborValue &value, QtCbor::Comparison mode) const
416 {
417 auto &e1 = elements.at(idx);
418 auto e2 = elementFromValue(value);
419 return compareElement_helper(this, e1, value.container, e2, mode);
420 }
421
422 void removeAt(qsizetype idx)
423 {
424 replaceAt(idx, {});
425 elements.remove(idx);
426 }
427
428 // doesn't apply to JSON
429 template <typename KeyType> QCborValueConstRef findCborMapKey(KeyType key)
430 {
431 qsizetype i = 0;
432 for ( ; i < elements.size(); i += 2) {
433 const auto &e = elements.at(i);
434 bool equals;
435 if constexpr (std::is_same_v<std::decay_t<KeyType>, QCborValue>) {
436 equals = (compareElement(i, key, QtCbor::Comparison::ForEquality) == 0);
437 } else if constexpr (std::is_integral_v<KeyType>) {
438 equals = (e.type == QCborValue::Integer && e.value == key);
439 } else {
440 // assume it's a string
441 equals = stringEqualsElement(i, key);
442 }
443 if (equals)
444 break;
445 }
446 return { this, i + 1 };
447 }
448 template <typename KeyType> static QCborValue findCborMapKey(const QCborValue &self, KeyType key)
449 {
450 if (self.isMap() && self.container) {
451 qsizetype idx = self.container->findCborMapKey(key).i;
452 if (idx < self.container->elements.size())
453 return self.container->valueAt(idx);
454 }
455 return QCborValue();
456 }
457 template <typename KeyType> static QCborValueRef
458 findOrAddMapKey(QCborContainerPrivate *container, KeyType key)
459 {
460 qsizetype size = 0;
461 qsizetype index = size + 1;
462 if (container) {
463 size = container->elements.size();
464 index = container->findCborMapKey<KeyType>(key).i; // returns size + 1 if not found
465 }
466 Q_ASSERT(index & 1);
467 Q_ASSERT((size & 1) == 0);
468
469 container = detach(container, qMax(index + 1, size));
470 Q_ASSERT(container);
471 Q_ASSERT((container->elements.size() & 1) == 0);
472
473 if (index >= size) {
474 container->append(key);
475 container->append(QCborValue());
476 }
477 Q_ASSERT(index < container->elements.size());
478 return { container, index };
479 }
480 template <typename KeyType> static QCborValueRef findOrAddMapKey(QCborMap &map, KeyType key);
481 template <typename KeyType> static QCborValueRef findOrAddMapKey(QCborValue &self, KeyType key);
482 template <typename KeyType> static QCborValueRef findOrAddMapKey(QCborValueRef self, KeyType key);
483
484#if QT_CONFIG(cborstreamreader)
488#endif
489};
490
491QT_END_NAMESPACE
492
493#endif // QCBORVALUE_P_H
QString stringAt(qsizetype idx) const
void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp=CopyContainer)
QByteArray::size_type usedData
const QtCbor::ByteData * byteData(QtCbor::Element e) const
void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
QCborContainerPrivate(QCborContainerPrivate &&)=default
QCborContainerPrivate * nextToDelete
void appendUtf8String(const char *str, qsizetype len)
void append(QCborValue &&v)
void append(const QString &s)
static QCborValueRef findOrAddMapKey(QCborMap &map, KeyType key)
Definition qcbormap.cpp:881
const QtCbor::ByteData * byteData(qsizetype idx) const
void appendByteData(const char *data, qsizetype len, QCborValue::Type type, QtCbor::Element::ValueFlags extraFlags={})
static QCborContainerPrivate * grow(QCborContainerPrivate *d, qsizetype index)
int stringCompareElement(const QtCbor::Element &e, String s, QtCbor::Comparison mode) const
static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1, const QCborContainerPrivate *c2, QtCbor::Element e2, QtCbor::Comparison mode) noexcept
QCborContainerPrivate(const QCborContainerPrivate &)=default
static QCborContainerPrivate * detach(QCborContainerPrivate *d, qsizetype reserved)
QCborContainerPrivate & operator=(QCborContainerPrivate &&)=delete
bool stringEqualsElement(const QtCbor::Element &e, String s) const
QCborContainerPrivate()=default
void removeAt(qsizetype idx)
static int compareUtf8(const QtCbor::ByteData *b, QLatin1StringView s)
QCborValueConstRef findCborMapKey(KeyType key)
void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp=CopyContainer)
QList< QtCbor::Element > elements
QCborContainerPrivate & operator=(const QCborContainerPrivate &)=delete
void appendAsciiString(const char *str, qsizetype len)
static QCborValueRef findOrAddMapKey(QCborValueRef self, KeyType key)
QCborValue extractAt(qsizetype idx)
QAnyStringView anyStringViewAt(qsizetype idx) const
void appendAsciiString(QStringView s)
void appendNonAsciiString(QStringView s)
void append(QtCbor::Undefined)
static qptrdiff addByteDataImpl(QByteArray &target, QByteArray::size_type &targetUsed, const char *block, qsizetype len)
QByteArray byteArrayAt(qsizetype idx) const
QCborContainerPrivate * containerAt(qsizetype idx, QCborValue::Type type) const
static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d=nullptr, ContainerDisposition disp=CopyContainer)
int compareElement(qsizetype idx, const QCborValue &value, QtCbor::Comparison mode) const
static QCborValueRef findOrAddMapKey(QCborContainerPrivate *container, KeyType key)
QCborValue extractAt_complex(QtCbor::Element e)
static QCborValueRef findOrAddMapKey(QCborValue &self, KeyType key)
qptrdiff addByteData(const char *block, qsizetype len)
static QtCbor::Element elementFromValue(const QCborValue &value)
void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
static void resetValue(QCborValue &v)
static QCborValue findCborMapKey(const QCborValue &self, KeyType key)
bool stringEqualsElement(qsizetype idx, String s) const
QCborValue valueAt(qsizetype idx) const
void append(qint64 value)
static QCborContainerPrivate * clone(QCborContainerPrivate *d, qsizetype reserved=-1)
\inmodule QtCore\reentrant
Definition qcborvalue.h:48
Combined button and popup list for selecting options.
QDebug operator<<(QDebug dbg, const QCborArray &a)
size_t qHash(const QCborArray &array, size_t seed)
QDataStream & operator>>(QDataStream &stream, QCborArray &value)
Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE)
\inmodule QtCore\reentrant
Definition qcborvalue.h:38
QString toUtf8String() const
QStringView asStringView() const
QUtf8StringView asUtf8StringView() const
QLatin1StringView asLatin1() const
QString asQStringRaw() const
const QChar * utf16() const
QString toString() const
const char * byte() const
QByteArray::size_type len
QByteArray asByteArrayView() const
QByteArray toByteArray() const
double fpvalue() const
Element(qint64 v=0, QCborValue::Type t=QCborValue::Undefined, ValueFlags f={})
Element(QCborContainerPrivate *d, QCborValue::Type t, ValueFlags f={})
ValueFlags flags