Coverage Report

Created: 2025-01-09 06:07

/src/arduinojson/src/ArduinoJson/Json/JsonDeserializer.hpp
Line
Count
Source (jump to first uncovered line)
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/Json/EscapeSequence.hpp>
9
#include <ArduinoJson/Json/Latch.hpp>
10
#include <ArduinoJson/Json/Utf16.hpp>
11
#include <ArduinoJson/Json/Utf8.hpp>
12
#include <ArduinoJson/Memory/ResourceManager.hpp>
13
#include <ArduinoJson/Numbers/parseNumber.hpp>
14
#include <ArduinoJson/Polyfills/assert.hpp>
15
#include <ArduinoJson/Polyfills/type_traits.hpp>
16
#include <ArduinoJson/Polyfills/utility.hpp>
17
#include <ArduinoJson/Variant/VariantData.hpp>
18
19
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
20
21
template <typename TReader>
22
class JsonDeserializer {
23
 public:
24
  JsonDeserializer(ResourceManager* resources, TReader reader)
25
2.46k
      : stringBuilder_(resources),
26
2.46k
        foundSomething_(false),
27
2.46k
        latch_(reader),
28
2.46k
        resources_(resources) {}
29
30
  template <typename TFilter>
31
  DeserializationError parse(VariantData& variant, TFilter filter,
32
2.46k
                             DeserializationOption::NestingLimit nestingLimit) {
33
2.46k
    DeserializationError::Code err;
34
35
2.46k
    err = parseVariant(variant, filter, nestingLimit);
36
37
2.46k
    if (!err && latch_.last() != 0 && variant.isFloat()) {
38
      // We don't detect trailing characters earlier, so we need to check now
39
6
      return DeserializationError::InvalidInput;
40
6
    }
41
42
2.45k
    return err;
43
2.46k
  }
44
45
 private:
46
155k
  char current() {
47
155k
    return latch_.current();
48
155k
  }
49
50
73.2k
  void move() {
51
73.2k
    latch_.clear();
52
73.2k
  }
53
54
28.8k
  bool eat(char charToSkip) {
55
28.8k
    if (current() != charToSkip)
56
14.1k
      return false;
57
14.7k
    move();
58
14.7k
    return true;
59
28.8k
  }
60
61
  template <typename TFilter>
62
  DeserializationError::Code parseVariant(
63
      VariantData& variant, TFilter filter,
64
16.2k
      DeserializationOption::NestingLimit nestingLimit) {
65
16.2k
    DeserializationError::Code err;
66
67
16.2k
    err = skipSpacesAndComments();
68
16.2k
    if (err)
69
332
      return err;
70
71
15.9k
    switch (current()) {
72
2.60k
      case '[':
73
2.60k
        if (filter.allowArray())
74
2.60k
          return parseArray(variant.toArray(), filter, nestingLimit);
75
0
        else
76
0
          return skipArray(nestingLimit);
77
78
1.75k
      case '{':
79
1.75k
        if (filter.allowObject())
80
1.75k
          return parseObject(variant.toObject(), filter, nestingLimit);
81
0
        else
82
0
          return skipObject(nestingLimit);
83
84
759
      case '\"':
85
1.28k
      case '\'':
86
1.28k
        if (filter.allowValue())
87
1.28k
          return parseStringValue(variant);
88
0
        else
89
0
          return skipQuotedString();
90
91
277
      case 't':
92
277
        if (filter.allowValue())
93
277
          variant.setBoolean(true);
94
277
        return skipKeyword("true");
95
96
248
      case 'f':
97
248
        if (filter.allowValue())
98
248
          variant.setBoolean(false);
99
248
        return skipKeyword("false");
100
101
279
      case 'n':
102
        // the variant should already by null, except if the same object key was
103
        // used twice, as in {"a":1,"a":null}
104
279
        return skipKeyword("null");
105
106
9.47k
      default:
107
9.47k
        if (filter.allowValue())
108
9.47k
          return parseNumericValue(variant);
109
0
        else
110
0
          return skipNumericValue();
111
15.9k
    }
112
15.9k
  }
113
114
  DeserializationError::Code skipVariant(
115
0
      DeserializationOption::NestingLimit nestingLimit) {
116
0
    DeserializationError::Code err;
117
118
0
    err = skipSpacesAndComments();
119
0
    if (err)
120
0
      return err;
121
122
0
    switch (current()) {
123
0
      case '[':
124
0
        return skipArray(nestingLimit);
125
126
0
      case '{':
127
0
        return skipObject(nestingLimit);
128
129
0
      case '\"':
130
0
      case '\'':
131
0
        return skipQuotedString();
132
133
0
      case 't':
134
0
        return skipKeyword("true");
135
136
0
      case 'f':
137
0
        return skipKeyword("false");
138
139
0
      case 'n':
140
0
        return skipKeyword("null");
141
142
0
      default:
143
0
        return skipNumericValue();
144
0
    }
145
0
  }
146
147
  template <typename TFilter>
148
  DeserializationError::Code parseArray(
149
      ArrayData& array, TFilter filter,
150
2.60k
      DeserializationOption::NestingLimit nestingLimit) {
151
2.60k
    DeserializationError::Code err;
152
153
2.60k
    if (nestingLimit.reached())
154
5
      return DeserializationError::TooDeep;
155
156
    // Skip opening braket
157
2.60k
    ARDUINOJSON_ASSERT(current() == '[');
158
2.60k
    move();
159
160
    // Skip spaces
161
2.60k
    err = skipSpacesAndComments();
162
2.60k
    if (err)
163
42
      return err;
164
165
    // Empty array?
166
2.55k
    if (eat(']'))
167
169
      return DeserializationError::Ok;
168
169
2.39k
    TFilter elementFilter = filter[0UL];
170
171
    // Read each value
172
11.1k
    for (;;) {
173
11.1k
      if (elementFilter.allow()) {
174
        // Allocate slot in array
175
11.1k
        VariantData* value = array.addElement(resources_);
176
11.1k
        if (!value)
177
0
          return DeserializationError::NoMemory;
178
179
        // 1 - Parse value
180
11.1k
        err = parseVariant(*value, elementFilter, nestingLimit.decrement());
181
11.1k
        if (err)
182
945
          return err;
183
11.1k
      } else {
184
0
        err = skipVariant(nestingLimit.decrement());
185
0
        if (err)
186
0
          return err;
187
0
      }
188
189
      // 2 - Skip spaces
190
10.2k
      err = skipSpacesAndComments();
191
10.2k
      if (err)
192
269
        return err;
193
194
      // 3 - More values?
195
9.96k
      if (eat(']'))
196
1.15k
        return DeserializationError::Ok;
197
8.80k
      if (!eat(','))
198
17
        return DeserializationError::InvalidInput;
199
8.80k
    }
200
2.39k
  }
201
202
  DeserializationError::Code skipArray(
203
0
      DeserializationOption::NestingLimit nestingLimit) {
204
0
    DeserializationError::Code err;
205
206
0
    if (nestingLimit.reached())
207
0
      return DeserializationError::TooDeep;
208
209
    // Skip opening braket
210
0
    ARDUINOJSON_ASSERT(current() == '[');
211
0
    move();
212
213
    // Read each value
214
0
    for (;;) {
215
      // 1 - Skip value
216
0
      err = skipVariant(nestingLimit.decrement());
217
0
      if (err)
218
0
        return err;
219
220
      // 2 - Skip spaces
221
0
      err = skipSpacesAndComments();
222
0
      if (err)
223
0
        return err;
224
225
      // 3 - More values?
226
0
      if (eat(']'))
227
0
        return DeserializationError::Ok;
228
0
      if (!eat(','))
229
0
        return DeserializationError::InvalidInput;
230
0
    }
231
0
  }
232
233
  template <typename TFilter>
234
  DeserializationError::Code parseObject(
235
      ObjectData& object, TFilter filter,
236
1.75k
      DeserializationOption::NestingLimit nestingLimit) {
237
1.75k
    DeserializationError::Code err;
238
239
1.75k
    if (nestingLimit.reached())
240
1
      return DeserializationError::TooDeep;
241
242
    // Skip opening brace
243
1.75k
    ARDUINOJSON_ASSERT(current() == '{');
244
1.75k
    move();
245
246
    // Skip spaces
247
1.75k
    err = skipSpacesAndComments();
248
1.75k
    if (err)
249
45
      return err;
250
251
    // Empty object?
252
1.70k
    if (eat('}'))
253
242
      return DeserializationError::Ok;
254
255
    // Read each key value pair
256
2.81k
    for (;;) {
257
      // Parse key
258
2.81k
      err = parseKey();
259
2.81k
      if (err)
260
50
        return err;
261
262
      // Skip spaces
263
2.76k
      err = skipSpacesAndComments();
264
2.76k
      if (err)
265
130
        return err;
266
267
      // Colon
268
2.63k
      if (!eat(':'))
269
25
        return DeserializationError::InvalidInput;
270
271
2.60k
      JsonString key = stringBuilder_.str();
272
273
2.60k
      TFilter memberFilter = filter[key];
274
275
2.60k
      if (memberFilter.allow()) {
276
2.60k
        auto member = object.getMember(adaptString(key), resources_);
277
2.60k
        if (!member) {
278
          // Save key in memory pool.
279
2.12k
          auto savedKey = stringBuilder_.save();
280
281
          // Allocate slot in object
282
2.12k
          member = object.addMember(savedKey, resources_);
283
2.12k
          if (!member)
284
0
            return DeserializationError::NoMemory;
285
2.12k
        } else {
286
485
          member->clear(resources_);
287
485
        }
288
289
        // Parse value
290
2.60k
        err = parseVariant(*member, memberFilter, nestingLimit.decrement());
291
2.60k
        if (err)
292
763
          return err;
293
2.60k
      } else {
294
0
        err = skipVariant(nestingLimit.decrement());
295
0
        if (err)
296
0
          return err;
297
0
      }
298
299
      // Skip spaces
300
1.84k
      err = skipSpacesAndComments();
301
1.84k
      if (err)
302
73
        return err;
303
304
      // More keys/values?
305
1.77k
      if (eat('}'))
306
364
        return DeserializationError::Ok;
307
1.40k
      if (!eat(','))
308
21
        return DeserializationError::InvalidInput;
309
310
      // Skip spaces
311
1.38k
      err = skipSpacesAndComments();
312
1.38k
      if (err)
313
40
        return err;
314
1.38k
    }
315
1.46k
  }
316
317
  DeserializationError::Code skipObject(
318
0
      DeserializationOption::NestingLimit nestingLimit) {
319
0
    DeserializationError::Code err;
320
321
0
    if (nestingLimit.reached())
322
0
      return DeserializationError::TooDeep;
323
324
    // Skip opening brace
325
0
    ARDUINOJSON_ASSERT(current() == '{');
326
0
    move();
327
328
    // Skip spaces
329
0
    err = skipSpacesAndComments();
330
0
    if (err)
331
0
      return err;
332
333
    // Empty object?
334
0
    if (eat('}'))
335
0
      return DeserializationError::Ok;
336
337
    // Read each key value pair
338
0
    for (;;) {
339
      // Skip key
340
0
      err = skipKey();
341
0
      if (err)
342
0
        return err;
343
344
      // Skip spaces
345
0
      err = skipSpacesAndComments();
346
0
      if (err)
347
0
        return err;
348
349
      // Colon
350
0
      if (!eat(':'))
351
0
        return DeserializationError::InvalidInput;
352
353
      // Skip value
354
0
      err = skipVariant(nestingLimit.decrement());
355
0
      if (err)
356
0
        return err;
357
358
      // Skip spaces
359
0
      err = skipSpacesAndComments();
360
0
      if (err)
361
0
        return err;
362
363
      // More keys/values?
364
0
      if (eat('}'))
365
0
        return DeserializationError::Ok;
366
0
      if (!eat(','))
367
0
        return DeserializationError::InvalidInput;
368
369
0
      err = skipSpacesAndComments();
370
0
      if (err)
371
0
        return err;
372
0
    }
373
0
  }
374
375
2.81k
  DeserializationError::Code parseKey() {
376
2.81k
    stringBuilder_.startString();
377
2.81k
    if (isQuote(current())) {
378
181
      return parseQuotedString();
379
2.63k
    } else {
380
2.63k
      return parseNonQuotedString();
381
2.63k
    }
382
2.81k
  }
383
384
1.28k
  DeserializationError::Code parseStringValue(VariantData& variant) {
385
1.28k
    DeserializationError::Code err;
386
387
1.28k
    stringBuilder_.startString();
388
389
1.28k
    err = parseQuotedString();
390
1.28k
    if (err)
391
238
      return err;
392
393
1.04k
    variant.setOwnedString(stringBuilder_.save());
394
395
1.04k
    return DeserializationError::Ok;
396
1.28k
  }
397
398
1.46k
  DeserializationError::Code parseQuotedString() {
399
1.46k
#if ARDUINOJSON_DECODE_UNICODE
400
1.46k
    Utf16::Codepoint codepoint;
401
1.46k
    DeserializationError::Code err;
402
1.46k
#endif
403
1.46k
    const char stopChar = current();
404
405
1.46k
    move();
406
5.60k
    for (;;) {
407
5.60k
      char c = current();
408
5.60k
      move();
409
5.60k
      if (c == stopChar)
410
1.21k
        break;
411
412
4.39k
      if (c == '\0')
413
209
        return DeserializationError::IncompleteInput;
414
415
4.18k
      if (c == '\\') {
416
718
        c = current();
417
418
718
        if (c == '\0')
419
2
          return DeserializationError::IncompleteInput;
420
421
716
        if (c == 'u') {
422
630
#if ARDUINOJSON_DECODE_UNICODE
423
630
          move();
424
630
          uint16_t codeunit;
425
630
          err = parseHex4(codeunit);
426
630
          if (err)
427
24
            return err;
428
606
          if (codepoint.append(codeunit))
429
525
            Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
430
#else
431
          stringBuilder_.append('\\');
432
#endif
433
606
          continue;
434
630
        }
435
436
        // replace char
437
86
        c = EscapeSequence::unescapeChar(c);
438
86
        if (c == '\0')
439
11
          return DeserializationError::InvalidInput;
440
75
        move();
441
75
      }
442
443
3.53k
      stringBuilder_.append(c);
444
3.53k
    }
445
446
1.21k
    if (!stringBuilder_.isValid())
447
0
      return DeserializationError::NoMemory;
448
449
1.21k
    return DeserializationError::Ok;
450
1.21k
  }
451
452
2.63k
  DeserializationError::Code parseNonQuotedString() {
453
2.63k
    char c = current();
454
2.63k
    ARDUINOJSON_ASSERT(c);
455
456
2.63k
    if (canBeInNonQuotedString(c)) {  // no quotes
457
5.24k
      do {
458
5.24k
        move();
459
5.24k
        stringBuilder_.append(c);
460
5.24k
        c = current();
461
5.24k
      } while (canBeInNonQuotedString(c));
462
2.58k
    } else {
463
42
      return DeserializationError::InvalidInput;
464
42
    }
465
466
2.58k
    if (!stringBuilder_.isValid())
467
0
      return DeserializationError::NoMemory;
468
469
2.58k
    return DeserializationError::Ok;
470
2.58k
  }
471
472
0
  DeserializationError::Code skipKey() {
473
0
    if (isQuote(current())) {
474
0
      return skipQuotedString();
475
0
    } else {
476
0
      return skipNonQuotedString();
477
0
    }
478
0
  }
479
480
0
  DeserializationError::Code skipQuotedString() {
481
0
    const char stopChar = current();
482
483
0
    move();
484
0
    for (;;) {
485
0
      char c = current();
486
0
      move();
487
0
      if (c == stopChar)
488
0
        break;
489
0
      if (c == '\0')
490
0
        return DeserializationError::IncompleteInput;
491
0
      if (c == '\\') {
492
0
        if (current() != '\0')
493
0
          move();
494
0
      }
495
0
    }
496
497
0
    return DeserializationError::Ok;
498
0
  }
499
500
0
  DeserializationError::Code skipNonQuotedString() {
501
0
    char c = current();
502
0
    while (canBeInNonQuotedString(c)) {
503
0
      move();
504
0
      c = current();
505
0
    }
506
0
    return DeserializationError::Ok;
507
0
  }
508
509
9.47k
  DeserializationError::Code parseNumericValue(VariantData& result) {
510
9.47k
    uint8_t n = 0;
511
512
9.47k
    char c = current();
513
38.8k
    while (canBeInNumber(c) && n < 63) {
514
29.4k
      move();
515
29.4k
      buffer_[n++] = c;
516
29.4k
      c = current();
517
29.4k
    }
518
9.47k
    buffer_[n] = 0;
519
520
9.47k
    auto number = parseNumber(buffer_);
521
9.47k
    switch (number.type()) {
522
2.96k
      case NumberType::UnsignedInteger:
523
2.96k
        if (result.setInteger(number.asUnsignedInteger(), resources_))
524
2.96k
          return DeserializationError::Ok;
525
0
        else
526
0
          return DeserializationError::NoMemory;
527
528
578
      case NumberType::SignedInteger:
529
578
        if (result.setInteger(number.asSignedInteger(), resources_))
530
578
          return DeserializationError::Ok;
531
0
        else
532
0
          return DeserializationError::NoMemory;
533
534
4.76k
      case NumberType::Float:
535
4.76k
        if (result.setFloat(number.asFloat(), resources_))
536
4.76k
          return DeserializationError::Ok;
537
0
        else
538
0
          return DeserializationError::NoMemory;
539
540
0
#if ARDUINOJSON_USE_DOUBLE
541
1.02k
      case NumberType::Double:
542
1.02k
        if (result.setFloat(number.asDouble(), resources_))
543
1.02k
          return DeserializationError::Ok;
544
0
        else
545
0
          return DeserializationError::NoMemory;
546
0
#endif
547
548
142
      default:
549
142
        return DeserializationError::InvalidInput;
550
9.47k
    }
551
9.47k
  }
552
553
0
  DeserializationError::Code skipNumericValue() {
554
0
    char c = current();
555
0
    while (canBeInNumber(c)) {
556
0
      move();
557
0
      c = current();
558
0
    }
559
0
    return DeserializationError::Ok;
560
0
  }
561
562
630
  DeserializationError::Code parseHex4(uint16_t& result) {
563
630
    result = 0;
564
3.07k
    for (uint8_t i = 0; i < 4; ++i) {
565
2.46k
      char digit = current();
566
2.46k
      if (!digit)
567
14
        return DeserializationError::IncompleteInput;
568
2.45k
      uint8_t value = decodeHex(digit);
569
2.45k
      if (value > 0x0F)
570
10
        return DeserializationError::InvalidInput;
571
2.44k
      result = uint16_t((result << 4) | value);
572
2.44k
      move();
573
2.44k
    }
574
606
    return DeserializationError::Ok;
575
630
  }
576
577
57.0k
  static inline bool isBetween(char c, char min, char max) {
578
57.0k
    return min <= c && c <= max;
579
57.0k
  }
580
581
38.8k
  static inline bool canBeInNumber(char c) {
582
38.8k
    return isBetween(c, '0', '9') || c == '+' || c == '-' || c == '.' ||
583
#if ARDUINOJSON_ENABLE_NAN || ARDUINOJSON_ENABLE_INFINITY
584
           isBetween(c, 'A', 'Z') || isBetween(c, 'a', 'z');
585
#else
586
38.8k
           c == 'e' || c == 'E';
587
38.8k
#endif
588
38.8k
  }
589
590
7.87k
  static inline bool canBeInNonQuotedString(char c) {
591
7.87k
    return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
592
7.87k
           isBetween(c, 'A', 'Z');
593
7.87k
  }
594
595
2.81k
  static inline bool isQuote(char c) {
596
2.81k
    return c == '\'' || c == '\"';
597
2.81k
  }
598
599
2.45k
  static inline uint8_t decodeHex(char c) {
600
2.45k
    if (c < 'A')
601
1.64k
      return uint8_t(c - '0');
602
814
    c = char(c & ~0x20);  // uppercase
603
814
    return uint8_t(c - 'A' + 10);
604
2.45k
  }
605
606
36.8k
  DeserializationError::Code skipSpacesAndComments() {
607
42.9k
    for (;;) {
608
42.9k
      switch (current()) {
609
        // end of string
610
931
        case '\0':
611
931
          return foundSomething_ ? DeserializationError::IncompleteInput
612
931
                                 : DeserializationError::EmptyInput;
613
614
        // spaces
615
1.57k
        case ' ':
616
2.96k
        case '\t':
617
4.37k
        case '\r':
618
6.07k
        case '\n':
619
6.07k
          move();
620
6.07k
          continue;
621
622
#if ARDUINOJSON_ENABLE_COMMENTS
623
        // comments
624
        case '/':
625
          move();  // skip '/'
626
          switch (current()) {
627
            // block comment
628
            case '*': {
629
              move();  // skip '*'
630
              bool wasStar = false;
631
              for (;;) {
632
                char c = current();
633
                if (c == '\0')
634
                  return DeserializationError::IncompleteInput;
635
                if (c == '/' && wasStar) {
636
                  move();
637
                  break;
638
                }
639
                wasStar = c == '*';
640
                move();
641
              }
642
              break;
643
            }
644
645
            // trailing comment
646
            case '/':
647
              // no need to skip "//"
648
              for (;;) {
649
                move();
650
                char c = current();
651
                if (c == '\0')
652
                  return DeserializationError::IncompleteInput;
653
                if (c == '\n')
654
                  break;
655
              }
656
              break;
657
658
            // not a comment, just a '/'
659
            default:
660
              return DeserializationError::InvalidInput;
661
          }
662
          break;
663
#endif
664
665
35.9k
        default:
666
35.9k
          foundSomething_ = true;
667
35.9k
          return DeserializationError::Ok;
668
42.9k
      }
669
42.9k
    }
670
36.8k
  }
671
672
804
  DeserializationError::Code skipKeyword(const char* s) {
673
4.02k
    while (*s) {
674
3.30k
      char c = current();
675
3.30k
      if (c == '\0')
676
37
        return DeserializationError::IncompleteInput;
677
3.26k
      if (*s != c)
678
45
        return DeserializationError::InvalidInput;
679
3.21k
      ++s;
680
3.21k
      move();
681
3.21k
    }
682
722
    return DeserializationError::Ok;
683
804
  }
684
685
  StringBuilder stringBuilder_;
686
  bool foundSomething_;
687
  Latch<TReader> latch_;
688
  ResourceManager* resources_;
689
  char buffer_[64];  // using a member instead of a local variable because it
690
                     // ended in the recursive path after compiler inlined the
691
                     // code
692
};
693
694
ARDUINOJSON_END_PRIVATE_NAMESPACE
695
696
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
697
698
// Parses a JSON input, filters, and puts the result in a JsonDocument.
699
// https://arduinojson.org/v7/api/json/deserializejson/
700
template <typename TDestination, typename... Args,
701
          detail::enable_if_t<
702
              detail::is_deserialize_destination<TDestination>::value, int> = 0>
703
inline DeserializationError deserializeJson(TDestination&& dst,
704
                                            Args&&... args) {
705
  using namespace detail;
706
  return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
707
                                       detail::forward<Args>(args)...);
708
}
709
710
// Parses a JSON input, filters, and puts the result in a JsonDocument.
711
// https://arduinojson.org/v7/api/json/deserializejson/
712
template <typename TDestination, typename TChar, typename... Args,
713
          detail::enable_if_t<
714
              detail::is_deserialize_destination<TDestination>::value, int> = 0>
715
inline DeserializationError deserializeJson(TDestination&& dst, TChar* input,
716
2.46k
                                            Args&&... args) {
717
2.46k
  using namespace detail;
718
2.46k
  return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
719
2.46k
                                       input, detail::forward<Args>(args)...);
720
2.46k
}
721
722
ARDUINOJSON_END_PUBLIC_NAMESPACE