Coverage Report

Created: 2024-09-08 06:19

/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
      : stringBuilder_(resources),
26
        foundSomething_(false),
27
        latch_(reader),
28
2.40k
        resources_(resources) {}
29
30
  template <typename TFilter>
31
  DeserializationError parse(VariantData& variant, TFilter filter,
32
2.40k
                             DeserializationOption::NestingLimit nestingLimit) {
33
2.40k
    DeserializationError::Code err;
34
35
2.40k
    err = parseVariant(variant, filter, nestingLimit);
36
37
2.40k
    if (!err && latch_.last() != 0 && variant.isFloat()) {
38
      // We don't detect trailing characters earlier, so we need to check now
39
9
      return DeserializationError::InvalidInput;
40
9
    }
41
42
2.39k
    return err;
43
2.40k
  }
44
45
 private:
46
140k
  char current() {
47
140k
    return latch_.current();
48
140k
  }
49
50
70.0k
  void move() {
51
70.0k
    latch_.clear();
52
70.0k
  }
53
54
24.5k
  bool eat(char charToSkip) {
55
24.5k
    if (current() != charToSkip)
56
11.6k
      return false;
57
12.9k
    move();
58
12.9k
    return true;
59
24.5k
  }
60
61
  template <typename TFilter>
62
  DeserializationError::Code parseVariant(
63
      VariantData& variant, TFilter filter,
64
13.6k
      DeserializationOption::NestingLimit nestingLimit) {
65
13.6k
    DeserializationError::Code err;
66
67
13.6k
    err = skipSpacesAndComments();
68
13.6k
    if (err)
69
282
      return err;
70
71
13.3k
    switch (current()) {
72
2.03k
      case '[':
73
2.03k
        if (filter.allowArray())
74
2.03k
          return parseArray(variant.toArray(), filter, nestingLimit);
75
0
        else
76
0
          return skipArray(nestingLimit);
77
78
1.83k
      case '{':
79
1.83k
        if (filter.allowObject())
80
1.83k
          return parseObject(variant.toObject(), filter, nestingLimit);
81
0
        else
82
0
          return skipObject(nestingLimit);
83
84
910
      case '\"':
85
1.30k
      case '\'':
86
1.30k
        if (filter.allowValue())
87
1.30k
          return parseStringValue(variant);
88
0
        else
89
0
          return skipQuotedString();
90
91
278
      case 't':
92
278
        if (filter.allowValue())
93
278
          variant.setBoolean(true);
94
278
        return skipKeyword("true");
95
96
247
      case 'f':
97
247
        if (filter.allowValue())
98
247
          variant.setBoolean(false);
99
247
        return skipKeyword("false");
100
101
281
      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
281
        return skipKeyword("null");
105
106
7.40k
      default:
107
7.40k
        if (filter.allowValue())
108
7.40k
          return parseNumericValue(variant);
109
0
        else
110
0
          return skipNumericValue();
111
13.3k
    }
112
13.3k
  }
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.03k
      DeserializationOption::NestingLimit nestingLimit) {
151
2.03k
    DeserializationError::Code err;
152
153
2.03k
    if (nestingLimit.reached())
154
4
      return DeserializationError::TooDeep;
155
156
    // Skip opening braket
157
2.02k
    ARDUINOJSON_ASSERT(current() == '[');
158
2.02k
    move();
159
160
    // Skip spaces
161
2.02k
    err = skipSpacesAndComments();
162
2.02k
    if (err)
163
42
      return err;
164
165
    // Empty array?
166
1.98k
    if (eat(']'))
167
177
      return DeserializationError::Ok;
168
169
1.80k
    TFilter elementFilter = filter[0UL];
170
171
    // Read each value
172
8.29k
    for (;;) {
173
8.29k
      if (elementFilter.allow()) {
174
        // Allocate slot in array
175
8.29k
        VariantData* value = array.addElement(resources_);
176
8.29k
        if (!value)
177
0
          return DeserializationError::NoMemory;
178
179
        // 1 - Parse value
180
8.29k
        err = parseVariant(*value, elementFilter, nestingLimit.decrement());
181
8.29k
        if (err)
182
592
          return err;
183
8.29k
      } else {
184
0
        err = skipVariant(nestingLimit.decrement());
185
0
        if (err)
186
0
          return err;
187
0
      }
188
189
      // 2 - Skip spaces
190
7.70k
      err = skipSpacesAndComments();
191
7.70k
      if (err)
192
246
        return err;
193
194
      // 3 - More values?
195
7.45k
      if (eat(']'))
196
949
        return DeserializationError::Ok;
197
6.50k
      if (!eat(','))
198
21
        return DeserializationError::InvalidInput;
199
6.50k
    }
200
1.80k
  }
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.83k
      DeserializationOption::NestingLimit nestingLimit) {
237
1.83k
    DeserializationError::Code err;
238
239
1.83k
    if (nestingLimit.reached())
240
2
      return DeserializationError::TooDeep;
241
242
    // Skip opening brace
243
1.83k
    ARDUINOJSON_ASSERT(current() == '{');
244
1.83k
    move();
245
246
    // Skip spaces
247
1.83k
    err = skipSpacesAndComments();
248
1.83k
    if (err)
249
42
      return err;
250
251
    // Empty object?
252
1.78k
    if (eat('}'))
253
249
      return DeserializationError::Ok;
254
255
    // Read each key value pair
256
3.17k
    for (;;) {
257
      // Parse key
258
3.17k
      err = parseKey();
259
3.17k
      if (err)
260
55
        return err;
261
262
      // Skip spaces
263
3.12k
      err = skipSpacesAndComments();
264
3.12k
      if (err)
265
133
        return err;
266
267
      // Colon
268
2.98k
      if (!eat(':'))
269
23
        return DeserializationError::InvalidInput;
270
271
2.96k
      JsonString key = stringBuilder_.str();
272
273
2.96k
      TFilter memberFilter = filter[key.c_str()];
274
275
2.96k
      if (memberFilter.allow()) {
276
2.96k
        auto member = object.getMember(adaptString(key.c_str()), resources_);
277
2.96k
        if (!member) {
278
          // Save key in memory pool.
279
2.46k
          auto savedKey = stringBuilder_.save();
280
281
          // Allocate slot in object
282
2.46k
          member = object.addMember(savedKey, resources_);
283
2.46k
          if (!member)
284
0
            return DeserializationError::NoMemory;
285
2.46k
        } else {
286
506
          member->clear(resources_);
287
506
        }
288
289
        // Parse value
290
2.96k
        err = parseVariant(*member, memberFilter, nestingLimit.decrement());
291
2.96k
        if (err)
292
792
          return err;
293
2.96k
      } else {
294
0
        err = skipVariant(nestingLimit.decrement());
295
0
        if (err)
296
0
          return err;
297
0
      }
298
299
      // Skip spaces
300
2.17k
      err = skipSpacesAndComments();
301
2.17k
      if (err)
302
75
        return err;
303
304
      // More keys/values?
305
2.09k
      if (eat('}'))
306
397
        return DeserializationError::Ok;
307
1.70k
      if (!eat(','))
308
24
        return DeserializationError::InvalidInput;
309
310
      // Skip spaces
311
1.67k
      err = skipSpacesAndComments();
312
1.67k
      if (err)
313
40
        return err;
314
1.67k
    }
315
1.53k
  }
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
3.17k
  DeserializationError::Code parseKey() {
376
3.17k
    stringBuilder_.startString();
377
3.17k
    if (isQuote(current())) {
378
212
      return parseQuotedString();
379
2.96k
    } else {
380
2.96k
      return parseNonQuotedString();
381
2.96k
    }
382
3.17k
  }
