Coverage Report

Created: 2026-01-13 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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.69k
      : resources_(resources),
22
1.69k
        reader_(reader),
23
1.69k
        stringBuffer_(resources),
24
1.69k
        foundSomething_(false) {}
25
26
  template <typename TFilter>
27
  DeserializationError parse(VariantData* variant, TFilter filter,
28
1.69k
                             DeserializationOption::NestingLimit nestingLimit) {
29
1.69k
    DeserializationError::Code err;
30
1.69k
    err = parseVariant(variant, filter, nestingLimit);
31
1.69k
    return foundSomething_ ? err : DeserializationError::EmptyInput;
32
1.69k
  }
33
34
 private:
35
  template <typename TFilter>
36
  DeserializationError::Code parseVariant(
37
      VariantData* variant, TFilter filter,
38
15.3k
      DeserializationOption::NestingLimit nestingLimit) {
39
15.3k
    DeserializationError::Code err;
40
41
15.3k
    uint8_t header[5];
42
15.3k
    err = readBytes(header, 1);
43
15.3k
    if (err)
44
280
      return err;
45
46
15.0k
    const uint8_t& code = header[0];
47
48
15.0k
    foundSomething_ = true;
49
50
15.0k
    bool allowValue = filter.allowValue();
51
52
15.0k
    if (allowValue) {
53
      // callers pass a null pointer only when value must be ignored
54
15.0k
      ARDUINOJSON_ASSERT(variant != 0);
55
15.0k
    }
56
57
15.0k
    if (code >= 0xcc && code <= 0xd3) {
58
1.04k
      auto width = uint8_t(1U << ((code - 0xcc) % 4));
59
1.04k
      if (allowValue)
60
1.04k
        return readInteger(variant, width, code >= 0xd0);
61
0
      else
62
0
        return skipBytes(width);
63
1.04k
    }
64
65
14.0k
    switch (code) {
66
407
      case 0xc0:
67
        // already null
68
407
        return DeserializationError::Ok;
69
70
3
      case 0xc1:
71
3
        return DeserializationError::InvalidInput;
72
73
376
      case 0xc2:
74
660
      case 0xc3:
75
660
        if (allowValue)
76
660
          variant->setBoolean(code == 0xc3);
77
660
        return DeserializationError::Ok;
78
79
473
      case 0xca:
80
473
        if (allowValue)
81
473
          return readFloat<float>(variant);
82
0
        else
83
0
          return skipBytes(4);
84
85
101
      case 0xcb:
86
101
        if (allowValue)
87
101
          return readDouble<double>(variant);
88
0
        else
89
0
          return skipBytes(8);
90
14.0k
    }
91
92
12.3k
    if (code <= 0x7f || code >= 0xe0) {  // fixint
93
3.21k
      if (allowValue)
94
3.21k
        VariantImpl::setInteger(static_cast<int8_t>(code), variant, resources_);
95
3.21k
      return DeserializationError::Ok;
96
3.21k
    }
97
98
9.13k
    uint8_t sizeBytes = 0;
99
9.13k
    size_t size = 0;
100
9.13k
    bool isExtension = code >= 0xc7 && code <= 0xc9;
101
102
9.13k
    switch (code) {
103
630
      case 0xc4:  // bin 8
104
749
      case 0xc7:  // ext 8
105
1.09k
      case 0xd9:  // str 8
106
1.09k
        sizeBytes = 1;
107
1.09k
        break;
108
109
108
      case 0xc5:  // bin 16
110
197
      case 0xc8:  // ext 16
111
362
      case 0xda:  // str 16
112
580
      case 0xdc:  // array 16
113
744
      case 0xde:  // map 16
114
744
        sizeBytes = 2;
115
744
        break;
116
117
103
      case 0xc6:  // bin 32
118
196
      case 0xc9:  // ext 32
119
371
      case 0xdb:  // str 32
120
625
      case 0xdd:  // array 32
121
772
      case 0xdf:  // map 32
122
772
        sizeBytes = 4;
123
772
        break;
124
9.13k
    }
125
126
9.13k
    if (code >= 0xd4 && code <= 0xd8) {  // fixext
127
385
      size = size_t(1) << (code - 0xd4);
128
385
      isExtension = true;
129
385
    }
130
131
9.13k
    switch (code & 0xf0) {
132
2.43k
      case 0x90:  // fixarray
133
3.54k
      case 0x80:  // fixmap
134
3.54k
        size = code & 0x0F;
135
3.54k
        break;
136
9.13k
    }
137
138
9.13k
    switch (code & 0xe0) {
139
2.60k
      case 0xa0:  // fixstr
140
2.60k
        size = code & 0x1f;
141
2.60k
        break;
142
9.13k
    }
143
144
9.13k
    if (sizeBytes) {
145
2.60k
      err = readBytes(header + 1, sizeBytes);
146
2.60k
      if (err)
147
101
        return err;
148
149
2.50k
      uint32_t size32 = 0;
150
7.91k
      for (uint8_t i = 0; i < sizeBytes; i++)
151
5.40k
        size32 = (size32 << 8) | header[i + 1];
152
153
2.50k
      size = size_t(size32);
154
2.50k
      if (size < size32)                        // integer overflow
155
0
        return DeserializationError::NoMemory;  // (not testable on 32/64-bit)
156
2.50k
    }
157
158
    // array 16, 32 and fixarray
159
9.03k
    if (code == 0xdc || code == 0xdd || (code & 0xf0) == 0x90)
160
2.88k
      return readArray(variant, size, filter, nestingLimit);
161
162
    // map 16, 32 and fixmap
163
6.15k
    if (code == 0xde || code == 0xdf || (code & 0xf0) == 0x80)
164
1.40k
      return readObject(variant, size, filter, nestingLimit);
165
166
    // str 8, 16, 32 and fixstr
167
4.74k
    if (code == 0xd9 || code == 0xda || code == 0xdb || (code & 0xe0) == 0xa0) {
168
3.26k
      if (allowValue)
169
3.26k
        return readString(variant, size);
170
0
      else
171
0
        return skipBytes(size);
172
3.26k
    }
173
174
1.48k
    if (isExtension)
175
665
      size++;  // to include the type
176
177
1.48k
    if (allowValue)
178
1.48k
      return readRawString(variant, header, uint8_t(1 + sizeBytes), size);
179
0
    else
180
0
      return skipBytes(size);
181
1.48k
  }
