• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bblanchon / ArduinoJson / 9564476518

18 Jun 2024 11:51AM UTC coverage: 99.484% (-0.004%) from 99.488%
9564476518

push

github

bblanchon
CI: update macOS runner to `macos-13`

3854 of 3874 relevant lines covered (99.48%)

10863.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.09
/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2024, 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)
492✔
21
      : resources_(resources),
22
        reader_(reader),
23
        stringBuffer_(resources),
24
        foundSomething_(false) {}
492✔
25

26
  template <typename TFilter>
27
  DeserializationError parse(VariantData& variant, TFilter filter,
492✔
28
                             DeserializationOption::NestingLimit nestingLimit) {
29
    DeserializationError::Code err;
30
    err = parseVariant(&variant, filter, nestingLimit);
492✔
31
    return foundSomething_ ? err : DeserializationError::EmptyInput;
492✔
32
  }
33

34
 private:
35
  template <typename TFilter>
36
  DeserializationError::Code parseVariant(
825✔
37
      VariantData* variant, TFilter filter,
38
      DeserializationOption::NestingLimit nestingLimit) {
39
    DeserializationError::Code err;
40

41
    uint8_t header[5];
42
    err = readBytes(header, 1);
825✔
43
    if (err)
825✔
44
      return err;
11✔
45

46
    const uint8_t& code = header[0];
814✔
47

48
    foundSomething_ = true;
814✔
49

50
    bool allowValue = filter.allowValue();
814✔
51

52
    if (allowValue) {
53
      // callers pass a null pointer only when value must be ignored
54
      ARDUINOJSON_ASSERT(variant != 0);
55
    }
56

57
    if (code >= 0xcc && code <= 0xd3) {
814✔
58
      auto width = uint8_t(1U << ((code - 0xcc) % 4));
92✔
59
      if (allowValue)
92✔
60
        return readInteger(variant, width, code >= 0xd0);
67✔
61
      else
62
        return skipBytes(width);
25✔
63
    }
64

65
    switch (code) {
722✔
66
      case 0xc0:
5✔
67
        // already null
68
        return DeserializationError::Ok;
5✔
69

70
      case 0xc1:
1✔
71
        return DeserializationError::InvalidInput;
1✔
72

73
      case 0xc2:
10✔
74
      case 0xc3:
75
        if (allowValue)
10✔
76
          variant->setBoolean(code == 0xc3);
4✔
77
        return DeserializationError::Ok;
10✔
78

79
      case 0xca:
20✔
80
        if (allowValue)
20✔
81
          return readFloat<float>(variant);
11✔
82
        else
83
          return skipBytes(4);
9✔
84

85
      case 0xcb:
19✔
86
        if (allowValue)
19✔
87
          return readDouble<double>(variant);
16✔
88
        else
89
          return skipBytes(8);
3✔
90
    }
91

92
    if (code <= 0x7f || code >= 0xe0) {  // fixint
667✔
93
      if (allowValue)
200✔
94
        variant->setInteger(static_cast<int8_t>(code));
152✔
95
      return DeserializationError::Ok;
200✔
96
    }
97

98
    uint8_t sizeBytes = 0;
467✔
99
    size_t size = 0;
467✔
100
    bool isExtension = code >= 0xc7 && code <= 0xc9;
467✔
101

102
    switch (code) {
467✔
103
      case 0xc4:  // bin 8
32✔
104
      case 0xc7:  // ext 8
105
      case 0xd9:  // str 8
106
        sizeBytes = 1;
32✔
107
        break;
32✔
108

109
      case 0xc5:  // bin 16
70✔
110
      case 0xc8:  // ext 16
111
      case 0xda:  // str 16
112
      case 0xdc:  // array 16
113
      case 0xde:  // map 16
114
        sizeBytes = 2;
70✔
115
        break;
70✔
116

117
      case 0xc6:  // bin 32
82✔
118
      case 0xc9:  // ext 32
119
      case 0xdb:  // str 32
120
      case 0xdd:  // array 32
121
      case 0xdf:  // map 32
122
        sizeBytes = 4;
82✔
123
        break;
82✔
124
    }
125

126
    if (code >= 0xd4 && code <= 0xd8) {  // fixext
467✔
127
      size = size_t(1) << (code - 0xd4);
51✔
128
      isExtension = true;
51✔
129
    }
130

131
    switch (code & 0xf0) {
467✔
132
      case 0x90:  // fixarray
187✔
133
      case 0x80:  // fixmap
134
        size = code & 0x0F;
187✔
135
        break;
187✔
136
    }
137

138
    switch (code & 0xe0) {
467✔
139
      case 0xa0:  // fixstr
45✔
140
        size = code & 0x1f;
45✔
141
        break;
45✔
142
    }
143

144
    if (sizeBytes) {
467✔
145
      err = readBytes(header + 1, sizeBytes);
184✔
146
      if (err)
184✔
147
        return err;
39✔
148

149
      uint32_t size32 = 0;
145✔
150
      for (uint8_t i = 0; i < sizeBytes; i++)
524✔
151
        size32 = (size32 << 8) | header[i + 1];
379✔
152

153
      size = size_t(size32);
145✔
154
      if (size < size32)                        // integer overflow
145✔
155
        return DeserializationError::NoMemory;  // (not testable on 32/64-bit)
×
156
    }
157

158
    // array 16, 32 and fixarray
159
    if (code == 0xdc || code == 0xdd || (code & 0xf0) == 0x90)
428✔
160
      return readArray(variant, size, filter, nestingLimit);
69✔
161

162
    // map 16, 32 and fixmap
163
    if (code == 0xde || code == 0xdf || (code & 0xf0) == 0x80)
359✔
164
      return readObject(variant, size, filter, nestingLimit);
180✔
165

166
    // str 8, 16, 32 and fixstr
167
    if (code == 0xd9 || code == 0xda || code == 0xdb || (code & 0xe0) == 0xa0) {
179✔
168
      if (allowValue)
87✔
169
        return readString(variant, size);
68✔
170
      else
171
        return skipBytes(size);
19✔
172
    }
173

174
    if (isExtension)
92✔
175
      size++;  // to include the type
72✔
176

177
    if (allowValue)
92✔
178
      return readRawString(variant, header, uint8_t(1 + sizeBytes), size);
81✔
179
    else
180
      return skipBytes(size);
11✔
181
  }
