1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
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 #include "qbinaryjson_p.h"
41 
42 #include <qjsonobject.h>
43 #include <qjsonarray.h>
44 
45 QT_BEGIN_NAMESPACE
46 
47 namespace QBinaryJsonPrivate {
48 
49 static Q_CONSTEXPR Base emptyArray  = {
50     { qle_uint(sizeof(Base)) },
51     { 0 },
52     { qle_uint(0) }
53 };
54 
55 static Q_CONSTEXPR Base emptyObject = {
56     { qle_uint(sizeof(Base)) },
57     { qToLittleEndian(1U) },
58     { qle_uint(0) }
59 };
60 
compact()61 void MutableData::compact()
62 {
63     Q_STATIC_ASSERT(sizeof(Value) == sizeof(offset));
64 
65     Base *base = header->root();
66     int reserve = 0;
67     if (base->is_object) {
68         auto *o = static_cast<Object *>(base);
69         for (uint i = 0; i < o->length; ++i)
70             reserve += o->entryAt(i)->usedStorage(o);
71     } else {
72         auto *a = static_cast<Array *>(base);
73         for (uint i = 0; i < a->length; ++i)
74             reserve += a->at(i)->usedStorage(a);
75     }
76 
77     uint size = sizeof(Base) + reserve + base->length * sizeof(offset);
78     uint alloc = sizeof(Header) + size;
79     auto *h = reinterpret_cast<Header *>(malloc(alloc));
80     Q_CHECK_PTR(h);
81     h->tag = QJsonDocument::BinaryFormatTag;
82     h->version = 1;
83     Base *b = h->root();
84     b->size = size;
85     b->is_object = header->root()->is_object;
86     b->length = base->length;
87     b->tableOffset = reserve + sizeof(Array);
88 
89     uint offset = sizeof(Base);
90     if (b->is_object) {
91         const auto *o = static_cast<const Object *>(base);
92         auto *no = static_cast<Object *>(b);
93 
94         for (uint i = 0; i < o->length; ++i) {
95             no->table()[i] = offset;
96 
97             const Entry *e = o->entryAt(i);
98             Entry *ne = no->entryAt(i);
99             uint s = e->size();
100             memcpy(ne, e, s);
101             offset += s;
102             uint dataSize = e->value.usedStorage(o);
103             if (dataSize) {
104                 memcpy(reinterpret_cast<char *>(no) + offset, e->value.data(o), dataSize);
105                 ne->value.value = offset;
106                 offset += dataSize;
107             }
108         }
109     } else {
110         const auto *a = static_cast<const Array *>(base);
111         auto *na = static_cast<Array *>(b);
112 
113         for (uint i = 0; i < a->length; ++i) {
114             const Value *v = a->at(i);
115             Value *nv = na->at(i);
116             *nv = *v;
117             uint dataSize = v->usedStorage(a);
118             if (dataSize) {
119                 memcpy(reinterpret_cast<char *>(na) + offset, v->data(a), dataSize);
120                 nv->value = offset;
121                 offset += dataSize;
122             }
123         }
124     }
125     Q_ASSERT(offset == uint(b->tableOffset));
126 
127     free(header);
128     header = h;
129     this->alloc = alloc;
130     compactionCounter = 0;
131 }
132 
isValid() const133 bool ConstData::isValid() const
134 {
135     if (header->tag != QJsonDocument::BinaryFormatTag || header->version != 1U)
136         return false;
137 
138     const Base *root = header->root();
139     const uint maxSize = alloc - sizeof(Header);
140     return root->is_object
141             ? static_cast<const Object *>(root)->isValid(maxSize)
142             : static_cast<const Array *>(root)->isValid(maxSize);
143 }
144 
toJsonDocument() const145 QJsonDocument ConstData::toJsonDocument() const
146 {
147     const Base *root = header->root();
148     return root->is_object
149             ? QJsonDocument(static_cast<const Object *>(root)->toJsonObject())
150             : QJsonDocument(static_cast<const Array *>(root)->toJsonArray());
151 }
152 
reserveSpace(uint dataSize,uint posInTable,uint numItems,bool replace)153 uint Base::reserveSpace(uint dataSize, uint posInTable, uint numItems, bool replace)
154 {
155     Q_ASSERT(posInTable <= length);
156     if (size + dataSize >= Value::MaxSize) {
157         qWarning("QJson: Document too large to store in data structure %d %d %d",
158                  uint(size), dataSize, Value::MaxSize);
159         return 0;
160     }
161 
162     offset off = tableOffset;
163     // move table to new position
164     if (replace) {
165         memmove(reinterpret_cast<char *>(table()) + dataSize, table(), length * sizeof(offset));
166     } else {
167         memmove(reinterpret_cast<char *>(table() + posInTable + numItems) + dataSize,
168                 table() + posInTable, (length - posInTable) * sizeof(offset));
169         memmove(reinterpret_cast<char *>(table()) + dataSize, table(), posInTable * sizeof(offset));
170     }
171     tableOffset += dataSize;
172     for (uint i = 0; i < numItems; ++i)
173         table()[posInTable + i] = off;
174     size += dataSize;
175     if (!replace) {
176         length += numItems;
177         size += numItems * sizeof(offset);
178     }
179     return off;
180 }
181 
indexOf(QStringView key,bool * exists) const182 uint Object::indexOf(QStringView key, bool *exists) const
183 {
184     uint min = 0;
185     uint n = length;
186     while (n > 0) {
187         uint half = n >> 1;
188         uint middle = min + half;
189         if (*entryAt(middle) >= key) {
190             n = half;
191         } else {
192             min = middle + 1;
193             n -= half + 1;
194         }
195     }
196     if (min < length && *entryAt(min) == key) {
197         *exists = true;
198         return min;
199     }
200     *exists = false;
201     return min;
202 }
203 
toJsonObject() const204 QJsonObject Object::toJsonObject() const
205 {
206     QJsonObject object;
207     for (uint i = 0; i < length; ++i) {
208         const Entry *e = entryAt(i);
209         object.insert(e->key(), e->value.toJsonValue(this));
210     }
211     return object;
212 }
213 
isValid(uint maxSize) const214 bool Object::isValid(uint maxSize) const
215 {
216     if (size > maxSize || tableOffset + length * sizeof(offset) > size)
217         return false;
218 
219     QString lastKey;
220     for (uint i = 0; i < length; ++i) {
221         if (table()[i] + sizeof(Entry) >= tableOffset)
222             return false;
223         const Entry *e = entryAt(i);
224         if (!e->isValid(tableOffset - table()[i]))
225             return false;
226         const QString key = e->key();
227         if (key < lastKey)
228             return false;
229         if (!e->value.isValid(this))
230             return false;
231         lastKey = key;
232     }
233     return true;
234 }
235 
toJsonArray() const236 QJsonArray Array::toJsonArray() const
237 {
238     QJsonArray array;
239     const offset *values = table();
240     for (uint i = 0; i < length; ++i)
241         array.append(reinterpret_cast<const Value *>(values + i)->toJsonValue(this));
242     return array;
243 }
244 
isValid(uint maxSize) const245 bool Array::isValid(uint maxSize) const
246 {
247     if (size > maxSize || tableOffset + length * sizeof(offset) > size)
248         return false;
249 
250     const offset *values = table();
251     for (uint i = 0; i < length; ++i) {
252         if (!reinterpret_cast<const Value *>(values + i)->isValid(this))
253             return false;
254     }
255     return true;
256 }
257 
usedStorage(const Base * b) const258 uint Value::usedStorage(const Base *b) const
259 {
260     uint s = 0;
261     switch (type) {
262     case QJsonValue::Double:
263         if (!latinOrIntValue)
264             s = sizeof(double);
265         break;
266     case QJsonValue::String: {
267         const char *d = data(b);
268         s = latinOrIntValue
269                 ? (sizeof(ushort)
270                    + qFromLittleEndian(*reinterpret_cast<const ushort *>(d)))
271                 : (sizeof(int)
272                    + sizeof(ushort) * qFromLittleEndian(*reinterpret_cast<const int *>(d)));
273         break;
274     }
275     case QJsonValue::Array:
276     case QJsonValue::Object:
277         s = base(b)->size;
278         break;
279     case QJsonValue::Null:
280     case QJsonValue::Bool:
281     default:
282         break;
283     }
284     return alignedSize(s);
285 }
286 
toJsonValue(const Base * b) const287 QJsonValue Value::toJsonValue(const Base *b) const
288 {
289     switch (type) {
290     case QJsonValue::Null:
291         return QJsonValue(QJsonValue::Null);
292     case QJsonValue::Bool:
293         return QJsonValue(toBoolean());
294     case QJsonValue::Double:
295         return QJsonValue(toDouble(b));
296     case QJsonValue::String:
297         return QJsonValue(toString(b));
298     case QJsonValue::Array:
299         return static_cast<const Array *>(base(b))->toJsonArray();
300     case QJsonValue::Object:
301         return static_cast<const Object *>(base(b))->toJsonObject();
302     case QJsonValue::Undefined:
303         return QJsonValue(QJsonValue::Undefined);
304     }
305     Q_UNREACHABLE();
306     return QJsonValue(QJsonValue::Undefined);
307 }
308 
isValidValueOffset(uint offset,uint tableOffset)309 inline bool isValidValueOffset(uint offset, uint tableOffset)
310 {
311     return offset >= sizeof(Base)
312         && offset + sizeof(uint) <= tableOffset;
313 }
314 
isValid(const Base * b) const315 bool Value::isValid(const Base *b) const
316 {
317     switch (type) {
318     case QJsonValue::Null:
319     case QJsonValue::Bool:
320         return true;
321     case QJsonValue::Double:
322         return latinOrIntValue || isValidValueOffset(value, b->tableOffset);
323     case QJsonValue::String:
324         if (!isValidValueOffset(value, b->tableOffset))
325             return false;
326         if (latinOrIntValue)
327             return asLatin1String(b).isValid(b->tableOffset - value);
328         return asString(b).isValid(b->tableOffset - value);
329     case QJsonValue::Array:
330         return isValidValueOffset(value, b->tableOffset)
331             && static_cast<const Array *>(base(b))->isValid(b->tableOffset - value);
332     case QJsonValue::Object:
333         return isValidValueOffset(value, b->tableOffset)
334             && static_cast<const Object *>(base(b))->isValid(b->tableOffset - value);
335     default:
336         return false;
337     }
338 }
339 
requiredStorage(const QBinaryJsonValue & v,bool * compressed)340 uint Value::requiredStorage(const QBinaryJsonValue &v, bool *compressed)
341 {
342     *compressed = false;
343     switch (v.type()) {
344     case QJsonValue::Double:
345         if (QBinaryJsonPrivate::compressedNumber(v.toDouble()) != INT_MAX) {
346             *compressed = true;
347             return 0;
348         }
349         return sizeof(double);
350     case QJsonValue::String: {
351         QString s = v.toString();
352         *compressed = QBinaryJsonPrivate::useCompressed(s);
353         return QBinaryJsonPrivate::qStringSize(s, *compressed);
354     }
355     case QJsonValue::Array:
356     case QJsonValue::Object:
357         return v.base ? uint(v.base->size) : sizeof(QBinaryJsonPrivate::Base);
358     case QJsonValue::Undefined:
359     case QJsonValue::Null:
360     case QJsonValue::Bool:
361         break;
362     }
363     return 0;
364 }
365 
valueToStore(const QBinaryJsonValue & v,uint offset)366 uint Value::valueToStore(const QBinaryJsonValue &v, uint offset)
367 {
368     switch (v.type()) {
369     case QJsonValue::Undefined:
370     case QJsonValue::Null:
371         break;
372     case QJsonValue::Bool:
373         return v.toBool();
374     case QJsonValue::Double: {
375         int c = QBinaryJsonPrivate::compressedNumber(v.toDouble());
376         if (c != INT_MAX)
377             return c;
378     }
379         Q_FALLTHROUGH();
380     case QJsonValue::String:
381     case QJsonValue::Array:
382     case QJsonValue::Object:
383         return offset;
384     }
385     return 0;
386 }
387 
copyData(const QBinaryJsonValue & v,char * dest,bool compressed)388 void Value::copyData(const QBinaryJsonValue &v, char *dest, bool compressed)
389 {
390     switch (v.type()) {
391     case QJsonValue::Double:
392         if (!compressed)
393             qToLittleEndian(v.toDouble(), dest);
394         break;
395     case QJsonValue::String: {
396         const QString str = v.toString();
397         QBinaryJsonPrivate::copyString(dest, str, compressed);
398         break;
399     }
400     case QJsonValue::Array:
401     case QJsonValue::Object: {
402         const QBinaryJsonPrivate::Base *b = v.base;
403         if (!b)
404             b = (v.type() == QJsonValue::Array ? &emptyArray : &emptyObject);
405         memcpy(dest, b, b->size);
406         break;
407     }
408     default:
409         break;
410     }
411 }
412 
413 } // namespace QBinaryJsonPrivate
414 
415 QT_END_NAMESPACE
416