182
183
2.68k
  DeserializationError::Code readByte(uint8_t& value) {
184
2.68k
    int c = reader_.read();
185
2.68k
    if (c < 0)
186
83
      return DeserializationError::IncompleteInput;
187
2.60k
    value = static_cast<uint8_t>(c);
188
2.60k
    return DeserializationError::Ok;
189
2.68k
  }
190
191
26.2k
  DeserializationError::Code readBytes(void* p, size_t n) {
192
26.2k
    if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
193
25.5k
      return DeserializationError::Ok;
194
641
    return DeserializationError::IncompleteInput;
195
26.2k
  }
196
197
  template <typename T>
198
574
  DeserializationError::Code readBytes(T& value) {
199
574
    return readBytes(&value, sizeof(value));
200
574
  }
ArduinoJson::V742HB42::DeserializationError::Code ArduinoJson::V742HB42::detail::MsgPackDeserializer<ArduinoJson::V742HB42::detail::BoundedReader<unsigned char const*, void> >::readBytes<float>(float&)
Line
Count
Source
198
473
  DeserializationError::Code readBytes(T& value) {
199
473
    return readBytes(&value, sizeof(value));
200
473
  }
ArduinoJson::V742HB42::DeserializationError::Code ArduinoJson::V742HB42::detail::MsgPackDeserializer<ArduinoJson::V742HB42::detail::BoundedReader<unsigned char const*, void> >::readBytes<double>(double&)
Line
Count
Source
198
101
  DeserializationError::Code readBytes(T& value) {
199
101
    return readBytes(&value, sizeof(value));
200
101
  }
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.04k
                                         bool isSigned) {
212
1.04k
    uint8_t buffer[8];
213
214
1.04k
    auto err = readBytes(buffer, width);
215
1.04k
    if (err)
216
14
      return err;
217
218
1.02k
    union {
219
1.02k
      int64_t signedValue;
220
1.02k
      uint64_t unsignedValue;
221
1.02k
    };
222
223
1.02k
    if (isSigned)
224
537
      signedValue = static_cast<int8_t>(buffer[0]);  // propagate sign bit
225
489
    else
226
489
      unsignedValue = static_cast<uint8_t>(buffer[0]);
227
228
4.35k
    for (uint8_t i = 1; i < width; i++)
229
3.33k
      unsignedValue = (unsignedValue << 8) | buffer[i];
230
231
1.02k
    if (isSigned) {
232
537
      auto truncatedValue = static_cast<JsonInteger>(signedValue);
233
537
      if (truncatedValue == signedValue) {
234
537
        if (!VariantImpl::setInteger(truncatedValue, variant, resources_))
235
0
          return DeserializationError::NoMemory;
236
537
      }
237
      // else set null on overflow
238
537
    } else {
239
489
      auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
240
489
      if (truncatedValue == unsignedValue)
241
489
        if (!VariantImpl::setInteger(truncatedValue, variant, resources_))
242
0
          return DeserializationError::NoMemory;
243
      // else set null on overflow
244
489
    }
245
246
1.02k
    return DeserializationError::Ok;
247
1.02k
  }