383
384
1.30k
  DeserializationError::Code parseStringValue(VariantData& variant) {
385
1.30k
    DeserializationError::Code err;
386
387
1.30k
    stringBuilder_.startString();
388
389
1.30k
    err = parseQuotedString();
390
1.30k
    if (err)
391
231
      return err;
392
393
1.07k
    variant.setOwnedString(stringBuilder_.save());
394
395
1.07k
    return DeserializationError::Ok;
396
1.30k
  }
397
398
1.51k
  DeserializationError::Code parseQuotedString() {
399
1.51k
#if ARDUINOJSON_DECODE_UNICODE
400
1.51k
    Utf16::Codepoint codepoint;
401
1.51k
    DeserializationError::Code err;
402
1.51k
#endif
403
1.51k
    const char stopChar = current();
404
405
1.51k
    move();
406
6.27k
    for (;;) {
407
6.27k
      char c = current();
408
6.27k
      move();
409
6.27k
      if (c == stopChar)
410
1.27k
        break;
411
412
4.99k
      if (c == '\0')
413
200
        return DeserializationError::IncompleteInput;
414
415
4.79k
      if (c == '\\') {
416
755
        c = current();
417
418
755
        if (c == '\0')
419
2
          return DeserializationError::IncompleteInput;
420
421
753
        if (c == 'u') {
422
641
#if ARDUINOJSON_DECODE_UNICODE
423
641
          move();
424
641
          uint16_t codeunit;
425
641
          err = parseHex4(codeunit);
426
641
          if (err)
427
26
            return err;
428
615
          if (codepoint.append(codeunit))
429
538
            Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
430
#else
431
          stringBuilder_.append('\\');
432
#endif
433
615
          continue;
434
641
        }
435
436
        // replace char
437
112
        c = EscapeSequence::unescapeChar(c);
438
112
        if (c == '\0')
439
11
          return DeserializationError::InvalidInput;
440
101
        move();
441
101
      }
442
443
4.14k
      stringBuilder_.append(c);
444
4.14k
    }
445
446
1.27k
    if (!stringBuilder_.isValid())
447
0
      return DeserializationError::NoMemory;
448
449
1.27k
    return DeserializationError::Ok;
450
1.27k
  }
