/src/arduinojson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
Line | Count | Source |
1 | | // ArduinoJson - https://arduinojson.org |
2 | | // Copyright © 2014-2025, Benoit BLANCHON |
3 | | // MIT License |
4 | | |
5 | | #pragma once |
6 | | |
7 | | #include <ArduinoJson/Deserialization/deserialize.hpp> |
8 | | #include <ArduinoJson/Memory/ResourceManager.hpp> |
9 | | #include <ArduinoJson/Memory/StringBuffer.hpp> |
10 | | #include <ArduinoJson/MsgPack/endianness.hpp> |
11 | | #include <ArduinoJson/MsgPack/ieee754.hpp> |
12 | | #include <ArduinoJson/Polyfills/type_traits.hpp> |
13 | | #include <ArduinoJson/Variant/VariantData.hpp> |
14 | | |
15 | | ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE |
16 | | |
17 | | template <typename TReader> |
18 | | class MsgPackDeserializer { |
19 | | public: |
20 | | MsgPackDeserializer(ResourceManager* resources, TReader reader) |
21 | 1.70k | : resources_(resources), |
22 | 1.70k | reader_(reader), |
23 | 1.70k | stringBuffer_(resources), |
24 | 1.70k | foundSomething_(false) {} |
25 | | |
26 | | template <typename TFilter> |
27 | | DeserializationError parse(VariantData* variant, TFilter filter, |
28 | 1.70k | DeserializationOption::NestingLimit nestingLimit) { |
29 | 1.70k | DeserializationError::Code err; |
30 | 1.70k | err = parseVariant(variant, filter, nestingLimit); |
31 | 1.70k | return foundSomething_ ? err : DeserializationError::EmptyInput; |
32 | 1.70k | } |
33 | | |
34 | | private: |
35 | | template <typename TFilter> |
36 | | DeserializationError::Code parseVariant( |
37 | | VariantData* variant, TFilter filter, |
38 | 15.8k | DeserializationOption::NestingLimit nestingLimit) { |
39 | 15.8k | DeserializationError::Code err; |
40 | | |
41 | 15.8k | uint8_t header[5]; |
42 | 15.8k | err = readBytes(header, 1); |
43 | 15.8k | if (err) |
44 | 298 | return err; |
45 | | |
46 | 15.5k | const uint8_t& code = header[0]; |
47 | | |
48 | 15.5k | foundSomething_ = true; |
49 | | |
50 | 15.5k | bool allowValue = filter.allowValue(); |
51 | | |
52 | 15.5k | if (allowValue) { |
53 | | // callers pass a null pointer only when value must be ignored |
54 | 15.5k | ARDUINOJSON_ASSERT(variant != 0); |
55 | 15.5k | } |
56 | | |
57 | 15.5k | if (code >= 0xcc && code <= 0xd3) { |
58 | 1.07k | auto width = uint8_t(1U << ((code - 0xcc) % 4)); |
59 | 1.07k | if (allowValue) |
60 | 1.07k | return readInteger(variant, width, code >= 0xd0); |
61 | 0 | else |
62 | 0 | return skipBytes(width); |
63 | 1.07k | } |
64 | | |
65 | 14.4k | switch (code) { |
66 | 359 | case 0xc0: |
67 | | // already null |
68 | 359 | return DeserializationError::Ok; |
69 | | |
70 | 3 | case 0xc1: |
71 | 3 | return DeserializationError::InvalidInput; |
72 | | |
73 | 348 | case 0xc2: |
74 | 566 | case 0xc3: |
75 | 566 | if (allowValue) |
76 | 566 | variant->setBoolean(code == 0xc3); |
77 | 566 | return DeserializationError::Ok; |
78 | | |
79 | 474 | case 0xca: |
80 | 474 | if (allowValue) |
81 | 474 | return readFloat<float>(variant); |
82 | 0 | else |
83 | 0 | return skipBytes(4); |
84 | | |
85 | 125 | case 0xcb: |
86 | 125 | if (allowValue) |
87 | 125 | return readDouble<double>(variant); |
88 | 0 | else |
89 | 0 | return skipBytes(8); |
90 | 14.4k | } |
91 | | |
92 | 12.9k | if (code <= 0x7f || code >= 0xe0) { // fixint |
93 | 3.42k | if (allowValue) |
94 | 3.42k | VariantImpl::setInteger(static_cast<int8_t>(code), variant, resources_); |
95 | 3.42k | return DeserializationError::Ok; |
96 | 3.42k | } |
97 | | |
98 | 9.51k | uint8_t sizeBytes = 0; |
99 | 9.51k | size_t size = 0; |
100 | 9.51k | bool isExtension = code >= 0xc7 && code <= 0xc9; |
101 | | |
102 | 9.51k | switch (code) { |
103 | 593 | case 0xc4: // bin 8 |
104 | 746 | case 0xc7: // ext 8 |
105 | 1.12k | case 0xd9: // str 8 |
106 | 1.12k | sizeBytes = 1; |
107 | 1.12k | break; |
108 | | |
109 | 121 | case 0xc5: // bin 16 |
110 | 211 | case 0xc8: // ext 16 |
111 | 377 | case 0xda: // str 16 |
112 | 599 | case 0xdc: // array 16 |
113 | 765 | case 0xde: // map 16 |
114 | 765 | sizeBytes = 2; |
115 | 765 | break; |
116 | | |
117 | 107 | case 0xc6: // bin 32 |
118 | 191 | case 0xc9: // ext 32 |
119 | 367 | case 0xdb: // str 32 |
120 | 620 | case 0xdd: // array 32 |
121 | 768 | case 0xdf: // map 32 |
122 | 768 | sizeBytes = 4; |
123 | 768 | break; |
124 | 9.51k | } |
125 | | |
126 | 9.51k | if (code >= 0xd4 && code <= 0xd8) { // fixext |
127 | 338 | size = size_t(1) << (code - 0xd4); |
128 | 338 | isExtension = true; |
129 | 338 | } |
130 | | |
131 | 9.51k | switch (code & 0xf0) { |
132 | 2.96k | case 0x90: // fixarray |
133 | 3.98k | case 0x80: // fixmap |
134 | 3.98k | size = code & 0x0F; |
135 | 3.98k | break; |
136 | 9.51k | } |
137 | | |
138 | 9.51k | switch (code & 0xe0) { |
139 | 2.53k | case 0xa0: // fixstr |
140 | 2.53k | size = code & 0x1f; |
141 | 2.53k | break; |
142 | 9.51k | } |
143 | | |
144 | 9.51k | if (sizeBytes) { |
145 | 2.65k | err = readBytes(header + 1, sizeBytes); |
146 | 2.65k | if (err) |
147 | 103 | return err; |
148 | | |
149 | 2.55k | uint32_t size32 = 0; |
150 | 8.01k | for (uint8_t i = 0; i < sizeBytes; i++) |
151 | 5.46k | size32 = (size32 << 8) | header[i + 1]; |
152 | | |
153 | 2.55k | size = size_t(size32); |
154 | 2.55k | if (size < size32) // integer overflow |
155 | 0 | return DeserializationError::NoMemory; // (not testable on 32/64-bit) |
156 | 2.55k | } |
157 | | |
158 | | // array 16, 32 and fixarray |
159 | 9.41k | if (code == 0xdc || code == 0xdd || (code & 0xf0) == 0x90) |
160 | 3.42k | return readArray(variant, size, filter, nestingLimit); |
161 | | |
162 | | // map 16, 32 and fixmap |
163 | 5.99k | if (code == 0xde || code == 0xdf || (code & 0xf0) == 0x80) |
164 | 1.32k | return readObject(variant, size, filter, nestingLimit); |
165 | | |
166 | | // str 8, 16, 32 and fixstr |
167 | 4.67k | if (code == 0xd9 || code == 0xda || code == 0xdb || (code & 0xe0) == 0xa0) { |
168 | 3.22k | if (allowValue) |
169 | 3.22k | return readString(variant, size); |
170 | 0 | else |
171 | 0 | return skipBytes(size); |
172 | 3.22k | } |
173 | | |
174 | 1.44k | if (isExtension) |
175 | 644 | size++; // to include the type |
176 | | |
177 | 1.44k | if (allowValue) |
178 | 1.44k | return readRawString(variant, header, uint8_t(1 + sizeBytes), size); |
179 | 0 | else |
180 | 0 | return skipBytes(size); |
181 | 1.44k | } |
182 | | |
183 | 2.59k | DeserializationError::Code readByte(uint8_t& value) { |
184 | 2.59k | int c = reader_.read(); |
185 | 2.59k | if (c < 0) |
186 | 79 | return DeserializationError::IncompleteInput; |
187 | 2.51k | value = static_cast<uint8_t>(c); |
188 | 2.51k | return DeserializationError::Ok; |
189 | 2.59k | } |
190 | | |
191 | 26.6k | DeserializationError::Code readBytes(void* p, size_t n) { |
192 | 26.6k | if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n) |
193 | 26.0k | return DeserializationError::Ok; |
194 | 671 | return DeserializationError::IncompleteInput; |
195 | 26.6k | } |
196 | | |
197 | | template <typename T> |
198 | 599 | DeserializationError::Code readBytes(T& value) { |
199 | 599 | return readBytes(&value, sizeof(value)); |
200 | 599 | } ArduinoJson::V742HB42::DeserializationError::Code ArduinoJson::V742HB42::detail::MsgPackDeserializer<ArduinoJson::V742HB42::detail::BoundedReader<unsigned char const*, void> >::readBytes<float>(float&) Line | Count | Source | 198 | 474 | DeserializationError::Code readBytes(T& value) { | 199 | 474 | return readBytes(&value, sizeof(value)); | 200 | 474 | } |
ArduinoJson::V742HB42::DeserializationError::Code ArduinoJson::V742HB42::detail::MsgPackDeserializer<ArduinoJson::V742HB42::detail::BoundedReader<unsigned char const*, void> >::readBytes<double>(double&) Line | Count | Source | 198 | 125 | DeserializationError::Code readBytes(T& value) { | 199 | 125 | return readBytes(&value, sizeof(value)); | 200 | 125 | } |
|
201 | | |
202 | 0 | DeserializationError::Code skipBytes(size_t n) { |
203 | 0 | for (; n; --n) { |
204 | 0 | if (reader_.read() < 0) |
205 | 0 | return DeserializationError::IncompleteInput; |
206 | 0 | } |
207 | 0 | return DeserializationError::Ok; |
208 | 0 | } |
209 | | |
210 | | DeserializationError::Code readInteger(VariantData* variant, uint8_t width, |
211 | 1.07k | bool isSigned) { |
212 | 1.07k | uint8_t buffer[8]; |
213 | | |
214 | 1.07k | auto err = readBytes(buffer, width); |
215 | 1.07k | if (err) |
216 | 14 | return err; |
217 | | |
218 | 1.05k | union { |
219 | 1.05k | int64_t signedValue; |
220 | 1.05k | uint64_t unsignedValue; |
221 | 1.05k | }; |
222 | | |
223 | 1.05k | if (isSigned) |
224 | 551 | signedValue = static_cast<int8_t>(buffer[0]); // propagate sign bit |
225 | 506 | else |
226 | 506 | unsignedValue = static_cast<uint8_t>(buffer[0]); |
227 | | |
228 | 4.47k | for (uint8_t i = 1; i < width; i++) |
229 | 3.41k | unsignedValue = (unsignedValue << 8) | buffer[i]; |
230 | | |
231 | 1.05k | if (isSigned) { |
232 | 551 | auto truncatedValue = static_cast<JsonInteger>(signedValue); |
233 | 551 | if (truncatedValue == signedValue) { |
234 | 551 | if (!VariantImpl::setInteger(truncatedValue, variant, resources_)) |
235 | 0 | return DeserializationError::NoMemory; |
236 | 551 | } |
237 | | // else set null on overflow |
238 | 551 | } else { |
239 | 506 | auto truncatedValue = static_cast<JsonUInt>(unsignedValue); |
240 | 506 | if (truncatedValue == unsignedValue) |
241 | 506 | if (!VariantImpl::setInteger(truncatedValue, variant, resources_)) |
242 | 0 | return DeserializationError::NoMemory; |
243 | | // else set null on overflow |
244 | 506 | } |
245 | | |
246 | 1.05k | return DeserializationError::Ok; |
247 | 1.05k | } |
248 | | |
249 | | template <typename T> |
250 | | enable_if_t<sizeof(T) == 4, DeserializationError::Code> readFloat( |
251 | 474 | VariantData* variant) { |
252 | 474 | DeserializationError::Code err; |
253 | 474 | T value; |
254 | | |
255 | 474 | err = readBytes(value); |
256 | 474 | if (err) |
257 | 8 | return err; |
258 | | |
259 | 466 | fixEndianness(value); |
260 | 466 | VariantImpl::setFloat(value, variant, resources_); |
261 | | |
262 | 466 | return DeserializationError::Ok; |
263 | 474 | } |
264 | | |
265 | | template <typename T> |
266 | | enable_if_t<sizeof(T) == 8, DeserializationError::Code> readDouble( |
267 | 125 | VariantData* variant) { |
268 | 125 | DeserializationError::Code err; |
269 | 125 | T value; |
270 | | |
271 | 125 | err = readBytes(value); |
272 | 125 | if (err) |
273 | 10 | return err; |
274 | | |
275 | 115 | fixEndianness(value); |
276 | 115 | if (VariantImpl::setFloat(value, variant, resources_)) |
277 | 115 | return DeserializationError::Ok; |
278 | 0 | else |
279 | 0 | return DeserializationError::NoMemory; |
280 | 115 | } |
281 | | |
282 | | template <typename T> |
283 | | enable_if_t<sizeof(T) == 4, DeserializationError::Code> readDouble( |
284 | | VariantData* variant) { |
285 | | DeserializationError::Code err; |
286 | | uint8_t i[8]; // input is 8 bytes |
287 | | T value; // output is 4 bytes |
288 | | uint8_t* o = reinterpret_cast<uint8_t*>(&value); |
289 | | |
290 | | err = readBytes(i, 8); |
291 | | if (err) |
292 | | return err; |
293 | | |
294 | | doubleToFloat(i, o); |
295 | | fixEndianness(value); |
296 | | VariantImpl::setFloat(value, variant, resources_); |
297 | | |
298 | | return DeserializationError::Ok; |
299 | | } |
300 | | |
301 | 3.22k | DeserializationError::Code readString(VariantData* variant, size_t n) { |
302 | 3.22k | DeserializationError::Code err; |
303 | | |
304 | 3.22k | err = readString(n); |
305 | 3.22k | if (err) |
306 | 153 | return err; |
307 | | |
308 | 3.07k | stringBuffer_.save(variant); |
309 | 3.07k | return DeserializationError::Ok; |
310 | 3.22k | } |
311 | | |
312 | 5.19k | DeserializationError::Code readString(size_t n) { |
313 | 5.19k | char* p = stringBuffer_.reserve(n); |
314 | 5.19k | if (!p) |
315 | 48 | return DeserializationError::NoMemory; |
316 | | |
317 | 5.14k | return readBytes(p, n); |
318 | 5.19k | } |
319 | | |
320 | | DeserializationError::Code readRawString(VariantData* variant, |
321 | | const void* header, |
322 | 1.44k | uint8_t headerSize, size_t n) { |
323 | 1.44k | auto totalSize = size_t(headerSize + n); |
324 | 1.44k | if (totalSize < n) // integer overflow |
325 | 0 | return DeserializationError::NoMemory; // (not testable on 64-bit) |
326 | | |
327 | 1.44k | char* p = stringBuffer_.reserve(totalSize); |
328 | 1.44k | if (!p) |
329 | 61 | return DeserializationError::NoMemory; |
330 | | |
331 | 1.38k | memcpy(p, header, headerSize); |
332 | | |
333 | 1.38k | auto err = readBytes(p + headerSize, n); |
334 | 1.38k | if (err) |
335 | 120 | return err; |
336 | | |
337 | 1.26k | stringBuffer_.saveRaw(variant); |
338 | 1.26k | return DeserializationError::Ok; |
339 | 1.38k | } |
340 | | |
341 | | template <typename TFilter> |
342 | | DeserializationError::Code readArray( |
343 | | VariantData* variant, size_t n, TFilter filter, |
344 | 3.42k | DeserializationOption::NestingLimit nestingLimit) { |
345 | 3.42k | DeserializationError::Code err; |
346 | | |
347 | 3.42k | if (nestingLimit.reached()) |
348 | 5 | return DeserializationError::TooDeep; |
349 | | |
350 | 3.41k | bool allowArray = filter.allowArray(); |
351 | | |
352 | 3.41k | if (allowArray) { |
353 | 3.41k | ARDUINOJSON_ASSERT(variant != 0); |
354 | 3.41k | variant->toArray(); |
355 | 3.41k | } |
356 | | |
357 | 3.41k | TFilter elementFilter = filter[0U]; |
358 | | |
359 | 14.7k | for (; n; --n) { |
360 | 12.1k | VariantData* value; |
361 | | |
362 | 12.1k | if (elementFilter.allow()) { |
363 | 12.1k | value = VariantImpl::addNewElement(variant, resources_); |
364 | 12.1k | if (!value) |
365 | 0 | return DeserializationError::NoMemory; |
366 | 12.1k | } else { |
367 | 0 | value = 0; |
368 | 0 | } |
369 | | |
370 | 12.1k | err = parseVariant(value, elementFilter, nestingLimit.decrement()); |
371 | 12.1k | if (err) |
372 | 881 | return err; |
373 | 12.1k | } |
374 | | |
375 | 2.53k | return DeserializationError::Ok; |
376 | 3.41k | } |
377 | | |
378 | | template <typename TFilter> |
379 | | DeserializationError::Code readObject( |
380 | | VariantData* variant, size_t n, TFilter filter, |
381 | 1.32k | DeserializationOption::NestingLimit nestingLimit) { |
382 | 1.32k | DeserializationError::Code err; |
383 | | |
384 | 1.32k | if (nestingLimit.reached()) |
385 | 1 | return DeserializationError::TooDeep; |
386 | | |
387 | 1.32k | if (filter.allowObject()) { |
388 | 1.32k | ARDUINOJSON_ASSERT(variant != 0); |
389 | 1.32k | variant->toObject(); |
390 | 1.32k | } |
391 | | |
392 | 3.09k | for (; n; --n) { |
393 | 2.06k | err = readKey(); |
394 | 2.06k | if (err) |
395 | 113 | return err; |
396 | | |
397 | 1.95k | JsonString key = stringBuffer_.str(); |
398 | 1.95k | TFilter memberFilter = filter[key.c_str()]; |
399 | 1.95k | VariantData* member = 0; |
400 | | |
401 | 1.95k | if (memberFilter.allow()) { |
402 | 1.95k | auto keyVariant = VariantImpl::addPair(&member, variant, resources_); |
403 | 1.95k | if (!keyVariant) |
404 | 0 | return DeserializationError::NoMemory; |
405 | | |
406 | 1.95k | stringBuffer_.save(keyVariant); |
407 | 1.95k | } |
408 | | |
409 | 1.95k | err = parseVariant(member, memberFilter, nestingLimit.decrement()); |
410 | 1.95k | if (err) |
411 | 184 | return err; |
412 | 1.95k | } |
413 | | |
414 | 1.02k | return DeserializationError::Ok; |
415 | 1.32k | } |
416 | | |
417 | 2.06k | DeserializationError::Code readKey() { |
418 | 2.06k | DeserializationError::Code err; |
419 | 2.06k | uint8_t code; |
420 | | |
421 | 2.06k | err = readByte(code); |
422 | 2.06k | if (err) |
423 | 64 | return err; |
424 | | |
425 | 2.00k | if ((code & 0xe0) == 0xa0) |
426 | 1.78k | return readString(code & 0x1f); |
427 | | |
428 | 212 | if (code >= 0xd9 && code <= 0xdb) { |
429 | 191 | uint8_t sizeBytes = uint8_t(1U << (code - 0xd9)); |
430 | 191 | uint32_t size = 0; |
431 | 708 | for (uint8_t i = 0; i < sizeBytes; i++) { |
432 | 532 | err = readByte(code); |
433 | 532 | if (err) |
434 | 15 | return err; |
435 | 517 | size = (size << 8) | code; |
436 | 517 | } |
437 | 176 | return readString(size); |
438 | 191 | } |
439 | | |
440 | 21 | return DeserializationError::InvalidInput; |
441 | 212 | } |
442 | | |
443 | | ResourceManager* resources_; |
444 | | TReader reader_; |
445 | | StringBuffer stringBuffer_; |
446 | | bool foundSomething_; |
447 | | }; |
448 | | |
449 | | ARDUINOJSON_END_PRIVATE_NAMESPACE |
450 | | |
451 | | ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE |
452 | | |
453 | | // Parses a MessagePack input and puts the result in a JsonDocument. |
454 | | // https://arduinojson.org/v7/api/msgpack/deserializemsgpack/ |
455 | | template <typename TDestination, typename... Args, |
456 | | detail::enable_if_t< |
457 | | detail::is_deserialize_destination<TDestination>::value, int> = 0> |
458 | | inline DeserializationError deserializeMsgPack(TDestination&& dst, |
459 | | Args&&... args) { |
460 | | using namespace detail; |
461 | | return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst), |
462 | | detail::forward<Args>(args)...); |
463 | | } |
464 | | |
465 | | // Parses a MessagePack input and puts the result in a JsonDocument. |
466 | | // https://arduinojson.org/v7/api/msgpack/deserializemsgpack/ |
467 | | template <typename TDestination, typename TChar, typename... Args, |
468 | | detail::enable_if_t< |
469 | | detail::is_deserialize_destination<TDestination>::value, int> = 0> |
470 | | inline DeserializationError deserializeMsgPack(TDestination&& dst, TChar* input, |
471 | 1.70k | Args&&... args) { |
472 | 1.70k | using namespace detail; |
473 | 1.70k | return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst), |
474 | 1.70k | input, |
475 | 1.70k | detail::forward<Args>(args)...); |
476 | 1.70k | } |
477 | | |
478 | | ARDUINOJSON_END_PUBLIC_NAMESPACE |