248
249
  template <typename T>
250
  enable_if_t<sizeof(T) == 4, DeserializationError::Code> readFloat(
251
473
      VariantData* variant) {
252
473
    DeserializationError::Code err;
253
473
    T value;
254
255
473
    err = readBytes(value);
256
473
    if (err)
257
8
      return err;
258
259
465
    fixEndianness(value);
260
465
    VariantImpl::setFloat(value, variant, resources_);
261
262
465
    return DeserializationError::Ok;
263
473
  }
264
265
  template <typename T>
266
  enable_if_t<sizeof(T) == 8, DeserializationError::Code> readDouble(
267
101
      VariantData* variant) {
268
101
    DeserializationError::Code err;
269
101
    T value;
270
271
101
    err = readBytes(value);
272
101
    if (err)
273
10
      return err;
274
275
91
    fixEndianness(value);
276
91
    if (VariantImpl::setFloat(value, variant, resources_))
277
91
      return DeserializationError::Ok;
278
0
    else
279
0
      return DeserializationError::NoMemory;
280
91
  }
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.26k
  DeserializationError::Code readString(VariantData* variant, size_t n) {
302
3.26k
    DeserializationError::Code err;
303
304
3.26k
    err = readString(n);
305
3.26k
    if (err)
306
150
      return err;
307
308
3.11k
    stringBuffer_.save(variant);
309
3.11k
    return DeserializationError::Ok;
310
3.26k
  }
311
312
5.31k
  DeserializationError::Code readString(size_t n) {
313
5.31k
    char* p = stringBuffer_.reserve(n);
314
5.31k
    if (!p)
315
49
      return DeserializationError::NoMemory;
316
317
5.26k
    return readBytes(p, n);
318
5.31k
  }
319
320
  DeserializationError::Code readRawString(VariantData* variant,
321
                                           const void* header,
322
1.48k
                                           uint8_t headerSize, size_t n) {
323
1.48k
    auto totalSize = size_t(headerSize + n);
324
1.48k
    if (totalSize < n)                        // integer overflow
325
0
      return DeserializationError::NoMemory;  // (not testable on 64-bit)
326
327
1.48k
    char* p = stringBuffer_.reserve(totalSize);
328
1.48k
    if (!p)
329
59
      return DeserializationError::NoMemory;
330
331
1.42k
    memcpy(p, header, headerSize);
332
333
1.42k
    auto err = readBytes(p + headerSize, n);
334
1.42k
    if (err)
335
111
      return err;
336
337
1.31k
    stringBuffer_.saveRaw(variant);
338
1.31k
    return DeserializationError::Ok;
339
1.42k
  }
340
341
  template <typename TFilter>
