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 
61 QT_BEGIN_NAMESPACE
62 
63 namespace QtCbor {
64 struct Undefined {};
65 struct 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 = {})
valueElement83         : value(v), type(t), flags(f)
84     {}
85 
86     Element(QCborContainerPrivate *d, QCborValue::Type t, ValueFlags f = {})
containerElement87         : container(d), type(t), flags(f | IsContainer)
88     {}
89 
fpvalueElement90     double fpvalue() const
91     {
92         double d;
93         memcpy(&d, &value, sizeof(d));
94         return d;
95     }
96 };
97 Q_DECLARE_OPERATORS_FOR_FLAGS(Element::ValueFlags)
98 Q_STATIC_ASSERT(sizeof(Element) == 16);
99 
100 struct ByteData
101 {
102     QByteArray::size_type len;
103 
byteByteData104     const char *byte() const        { return reinterpret_cast<const char *>(this + 1); }
byteByteData105     char *byte()                    { return reinterpret_cast<char *>(this + 1); }
utf16ByteData106     const QChar *utf16() const      { return reinterpret_cast<const QChar *>(this + 1); }
utf16ByteData107     QChar *utf16()                  { return reinterpret_cast<QChar *>(this + 1); }
108 
toByteArrayByteData109     QByteArray toByteArray() const  { return QByteArray(byte(), len); }
toStringByteData110     QString toString() const        { return QString(utf16(), len / 2); }
toUtf8StringByteData111     QString toUtf8String() const    { return QString::fromUtf8(byte(), len); }
112 
asByteArrayViewByteData113     QByteArray asByteArrayView() const { return QByteArray::fromRawData(byte(), len); }
asLatin1ByteData114     QLatin1String asLatin1() const  { return QLatin1String(byte(), len); }
asStringViewByteData115     QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
asQStringRawByteData116     QString asQStringRaw() const    { return QString::fromRawData(utf16(), len / 2); }
117 };
118 Q_STATIC_ASSERT(std::is_trivial<ByteData>::value);
119 Q_STATIC_ASSERT(std::is_standard_layout<ByteData>::value);
120 } // namespace QtCbor
121 
122 Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE);
123 
124 class QCborContainerPrivate : public QSharedData
125 {
126     friend class QExplicitlySharedDataPointer<QCborContainerPrivate>;
127     ~QCborContainerPrivate();
128 
129 public:
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 
deref()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 
addByteData(const char * block,qsizetype len)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(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(b->byte(), block, len);
171 
172         return offset;
173     }
174 
byteData(QtCbor::Element e)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     }
byteData(qsizetype idx)188     const QtCbor::ByteData *byteData(qsizetype idx) const
189     {
190         return byteData(elements.at(idx));
191     }
192 
containerAt(qsizetype idx,QCborValue::Type type)193     QCborContainerPrivate *containerAt(qsizetype idx, QCborValue::Type type) const
194     {
195         const QtCbor::Element &e = elements.at(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);
replaceAt_internal(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(*elements.insert(elements.begin() + idx, {}), value, disp);
226     }
227 
append(QtCbor::Undefined)228     void append(QtCbor::Undefined)
229     {
230         elements.append(QtCbor::Element());
231     }
append(qint64 value)232     void append(qint64 value)
233     {
234         elements.append(QtCbor::Element(value , QCborValue::Integer));
235     }
append(QCborTag tag)236     void append(QCborTag tag)
237     {
238         elements.append(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(QtCbor::Element(addByteData(data, len), type,
244                                         QtCbor::Element::HasByteData | extraFlags));
245     }
append(QLatin1String s)246     void append(QLatin1String s)
247     {
248         if (!QtPrivate::isAscii(s))
249             return append(QString(s));
250 
251         // US-ASCII is a subset of UTF-8, so we can keep in 8-bit
252         appendByteData(s.latin1(), s.size(), QCborValue::String,
253                        QtCbor::Element::StringIsAscii);
254     }
255     void appendAsciiString(QStringView s);
256 
257 #if QT_STRINGVIEW_LEVEL < 2
append(const QString & s)258     void append(const QString &s)
259     {
260         append(qToStringViewIgnoringNull(s));
261     }
262 #endif
263 
append(QStringView s)264     void append(QStringView s)
265     {
266         if (QtPrivate::isAscii(s))
267             appendAsciiString(s);
268         else
269             appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
270                            QCborValue::String, QtCbor::Element::StringIsUtf16);
271     }
append(const QCborValue & v)272     void append(const QCborValue &v)
273     {
274         insertAt(elements.size(), v);
275     }
276 
byteArrayAt(qsizetype idx)277     QByteArray byteArrayAt(qsizetype idx) const
278     {
279         const auto &e = elements.at(idx);
280         const auto data = byteData(e);
281         if (!data)
282             return QByteArray();
283         return data->toByteArray();
284     }
stringAt(qsizetype idx)285     QString stringAt(qsizetype idx) const
286     {
287         const auto &e = elements.at(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 
resetValue(QCborValue & v)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 
valueAt(qsizetype idx)314     QCborValue valueAt(qsizetype idx) const
315     {
316         const auto &e = elements.at(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(QCborValue::Invalid, 0, nullptr);
322             }
323             return makeValue(e.type, -1, e.container);
324         } else if (e.flags & QtCbor::Element::HasByteData) {
325             return makeValue(e.type, idx, const_cast<QCborContainerPrivate *>(this));
326         }
327         return makeValue(e.type, e.value);
328     }
329     QCborValue extractAt_complex(QtCbor::Element e);
extractAt(qsizetype idx)330     QCborValue extractAt(qsizetype idx)
331     {
332         QtCbor::Element e;
333         qSwap(e, 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(QCborValue::Invalid, 0, nullptr);
340             }
341             return makeValue(e.type, -1, e.container, MoveContainer);
342         } else if (e.flags & QtCbor::Element::HasByteData) {
343             return extractAt_complex(e);
344         }
345         return makeValue(e.type, e.value);
346     }
347 
elementFromValue(const QCborValue & value)348     static QtCbor::Element elementFromValue(const QCborValue &value)
349     {
350         if (value.n >= 0 && value.container)
351             return value.container->elements.at(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 
compareUtf8(const QtCbor::ByteData * b,const QLatin1String & s)363     static int compareUtf8(const QtCbor::ByteData *b, const QLatin1String &s)
364     {
365         return QUtf8::compareUtf8(b->byte(), b->len, s);
366     }
367 
compareUtf8(const QtCbor::ByteData * b,QStringView s)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>
stringCompareElement(const QtCbor::Element & e,String s)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>
stringEqualsElement(const QtCbor::Element & e,String s)389     bool stringEqualsElement(const QtCbor::Element &e, String s) const
390     {
391         return stringCompareElement(e, s) == 0;
392     }
393 
394     template<typename String>
stringEqualsElement(qsizetype idx,String s)395     bool stringEqualsElement(qsizetype idx, String s) const
396     {
397         return stringEqualsElement(elements.at(idx), s);
398     }
399 
400     static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
401                                      const QCborContainerPrivate *c2, QtCbor::Element e2);
compareElement(qsizetype idx,const QCborValue & value)402     int compareElement(qsizetype idx, const QCborValue &value) const
403     {
404         auto &e1 = elements.at(idx);
405         auto e2 = elementFromValue(value);
406         return compareElement_helper(this, e1, value.container, e2);
407     }
408 
removeAt(qsizetype idx)409     void removeAt(qsizetype idx)
410     {
411         replaceAt(idx, {});
412         elements.remove(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 
420 QT_END_NAMESPACE
421 
422 #endif // QCBORVALUE_P_H
423