182

183
  DeserializationError::Code readByte(uint8_t& value) {
309✔
184
    int c = reader_.read();
309✔
185
    if (c < 0)
309✔
186
      return DeserializationError::IncompleteInput;
5✔
187
    value = static_cast<uint8_t>(c);
304✔
188
    return DeserializationError::Ok;
304✔
189
  }
190

191
  DeserializationError::Code readBytes(void* p, size_t n) {
1,518✔
192
    if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
1,518✔
193
      return DeserializationError::Ok;
1,342✔
194
    return DeserializationError::IncompleteInput;
176✔
195
  }
196

197
  template <typename T>
198
  DeserializationError::Code readBytes(T& value) {
27✔
199
    return readBytes(&value, sizeof(value));
27✔
200
  }
201

202
  DeserializationError::Code skipBytes(size_t n) {
392✔
203
    for (; n; --n) {
392✔
204
      if (reader_.read() < 0)
326✔
205
        return DeserializationError::IncompleteInput;
1✔
206
    }
207
    return DeserializationError::Ok;
66✔
208
  }
209

210
  DeserializationError::Code readInteger(VariantData* variant, uint8_t width,
67✔
211
                                         bool isSigned) {
212
    uint8_t buffer[8];
213

214
    auto err = readBytes(buffer, width);
67✔
215
    if (err)
67✔
216
      return err;
30✔
217

218
    union {
219
      int64_t signedValue;
220
      uint64_t unsignedValue;
221
    };
144✔
222

223
    if (isSigned)
37✔
224
      signedValue = static_cast<int8_t>(buffer[0]);  // propagate sign bit
15✔
225
    else
226
      unsignedValue = static_cast<uint8_t>(buffer[0]);
22✔
227

228
    for (uint8_t i = 1; i < width; i++)
144✔
229
      unsignedValue = (unsignedValue << 8) | buffer[i];
107✔
230

231
    if (isSigned) {
37✔
232
      auto truncatedValue = static_cast<JsonInteger>(signedValue);
15✔
233
      if (truncatedValue == signedValue)
15✔
234
        variant->setInteger(truncatedValue);
15✔
235
      // else set null on overflow
236
    } else {
237
      auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
22✔
238
      if (truncatedValue == unsignedValue)
22✔
239
        variant->setInteger(truncatedValue);
22✔
240
      // else set null on overflow
241
    }
242

243
    return DeserializationError::Ok;
37✔
244
  }
