Coverage Report

Created: 2026-01-16 07:01

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.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