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