451
452
2.96k
  DeserializationError::Code parseNonQuotedString() {
453
2.96k
    char c = current();
454
2.96k
    ARDUINOJSON_ASSERT(c);
455
456
2.96k
    if (canBeInNonQuotedString(c)) {  // no quotes
457
5.10k
      do {
458
5.10k
        move();
459
5.10k
        stringBuilder_.append(c);
460
5.10k
        c = current();
461
5.10k
      } while (canBeInNonQuotedString(c));
462
2.91k
    } else {
463
47
      return DeserializationError::InvalidInput;
464
47
    }
465
466
2.91k
    if (!stringBuilder_.isValid())
467
0
      return DeserializationError::NoMemory;
468
469
2.91k
    return DeserializationError::Ok;
470
2.91k
  }
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
7.40k
  DeserializationError::Code parseNumericValue(VariantData& result) {
510
7.40k
    uint8_t n = 0;
511
512
7.40k
    char c = current();
513
35.2k
    while (canBeInNumber(c) && n < 63) {
514
27.8k
      move();
515
27.8k
      buffer_[n++] = c;
516
27.8k
      c = current();
517
27.8k
    }
518
7.40k
    buffer_[n] = 0;
519
520
7.40k
    auto number = parseNumber(buffer_);
521
7.40k
    switch (number.type()) {
522
1.67k
      case NumberType::UnsignedInteger:
523
1.67k
        if (result.setInteger(number.asUnsignedInteger(), resources_))
524
1.67k
          return DeserializationError::Ok;
525
0
        else
526
0
          return DeserializationError::NoMemory;
527
528
600
      case NumberType::SignedInteger:
529
600
        if (result.setInteger(number.asSignedInteger(), resources_))
530
600
          return DeserializationError::Ok;
531
0
        else
532
0
          return DeserializationError::NoMemory;
533
534
3.88k
      case NumberType::Float:
535
3.88k
        if (result.setFloat(number.asFloat(), resources_))
536
3.88k
          return DeserializationError::Ok;
537
0
        else
538
0
          return DeserializationError::NoMemory;
539
540
0
#if ARDUINOJSON_USE_DOUBLE
541
1.08k
      case NumberType::Double:
542
1.08k
        if (result.setFloat(number.asDouble(), resources_))
543
1.08k
          return DeserializationError::Ok;
544
0
        else
545
0
          return DeserializationError::NoMemory;
546
0
#endif
547
548
161
      default:
549
161
        return DeserializationError::InvalidInput;
550
7.40k
    }
551
7.40k
  }
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
641
  DeserializationError::Code parseHex4(uint16_t& result) {
563
641
    result = 0;
564
3.12k
    for (uint8_t i = 0; i < 4; ++i) {
565
2.51k
      char digit = current();
566
2.51k
      if (!digit)
567
18
        return DeserializationError::IncompleteInput;
568
2.49k
      uint8_t value = decodeHex(digit);
569
2.49k
      if (value > 0x0F)
570
8
        return DeserializationError::InvalidInput;
571
2.48k
      result = uint16_t((result << 4) | value);
572
2.48k
      move();
573
2.48k
    }
574
615
    return DeserializationError::Ok;
575
641
  }
