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/qstringconverter_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(&d, &value, sizeof(d));
94 return d;
95 }
96};
97Q_DECLARE_OPERATORS_FOR_FLAGS(Element::ValueFlags)
98static_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(byte(), len); }
112
113 QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), 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(), len / 2); }
117};
118static_assert(std::is_trivial<ByteData>::value);
119static_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
132 QByteArray::size_type usedData = 0;
133 QByteArray data;
134 QList<QtCbor::Element> elements;
135
136 void deref() { if (!ref.deref()) delete this; }
137 void compact(qsizetype reserved);
138 static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
139 static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
140 static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
141
142 qptrdiff addByteData(const char *block, qsizetype len)
143 {
144 // This function does not do overflow checking, since the len parameter
145 // is expected to be trusted. There's another version of this function
146 // in decodeStringFromCbor(), which checks.
147
148 qptrdiff offset = data.size();
149
150 // align offset
151 offset += alignof(QtCbor::ByteData) - 1;
152 offset &= ~(alignof(QtCbor::ByteData) - 1);
153
154 qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
155
156 usedData += increment;
157 data.resize(offset + increment);
158
159 char *ptr = data.begin() + offset;
160 auto b = new (ptr) QtCbor::ByteData;
161 b->len = len;
162 if (block)
163 memcpy(b->byte(), block, len);
164
165 return offset;
166 }
167
168 const QtCbor::ByteData *byteData(QtCbor::Element e) const
169 {
170 if ((e.flags & QtCbor::Element::HasByteData) == 0)
171 return nullptr;
172
173 size_t offset = size_t(e.value);
174 Q_ASSERT((offset % alignof(QtCbor::ByteData)) == 0);
175 Q_ASSERT(offset + sizeof(QtCbor::ByteData) <= size_t(data.size()));
176
177 auto b = reinterpret_cast<const QtCbor::ByteData *>(data.constData() + offset);
178 Q_ASSERT(offset + sizeof(*b) + size_t(b->len) <= size_t(data.size()));
179 return b;
180 }
181 const QtCbor::ByteData *byteData(qsizetype idx) const
182 {
183 return byteData(elements.at(idx));
184 }
185
186 QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
187 {
188 const QtCbor::Element &e = elements.at(idx);
189 if (e.type != type || (e.flags & QtCbor::Element::IsContainer) == 0)
190 return nullptr;
191 return e.container;
192 }
193
194 void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp);
195 void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
196 {
197 if (value.container)
198 return replaceAt_complex(e, value, disp);
199
200 e = { value.value_helper(), value.type() };
201 if (value.isContainer())
202 e.container = nullptr;
203 }
204 void replaceAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
205 {
206 QtCbor::Element &e = elements[idx];
207 if (e.flags & QtCbor::Element::IsContainer) {
208 e.container->deref();
209 e.container = nullptr;
210 e.flags = {};
211 } else if (auto b = byteData(e)) {
212 usedData -= b->len + sizeof(QtCbor::ByteData);
213 }
214 replaceAt_internal(e, value, disp);
215 }
216 void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
217 {
218 replaceAt_internal(*elements.insert(elements.begin() + int(idx), {}), value, disp);
219 }
220
221 void append(QtCbor::Undefined)
222 {
223 elements.append(QtCbor::Element());
224 }
225 void append(qint64 value)
226 {
227 elements.append(QtCbor::Element(value , QCborValue::Integer));
228 }
229 void append(QCborTag tag)
230 {
231 elements.append(QtCbor::Element(qint64(tag), QCborValue::Tag));
232 }
233 void appendByteData(const char *data, qsizetype len, QCborValue::Type type,
234 QtCbor::Element::ValueFlags extraFlags = {})
235 {
236 elements.append(QtCbor::Element(addByteData(data, len), type,
237 QtCbor::Element::HasByteData | extraFlags));
238 }
239 void appendAsciiString(const QString &s);
240 void appendAsciiString(const char *str, qsizetype len)
241 {
242 appendByteData(str, len, QCborValue::String, QtCbor::Element::StringIsAscii);
243 }
244 void appendUtf8String(const char *str, qsizetype len)
245 {
246 appendByteData(str, len, QCborValue::String);
247 }
248 void append(QLatin1String s)
249 {
250 if (!QtPrivate::isAscii(s))
251 return append(QString(s));
252
253 // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
254 appendByteData(s.latin1(), s.size(), QCborValue::String,
255 QtCbor::Element::StringIsAscii);
256 }
257 void appendAsciiString(QStringView s);
258
259#if QT_STRINGVIEW_LEVEL < 2
260 void append(const QString &s)
261 {
262 append(qToStringViewIgnoringNull(s));
263 }
264#endif
265
266 void append(QStringView s)
267 {
268 if (QtPrivate::isAscii(s))
269 appendAsciiString(s);
270 else
271 appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
272 QCborValue::String, QtCbor::Element::StringIsUtf16);
273 }
274 void append(const QCborValue &v)
275 {
276 insertAt(elements.size(), v);
277 }
278
279 QByteArray byteArrayAt(qsizetype idx) const
280 {
281 const auto &e = elements.at(idx);
282 const auto data = byteData(e);
283 if (!data)
284 return QByteArray();
285 return data->toByteArray();
286 }
287 QString stringAt(qsizetype idx) const
288 {
289 const auto &e = elements.at(idx);
290 const auto data = byteData(e);
291 if (!data)
292 return QString();
293 if (e.flags & QtCbor::Element::StringIsUtf16)
294 return data->toString();
295 if (e.flags & QtCbor::Element::StringIsAscii)
296 return data->asLatin1();
297 return data->toUtf8String();
298 }
299
300 static void resetValue(QCborValue &v)
301 {
302 v.container = nullptr;
303 }
304
305 static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr,
306 ContainerDisposition disp = CopyContainer)
307 {
308 QCborValue result(type);
309 result.n = n;
310 result.container = d;
311 if (d && disp == CopyContainer)
312 d->ref.ref();
313 return result;
314 }
315
316 QCborValue valueAt(qsizetype idx) const
317 {
318 const auto &e = elements.at(idx);
319
320 if (e.flags & QtCbor::Element::IsContainer) {
321 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
322 // invalid tags can be created due to incomplete parsing
323 return makeValue(QCborValue::Invalid, 0, nullptr);
324 }
325 return makeValue(e.type, -1, e.container);
326 } else if (e.flags & QtCbor::Element::HasByteData) {
327 return makeValue(e.type, idx, const_cast<QCborContainerPrivate *>(this));
328 }
329 return makeValue(e.type, e.value);
330 }
331 QCborValue extractAt_complex(QtCbor::Element e);
332 QCborValue extractAt(qsizetype idx)
333 {
334 QtCbor::Element e;
335 qSwap(e, elements[idx]);
336
337 if (e.flags & QtCbor::Element::IsContainer) {
338 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
339 // invalid tags can be created due to incomplete parsing
340 e.container->deref();
341 return makeValue(QCborValue::Invalid, 0, nullptr);
342 }
343 return makeValue(e.type, -1, e.container, MoveContainer);
344 } else if (e.flags & QtCbor::Element::HasByteData) {
345 return extractAt_complex(e);
346 }
347 return makeValue(e.type, e.value);
348 }
349
350 static QtCbor::Element elementFromValue(const QCborValue &value)
351 {
352 if (value.n >= 0 && value.container)
353 return value.container->elements.at(value.n);
354
355 QtCbor::Element e;
356 e.value = value.n;
357 e.type = value.t;
358 if (value.container) {
359 e.container = value.container;
360 e.flags = QtCbor::Element::IsContainer;
361 }
362 return e;
363 }
364
365 static int compareUtf8(const QtCbor::ByteData *b, const QLatin1String &s)
366 {
367 return QUtf8::compareUtf8(QByteArrayView(b->byte(), b->len), s);
368 }
369
370 static int compareUtf8(const QtCbor::ByteData *b, QStringView s)
371 {
372 return QUtf8::compareUtf8(QByteArrayView(b->byte(), b->len), s);
373 }
374
375 template<typename String>
376 int stringCompareElement(const QtCbor::Element &e, String s) const
377 {
378 if (e.type != QCborValue::String)
379 return int(e.type) - int(QCborValue::String);
380
381 const QtCbor::ByteData *b = byteData(e);
382 if (!b)
383 return s.isEmpty() ? 0 : -1;
384
385 if (e.flags & QtCbor::Element::StringIsUtf16)
386 return QtPrivate::compareStrings(b->asStringView(), s);
387 return compareUtf8(b, s);
388 }
389
390 template<typename String>
391 bool stringEqualsElement(const QtCbor::Element &e, String s) const
392 {
393 return stringCompareElement(e, s) == 0;
394 }
395
396 template<typename String>
397 bool stringEqualsElement(qsizetype idx, String s) const
398 {
399 return stringEqualsElement(elements.at(idx), s);
400 }
401
402 static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
403 const QCborContainerPrivate *c2, QtCbor::Element e2);
404 int compareElement(qsizetype idx, const QCborValue &value) const
405 {
406 auto &e1 = elements.at(idx);
407 auto e2 = elementFromValue(value);
408 return compareElement_helper(this, e1, value.container, e2);
409 }
410
411 void removeAt(qsizetype idx)
412 {
413 replaceAt(idx, {});
414 elements.remove(idx);
415 }
416
417 void decodeValueFromCbor(QCborStreamReader &reader, int remainiingStackDepth);
418 void decodeStringFromCbor(QCborStreamReader &reader);
419 static inline void setErrorInReader(QCborStreamReader &reader, QCborError error);
420};
421
422QT_END_NAMESPACE
423
424#endif // QCBORVALUE_P_H
425