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(&d, &value, 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(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};
118Q_STATIC_ASSERT(std::is_pod<ByteData>::value);
119} // namespace QtCbor
120
121Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE);
122
123class QCborContainerPrivate : public QSharedData
124{
125 friend class QExplicitlySharedDataPointer<QCborContainerPrivate>;
126 ~QCborContainerPrivate();
127
128public:
129 enum ContainerDisposition { CopyContainer, MoveContainer };
130
131 QByteArray::size_type usedData = 0;
132 QByteArray data;
133 QVector<QtCbor::Element> elements;
134
135 void deref() { if (!ref.deref()) delete this; }
136 void compact(qsizetype reserved);
137 static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
138 static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
139 static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
140
141 qptrdiff addByteData(const char *block, qsizetype len)
142 {
143 // This function does not do overflow checking, since the len parameter
144 // is expected to be trusted. There's another version of this function
145 // in decodeStringFromCbor(), which checks.
146
147 qptrdiff offset = data.size();
148
149 // align offset
150 offset += Q_ALIGNOF(QtCbor::ByteData) - 1;
151 offset &= ~(Q_ALIGNOF(QtCbor::ByteData) - 1);
152
153 qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
154
155 usedData += increment;
156 data.resize(offset + increment);
157
158 char *ptr = data.begin() + offset;
159 auto b = new (ptr) QtCbor::ByteData;
160 b->len = len;
161 if (block)
162 memcpy(b->byte(), block, len);
163
164 return offset;
165 }
166
167 const QtCbor::ByteData *byteData(QtCbor::Element e) const
168 {
169 if ((e.flags & QtCbor::Element::HasByteData) == 0)
170 return nullptr;
171
172 size_t offset = size_t(e.value);
173 Q_ASSERT((offset % Q_ALIGNOF(QtCbor::ByteData)) == 0);
174 Q_ASSERT(offset + sizeof(QtCbor::ByteData) <= size_t(data.size()));
175
176 auto b = reinterpret_cast<const QtCbor::ByteData *>(data.constData() + offset);
177 Q_ASSERT(offset + sizeof(*b) + size_t(b->len) <= size_t(data.size()));
178 return b;
179 }
180 const QtCbor::ByteData *byteData(qsizetype idx) const
181 {
182 return byteData(elements.at(idx));
183 }
184
185 QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
186 {
187 const QtCbor::Element &e = elements.at(idx);
188 if (e.type != type || (e.flags & QtCbor::Element::IsContainer) == 0)
189 return nullptr;
190 return e.container;
191 }
192
193 void replaceAt_complex(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp);
194 void replaceAt_internal(QtCbor::Element &e, const QCborValue &value, ContainerDisposition disp)
195 {
196 if (value.container)
197 return replaceAt_complex(e, value, disp);
198
199 e.value = value.value_helper();
200 e.type = 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() + 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 append(QLatin1String s)
240 {
241 if (!QtPrivate::isAscii(s))
242 return append(QString(s));
243
244 // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
245 appendByteData(s.latin1(), s.size(), QCborValue::String,
246 QtCbor::Element::StringIsAscii);
247 }
248 void appendAsciiString(const QString &s);
249 void append(const QString &s)
250 {
251 if (QtPrivate::isAscii(s))
252 appendAsciiString(s);
253 else
254 appendByteData(reinterpret_cast<const char *>(s.constData()), s.size() * 2,
255 QCborValue::String, QtCbor::Element::StringIsUtf16);
256 }
257 void append(const QCborValue &v)
258 {
259 insertAt(elements.size(), v);
260 }
261
262 QByteArray byteArrayAt(qsizetype idx) const
263 {
264 const auto &e = elements.at(idx);
265 const auto data = byteData(e);
266 if (!data)
267 return QByteArray();
268 return data->toByteArray();
269 }
270 QString stringAt(qsizetype idx) const
271 {
272 const auto &e = elements.at(idx);
273 const auto data = byteData(e);
274 if (!data)
275 return QString();
276 if (e.flags & QtCbor::Element::StringIsUtf16)
277 return data->toString();
278 if (e.flags & QtCbor::Element::StringIsAscii)
279 return data->asLatin1();
280 return data->toUtf8String();
281 }
282
283 static void resetValue(QCborValue &v)
284 {
285 v.container = nullptr;
286 }
287
288 static QCborValue makeValue(QCborValue::Type type, qint64 n, QCborContainerPrivate *d = nullptr,
289 ContainerDisposition disp = CopyContainer)
290 {
291 QCborValue result(type);
292 result.n = n;
293 result.container = d;
294 if (d && disp == CopyContainer)
295 d->ref.ref();
296 return result;
297 }
298
299 QCborValue valueAt(qsizetype idx) const
300 {
301 const auto &e = elements.at(idx);
302
303 if (e.flags & QtCbor::Element::IsContainer) {
304 if (e.type == QCborValue::Tag && e.container->elements.size() != 2) {
305 // invalid tags can be created due to incomplete parsing
306 return makeValue(QCborValue::Invalid, 0, nullptr);
307 }
308 return makeValue(e.type, -1, e.container);
309 } else if (e.flags & QtCbor::Element::HasByteData) {
310 return makeValue(e.type, idx, const_cast<QCborContainerPrivate *>(this));
311 }
312 return makeValue(e.type, e.value);
313 }
314 QCborValue extractAt_complex(QtCbor::Element e);
315 QCborValue extractAt(qsizetype idx)
316 {
317 QtCbor::Element e;
318 qSwap(e, elements[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 e.container->deref();
324 return makeValue(QCborValue::Invalid, 0, nullptr);
325 }
326 return makeValue(e.type, -1, e.container, MoveContainer);
327 } else if (e.flags & QtCbor::Element::HasByteData) {
328 return extractAt_complex(e);
329 }
330 return makeValue(e.type, e.value);
331 }
332
333 static QtCbor::Element elementFromValue(const QCborValue &value)
334 {
335 if (value.n >= 0 && value.container)
336 return value.container->elements.at(value.n);
337
338 QtCbor::Element e;
339 e.value = value.n;
340 e.type = value.t;
341 if (value.container) {
342 e.container = value.container;
343 e.flags = QtCbor::Element::IsContainer;
344 }
345 return e;
346 }
347
348 bool stringEqualsElement(qsizetype idx, QLatin1String s) const
349 {
350 const auto &e = elements.at(idx);
351 if (e.type != QCborValue::String)
352 return false;
353
354 const QtCbor::ByteData *b = byteData(idx);
355 if (!b)
356 return s.isEmpty();
357
358 if (e.flags & QtCbor::Element::StringIsUtf16)
359 return QtPrivate::compareStrings(b->asStringView(), s) == 0;
360 return QUtf8::compareUtf8(b->byte(), b->len, s) == 0;
361 }
362 bool stringEqualsElement(qsizetype idx, const QString &s) const
363 {
364 const auto &e = elements.at(idx);
365 if (e.type != QCborValue::String)
366 return false;
367
368 const QtCbor::ByteData *b = byteData(idx);
369 if (!b)
370 return s.isEmpty();
371
372 if (e.flags & QtCbor::Element::StringIsUtf16)
373 return QtPrivate::compareStrings(b->asStringView(), s) == 0;
374 return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size()) == 0;
375 }
376
377 static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
378 const QCborContainerPrivate *c2, QtCbor::Element e2);
379 int compareElement(qsizetype idx, const QCborValue &value) const
380 {
381 auto &e1 = elements.at(idx);
382 auto e2 = elementFromValue(value);
383 return compareElement_helper(this, e1, value.container, e2);
384 }
385
386 void removeAt(qsizetype idx)
387 {
388 replaceAt(idx, {});
389 elements.remove(idx);
390 }
391
392 void decodeValueFromCbor(QCborStreamReader &reader);
393 void decodeFromCbor(QCborStreamReader &reader);
394 void decodeStringFromCbor(QCborStreamReader &reader);
395};
396
397QT_END_NAMESPACE
398
399#endif // QCBORVALUE_P_H
400