245

246
  template <typename T>
247
  enable_if_t<sizeof(T) == 4, DeserializationError::Code> readFloat(
11✔
248
      VariantData* variant) {
249
    DeserializationError::Code err;
250
    T value;
251

252
    err = readBytes(value);
11✔
253
    if (err)
11✔
254
      return err;
4✔
255

256
    fixEndianness(value);
7✔
257
    variant->setFloat(value);
7✔
258

259
    return DeserializationError::Ok;
7✔
260
  }
261

262
  template <typename T>
263
  enable_if_t<sizeof(T) == 8, DeserializationError::Code> readDouble(
16✔
264
      VariantData* variant) {
265
    DeserializationError::Code err;
266
    T value;
267

268
    err = readBytes(value);
16✔
269
    if (err)
16✔
270
      return err;
8✔
271

272
    fixEndianness(value);
8✔
273
    variant->setFloat(value);
8✔
274

275
    return DeserializationError::Ok;
8✔
276
  }
277

278
  template <typename T>
279
  enable_if_t<sizeof(T) == 4, DeserializationError::Code> readDouble(
280
      VariantData* variant) {
281
    DeserializationError::Code err;
282
    uint8_t i[8];  // input is 8 bytes
283
    T value;       // output is 4 bytes
284
    uint8_t* o = reinterpret_cast<uint8_t*>(&value);
285

286
    err = readBytes(i, 8);
287
    if (err)
288
      return err;
289

290
    doubleToFloat(i, o);
291
    fixEndianness(value);
292
    variant->setFloat(value);
293

294
    return DeserializationError::Ok;
295
  }
296

297
  DeserializationError::Code readString(VariantData* variant, size_t n) {
68✔
298
    DeserializationError::Code err;
299

300
    err = readString(n);
68✔
301
    if (err)
68✔
302
      return err;
34✔
303

304
    variant->setOwnedString(stringBuffer_.save());
34✔
305
    return DeserializationError::Ok;
34✔
306
  }
307

308
  DeserializationError::Code readString(size_t n) {
351✔
309
    char* p = stringBuffer_.reserve(n);
351✔
310
    if (!p)
351✔
311
      return DeserializationError::NoMemory;
10✔
312

313
    return readBytes(p, n);
341✔
314
  }
315

316
  DeserializationError::Code readRawString(VariantData* variant,
81✔
317
                                           const void* header,
318
                                           uint8_t headerSize, size_t n) {
319
    auto totalSize = size_t(headerSize + n);
81✔
320
    if (totalSize < n)                        // integer overflow
81✔
321
      return DeserializationError::NoMemory;  // (not testable on 64-bit)
×
322

323
    char* p = stringBuffer_.reserve(totalSize);
81✔
324
    if (!p)
81✔
325
      return DeserializationError::NoMemory;
7✔
326

327
    memcpy(p, header, headerSize);
74✔
328

329
    auto err = readBytes(p + headerSize, n);
74✔
330
    if (err)
74✔
331
      return err;
45✔
332

333
    variant->setRawString(stringBuffer_.save());
29✔
334
    return DeserializationError::Ok;
29✔
335
  }
336

337
  template <typename TFilter>
338
  DeserializationError::Code readArray(
69✔
339
      VariantData* variant, size_t n, TFilter filter,
340
      DeserializationOption::NestingLimit nestingLimit) {
341
    DeserializationError::Code err;
342

343
    if (nestingLimit.reached())
69✔
344
      return DeserializationError::TooDeep;
9✔
345

346
    bool allowArray = filter.allowArray();
60✔
347

348
    ArrayData* array;
349
    if (allowArray) {
60✔
350
      ARDUINOJSON_ASSERT(variant != 0);
351
      array = &variant->toArray();
48✔
352
    } else {
353
      array = 0;
12✔
354
    }
355

356
    TFilter elementFilter = filter[0U];
60✔
357

358
    for (; n; --n) {
116✔
359
      VariantData* value;
360

361
      if (elementFilter.allow()) {
71✔
362
        ARDUINOJSON_ASSERT(array != 0);
363
        value = array->addElement(resources_);
49✔
364
        if (!value)
49✔
365
          return DeserializationError::NoMemory;
3✔
366
      } else {
367
        value = 0;
22✔
368
      }
369

370
      err = parseVariant(value, elementFilter, nestingLimit.decrement());
68✔
371
      if (err)
68✔
372
        return err;
12✔
373
    }
374

375
    return DeserializationError::Ok;
45✔
376
  }