342
  DeserializationError::Code readArray(
343
      VariantData* variant, size_t n, TFilter filter,
344
2.88k
      DeserializationOption::NestingLimit nestingLimit) {
345
2.88k
    DeserializationError::Code err;
346
347
2.88k
    if (nestingLimit.reached())
348
5
      return DeserializationError::TooDeep;
349
350
2.88k
    bool allowArray = filter.allowArray();
351
352
2.88k
    if (allowArray) {
353
2.88k
      ARDUINOJSON_ASSERT(variant != 0);
354
2.88k
      variant->toArray();
355
2.88k
    }
356
357
2.88k
    TFilter elementFilter = filter[0U];
358
359
13.6k
    for (; n; --n) {
360
11.5k
      VariantData* value;
361
362
11.5k
      if (elementFilter.allow()) {
363
11.5k
        value = VariantImpl::addNewElement(variant, resources_);
364
11.5k
        if (!value)
365
0
          return DeserializationError::NoMemory;
366
11.5k
      } else {
367
0
        value = 0;
368
0
      }
369
370
11.5k
      err = parseVariant(value, elementFilter, nestingLimit.decrement());
371
11.5k
      if (err)
372
848
        return err;
373
11.5k
    }
374
375
2.03k
    return DeserializationError::Ok;
376
2.88k
  }
377
378
  template <typename TFilter>
379
  DeserializationError::Code readObject(
380
      VariantData* variant, size_t n, TFilter filter,
381
1.40k
      DeserializationOption::NestingLimit nestingLimit) {
382
1.40k
    DeserializationError::Code err;
383
384
1.40k
    if (nestingLimit.reached())
385
1
      return DeserializationError::TooDeep;
386
387
1.40k
    if (filter.allowObject()) {
388
1.40k
      ARDUINOJSON_ASSERT(variant != 0);
389
1.40k
      variant->toObject();
390
1.40k
    }
391
392
3.27k
    for (; n; --n) {
393
2.15k
      err = readKey();
394
2.15k
      if (err)
395
122
        return err;
396
397
2.03k
      JsonString key = stringBuffer_.str();
398
2.03k
      TFilter memberFilter = filter[key.c_str()];
399
2.03k
      VariantData* member = 0;
400
401
2.03k
      if (memberFilter.allow()) {
402
2.03k
        auto keyVariant = VariantImpl::addPair(&member, variant, resources_);
403
2.03k
        if (!keyVariant)
404
0
          return DeserializationError::NoMemory;
405
406
2.03k
        stringBuffer_.save(keyVariant);
407
2.03k
      }
408
409
2.03k
      err = parseVariant(member, memberFilter, nestingLimit.decrement());
410
2.03k
      if (err)
411
168
        return err;
412
2.03k
    }
413
414
1.11k
    return DeserializationError::Ok;
415
1.40k
  }
416
417
2.15k
  DeserializationError::Code readKey() {
418
2.15k
    DeserializationError::Code err;
419
2.15k
    uint8_t code;
420
421
2.15k
    err = readByte(code);
422
2.15k
    if (err)
423
68
      return err;
424
425
2.08k
    if ((code & 0xe0) == 0xa0)
426
1.87k
      return readString(code & 0x1f);
427
428
215
    if (code >= 0xd9 && code <= 0xdb) {
429
192
      uint8_t sizeBytes = uint8_t(1U << (code - 0xd9));
430
192
      uint32_t size = 0;
431
708
      for (uint8_t i = 0; i < sizeBytes; i++) {
432
531
        err = readByte(code);
433
531
        if (err)
434
15
          return err;
435
516
        size = (size << 8) | code;
436
516
      }
437
177
      return readString(size);
438
192
    }
439
440
23
    return DeserializationError::InvalidInput;
441
215
  }
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.69k
                                               Args&&... args) {
472
1.69k
  using namespace detail;
473
1.69k
  return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
474
1.69k
                                          input,
475
1.69k
                                          detail::forward<Args>(args)...);
476
1.69k
}
477
478
ARDUINOJSON_END_PUBLIC_NAMESPACE