Minh Nguyen / ArduinoJson
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers JsonDeserializer.hpp Source File

JsonDeserializer.hpp

00001 // ArduinoJson - arduinojson.org
00002 // Copyright Benoit Blanchon 2014-2021
00003 // MIT License
00004 
00005 #pragma once
00006 
00007 #include <ArduinoJson/Deserialization/deserialize.hpp>
00008 #include <ArduinoJson/Json/EscapeSequence.hpp>
00009 #include <ArduinoJson/Json/Latch.hpp>
00010 #include <ArduinoJson/Json/Utf16.hpp>
00011 #include <ArduinoJson/Json/Utf8.hpp>
00012 #include <ArduinoJson/Memory/MemoryPool.hpp>
00013 #include <ArduinoJson/Numbers/parseNumber.hpp>
00014 #include <ArduinoJson/Polyfills/assert.hpp>
00015 #include <ArduinoJson/Polyfills/type_traits.hpp>
00016 #include <ArduinoJson/Variant/VariantData.hpp>
00017 
00018 namespace ARDUINOJSON_NAMESPACE {
00019 
00020 template <typename TReader, typename TStringStorage>
00021 class JsonDeserializer {
00022  public:
00023   JsonDeserializer(MemoryPool &pool, TReader reader,
00024                    TStringStorage stringStorage)
00025       : _stringStorage(stringStorage),
00026         _foundSomething(false),
00027         _latch(reader),
00028         _pool(&pool),
00029         _error(DeserializationError::Ok) {}
00030 
00031   template <typename TFilter>
00032   DeserializationError parse(VariantData &variant, TFilter filter,
00033                              NestingLimit nestingLimit) {
00034     parseVariant(variant, filter, nestingLimit);
00035 
00036     if (!_error && _latch.last() != 0 && !variant.isEnclosed()) {
00037       // We don't detect trailing characters earlier, so we need to check now
00038       return DeserializationError::InvalidInput;
00039     }
00040 
00041     return _error;
00042   }
00043 
00044  private:
00045   char current() {
00046     return _latch.current();
00047   }
00048 
00049   void move() {
00050     _latch.clear();
00051   }
00052 
00053   bool eat(char charToSkip) {
00054     if (current() != charToSkip)
00055       return false;
00056     move();
00057     return true;
00058   }
00059 
00060   template <typename TFilter>
00061   bool parseVariant(VariantData &variant, TFilter filter,
00062                     NestingLimit nestingLimit) {
00063     if (!skipSpacesAndComments())
00064       return false;
00065 
00066     switch (current()) {
00067       case '[':
00068         if (filter.allowArray())
00069           return parseArray(variant.toArray(), filter, nestingLimit);
00070         else
00071           return skipArray(nestingLimit);
00072 
00073       case '{':
00074         if (filter.allowObject())
00075           return parseObject(variant.toObject(), filter, nestingLimit);
00076         else
00077           return skipObject(nestingLimit);
00078 
00079       case '\"':
00080       case '\'':
00081         if (filter.allowValue())
00082           return parseStringValue(variant);
00083         else
00084           return skipString();
00085 
00086       default:
00087         if (filter.allowValue())
00088           return parseNumericValue(variant);
00089         else
00090           return skipNumericValue();
00091     }
00092   }
00093 
00094   bool skipVariant(NestingLimit nestingLimit) {
00095     if (!skipSpacesAndComments())
00096       return false;
00097 
00098     switch (current()) {
00099       case '[':
00100         return skipArray(nestingLimit);
00101 
00102       case '{':
00103         return skipObject(nestingLimit);
00104 
00105       case '\"':
00106       case '\'':
00107         return skipString();
00108 
00109       default:
00110         return skipNumericValue();
00111     }
00112   }
00113 
00114   template <typename TFilter>
00115   bool parseArray(CollectionData &array, TFilter filter,
00116                   NestingLimit nestingLimit) {
00117     if (nestingLimit.reached()) {
00118       _error = DeserializationError::TooDeep;
00119       return false;
00120     }
00121 
00122     // Skip opening braket
00123     ARDUINOJSON_ASSERT(current() == '[');
00124     move();
00125 
00126     // Skip spaces
00127     if (!skipSpacesAndComments())
00128       return false;
00129 
00130     // Empty array?
00131     if (eat(']'))
00132       return true;
00133 
00134     TFilter memberFilter = filter[0UL];
00135 
00136     // Read each value
00137     for (;;) {
00138       if (memberFilter.allow()) {
00139         // Allocate slot in array
00140         VariantData *value = array.addElement(_pool);
00141         if (!value) {
00142           _error = DeserializationError::NoMemory;
00143           return false;
00144         }
00145 
00146         // 1 - Parse value
00147         if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
00148           return false;
00149       } else {
00150         if (!skipVariant(nestingLimit.decrement()))
00151           return false;
00152       }
00153 
00154       // 2 - Skip spaces
00155       if (!skipSpacesAndComments())
00156         return false;
00157 
00158       // 3 - More values?
00159       if (eat(']'))
00160         return true;
00161       if (!eat(',')) {
00162         _error = DeserializationError::InvalidInput;
00163         return false;
00164       }
00165     }
00166   }
00167 
00168   bool skipArray(NestingLimit nestingLimit) {
00169     if (nestingLimit.reached()) {
00170       _error = DeserializationError::TooDeep;
00171       return false;
00172     }
00173 
00174     // Skip opening braket
00175     ARDUINOJSON_ASSERT(current() == '[');
00176     move();
00177 
00178     // Read each value
00179     for (;;) {
00180       // 1 - Skip value
00181       if (!skipVariant(nestingLimit.decrement()))
00182         return false;
00183 
00184       // 2 - Skip spaces
00185       if (!skipSpacesAndComments())
00186         return false;
00187 
00188       // 3 - More values?
00189       if (eat(']'))
00190         return true;
00191       if (!eat(',')) {
00192         _error = DeserializationError::InvalidInput;
00193         return false;
00194       }
00195     }
00196   }
00197 
00198   template <typename TFilter>
00199   bool parseObject(CollectionData &object, TFilter filter,
00200                    NestingLimit nestingLimit) {
00201     if (nestingLimit.reached()) {
00202       _error = DeserializationError::TooDeep;
00203       return false;
00204     }
00205 
00206     // Skip opening brace
00207     ARDUINOJSON_ASSERT(current() == '{');
00208     move();
00209 
00210     // Skip spaces
00211     if (!skipSpacesAndComments())
00212       return false;
00213 
00214     // Empty object?
00215     if (eat('}'))
00216       return true;
00217 
00218     // Read each key value pair
00219     for (;;) {
00220       // Parse key
00221       if (!parseKey())
00222         return false;
00223 
00224       // Skip spaces
00225       if (!skipSpacesAndComments())
00226         return false;
00227 
00228       // Colon
00229       if (!eat(':')) {
00230         _error = DeserializationError::InvalidInput;
00231         return false;
00232       }
00233 
00234       const char *key = _stringStorage.c_str();
00235 
00236       TFilter memberFilter = filter[key];
00237 
00238       if (memberFilter.allow()) {
00239         VariantData *variant = object.getMember(adaptString(key));
00240         if (!variant) {
00241           // Save key in memory pool.
00242           // This MUST be done before adding the slot.
00243           key = _stringStorage.save();
00244 
00245           // Allocate slot in object
00246           VariantSlot *slot = object.addSlot(_pool);
00247           if (!slot) {
00248             _error = DeserializationError::NoMemory;
00249             return false;
00250           }
00251 
00252           slot->setKey(key, typename TStringStorage::storage_policy());
00253 
00254           variant = slot->data();
00255         }
00256 
00257         // Parse value
00258         if (!parseVariant(*variant, memberFilter, nestingLimit.decrement()))
00259           return false;
00260       } else {
00261         if (!skipVariant(nestingLimit.decrement()))
00262           return false;
00263       }
00264 
00265       // Skip spaces
00266       if (!skipSpacesAndComments())
00267         return false;
00268 
00269       // More keys/values?
00270       if (eat('}'))
00271         return true;
00272       if (!eat(',')) {
00273         _error = DeserializationError::InvalidInput;
00274         return false;
00275       }
00276 
00277       // Skip spaces
00278       if (!skipSpacesAndComments())
00279         return false;
00280     }
00281   }
00282 
00283   bool skipObject(NestingLimit nestingLimit) {
00284     if (nestingLimit.reached()) {
00285       _error = DeserializationError::TooDeep;
00286       return false;
00287     }
00288 
00289     // Skip opening brace
00290     ARDUINOJSON_ASSERT(current() == '{');
00291     move();
00292 
00293     // Skip spaces
00294     if (!skipSpacesAndComments())
00295       return false;
00296 
00297     // Empty object?
00298     if (eat('}'))
00299       return true;
00300 
00301     // Read each key value pair
00302     for (;;) {
00303       // Skip key
00304       if (!skipVariant(nestingLimit.decrement()))
00305         return false;
00306 
00307       // Skip spaces
00308       if (!skipSpacesAndComments())
00309         return false;
00310 
00311       // Colon
00312       if (!eat(':')) {
00313         _error = DeserializationError::InvalidInput;
00314         return false;
00315       }
00316 
00317       // Skip value
00318       if (!skipVariant(nestingLimit.decrement()))
00319         return false;
00320 
00321       // Skip spaces
00322       if (!skipSpacesAndComments())
00323         return false;
00324 
00325       // More keys/values?
00326       if (eat('}'))
00327         return true;
00328       if (!eat(',')) {
00329         _error = DeserializationError::InvalidInput;
00330         return false;
00331       }
00332     }
00333   }
00334 
00335   bool parseKey() {
00336     _stringStorage.startString();
00337     if (isQuote(current())) {
00338       return parseQuotedString();
00339     } else {
00340       return parseNonQuotedString();
00341     }
00342   }
00343 
00344   bool parseStringValue(VariantData &variant) {
00345     _stringStorage.startString();
00346     if (!parseQuotedString())
00347       return false;
00348     const char *value = _stringStorage.save();
00349     variant.setStringPointer(value, typename TStringStorage::storage_policy());
00350     return true;
00351   }
00352 
00353   bool parseQuotedString() {
00354 #if ARDUINOJSON_DECODE_UNICODE
00355     Utf16::Codepoint codepoint;
00356 #endif
00357     const char stopChar = current();
00358 
00359     move();
00360     for (;;) {
00361       char c = current();
00362       move();
00363       if (c == stopChar)
00364         break;
00365 
00366       if (c == '\0') {
00367         _error = DeserializationError::IncompleteInput;
00368         return false;
00369       }
00370 
00371       if (c == '\\') {
00372         c = current();
00373 
00374         if (c == '\0') {
00375           _error = DeserializationError::IncompleteInput;
00376           return false;
00377         }
00378 
00379         if (c == 'u') {
00380 #if ARDUINOJSON_DECODE_UNICODE
00381           move();
00382           uint16_t codeunit;
00383           if (!parseHex4(codeunit))
00384             return false;
00385           if (codepoint.append(codeunit))
00386             Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
00387           continue;
00388 #else
00389           _error = DeserializationError::NotSupported;
00390           return false;
00391 #endif
00392         }
00393 
00394         // replace char
00395         c = EscapeSequence::unescapeChar(c);
00396         if (c == '\0') {
00397           _error = DeserializationError::InvalidInput;
00398           return false;
00399         }
00400         move();
00401       }
00402 
00403       _stringStorage.append(c);
00404     }
00405 
00406     _stringStorage.append('\0');
00407 
00408     if (!_stringStorage.isValid()) {
00409       _error = DeserializationError::NoMemory;
00410       return false;
00411     }
00412 
00413     return true;
00414   }
00415 
00416   bool parseNonQuotedString() {
00417     char c = current();
00418     ARDUINOJSON_ASSERT(c);
00419 
00420     if (canBeInNonQuotedString(c)) {  // no quotes
00421       do {
00422         move();
00423         _stringStorage.append(c);
00424         c = current();
00425       } while (canBeInNonQuotedString(c));
00426     } else {
00427       _error = DeserializationError::InvalidInput;
00428       return false;
00429     }
00430 
00431     _stringStorage.append('\0');
00432 
00433     if (!_stringStorage.isValid()) {
00434       _error = DeserializationError::NoMemory;
00435       return false;
00436     }
00437 
00438     return true;
00439   }
00440 
00441   bool skipString() {
00442     const char stopChar = current();
00443 
00444     move();
00445     for (;;) {
00446       char c = current();
00447       move();
00448       if (c == stopChar)
00449         break;
00450       if (c == '\0') {
00451         _error = DeserializationError::IncompleteInput;
00452         return false;
00453       }
00454       if (c == '\\') {
00455         if (current() != '\0')
00456           move();
00457       }
00458     }
00459 
00460     return true;
00461   }
00462 
00463   bool parseNumericValue(VariantData &result) {
00464     uint8_t n = 0;
00465 
00466     char c = current();
00467     while (canBeInNonQuotedString(c) && n < 63) {
00468       move();
00469       _buffer[n++] = c;
00470       c = current();
00471     }
00472     _buffer[n] = 0;
00473 
00474     c = _buffer[0];
00475     if (c == 't') {  // true
00476       result.setBoolean(true);
00477       if (n != 4) {
00478         _error = DeserializationError::IncompleteInput;
00479         return false;
00480       }
00481       return true;
00482     }
00483     if (c == 'f') {  // false
00484       result.setBoolean(false);
00485       if (n != 5) {
00486         _error = DeserializationError::IncompleteInput;
00487         return false;
00488       }
00489       return true;
00490     }
00491     if (c == 'n') {  // null
00492       // the variant is already null
00493       if (n != 4) {
00494         _error = DeserializationError::IncompleteInput;
00495         return false;
00496       }
00497       return true;
00498     }
00499 
00500     if (!parseNumber(_buffer, result)) {
00501       _error = DeserializationError::InvalidInput;
00502       return false;
00503     }
00504 
00505     return true;
00506   }
00507 
00508   bool skipNumericValue() {
00509     char c = current();
00510     while (canBeInNonQuotedString(c)) {
00511       move();
00512       c = current();
00513     }
00514     return true;
00515   }
00516 
00517   bool parseHex4(uint16_t &result) {
00518     result = 0;
00519     for (uint8_t i = 0; i < 4; ++i) {
00520       char digit = current();
00521       if (!digit) {
00522         _error = DeserializationError::IncompleteInput;
00523         return false;
00524       }
00525       uint8_t value = decodeHex(digit);
00526       if (value > 0x0F) {
00527         _error = DeserializationError::InvalidInput;
00528         return false;
00529       }
00530       result = uint16_t((result << 4) | value);
00531       move();
00532     }
00533     return true;
00534   }
00535 
00536   static inline bool isBetween(char c, char min, char max) {
00537     return min <= c && c <= max;
00538   }
00539 
00540   static inline bool canBeInNonQuotedString(char c) {
00541     return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
00542            isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.';
00543   }
00544 
00545   static inline bool isQuote(char c) {
00546     return c == '\'' || c == '\"';
00547   }
00548 
00549   static inline uint8_t decodeHex(char c) {
00550     if (c < 'A')
00551       return uint8_t(c - '0');
00552     c = char(c & ~0x20);  // uppercase
00553     return uint8_t(c - 'A' + 10);
00554   }
00555 
00556   bool skipSpacesAndComments() {
00557     for (;;) {
00558       switch (current()) {
00559         // end of string
00560         case '\0':
00561           _error = _foundSomething ? DeserializationError::IncompleteInput
00562                                    : DeserializationError::EmptyInput;
00563           return false;
00564 
00565         // spaces
00566         case ' ':
00567         case '\t':
00568         case '\r':
00569         case '\n':
00570           move();
00571           continue;
00572 
00573 #if ARDUINOJSON_ENABLE_COMMENTS
00574         // comments
00575         case '/':
00576           move();  // skip '/'
00577           switch (current()) {
00578             // block comment
00579             case '*': {
00580               move();  // skip '*'
00581               bool wasStar = false;
00582               for (;;) {
00583                 char c = current();
00584                 if (c == '\0') {
00585                   _error = DeserializationError::IncompleteInput;
00586                   return false;
00587                 }
00588                 if (c == '/' && wasStar) {
00589                   move();
00590                   break;
00591                 }
00592                 wasStar = c == '*';
00593                 move();
00594               }
00595               break;
00596             }
00597 
00598             // trailing comment
00599             case '/':
00600               // no need to skip "//"
00601               for (;;) {
00602                 move();
00603                 char c = current();
00604                 if (c == '\0') {
00605                   _error = DeserializationError::IncompleteInput;
00606                   return false;
00607                 }
00608                 if (c == '\n')
00609                   break;
00610               }
00611               break;
00612 
00613             // not a comment, just a '/'
00614             default:
00615               _error = DeserializationError::InvalidInput;
00616               return false;
00617           }
00618           break;
00619 #endif
00620 
00621         default:
00622           _foundSomething = true;
00623           return true;
00624       }
00625     }
00626   }
00627 
00628   TStringStorage _stringStorage;
00629   bool _foundSomething;
00630   Latch<TReader> _latch;
00631   MemoryPool *_pool;
00632   char _buffer[64];  // using a member instead of a local variable because it
00633                      // ended in the recursive path after compiler inlined the
00634                      // code
00635   DeserializationError _error;
00636 };
00637 
00638 //
00639 // deserializeJson(JsonDocument&, const std::string&, ...)
00640 //
00641 // ... = NestingLimit
00642 template <typename TString>
00643 DeserializationError deserializeJson(
00644     JsonDocument &doc, const TString &input,
00645     NestingLimit nestingLimit = NestingLimit()) {
00646   return deserialize<JsonDeserializer>(doc, input, nestingLimit,
00647                                        AllowAllFilter());
00648 }
00649 // ... = Filter, NestingLimit
00650 template <typename TString>
00651 DeserializationError deserializeJson(
00652     JsonDocument &doc, const TString &input, Filter filter,
00653     NestingLimit nestingLimit = NestingLimit()) {
00654   return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
00655 }
00656 // ... = NestingLimit, Filter
00657 template <typename TString>
00658 DeserializationError deserializeJson(JsonDocument &doc, const TString &input,
00659                                      NestingLimit nestingLimit, Filter filter) {
00660   return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
00661 }
00662 
00663 //
00664 // deserializeJson(JsonDocument&, std::istream&, ...)
00665 //
00666 // ... = NestingLimit
00667 template <typename TStream>
00668 DeserializationError deserializeJson(
00669     JsonDocument &doc, TStream &input,
00670     NestingLimit nestingLimit = NestingLimit()) {
00671   return deserialize<JsonDeserializer>(doc, input, nestingLimit,
00672                                        AllowAllFilter());
00673 }
00674 // ... = Filter, NestingLimit
00675 template <typename TStream>
00676 DeserializationError deserializeJson(
00677     JsonDocument &doc, TStream &input, Filter filter,
00678     NestingLimit nestingLimit = NestingLimit()) {
00679   return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
00680 }
00681 // ... = NestingLimit, Filter
00682 template <typename TStream>
00683 DeserializationError deserializeJson(JsonDocument &doc, TStream &input,
00684                                      NestingLimit nestingLimit, Filter filter) {
00685   return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
00686 }
00687 
00688 //
00689 // deserializeJson(JsonDocument&, char*, ...)
00690 //
00691 // ... = NestingLimit
00692 template <typename TChar>
00693 DeserializationError deserializeJson(
00694     JsonDocument &doc, TChar *input,
00695     NestingLimit nestingLimit = NestingLimit()) {
00696   return deserialize<JsonDeserializer>(doc, input, nestingLimit,
00697                                        AllowAllFilter());
00698 }
00699 // ... = Filter, NestingLimit
00700 template <typename TChar>
00701 DeserializationError deserializeJson(
00702     JsonDocument &doc, TChar *input, Filter filter,
00703     NestingLimit nestingLimit = NestingLimit()) {
00704   return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
00705 }
00706 // ... = NestingLimit, Filter
00707 template <typename TChar>
00708 DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
00709                                      NestingLimit nestingLimit, Filter filter) {
00710   return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
00711 }
00712 
00713 //
00714 // deserializeJson(JsonDocument&, char*, size_t, ...)
00715 //
00716 // ... = NestingLimit
00717 template <typename TChar>
00718 DeserializationError deserializeJson(
00719     JsonDocument &doc, TChar *input, size_t inputSize,
00720     NestingLimit nestingLimit = NestingLimit()) {
00721   return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
00722                                        AllowAllFilter());
00723 }
00724 // ... = Filter, NestingLimit
00725 template <typename TChar>
00726 DeserializationError deserializeJson(
00727     JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
00728     NestingLimit nestingLimit = NestingLimit()) {
00729   return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
00730                                        filter);
00731 }
00732 // ... = NestingLimit, Filter
00733 template <typename TChar>
00734 DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
00735                                      size_t inputSize,
00736                                      NestingLimit nestingLimit, Filter filter) {
00737   return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
00738                                        filter);
00739 }
00740 
00741 }  // namespace ARDUINOJSON_NAMESPACE