377

378
  template <typename TFilter>
379
  DeserializationError::Code readObject(
180✔
380
      VariantData* variant, size_t n, TFilter filter,
381
      DeserializationOption::NestingLimit nestingLimit) {
382
    DeserializationError::Code err;
383

384
    if (nestingLimit.reached())
180✔
385
      return DeserializationError::TooDeep;
7✔
386

387
    ObjectData* object;
388
    if (filter.allowObject()) {
173✔
389
      ARDUINOJSON_ASSERT(variant != 0);
390
      object = &variant->toObject();
163✔
391
    } else {
392
      object = 0;
10✔
393
    }
394

395
    for (; n; --n) {
422✔
396
      err = readKey();
289✔
397
      if (err)
289✔
398
        return err;
40✔
399

400
      JsonString key = stringBuffer_.str();
268✔
401
      TFilter memberFilter = filter[key.c_str()];
268✔
402
      VariantData* member;
403

404
      if (memberFilter.allow()) {
268✔
405
        ARDUINOJSON_ASSERT(object != 0);
406

407
        // Save key in memory pool.
408
        auto savedKey = stringBuffer_.save();
201✔
409

410
        member = object->addMember(savedKey, resources_);
201✔
411
        if (!member)
201✔
412
          return DeserializationError::NoMemory;
3✔
413
      } else {
414
        member = 0;
67✔
415
      }
416

417
      err = parseVariant(member, memberFilter, nestingLimit.decrement());
265✔
418
      if (err)
265✔
419
        return err;
16✔
420
    }
421

422
    return DeserializationError::Ok;
133✔
423
  }
424

425
  DeserializationError::Code readKey() {
289✔
426
    DeserializationError::Code err;
427
    uint8_t code;
428

429
    err = readByte(code);
289✔
430
    if (err)
289✔
431
      return err;
4✔
432

433
    if ((code & 0xe0) == 0xa0)
285✔
434
      return readString(code & 0x1f);
272✔
435

436
    if (code >= 0xd9 && code <= 0xdb) {
13✔
437
      uint8_t sizeBytes = uint8_t(1U << (code - 0xd9));
12✔
438
      uint32_t size = 0;
12✔
439
      for (uint8_t i = 0; i < sizeBytes; i++) {
31✔
440
        err = readByte(code);
20✔
441
        if (err)
20✔
442
          return err;
1✔
443
        size = (size << 8) | code;
19✔
444
      }
445
      return readString(size);
11✔
446
    }
447

448
    return DeserializationError::InvalidInput;
1✔
449
  }
450

451
  ResourceManager* resources_;
452
  TReader reader_;
453
  StringBuffer stringBuffer_;
454
  bool foundSomething_;
455
};
456

457
ARDUINOJSON_END_PRIVATE_NAMESPACE
458

459
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
460

461
// Parses a MessagePack input and puts the result in a JsonDocument.
462
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
463
template <typename TDestination, typename... Args>
464
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
465
                    DeserializationError>
466
deserializeMsgPack(TDestination&& dst, Args&&... args) {
49✔
467
  using namespace detail;
468
  return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
49✔
469
                                          detail::forward<Args>(args)...);
66✔
470
}
471

472
// Parses a MessagePack input and puts the result in a JsonDocument.
473
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
474
template <typename TDestination, typename TChar, typename... Args>
475
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
476
                    DeserializationError>
477
deserializeMsgPack(TDestination&& dst, TChar* input, Args&&... args) {
444✔
478
  using namespace detail;
479
  return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
444✔
480
                                          input,
481
                                          detail::forward<Args>(args)...);
777✔
482
}
483

484
ARDUINOJSON_END_PUBLIC_NAMESPACE
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc