1/****************************************************************************
2**
3** Copyright (C) 2018 Intel Corporation.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module 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 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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QCBORVALUE_P_H
41#define QCBORVALUE_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API.
48// This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include "qcborvalue.h"
55
56#include <private/qglobal_p.h>
57#include <private/qutfcodec_p.h>
58
59#include <math.h>
60
61QT_BEGIN_NAMESPACE
62
63namespace QtCbor {
64struct Undefined {};
65struct Element
66{
67 enum ValueFlag : quint32 {
68 IsContainer = 0x0001,
69 HasByteData = 0x0002,
70 StringIsUtf16 = 0x0004,
71 StringIsAscii = 0x0008
72 };
73 Q_DECLARE_FLAGS(ValueFlags, ValueFlag)
74
75 union {
76 qint64 value;
77 QCborContainerPrivate *container;
78 };
79 QCborValue::Type type;
80 ValueFlags flags = {};
81
82 Element(qint64 v = 0, QCborValue::Type t = QCborValue::Undefined, ValueFlags f = {})
83 : value(v), type(t), flags(f)
84 {}
85
86 Element(QCborContainerPrivate *d, QCborValue::Type t, ValueFlags f = {})
87 : container(d), type(t), flags(f | IsContainer)
88 {}
89
90 double fpvalue() const
91 {
92 double d;
93 memcpy(dest: &d, src: &value, n: sizeof(d));
94 return d;
95 }
96};
97Q_DECLARE_OPERATORS_FOR_FLAGS(Element::ValueFlags)
98Q_STATIC_ASSERT(sizeof(Element) == 16);
99
100struct ByteData
101{
102 QByteArray::size_type len;
103
104 const char *byte() const { return reinterpret_cast<const char *>(this + 1); }
105 char *byte() { return reinterpret_cast<char *>(this + 1); }
106 const QChar *utf16() const { return reinterpret_cast<const QChar *>(this + 1); }
107 QChar *utf16() { return reinterpret_cast<QChar *>(this + 1); }
108
109 QByteArray toByteArray() const { return QByteArray(byte(), len); }
110 QString toString() const { return QString(utf16(), len / 2); }
111 QString toUtf8String() const { return QString::fromUtf8(str: byte(), size: len); }
112
113 QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), size: len); }
114 QLatin1String asLatin1() const { return QLatin1String(byte(), len); }
115 QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
116 QString asQStringRaw() const { return QString::fromRawData(utf16(), size: len / 2); }
117};
118Q_STATIC_ASSERT(std::is_trivial<ByteData>::value);
119Q_STATIC_ASSERT(std::is_standard_layout<ByteData>::value);
120} // namespace QtCbor
121
122Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE);
123
124class QCborContainerPrivate : public QSharedData
125{
126 friend class QExplicitlySharedDataPointer<QCborContainerPrivate>;
127 ~QCborContainerPrivate();
128
129public:
130 enum ContainerDisposition { CopyContainer, MoveContainer };
131 enum class ConversionMode { FromRaw, FromVariantToJson };
132
133 QByteArray::size_type usedData = 0;
134 QByteArray data;
135 QVector<QtCbor::Element> elements;
136
137 void deref() { if (!ref.deref()) delete this; }
138 void compact(qsizetype reserved);
139 static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
140 static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
141 static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
142
143 static QCborMap fromVariantMap(const QVariantMap &map,
144 ConversionMode mode = ConversionMode::FromRaw);
145
146 static QCborArray fromVariantList(const QVariantList &list,
147 ConversionMode mode = ConversionMode::FromRaw);
148
149 qptrdiff addByteData(const char *block, qsizetype len)
150 {
151 // This function does not do overflow checking, since the len parameter
152 // is expected to be trusted. There's another version of this function
153 // in decodeStringFromCbor(), which checks.
154
155 qptrdiff offset = data.size();
156
157 // align offset
158 offset += Q_ALIGNOF(QtCbor::ByteData) - 1;
159 offset &= ~(Q_ALIGNOF(QtCbor::ByteData) - 1);
160
161 qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
162
163 usedData += increment;
164 data.resize(size: offset + increment);
165
166 char *ptr = data.begin() + offset;
167 auto b = new (ptr) QtCbor::ByteData;
168 b->len = len;
169 if (block)
170 memcpy(dest: b->byte(), src: block, n: len);
171
172 return offset;
173 }
174
175 const QtCbor::ByteData *byteData(QtCbor::Element e) const
176 {
177 if ((e.flags & QtCbor::Element::HasByteData) == 0)
178 return nullptr;
179
180 size_t offset = size_t(e.value);
181 Q_ASSERT((offset % Q_ALIGNOF(QtCbor::ByteData)) == 0);
182 Q_ASSERT(offset + sizeof(QtCbor::ByteData) <= size_t(data.size()));
183
184 auto b = reinterpret_cast<const QtCbor::ByteData *>(data.constData() + offset);
185 Q_ASSERT(offset + sizeof(*b) + size_t(b->len) <= size_t(data.size()));
186 return b;
187 }
188 const QtCbor::ByteData *byteData(qsizetype idx) const
189 {
190 return byteData(e: elements.at(i: idx));
191 }
192
193 QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
194 {
195 const QtCbor::Element &e = elements.at(i: idx);
196 if (e.type != type || (e.flags & QtCbor::Element::IsContainer) == 0)
197 return nullptr;
198 return e.container;
199 }
200
201 void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp);
202 void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
203 {
204 if (value.container)
205 return replaceAt_complex(e, value, disp);
206
207 e = { value.value_helper(), value.type() };
208 if (value.isContainer())
209 e.container = nullptr;
210 }
211 void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
212 {
213 QtCbor::Element &e = elements[idx];
214 if (e.flags & QtCbor::Element::IsContainer) {
215 e.container->deref();
216 e.container = nullptr;
217 e.flags = {};
218 } else if (auto b = byteData(e)) {
219 usedData -= b->len + sizeof(QtCbor::ByteData);
220 }
221 replaceAt_internal(e, value, disp);
222 }
223 void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
224 {
225 replaceAt_internal(e&: *elements.insert(before: elements.begin() + idx, t: {}), value, disp);
226 }
227
228 void append(QtCbor::Undefined)
229 {
230 elements.append(t: QtCbor::Element());
231 }
232 void append(qint64 value)
233 {
234 elements.append(t: QtCbor::Element(value , QCborValue::Integer));
235 }
236 void append(QCborTag tag)
237 {
238 elements.append(t: QtCbor::Element(qint64(tag), QCborValue::Tag));
239 }
240 void appendByteData(const char *data, qsizetype len, QCborValue::Type type,
241 QtCbor::Element::ValueFlags extraFlags = {})
242 {
243 elements.append(t: QtCbor::Element(addByteData(block: data, len), type,
244 QtCbor::Element::HasByteData | extraFlags));
245 }
246 void append(QLatin1String s)
247 {
248 if (!QtPrivate::isAscii(s))
249 return append(s: QString(s));
250
251 // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
252 appendByteData(data: s.latin1(), len: s.size(), type: QCborValue::String,
253 extraFlags: QtCbor::Element::StringIsAscii);
254 }
255 void appendAsciiString(QStringView s);
256
257#if QT_STRINGVIEW_LEVEL < 2
258 void append(const QString &s)
259 {
260 append(s: qToStringViewIgnoringNull(s));
261 }
262#endif
263
264 void append(QStringView s)
265 {
266 if (QtPrivate::isAscii(s))
267 appendAsciiString(s);
268 else
269 appendByteData(data: reinterpret_cast<const char *>(s.utf16()), len: s.size() * 2,
270 type: QCborValue::String, extraFlags: QtCbor::Element::StringIsUtf16);
271 }
272 void append(const QCborValue &v)
273 {
274 insertAt(idx: elements.size(), value: v);
275 }
276
277 QByteArray byteArrayAt(qsizetype idx) const
278 {
279 const auto &e = elements.at(i: idx);
280 const auto data = byteData(e);
281 if (!data)
282 return QByteArray();
283 return data->toByteArray();
284 }
285 QString stringAt(qsizetype idx) const
286 {
287 const auto &e = elements.at(i: idx);
288 const auto data = byteData(e);
289 if (!data)
290 return QString();
291 if (e.flags & QtCbor::Element::StringIsUtf16)
292 return data->toString();
293 if (e.flags & QtCbor::Element::StringIsAscii)
294 return data->asLatin1();
295 return data->toUtf8String();
296 }
297
298 static void resetValue(QCborValue &v)
299 {
300 v.container = nullptr;
301 }
302
303 static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr,
304 ContainerDisposition disp = CopyContainer)
305 {
306 QCborValue result(type);
307 result.n = n;
308 result.container = d;
309 if (d && disp == CopyContainer)
310 d->ref.ref();
311 return result;
312 }
313
314 QCborValue valueAt(qsizetype idx) const
315 {
316 const auto &e = elements.at(i: idx);
317
318 if (e.flags & QtCbor::Element::IsContainer) {
319 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
320 // invalid tags can be created due to incomplete parsing
321 return makeValue(type: QCborValue::Invalid, n: 0, d: nullptr);
322 }
323 return makeValue(type: e.type, n: -1, d: e.container);
324 } else if (e.flags & QtCbor::Element::HasByteData) {
325 return makeValue(type: e.type, n: idx, d: const_cast<QCborContainerPrivate *>(this));
326 }
327 return makeValue(type: e.type, n: e.value);
328 }
329 QCborValue extractAt_complex(QtCbor::Element e);
330 QCborValue extractAt(qsizetype idx)
331 {
332 QtCbor::Element e;
333 qSwap(value1&: e, value2&: elements[idx]);
334
335 if (e.flags & QtCbor::Element::IsContainer) {
336 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
337 // invalid tags can be created due to incomplete parsing
338 e.container->deref();
339 return makeValue(type: QCborValue::Invalid, n: 0, d: nullptr);
340 }
341 return makeValue(type: e.type, n: -1, d: e.container, disp: MoveContainer);
342 } else if (e.flags & QtCbor::Element::HasByteData) {
343 return extractAt_complex(e);
344 }
345 return makeValue(type: e.type, n: e.value);
346 }
347
348 static QtCbor::Element elementFromValue(const QCborValue &value)
349 {
350 if (value.n >= 0 && value.container)
351 return value.container->elements.at(i: value.n);
352
353 QtCbor::Element e;
354 e.value = value.n;
355 e.type = value.t;
356 if (value.container) {
357 e.container = value.container;
358 e.flags = QtCbor::Element::IsContainer;
359 }
360 return e;
361 }
362
363 static int compareUtf8(const QtCbor::ByteData *b, const QLatin1String &s)
364 {
365 return QUtf8::compareUtf8(b->byte(), b->len, s);
366 }
367
368 static int compareUtf8(const QtCbor::ByteData *b, QStringView s)
369 {
370 return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size());
371 }
372
373 template<typename String>
374 int stringCompareElement(const QtCbor::Element &e, String s) const
375 {
376 if (e.type != QCborValue::String)
377 return int(e.type) - int(QCborValue::String);
378
379 const QtCbor::ByteData *b = byteData(e);
380 if (!b)
381 return s.isEmpty() ? 0 : -1;
382
383 if (e.flags & QtCbor::Element::StringIsUtf16)
384 return QtPrivate::compareStrings(b->asStringView(), s);
385 return compareUtf8(b, s);
386 }
387
388 template<typename String>
389 bool stringEqualsElement(const QtCbor::Element &e, String s) const
390 {
391 return stringCompareElement(e, s) == 0;
392 }
393
394 template<typename String>
395 bool stringEqualsElement(qsizetype idx, String s) const
396 {
397 return stringEqualsElement(elements.at(i: idx), s);
398 }
399
400 static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
401 const QCborContainerPrivate *c2, QtCbor::Element e2);
402 int compareElement(qsizetype idx, const QCborValue &value) const
403 {
404 auto &e1 = elements.at(i: idx);
405 auto e2 = elementFromValue(value);
406 return compareElement_helper(c1: this, e1, c2: value.container, e2);
407 }
408
409 void removeAt(qsizetype idx)
410 {
411 replaceAt(idx, value: {});
412 elements.remove(i: idx);
413 }
414
415 void decodeValueFromCbor(QCborStreamReader &reader, int remainiingStackDepth);
416 void decodeStringFromCbor(QCborStreamReader &reader);
417 static inline void setErrorInReader(QCborStreamReader &reader, QCborError error);
418};
419
420QT_END_NAMESPACE
421
422#endif // QCBORVALUE_P_H
423

source code of qtbase/src/corelib/serialization/qcborvalue_p.h