blob: 2d4138dceb79c866c0cfaafb0a5197d27f0bdf05 [file] [log] [blame]
Jose Fonsecac296a3e2015-05-01 17:43:54 +01001/**************************************************************************
2 *
3 * Copyright 2015 VMware, Inc
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26
27#include "qubjson.h"
28
29#include <QDebug>
30#include <QVariant>
Jose Fonseca8a5f0ed2015-05-20 16:17:50 +010031#include <QDataStream>
Jose Fonsecac296a3e2015-05-01 17:43:54 +010032
33#include "ubjson.hpp"
34
35
36using namespace ubjson;
37
38
39static Marker
40readMarker(QDataStream &stream)
41{
Jose Fonsecae2e4c362015-05-21 16:12:22 +010042 if (stream.atEnd()) {
43 return MARKER_EOF;
44 }
Jose Fonsecac296a3e2015-05-01 17:43:54 +010045 quint8 byte;
46 stream >> byte;
Jose Fonsecae2e4c362015-05-21 16:12:22 +010047 return static_cast<Marker>(byte);
Jose Fonsecac296a3e2015-05-01 17:43:54 +010048}
49
50
51static int8_t
52readInt8(QDataStream &stream)
53{
Jose Fonseca46b88772015-05-19 16:52:10 +010054 qint8 i;
55 stream >> i;
56 return i;
Jose Fonsecac296a3e2015-05-01 17:43:54 +010057}
58
59static uint8_t
60readUInt8(QDataStream &stream)
61{
Jose Fonseca46b88772015-05-19 16:52:10 +010062 quint8 u;
63 stream >> u;
64 return u;
Jose Fonsecac296a3e2015-05-01 17:43:54 +010065}
66
67static int16_t
68readInt16(QDataStream &stream)
69{
Jose Fonseca46b88772015-05-19 16:52:10 +010070 qint16 i;
71 stream >> i;
72 return i;
Jose Fonsecac296a3e2015-05-01 17:43:54 +010073}
74
75static int32_t
76readInt32(QDataStream &stream)
77{
Jose Fonseca46b88772015-05-19 16:52:10 +010078 qint32 i;
79 stream >> i;
80 return i;
Jose Fonsecac296a3e2015-05-01 17:43:54 +010081}
82
83static int64_t
84readInt64(QDataStream &stream)
85{
Jose Fonseca46b88772015-05-19 16:52:10 +010086 qint64 i;
87 stream >> i;
88 return i;
Jose Fonsecac296a3e2015-05-01 17:43:54 +010089}
90
91static float
92readFloat32(QDataStream &stream)
93{
Jose Fonseca46b88772015-05-19 16:52:10 +010094 float f;
95 stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
96 stream >> f;
97 return f;
Jose Fonsecac296a3e2015-05-01 17:43:54 +010098}
99
Jose Fonseca318743f2015-05-21 23:58:14 +0100100static double
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100101readFloat64(QDataStream &stream)
102{
Jose Fonseca46b88772015-05-19 16:52:10 +0100103 double f;
104 stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
105 stream >> f;
106 return f;
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100107}
108
109
Jose Fonseca016b9342015-05-27 12:14:42 +0100110static int
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100111readSize(QDataStream &stream, Marker type)
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100112{
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100113 switch (type) {
Jose Fonseca016b9342015-05-27 12:14:42 +0100114 case MARKER_INT8: {
115 int8_t size = readInt8(stream);
116 Q_ASSERT(size >= 0);
117 return size;
118 }
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100119 case MARKER_UINT8:
120 return readUInt8(stream);
Jose Fonseca016b9342015-05-27 12:14:42 +0100121 case MARKER_INT16: {
122 int16_t size = readInt16(stream);
123 Q_ASSERT(size >= 0);
124 return size;
125 }
126 case MARKER_INT32: {
127 int32_t size = readInt32(stream);
128 Q_ASSERT(size >= 0);
129 return size;
130 }
131 case MARKER_INT64: {
132 int64_t size = readInt64(stream);
133 Q_ASSERT(size >= 0);
134 Q_ASSERT_X(size <= INT_MAX, "qubjson::readSize", "size too large (https://github.com/apitrace/apitrace/issues/343)");
135 return size;
136 }
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100137 default:
138 Q_UNIMPLEMENTED();
Jose Fonsecae2e4c362015-05-21 16:12:22 +0100139 case MARKER_EOF:
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100140 return 0;
141 }
142}
143
144
145static QString
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100146readChar(QDataStream &stream)
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100147{
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100148 qint8 c;
149 stream >> c;
150 Q_ASSERT(c >= 0);
151 return QChar(c);
152}
153
154
Jose Fonseca016b9342015-05-27 12:14:42 +0100155static int
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100156readSize(QDataStream &stream)
157{
158 Marker type = readMarker(stream);
159 return readSize(stream, type);
160}
161
162
163static QString
Jose Fonseca016b9342015-05-27 12:14:42 +0100164readString(QDataStream &stream, int size)
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100165{
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100166 char *buf = new char [size];
167 stream.readRawData(buf, size);
Jose Fonsecac9c987d2015-05-21 16:12:55 +0100168 QString str = QString::fromUtf8(buf, size);
169 delete [] buf;
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100170 return str;
171}
172
173
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100174static QString
175readString(QDataStream &stream)
176{
Jose Fonseca016b9342015-05-27 12:14:42 +0100177 int size = readSize(stream);
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100178 return readString(stream, size);
179}
180
181
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100182static QVariant
183readVariant(QDataStream &stream, Marker type);
184
185
186static QVariant
187readArray(QDataStream &stream)
188{
189 Marker marker = readMarker(stream);
190 if (marker == MARKER_TYPE) {
191 Marker type = readMarker(stream);
192 Q_ASSERT(type == MARKER_UINT8);
Jose Fonsecae2e4c362015-05-21 16:12:22 +0100193 Q_UNUSED(type);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100194 marker = readMarker(stream);
195 Q_ASSERT(marker == MARKER_COUNT);
Jose Fonseca016b9342015-05-27 12:14:42 +0100196 int count = readSize(stream);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100197 QByteArray array(count, Qt::Uninitialized);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100198 int read = stream.readRawData(array.data(), count);
199 Q_ASSERT(read == count);
Jose Fonsecae2e4c362015-05-21 16:12:22 +0100200 Q_UNUSED(read);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100201 return array;
Jose Fonseca21253f42015-05-22 00:04:57 +0100202 } else if (marker == MARKER_COUNT) {
Jose Fonseca016b9342015-05-27 12:14:42 +0100203 int count = readSize(stream);
Jose Fonseca21253f42015-05-22 00:04:57 +0100204 QVariantList array;
Jose Fonseca016b9342015-05-27 12:14:42 +0100205 for (int i = 0; i < count; ++i) {
Jose Fonseca21253f42015-05-22 00:04:57 +0100206 marker = readMarker(stream);
207 QVariant value = readVariant(stream, marker);
208 array.append(value);
209 }
210 return array;
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100211 } else {
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100212 QVariantList array;
Jose Fonsecae2e4c362015-05-21 16:12:22 +0100213 while (marker != MARKER_ARRAY_END &&
214 marker != MARKER_EOF) {
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100215 QVariant value = readVariant(stream, marker);
216 array.append(value);
217 marker = readMarker(stream);
218 }
219 return array;
220 }
221}
222
223
224static QVariantMap
225readObject(QDataStream &stream)
226{
227 QVariantMap object;
228 Marker marker = readMarker(stream);
Jose Fonsecae2e4c362015-05-21 16:12:22 +0100229 while (marker != MARKER_OBJECT_END &&
230 marker != MARKER_EOF) {
Jose Fonseca016b9342015-05-27 12:14:42 +0100231 int nameSize = readSize(stream, marker);
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100232 QString name = readString(stream, nameSize);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100233 marker = readMarker(stream);
234 QVariant value = readVariant(stream, marker);
235 object[name] = value;
236 marker = readMarker(stream);
237 }
238 return object;
239}
240
241
242static QVariant
243readVariant(QDataStream &stream, Marker type)
244{
245 switch (type) {
246 case MARKER_NULL:
247 return QVariant();
248 case MARKER_NOOP:
249 return QVariant();
250 case MARKER_TRUE:
251 return true;
252 case MARKER_FALSE:
253 return false;
254 case MARKER_INT8:
255 return readInt8(stream);
256 case MARKER_UINT8:
257 return readUInt8(stream);
258 case MARKER_INT16:
259 return readInt16(stream);
260 case MARKER_INT32:
261 return readInt32(stream);
262 case MARKER_INT64:
263 return (qlonglong)readInt64(stream);
264 case MARKER_FLOAT32:
265 return readFloat32(stream);
266 case MARKER_FLOAT64:
267 return readFloat64(stream);
268 case MARKER_HIGH_PRECISION:
269 Q_UNIMPLEMENTED();
270 return QVariant();
271 case MARKER_CHAR:
Jose Fonseca84f5e9a2015-05-22 00:03:13 +0100272 return readChar(stream);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100273 case MARKER_STRING:
274 return readString(stream);
275 case MARKER_ARRAY_BEGIN:
276 return readArray(stream);
277 case MARKER_OBJECT_BEGIN:
278 return readObject(stream);
279 case MARKER_ARRAY_END:
280 case MARKER_OBJECT_END:
281 case MARKER_TYPE:
282 case MARKER_COUNT:
283 default:
284 Q_ASSERT(0);
Jose Fonsecae2e4c362015-05-21 16:12:22 +0100285 case MARKER_EOF:
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100286 return QVariant();
287 }
288}
289
290
Jose Fonseca08fdb7b2015-05-21 21:41:50 +0100291QVariant decodeUBJSONObject(QIODevice *io)
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100292{
Jose Fonseca52aefcb2015-05-20 14:02:29 +0100293 QDataStream stream(io);
Jose Fonseca46b88772015-05-19 16:52:10 +0100294 stream.setByteOrder(QDataStream::BigEndian);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100295 Marker marker = readMarker(stream);
Jose Fonseca08fdb7b2015-05-21 21:41:50 +0100296 return readVariant(stream, marker);
Jose Fonsecac296a3e2015-05-01 17:43:54 +0100297}
298