576
577
54.3k
  static inline bool isBetween(char c, char min, char max) {
578
54.3k
    return min <= c && c <= max;
579
54.3k
  }
580
581
35.2k
  static inline bool canBeInNumber(char c) {
582
35.2k
    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
35.2k
           c == 'e' || c == 'E';
587
35.2k
#endif
588
35.2k
  }
589
590
8.06k
  static inline bool canBeInNonQuotedString(char c) {
591
8.06k
    return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
592
8.06k
           isBetween(c, 'A', 'Z');
593
8.06k
  }
594
595
3.17k
  static inline bool isQuote(char c) {
596
3.17k
    return c == '\'' || c == '\"';
597
3.17k
  }
598
599
2.49k
  static inline uint8_t decodeHex(char c) {
600
2.49k
    if (c < 'A')
601
1.87k
      return uint8_t(c - '0');
602
623
    c = char(c & ~0x20);  // uppercase
603
623
    return uint8_t(c - 'A' + 10);
604
2.49k
  }
605
606
32.1k
  DeserializationError::Code skipSpacesAndComments() {
607
38.2k
    for (;;) {
608
38.2k
      switch (current()) {
609
        // end of string
610
860
        case '\0':
611
860
          return foundSomething_ ? DeserializationError::IncompleteInput
612
860
                                 : DeserializationError::EmptyInput;
613
614
        // spaces
615
1.56k
        case ' ':
616
3.14k
        case '\t':
617
4.56k
        case '\r':
618
6.06k
        case '\n':
619
6.06k
          move();
620
6.06k
          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
31.3k
        default:
666
31.3k
          foundSomething_ = true;
667
31.3k
          return DeserializationError::Ok;
668
38.2k
      }
669
38.2k
    }
670
32.1k
  }
671
672
806
  DeserializationError::Code skipKeyword(const char* s) {
673
4.02k
    while (*s) {
674
3.30k
      char c = current();
675
3.30k
      if (c == '\0')
676
39
        return DeserializationError::IncompleteInput;
677
3.26k
      if (*s != c)
678
45
        return DeserializationError::InvalidInput;
679
3.22k
      ++s;
680
3.22k
      move();
681
3.22k
    }
682
722
    return DeserializationError::Ok;
683
806
  }
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<detail::is_deserialize_destination<TDestination>::value,
702
                    DeserializationError>
703
deserializeJson(TDestination&& dst, Args&&... args) {
704
  using namespace detail;
705
  return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
706
                                       detail::forward<Args>(args)...);
707
}
708
709
// Parses a JSON input, filters, and puts the result in a JsonDocument.
710
// https://arduinojson.org/v7/api/json/deserializejson/
711
template <typename TDestination, typename TChar, typename... Args>
712
detail::enable_if_t<detail::is_deserialize_destination<TDestination>::value,
713
                    DeserializationError>
714
2.40k
deserializeJson(TDestination&& dst, TChar* input, Args&&... args) {
715
2.40k
  using namespace detail;
716
2.40k
  return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
717
2.40k
                                       input, detail::forward<Args>(args)...);
718
2.40k
}
719
720
ARDUINOJSON_END_PUBLIC_NAMESPACE