Added new ArduinoJson library.

Disabled drum menus when drums not enabled.
Replaced all strcpy(),strncpy(),strcat(),strncat() against strlcpy()/strlcat.
dev
Holger Wirtz 2 years ago
parent 70f5c12484
commit a0d3fee52f
  1. 18
      MicroDexed.ino
  2. 161
      UI.hpp
  3. 29
      dexed_sd.cpp
  4. 2
      disp_plus.h
  5. 32
      midi_devices.hpp
  6. 35
      third-party/ArduinoJson/CHANGELOG.md
  7. 2
      third-party/ArduinoJson/CMakeLists.txt
  8. 82
      third-party/ArduinoJson/README.md
  9. 2
      third-party/ArduinoJson/appveyor.yml
  10. 367
      third-party/ArduinoJson/banner.svg
  11. 2
      third-party/ArduinoJson/examples/JsonFilterExample/JsonFilterExample.ino
  12. 19
      third-party/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino
  13. 28
      third-party/ArduinoJson/examples/StringExample/StringExample.ino
  14. 0
      third-party/ArduinoJson/extras/ci/particle.sh
  15. 0
      third-party/ArduinoJson/extras/scripts/build-arduino-package.sh
  16. 0
      third-party/ArduinoJson/extras/scripts/build-single-header.sh
  17. 0
      third-party/ArduinoJson/extras/scripts/get-release-body.sh
  18. 0
      third-party/ArduinoJson/extras/scripts/get-release-page.sh
  19. 0
      third-party/ArduinoJson/extras/scripts/publish-particle-library.sh
  20. 0
      third-party/ArduinoJson/extras/scripts/publish.sh
  21. 0
      third-party/ArduinoJson/extras/scripts/wandbox/publish.sh
  22. 4
      third-party/ArduinoJson/extras/tests/Cpp11/CMakeLists.txt
  23. 72
      third-party/ArduinoJson/extras/tests/Cpp11/stl_containers.cpp
  24. 2
      third-party/ArduinoJson/extras/tests/Helpers/api/String.h
  25. 2
      third-party/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt
  26. 2
      third-party/ArduinoJson/extras/tests/JsonArray/add.cpp
  27. 512
      third-party/ArduinoJson/extras/tests/JsonArray/compare.cpp
  28. 16
      third-party/ArduinoJson/extras/tests/JsonArray/get.cpp
  29. 3
      third-party/ArduinoJson/extras/tests/JsonArray/std_string.cpp
  30. 4
      third-party/ArduinoJson/extras/tests/JsonArray/subscript.cpp
  31. 48
      third-party/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp
  32. 2
      third-party/ArduinoJson/extras/tests/JsonDeserializer/input_types.cpp
  33. 6
      third-party/ArduinoJson/extras/tests/JsonDeserializer/invalid_input.cpp
  34. 44
      third-party/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp
  35. 67
      third-party/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp
  36. 2
      third-party/ArduinoJson/extras/tests/JsonDocument/remove.cpp
  37. 1
      third-party/ArduinoJson/extras/tests/JsonObject/CMakeLists.txt
  38. 512
      third-party/ArduinoJson/extras/tests/JsonObject/compare.cpp
  39. 2
      third-party/ArduinoJson/extras/tests/JsonObject/containsKey.cpp
  40. 2
      third-party/ArduinoJson/extras/tests/JsonObject/createNestedArray.cpp
  41. 2
      third-party/ArduinoJson/extras/tests/JsonObject/createNestedObject.cpp
  42. 2
      third-party/ArduinoJson/extras/tests/JsonObject/remove.cpp
  43. 3
      third-party/ArduinoJson/extras/tests/JsonObject/std_string.cpp
  44. 10
      third-party/ArduinoJson/extras/tests/JsonObject/subscript.cpp
  45. 4
      third-party/ArduinoJson/extras/tests/JsonVariant/CMakeLists.txt
  46. 6
      third-party/ArduinoJson/extras/tests/JsonVariant/compare.cpp
  47. 4
      third-party/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp
  48. 18
      third-party/ArduinoJson/extras/tests/JsonVariant/converters.cpp
  49. 28
      third-party/ArduinoJson/extras/tests/JsonVariant/createNested.cpp
  50. 35
      third-party/ArduinoJson/extras/tests/JsonVariant/isnull.cpp
  51. 28
      third-party/ArduinoJson/extras/tests/JsonVariant/set.cpp
  52. 87
      third-party/ArduinoJson/extras/tests/JsonVariant/shallowCopy.cpp
  53. 36
      third-party/ArduinoJson/extras/tests/JsonVariant/size.cpp
  54. 4
      third-party/ArduinoJson/extras/tests/JsonVariant/subscript.cpp
  55. 10
      third-party/ArduinoJson/extras/tests/MemoryPool/StringCopier.cpp
  56. 3
      third-party/ArduinoJson/extras/tests/MemoryPool/size.cpp
  57. 1
      third-party/ArduinoJson/extras/tests/Misc/CMakeLists.txt
  58. 23
      third-party/ArduinoJson/extras/tests/Misc/StringAdapters.cpp
  59. 35
      third-party/ArduinoJson/extras/tests/Misc/TypeTraits.cpp
  60. 2
      third-party/ArduinoJson/extras/tests/Misc/Utf8.cpp
  61. 115
      third-party/ArduinoJson/extras/tests/Misc/deprecated.cpp
  62. 6
      third-party/ArduinoJson/extras/tests/MsgPackDeserializer/filter.cpp
  63. 6
      third-party/ArduinoJson/extras/tests/MsgPackSerializer/serializeArray.cpp
  64. 1
      third-party/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp
  65. 3
      third-party/ArduinoJson/extras/tests/Numbers/CMakeLists.txt
  66. 58
      third-party/ArduinoJson/extras/tests/Numbers/convertNumber.cpp
  67. 4
      third-party/ArduinoJson/extras/tests/Numbers/parseNumber.cpp
  68. 2
      third-party/ArduinoJson/library.json
  69. 2
      third-party/ArduinoJson/library.properties
  70. 1
      third-party/ArduinoJson/logo.svg
  71. 34
      third-party/ArduinoJson/src/ArduinoJson.hpp
  72. 31
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayFunctions.hpp
  73. 28
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayImpl.hpp
  74. 121
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayIterator.hpp
  75. 213
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayRef.hpp
  76. 49
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayShortcuts.hpp
  77. 191
      third-party/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp
  78. 210
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp
  79. 134
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp
  80. 32
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArrayImpl.hpp
  81. 117
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArrayIterator.hpp
  82. 58
      third-party/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp
  83. 25
      third-party/ArduinoJson/src/ArduinoJson/Collection/CollectionData.hpp
  84. 62
      third-party/ArduinoJson/src/ArduinoJson/Collection/CollectionImpl.hpp
  85. 10
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Filter.hpp
  86. 3
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp
  87. 3
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Readers/RamReader.hpp
  88. 25
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Readers/VariantReader.hpp
  89. 30
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp
  90. 18
      third-party/ArduinoJson/src/ArduinoJson/Document/BasicJsonDocument.hpp
  91. 3
      third-party/ArduinoJson/src/ArduinoJson/Document/DynamicJsonDocument.hpp
  92. 284
      third-party/ArduinoJson/src/ArduinoJson/Document/JsonDocument.hpp
  93. 10
      third-party/ArduinoJson/src/ArduinoJson/Document/StaticJsonDocument.hpp
  94. 508
      third-party/ArduinoJson/src/ArduinoJson/Json/JsonDeserializer.hpp
  95. 31
      third-party/ArduinoJson/src/ArduinoJson/Json/JsonSerializer.hpp
  96. 23
      third-party/ArduinoJson/src/ArduinoJson/Json/PrettyJsonSerializer.hpp
  97. 8
      third-party/ArduinoJson/src/ArduinoJson/Json/TextFormatter.hpp
  98. 44
      third-party/ArduinoJson/src/ArduinoJson/Memory/MemoryPool.hpp
  99. 21
      third-party/ArduinoJson/src/ArduinoJson/Misc/Visitable.hpp
  100. 349
      third-party/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
  101. Some files were not shown because too many files have changed in this diff Show More

@ -748,7 +748,7 @@ void setup() {
//ep_modchorus.set_bypass(true);
strcpy(configuration.performance.name, "INIT Perf");
strlcpy(configuration.performance.name, "INIT Perf", sizeof(configuration.performance.name));
LCDML.OTHER_jumpToFunc(UI_func_voice_select);
}
@ -1589,7 +1589,7 @@ void handleSystemExclusive(byte* sysex, unsigned int len) {
Serial.println(F("One Voice bulk upload"));
show_patch(instance_id);
#endif
strncpy(g_voice_name[instance_id], (char*)&sysex[151], VOICE_NAME_LEN - 1);
strlcpy(g_voice_name[instance_id], (char*)&sysex[151], sizeof(g_voice_name[instance_id]));
if (LCDML.FUNC_getID() == LCDML.OTHER_getIDFromFunction(UI_func_voice_select)) {
LCDML.OTHER_updateFunc();
@ -2503,21 +2503,21 @@ void generate_version_string(char* buffer, uint8_t len) {
char tmp[3];
memset(buffer, 0, len);
strncat(buffer, VERSION, len);
strlcat(buffer, VERSION, len);
#if defined(ARDUINO_TEENSY36)
strncat(buffer, "-3.6", 4);
strlcat(buffer, "-3.6", 4);
#elif defined(ARDUINO_TEENSY40)
strncat(buffer, "-4.0", 4);
strlcat(buffer, "-4.0", 4);
#elif defined(ARDUINO_TEENSY41)
strncat(buffer, "-4.1", 4);
strlcat(buffer, "-4.1", 4);
#endif
#if defined(USE_FX)
strncat(buffer, "FX", 2);
strlcat(buffer, "FX", 2);
#endif
#if defined(MAX_NOTES)
strncat(buffer, "-", 1);
strlcat(buffer, "-", 1);
itoa(MAX_NOTES, tmp, 10);
strncat(buffer, tmp, 2);
strlcat(buffer, tmp, 2);
#endif
}

161
UI.hpp

@ -3981,6 +3981,7 @@ void UI_handle_OP(uint8_t param) {
}
}
#if NUM_DRUMS > 0
void _check_display_name(bool display_name, uint8_t digits) {
if (display_name == true) {
display.setCursor(0, 1);
@ -4052,8 +4053,19 @@ void _check_display_name_min_max(uint8_t input_mode, uint8_t input_type, uint8_t
break;
}
}
#endif
void UI_func_drum_midi_channel(uint8_t param) {
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("MIDI Channel"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
display.setCursor(0, 0);
@ -4088,17 +4100,25 @@ void UI_func_drum_midi_channel(uint8_t param) {
#endif
}
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
lcd_special_chars(SCROLLBAR);
encoderDir[ENC_R].reset();
}
}
void UI_func_drums_main_volume(uint8_t param) {
char tmp[6];
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("Main Volume"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
lcd_special_chars(BLOCKBAR);
@ -4118,6 +4138,7 @@ void UI_func_drums_main_volume(uint8_t param) {
master_mixer_l.gain(MASTER_MIX_CH_DRUMS, configuration.drums.main_vol);
}
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
@ -4127,6 +4148,16 @@ void UI_func_drums_main_volume(uint8_t param) {
}
void UI_func_drum_pitch(uint8_t param) {
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("Pitch"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
static bool display_name;
char tmp_val[5];
char tmp_name[9];
@ -4136,7 +4167,7 @@ void UI_func_drum_pitch(uint8_t param) {
midi_learn_mode = MIDI_LEARN_MODE_ON;
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(0, 0);
@ -4174,7 +4205,7 @@ void UI_func_drum_pitch(uint8_t param) {
Serial.printf("Drum pitch for active_sample=%d [%s]=%d\n", active_sample, drum_config[active_sample].name, configuration.drums.pitch[active_sample]);
#endif
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(1, 1);
@ -4185,7 +4216,7 @@ void UI_func_drum_pitch(uint8_t param) {
_check_display_name(display_name, 4);
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
encoderDir[ENC_L].reset();
@ -4194,6 +4225,16 @@ void UI_func_drum_pitch(uint8_t param) {
}
void UI_func_drum_vol_min_max(uint8_t param) {
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("Volume MIN MAX"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
static uint8_t input_mode;
static uint8_t input_type;
char tmp_val[5];
@ -4204,7 +4245,7 @@ void UI_func_drum_vol_min_max(uint8_t param) {
midi_learn_mode = MIDI_LEARN_MODE_ON;
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(0, 0);
@ -4269,7 +4310,7 @@ void UI_func_drum_vol_min_max(uint8_t param) {
Serial.printf_P(PSTR("Drum volume MAX for active_sample=%d [%s]=%d\n"), active_sample, drum_config[active_sample].name, configuration.drums.vol_max[active_sample]);
#endif
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(1, 1);
@ -4283,6 +4324,7 @@ void UI_func_drum_vol_min_max(uint8_t param) {
_check_display_name_min_max(input_mode, input_type, 2);
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
@ -4292,6 +4334,16 @@ void UI_func_drum_vol_min_max(uint8_t param) {
}
void UI_func_drum_pan(uint8_t param) {
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("Panorama"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
static bool display_name;
char tmp_val[5];
char tmp_name[9];
@ -4301,7 +4353,7 @@ void UI_func_drum_pan(uint8_t param) {
midi_learn_mode = MIDI_LEARN_MODE_ON;
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(0, 0);
@ -4339,7 +4391,7 @@ void UI_func_drum_pan(uint8_t param) {
Serial.printf("Drum panorama for active_sample=%d [%s]=%d\n", active_sample, drum_config[active_sample].name, configuration.drums.pan[active_sample]);
#endif
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(1, 1);
@ -4350,6 +4402,7 @@ void UI_func_drum_pan(uint8_t param) {
_check_display_name(display_name, 4);
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
@ -4359,6 +4412,16 @@ void UI_func_drum_pan(uint8_t param) {
}
void UI_func_drum_reverb_send(uint8_t param) {
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("Reverb Send"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
static bool display_name;
char tmp_val[5];
char tmp_name[9];
@ -4368,7 +4431,7 @@ void UI_func_drum_reverb_send(uint8_t param) {
midi_learn_mode = MIDI_LEARN_MODE_ON;
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(0, 0);
@ -4406,7 +4469,7 @@ void UI_func_drum_reverb_send(uint8_t param) {
Serial.printf("Reverb send for active_sample=%d [%s]=%d\n", active_sample, drum_config[active_sample].name, configuration.drums.reverb_send[active_sample]);
#endif
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(1, 1);
@ -4417,6 +4480,7 @@ void UI_func_drum_reverb_send(uint8_t param) {
_check_display_name(display_name, 2);
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
@ -4426,6 +4490,16 @@ void UI_func_drum_reverb_send(uint8_t param) {
}
void UI_func_drum_midi_note(uint8_t param) {
#if NUM_DRUMS > 0
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
encoderDir[ENC_R].reset();
display.setCursor(0, 0);
display.print(F("MIDI Note"));
display.setCursor(0, 1);
display.print(F("Not implemented."));
}
#else
static bool display_name;
char tmp_val[4];
char tmp_name[9];
@ -4438,7 +4512,7 @@ void UI_func_drum_midi_note(uint8_t param) {
midi_learn_mode = MIDI_LEARN_MODE_ON;
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(0, 0);
@ -4482,7 +4556,7 @@ void UI_func_drum_midi_note(uint8_t param) {
Serial.printf("Drum midinote for active_sample=%d [%s]=%d (%s)\n", active_sample, drum_config[active_sample].name, configuration.drums.midinote[active_sample], tmp_val);
#endif
memset(tmp_name, ' ', 8);
strncpy(tmp_name, drum_config[active_sample].name, strlen(drum_config[active_sample].name));
strlcpy(tmp_name, drum_config[active_sample].name, sizeof(drum_config[active_sample].name));
tmp_name[8] = '\0';
display.setCursor(1, 1);
@ -4496,6 +4570,7 @@ void UI_func_drum_midi_note(uint8_t param) {
else
midi_learn_mode = MIDI_LEARN_MODE_ON;
}
#endif
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
@ -4811,9 +4886,9 @@ void UI_func_voice_select(uint8_t param) {
char voice_name[VOICE_NAME_LEN];
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
if (!get_voice_by_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, configuration.dexed[selected_instance_id].voice, voice_name, sizeof(voice_name)))
strcpy(voice_name, "*ERROR*");
strlcpy(voice_name, "*ERROR*", sizeof(bank_name));
UI_update_instance_icons();
@ -4939,17 +5014,17 @@ void UI_func_voice_select(uint8_t param) {
}
if (strlen(g_bank_name[selected_instance_id]) > 0) {
strcpy(bank_name, g_bank_name[selected_instance_id]);
strlcpy(bank_name, g_bank_name[selected_instance_id], sizeof(bank_name));
} else {
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
}
if (strlen(g_voice_name[selected_instance_id]) > 0) {
strcpy(voice_name, g_voice_name[selected_instance_id]);
strlcpy(voice_name, g_voice_name[selected_instance_id], sizeof(voice_name));
} else {
if (!get_voice_by_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, configuration.dexed[selected_instance_id].voice, voice_name, sizeof(voice_name)))
strcpy(voice_name, "*ERROR*");
strlcpy(voice_name, "*ERROR*", sizeof(voice_name));
}
display.show(0, 0, 2, configuration.dexed[selected_instance_id].bank);
@ -5179,7 +5254,7 @@ void UI_func_save_voice(uint8_t param) {
char bank_name[BANK_NAME_LEN];
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*");
display.setCursor(0, 0);
display.print(F("Save to Bank"));
@ -5222,7 +5297,7 @@ void UI_func_save_voice(uint8_t param) {
configuration.dexed[selected_instance_id].bank = constrain(configuration.dexed[selected_instance_id].bank - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1);
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
display.show(1, 0, 2, configuration.dexed[selected_instance_id].bank);
display.show(1, 3, 10, bank_name);
@ -5234,9 +5309,9 @@ void UI_func_save_voice(uint8_t param) {
configuration.dexed[selected_instance_id].voice = constrain(configuration.dexed[selected_instance_id].voice - ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1);
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strncpy(bank_name, "*ERROR*", sizeof(bank_name) - 1);
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
if (!get_voice_by_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, configuration.dexed[selected_instance_id].voice, voice_name, sizeof(voice_name)))
strncpy(voice_name, "*ERROR*", sizeof(voice_name) - 1);
strlcpy(voice_name, "*ERROR*", sizeof(voice_name));
display.show(1, 0, 2, configuration.dexed[selected_instance_id].voice + 1);
display.show(1, 3, 10, voice_name);
@ -5256,7 +5331,7 @@ void UI_func_save_voice(uint8_t param) {
switch (mode) {
case 1:
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strncpy(bank_name, "*ERROR*", sizeof(bank_name) - 1);
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
display.setCursor(0, 0);
display.print(F("Save to Bank"));
display.show(1, 0, 2, configuration.dexed[selected_instance_id].bank);
@ -5266,9 +5341,9 @@ void UI_func_save_voice(uint8_t param) {
break;
case 2:
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strncpy(bank_name, "*ERROR*", sizeof(bank_name) - 1);
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
if (!get_voice_by_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, configuration.dexed[selected_instance_id].voice, voice_name, sizeof(voice_name)))
strncpy(voice_name, "*ERROR*", sizeof(voice_name) - 1);
strlcpy(voice_name, "*ERROR*", sizeof(voice_name));
display.show(0, 0, 16, "Save to Bank");
display.show(0, 13, 2, configuration.dexed[selected_instance_id].bank);
@ -5339,7 +5414,7 @@ void UI_func_sysex_receive_bank(uint8_t param) {
display.setCursor(14, 1);
display.print(F("]"));
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, receive_bank_filename, sizeof(receive_bank_filename)))
strcpy(receive_bank_filename, "*ERROR*");
strlcpy(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename));
display.show(1, 0, 2, bank_number);
display.show(1, 3, 10, receive_bank_filename);
}
@ -5352,7 +5427,7 @@ void UI_func_sysex_receive_bank(uint8_t param) {
case 0:
bank_number = constrain(bank_number + ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1);
if (!get_bank_name(bank_number, receive_bank_filename, sizeof(receive_bank_filename)))
strcpy(receive_bank_filename, "*ERROR*");
strlcpy(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename));
display.show(1, 0, 2, bank_number);
display.show(1, 3, 10, receive_bank_filename);
break;
@ -5372,7 +5447,7 @@ void UI_func_sysex_receive_bank(uint8_t param) {
case 0:
bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1);
if (!get_bank_name(bank_number, receive_bank_filename, sizeof(receive_bank_filename)))
strcpy(receive_bank_filename, "*ERROR*");
strlcpy(receive_bank_filename, "*ERROR*", sizeof(receive_bank_filename));
display.show(1, 0, 2, bank_number);
display.show(1, 3, 10, receive_bank_filename);
break;
@ -5392,7 +5467,7 @@ void UI_func_sysex_receive_bank(uint8_t param) {
if (mode == 0) {
if (!strcmp(receive_bank_filename, "*ERROR*")) {
yesno = true;
strcpy(receive_bank_filename, "NONAME");
strlcpy(receive_bank_filename, "NONAME", sizeof(receive_bank_filename));
mode = 2;
display.setCursor(0, 1);
display.print(F("[ ] "));
@ -5419,7 +5494,7 @@ void UI_func_sysex_receive_bank(uint8_t param) {
Serial.println(F("]"));
#endif
char tmp[CONFIG_FILENAME_LEN];
strcpy(tmp, receive_bank_filename);
strlcpy(tmp, receive_bank_filename, sizeof(tmp));
snprintf_P(receive_bank_filename, sizeof(receive_bank_filename), PSTR("/%d/%s.syx"), bank_number, tmp);
#ifdef DEBUG
Serial.print(F("Receiving into bank "));
@ -5497,7 +5572,7 @@ void UI_func_set_performance_name(uint8_t param) {
if (mode == 1) {
ui_select_name_state = UI_select_name(1, 1, configuration.performance.name_temp, BANK_NAME_LEN - 1, false);
if (ui_select_name_state == true) {
strcpy(configuration.performance.name, configuration.performance.name_temp);
strlcpy(configuration.performance.name, configuration.performance.name_temp, sizeof(configuration.performance.name));
mode = 0xff;
display.noBlink();
display.setCursor(0, 1);
@ -5509,7 +5584,7 @@ void UI_func_set_performance_name(uint8_t param) {
}
if (mode == 0) {
mode = 1;
strcpy(configuration.performance.name_temp, configuration.performance.name);
strlcpy(configuration.performance.name_temp, configuration.performance.name, sizeof(configuration.performance.name_temp));
display.setCursor(0, 1);
display.print(F("[ ] "));
ui_select_name_state = UI_select_name(1, 1, configuration.performance.name_temp, BANK_NAME_LEN - 1, true);
@ -5534,7 +5609,7 @@ void UI_func_sysex_send_bank(uint8_t param) {
display.setCursor(0, 0);
display.print(F("MIDI Send Bank"));
if (!get_bank_name(configuration.dexed[selected_instance_id].bank, bank_name, sizeof(bank_name)))
strncpy(bank_name, "*ERROR*", sizeof(bank_name) - 1);
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
display.show(1, 2, 1, "[");
display.show(1, 14, 1, "]");
display.show(1, 0, 2, configuration.dexed[selected_instance_id].bank);
@ -5551,7 +5626,7 @@ void UI_func_sysex_send_bank(uint8_t param) {
bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1);
}
if (!get_bank_name(bank_number, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
display.show(1, 0, 2, bank_number);
display.show(1, 3, 10, bank_name);
} else if (LCDML.BT_checkEnter() && encoderDir[ENC_R].ButtonShort()) {
@ -5626,7 +5701,7 @@ void UI_func_sysex_send_voice(uint8_t param) {
char bank_name[BANK_NAME_LEN];
if (!get_bank_name(bank_number, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
display.setCursor(0, 0);
display.print(F("MIDI Send Voice"));
@ -5650,7 +5725,7 @@ void UI_func_sysex_send_voice(uint8_t param) {
bank_number = constrain(bank_number - ENCODER[ENC_R].speed(), 0, MAX_BANKS - 1);
if (!get_bank_name(bank_number, bank_name, sizeof(bank_name)))
strcpy(bank_name, "*ERROR*");
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
display.show(1, 0, 2, bank_number);
display.show(1, 3, 10, bank_name);
@ -5661,9 +5736,9 @@ void UI_func_sysex_send_voice(uint8_t param) {
else if (LCDML.BT_checkUp() && voice_number > 0)
voice_number = constrain(voice_number - ENCODER[ENC_R].speed(), 0, MAX_VOICES - 1);
if (!get_bank_name(bank_number, bank_name, sizeof(bank_name)))
strncpy(bank_name, "*ERROR*", sizeof(bank_name) - 1);
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
if (!get_voice_by_bank_name(bank_number, bank_name, voice_number, voice_name, sizeof(voice_name)))
strncpy(voice_name, "*ERROR*", sizeof(voice_name) - 1);
strlcpy(voice_name, "*ERROR*", sizeof(voice_name));
display.show(1, 0, 2, voice_number + 1);
display.show(1, 3, 10, voice_name);
@ -5675,9 +5750,9 @@ void UI_func_sysex_send_voice(uint8_t param) {
switch (mode) {
case 1:
if (!get_bank_name(bank_number, bank_name, sizeof(bank_name)))
strncpy(bank_name, "*ERROR*", sizeof(bank_name) - 1);
strlcpy(bank_name, "*ERROR*", sizeof(bank_name));
if (!get_voice_by_bank_name(bank_number, bank_name, voice_number, voice_name, sizeof(voice_name)))
strncpy(voice_name, "*ERROR*", sizeof(voice_name) - 1);
strlcpy(voice_name, "*ERROR*", sizeof(voice_name));
display.show(1, 0, 2, voice_number + 1);
display.show(1, 3, 10, voice_name);
@ -6311,7 +6386,7 @@ void display_float(float var, uint8_t size_number, uint8_t size_fraction, bool z
if (brackets == true) {
char tmp[LCD_cols + 1];
strcpy(tmp, s);
strlcpy(tmp, s,sizeof(tmp));
snprintf_P(s, sizeof(s), PSTR("[%s]"), tmp);
}

@ -1176,14 +1176,7 @@ bool save_sd_performance_json(uint8_t number) {
SD.remove(filename);
json = SD.open(filename, FILE_WRITE);
if (json) {
for (uint8_t i = 0; i < FILENAME_LEN; i++) {
data_json["name"][i] = configuration.performance.name[i];
}
#if defined(DEBUG) && defined(DEBUG_SHOW_JSON)
Serial.println(F("Write JSON data:"));
serializeJsonPretty(data_json, Serial);
Serial.println();
#endif
strlcpy(data_json["name"] | "NoName", configuration.performance.name_temp, sizeof(configuration.performance.name_temp));
serializeJsonPretty(data_json, json);
json.close();
AudioInterrupts();
@ -1260,24 +1253,14 @@ void get_sd_performance_name_json(uint8_t number) {
json.close();
AudioInterrupts();
}
if (data_json["performance_name"][0] != 0) {
for (uint8_t i = 0; i < FILENAME_LEN; i++) {
configuration.performance.name_temp[i] = data_json["name"][i];
}
strlcpy(configuration.performance.name_temp, data_json["name"] | "NoName", sizeof(configuration.performance.name_temp));
#ifdef DEBUG
Serial.print(F("Get performance name for "));
Serial.print(number);
Serial.print(F(": "));
Serial.print(configuration.performance.name_temp);
Serial.println();
#endif
}
#ifdef DEBUG
else {
Serial.print(F("Cannot get performance name for "));
Serial.print(number);
Serial.println();
}
#endif
}
}
@ -1501,12 +1484,12 @@ void strip_extension(const char* s, char* target, uint8_t len) {
char tmp[CONFIG_FILENAME_LEN];
char* token;
strcpy(tmp, s);
strlcpy(tmp, s, len);
token = strtok(tmp, ".");
if (token == NULL)
strcpy(target, "*ERROR*");
strlcpy(target, "*ERROR*", len);
else
strcpy(target, token);
strlcpy(target, token, len);
target[len] = '\0';
}

@ -69,7 +69,7 @@ class Disp_Plus : public T
if (justify_right == true)
s += field_size - l;
strncpy(s, str, l);
strlcpy(s, str, l);
//setCursor(pos_x * getMaxCharWidth(), pos_y * getMaxCharHeight());
this->setCursor(pos_x, pos_y );

@ -78,31 +78,31 @@ void handle_generic(byte inChannel, byte inData1, byte inData2, const char *midi
switch(event) {
case midi::NoteOn:
handleNoteOn(inChannel, inData1, inData2);
strcpy(text, "NoteOn");
strlcpy(text, "NoteOn",sizeof(text));
break;
case midi::NoteOff:
handleNoteOff(inChannel, inData1, inData2);
strcpy(text, "NoteOff");
strlcpy(text, "NoteOff",sizeof(text));
break;
case midi::ControlChange:
handleControlChange(inChannel, inData1, inData2);
strcpy(text, "CC");
strlcpy(text, "CC",sizeof(text));
break;
case midi::AfterTouchChannel:
handleAfterTouch(inChannel, inData1);
strcpy(text, "Mono AT");
strlcpy(text, "Mono AT",sizeof(text));
break;
case midi::PitchBend:
handlePitchBend(inChannel, inData1);
strcpy(text, "PB");
strlcpy(text, "PB",sizeof(text));
break;
case midi::ProgramChange:
handleProgramChange(inChannel, inData1);
strcpy(text, "PC");
strlcpy(text, "PC",sizeof(text));
break;
case midi::AfterTouchPoly:
handleAfterTouchPoly(inChannel, inData1, inData2);
strcpy(text, "Poly AT");
strlcpy(text, "Poly AT",sizeof(text));
break;
default:
break;
@ -268,15 +268,15 @@ void handleSystemCommon_generic(byte inData1, const char *midi_device, midi::Mid
switch(event) {
case midi::TimeCodeQuarterFrame:
handleTimeCodeQuarterFrame(inData1);
strcpy(text, "TimeCodeQuarterFrame");
strlcpy(text, "TimeCodeQuarterFrame",sizeof(text));
break;
case midi::SongSelect:
handleSongSelect(inData1);
strcpy(text, "SongSelect");
strlcpy(text, "SongSelect",sizeof(text));
break;
case midi::TuneRequest:
handleTuneRequest();
strcpy(text, "TuneRequest");
strlcpy(text, "TuneRequest",sizeof(text));
break;
default:
break;
@ -364,27 +364,27 @@ void handleRealtime_generic(const char *midi_device, midi::MidiType event)
switch(event) {
case midi::Clock:
handleClock();
strcpy(text, "Clock");
strlcpy(text, "Clock",sizeof(text));
break;
case midi::Start:
handleStart();
strcpy(text, "Start");
strlcpy(text, "Start",sizeof(text));
break;
case midi::Continue:
handleContinue();
strcpy(text, "Continue");
strlcpy(text, "Continue",sizeof(text));
break;
case midi::Stop:
handleStop();
strcpy(text, "Stop");
strlcpy(text, "Stop",sizeof(text));
break;
case midi::ActiveSensing:
handleActiveSensing();
strcpy(text, "ActiveSensing");
strlcpy(text, "ActiveSensing",sizeof(text));
break;
case midi::SystemReset:
handleSystemReset();
strcpy(text, "SystemReset");
strlcpy(text, "SystemReset",sizeof(text));
break;
default:
break;

@ -1,6 +1,41 @@
ArduinoJson: change log
=======================
v6.20.0 (2022-12-26)
-------
* Add `JsonVariant::shallowCopy()` (issue #1343)
* Fix `9.22337e+18 is outside the range of representable values of type 'long'`
* Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst`
* Fix lax parsing of `true`, `false`, and `null` (issue #1781)
* Remove undocumented `accept()` functions
* Rename `addElement()` to `add()`
* Remove `getElement()`, `getOrAddElement()`, `getMember()`, and `getOrAddMember()`
* Remove undocumented `JsonDocument::data()` and `JsonDocument::memoryPool()`
* Remove undocumented `JsonArrayIterator::internal()` and `JsonObjectIterator::internal()`
* Rename things in `ARDUINOJSON_NAMESPACE` to match the public names
* Add documentation to most public symbols
* Remove support for naked `char` (was deprecated since 6.18.0)
> ### BREAKING CHANGES
>
> This release hides `JsonVariant`'s functions that were only intended for internal use.
> If you were using them in your programs, you must replace with `operator[]` and `to<JsonVariant>()`, like so:
>
> ```c++
> // before
> JsonVariant a = variant.getElement(idx);
> JsonVariant b = variant.getOrAddElement(idx);
> JsonVariant c = variant.getMember(key);
> JsonVariant d = variant.getOrAddMember(key);
>
> // after
> JsonVariant a = variant[idx];
> JsonVariant b = idx < variant.size() ? variant[idx] : variant[idx].to<JsonVariant>();
> JsonVariant c = variant[key];
> JsonVariant d = variant.containsKey(key) ? variant[key] : variant[key].to<JsonVariant>();
> ```
v6.19.4 (2022-04-05)
-------

@ -10,7 +10,7 @@ if(ESP_PLATFORM)
return()
endif()
project(ArduinoJson VERSION 6.19.4)
project(ArduinoJson VERSION 6.20.0)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)

@ -1,14 +1,15 @@
![ArduinoJson](banner.svg)
<p align="center">
<a href="https://arduinojson.org/"><img alt="ArduinoJson" src="logo.svg" /></a>
</p>
---
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/bblanchon/ArduinoJson/Continuous%20Integration?logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
[![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/bblanchon/ArduinoJson?label=quality&logo=lgtm)](https://lgtm.com/projects/g/bblanchon/ArduinoJson/)
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.19.4&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.19.4)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.19.4)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.19.4)
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.20.0&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.20.0)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.20.0)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.20.0)
[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github)](https://github.com/bblanchon/ArduinoJson/stargazers)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github)](https://github.com/sponsors/bblanchon)
@ -16,32 +17,32 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
## Features
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/?utm_source=github&utm_medium=readme)
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme)
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/?utm_source=github&utm_medium=readme)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#filtering)
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
* Supports single quotes as a string delimiter
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme)
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/?utm_source=github&utm_medium=readme)
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/?utm_source=github&utm_medium=readme)
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/?utm_source=github&utm_medium=readme)
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
* Efficient
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme)
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme)
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme)
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/?utm_source=github&utm_medium=readme)
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme)
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/?utm_source=github&utm_medium=readme)
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
* Versatile
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme)
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/?utm_source=github&utm_medium=readme), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/?utm_source=github&utm_medium=readme)
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/?utm_source=github&utm_medium=readme) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/?utm_source=github&utm_medium=readme)
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?utm_source=github&utm_medium=readme)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme#custom-writer)
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/?utm_source=github&utm_medium=readme)
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/)
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/)
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer)
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
* Portable
* Usable on any C++ project (not limited to Arduino)
* Compatible with C++98, C++11, C++14 and C++17
@ -69,15 +70,15 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Visual Micro](http://www.visualmicro.com/)
* [Visual Studio](https://www.visualstudio.com/)
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/?utm_source=github&utm_medium=readme)
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/)
* Well designed
* [Elegant API](http://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme)
* [Elegant API](http://arduinojson.org/v6/example/)
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
* Self-contained (no external dependency)
* `const` friendly
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/?utm_source=github&utm_medium=readme)
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/?utm_source=github&utm_medium=readme#integer-overflows)
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
* Well tested
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
* Continuously tested on
@ -87,12 +88,12 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/?utm_source=github&utm_medium=readme)
* [Examples](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme)
* [How-tos](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme)
* [FAQ](https://arduinojson.org/v6/faq/?utm_source=github&utm_medium=readme)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/?utm_source=github&utm_medium=readme)
* [Book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme)
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
* [Examples](https://arduinojson.org/v6/example/)
* [How-tos](https://arduinojson.org/v6/example/)
* [FAQ](https://arduinojson.org/v6/faq/)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
* [Book](https://arduinojson.org/book/)
* [Changelog](CHANGELOG.md)
* Vibrant user community
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
@ -118,7 +119,7 @@ double latitude = doc["data"][0];
double longitude = doc["data"][1];
```
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/decoding/?utm_source=github&utm_medium=readme)
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
### Serialization
@ -137,16 +138,13 @@ serializeJson(doc, Serial);
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
```
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/encoding/?utm_source=github&utm_medium=readme)
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
## Sponsors
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
<p>
<a href="https://techexplorations.com/" rel="sponsored">
<img alt="Tech Explorations" src="https://arduinojson.org/images/2021/10/techexplorations.png" width="200">
</a>
<a href="https://www.programmingelectronics.com/" rel="sponsored">
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
</a>

@ -1,4 +1,4 @@
version: 6.19.4.{build}
version: 6.20.0.{build}
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 32 KiB

@ -2,7 +2,7 @@
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
//
// This example shows how to use DeserializationOpion::Filter
// This example shows how to use DeserializationOption::Filter
//
// https://arduinojson.org/v6/example/filter/

@ -20,28 +20,27 @@ void setup() {
// WARNING: the strings in the input will be duplicated in the JsonDocument.
deserializeJson(doc, F("{\"sensor\":\"gps\",\"time\":1351824120,"
"\"data\":[48.756080,2.302038]}"));
JsonObject obj = doc.as<JsonObject>();
// You can use a Flash String to get an element of a JsonObject
// You can use a Flash String as a key to get a member from JsonDocument
// No duplication is done.
long time = obj[F("time")];
long time = doc[F("time")];
// You can use a Flash String to set an element of a JsonObject
// You can use a Flash String as a key to set a member of a JsonDocument
// WARNING: the content of the Flash String will be duplicated in the
// JsonDocument.
obj[F("time")] = time;
doc[F("time")] = time;
// You can set a Flash String to a JsonObject or JsonArray:
// You can set a Flash String as the content of a JsonVariant
// WARNING: the content of the Flash String will be duplicated in the
// JsonDocument.
obj["sensor"] = F("gps");
doc["sensor"] = F("gps");
// It works with serialized() too:
obj["sensor"] = serialized(F("\"gps\""));
obj["sensor"] = serialized(F("\xA3gps"), 3);
doc["sensor"] = serialized(F("\"gps\""));
doc["sensor"] = serialized(F("\xA3gps"), 3);
// You can compare the content of a JsonVariant to a Flash String
if (obj["sensor"] == F("gps")) {
if (doc["sensor"] == F("gps")) {
// ...
}
}

@ -20,42 +20,42 @@ void setup() {
String input =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
deserializeJson(doc, input);
JsonObject obj = doc.as<JsonObject>();
// You can use a String to get an element of a JsonObject
// You can use a String as a key to get a member from JsonDocument
// No duplication is done.
long time = obj[String("time")];
long time = doc[String("time")];
// You can use a String to set an element of a JsonObject
// You can use a String as a key to set a member of a JsonDocument
// WARNING: the content of the String will be duplicated in the JsonDocument.
obj[String("time")] = time;
doc[String("time")] = time;
// You can get a String from a JsonObject or JsonArray:
// You can get the content of a JsonVariant as a String
// No duplication is done, at least not in the JsonDocument.
String sensor = obj["sensor"];
String sensor = doc["sensor"];
// Unfortunately, the following doesn't work (issue #118):
// sensor = obj["sensor"]; // <- error "ambiguous overload for 'operator='"
// sensor = doc["sensor"]; // <- error "ambiguous overload for 'operator='"
// As a workaround, you need to replace by:
sensor = obj["sensor"].as<String>();
sensor = doc["sensor"].as<String>();
// You can set a String to a JsonObject or JsonArray:
// You can set a String as the content of a JsonVariant
// WARNING: the content of the String will be duplicated in the JsonDocument.
obj["sensor"] = sensor;
doc["sensor"] = sensor;
// It works with serialized() too:
obj["sensor"] = serialized(sensor);
doc["sensor"] = serialized(sensor);
// You can also concatenate strings
// WARNING: the content of the String will be duplicated in the JsonDocument.
obj[String("sen") + "sor"] = String("gp") + "s";
doc[String("sen") + "sor"] = String("gp") + "s";
// You can compare the content of a JsonObject with a String
if (obj["sensor"] == sensor) {
if (doc["sensor"] == sensor) {
// ...
}
// Lastly, you can print the resulting JSON to a String
// WARNING: it doesn't replace the content but appends to it
String output;
serializeJson(doc, output);
}

@ -15,6 +15,10 @@ if("cxx_long_long_type" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
list(APPEND SOURCES use_long_long_0.cpp use_long_long_1.cpp)
endif()
if("cxx_range_for" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND "cxx_generalized_initializers" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
list(APPEND SOURCES stl_containers.cpp)
endif()
if(NOT SOURCES)
return()
endif()

@ -0,0 +1,72 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
#include <string>
#include <vector>
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct Converter<std::vector<T> > {
static void toJson(const std::vector<T>& src, JsonVariant dst) {
JsonArray array = dst.to<JsonArray>();
for (T item : src)
array.add(item);
}
static std::vector<T> fromJson(JsonVariantConst src) {
std::vector<T> dst;
for (T item : src.as<JsonArrayConst>())
dst.push_back(item);
return dst;
}
static bool checkJson(JsonVariantConst src) {
JsonArrayConst array = src;
bool result = array;
for (JsonVariantConst item : array) {
if (!result)
break;
result = item.is<T>();
}
return result;
}
};
} // namespace ARDUINOJSON_NAMESPACE
TEST_CASE("vector<int>") {
SECTION("toJson") {
std::vector<int> v = {1, 2};
StaticJsonDocument<128> doc;
doc.set(v);
REQUIRE(doc.as<std::string>() == "[1,2]");
}
SECTION("fromJson") {
StaticJsonDocument<128> doc;
doc.add(1);
doc.add(2);
auto v = doc.as<std::vector<int> >();
REQUIRE(v.size() == 2);
CHECK(v[0] == 1);
CHECK(v[1] == 2);
}
SECTION("checkJson") {
StaticJsonDocument<128> doc;
CHECK(doc.is<std::vector<int> >() == false);
doc.add(1);
doc.add(2);
CHECK(doc.is<std::vector<int> >() == true);
doc.add("foo");
CHECK(doc.is<std::vector<int> >() == false);
}
}

@ -62,7 +62,7 @@ class String {
size_t _maxCapacity;
};
class StringSumHelper;
class StringSumHelper : public ::String {};
inline bool operator==(const std::string& lhs, const ::String& rhs) {
return lhs == rhs.c_str();

@ -5,10 +5,10 @@
add_executable(JsonArrayTests
add.cpp
clear.cpp
compare.cpp
copyArray.cpp
createNested.cpp
equals.cpp
get.cpp
isNull.cpp
iterator.cpp
memoryUsage.cpp

@ -42,7 +42,7 @@ TEST_CASE("JsonArray::add()") {
SECTION("vla") {
size_t i = 16;
char vla[i];
strcpy(vla, "world");
strlcpy(vla, "world");
array.add(vla);

@ -0,0 +1,512 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Compare JsonArray with JsonArray") {
StaticJsonDocument<256> doc;
SECTION("Compare with unbound") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonArray unbound;
CHECK(array != unbound);
CHECK_FALSE(array == unbound);
CHECK_FALSE(array <= unbound);
CHECK_FALSE(array >= unbound);
CHECK_FALSE(array > unbound);
CHECK_FALSE(array < unbound);
CHECK(unbound != array);
CHECK_FALSE(unbound == array);
CHECK_FALSE(unbound <= array);
CHECK_FALSE(unbound >= array);
CHECK_FALSE(unbound > array);
CHECK_FALSE(unbound < array);
}
SECTION("Compare with self") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
CHECK(array == array);
CHECK(array <= array);
CHECK(array >= array);
CHECK_FALSE(array != array);
CHECK_FALSE(array > array);
CHECK_FALSE(array < array);
}
SECTION("Compare with identical array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello");
array1.createNestedObject();
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello");
array2.createNestedObject();
CHECK(array1 == array2);
CHECK(array1 <= array2);
CHECK(array1 >= array2);
CHECK_FALSE(array1 != array2);
CHECK_FALSE(array1 > array2);
CHECK_FALSE(array1 < array2);
}
SECTION("Compare with different array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello1");
array1.createNestedObject();
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello2");
array2.createNestedObject();
CHECK(array1 != array2);
CHECK_FALSE(array1 == array2);
CHECK_FALSE(array1 > array2);
CHECK_FALSE(array1 < array2);
CHECK_FALSE(array1 <= array2);
CHECK_FALSE(array1 >= array2);
}
}
TEST_CASE("Compare JsonArray with JsonVariant") {
StaticJsonDocument<256> doc;
SECTION("Compare with self") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonVariant variant = array;
CHECK(array == variant);
CHECK(array <= variant);
CHECK(array >= variant);
CHECK_FALSE(array != variant);
CHECK_FALSE(array > variant);
CHECK_FALSE(array < variant);
CHECK(variant == array);
CHECK(variant <= array);
CHECK(variant >= array);
CHECK_FALSE(variant != array);
CHECK_FALSE(variant > array);
CHECK_FALSE(variant < array);
}
SECTION("Compare with identical array") {
JsonArray array = doc.createNestedArray();
array.add(1);
array.add("hello");
array.createNestedObject();
JsonVariant variant = doc.createNestedArray();
variant.add(1);
variant.add("hello");
variant.createNestedObject();
CHECK(array == variant);
CHECK(array <= variant);
CHECK(array >= variant);
CHECK_FALSE(array != variant);
CHECK_FALSE(array > variant);
CHECK_FALSE(array < variant);
CHECK(variant == array);
CHECK(variant <= array);
CHECK(variant >= array);
CHECK_FALSE(variant != array);
CHECK_FALSE(variant > array);
CHECK_FALSE(variant < array);
}
SECTION("Compare with different array") {
JsonArray array = doc.createNestedArray();
array.add(1);
array.add("hello1");
array.createNestedObject();
JsonVariant variant = doc.createNestedArray();
variant.add(1);
variant.add("hello2");
variant.createNestedObject();
CHECK(array != variant);
CHECK_FALSE(array == variant);
CHECK_FALSE(array > variant);
CHECK_FALSE(array < variant);
CHECK_FALSE(array <= variant);
CHECK_FALSE(array >= variant);
}
}
TEST_CASE("Compare JsonArray with JsonVariantConst") {
StaticJsonDocument<256> doc;
SECTION("Compare with unbound") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonVariantConst unbound;
CHECK(array != unbound);
CHECK_FALSE(array == unbound);
CHECK_FALSE(array <= unbound);
CHECK_FALSE(array >= unbound);
CHECK_FALSE(array > unbound);
CHECK_FALSE(array < unbound);
CHECK(unbound != array);
CHECK_FALSE(unbound == array);
CHECK_FALSE(unbound <= array);
CHECK_FALSE(unbound >= array);
CHECK_FALSE(unbound > array);
CHECK_FALSE(unbound < array);
}
SECTION("Compare with self") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonVariantConst variant = array;
CHECK(array == variant);
CHECK(array <= variant);
CHECK(array >= variant);
CHECK_FALSE(array != variant);
CHECK_FALSE(array > variant);
CHECK_FALSE(array < variant);
CHECK(variant == array);
CHECK(variant <= array);
CHECK(variant >= array);
CHECK_FALSE(variant != array);
CHECK_FALSE(variant > array);
CHECK_FALSE(variant < array);
}
SECTION("Compare with identical array") {
JsonArray array = doc.createNestedArray();
array.add(1);
array.add("hello");
array.createNestedObject();
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello");
array2.createNestedObject();
JsonVariantConst variant = array2;
CHECK(array == variant);
CHECK(array <= variant);
CHECK(array >= variant);
CHECK_FALSE(array != variant);
CHECK_FALSE(array > variant);
CHECK_FALSE(array < variant);
CHECK(variant == array);
CHECK(variant <= array);
CHECK(variant >= array);
CHECK_FALSE(variant != array);
CHECK_FALSE(variant > array);
CHECK_FALSE(variant < array);
}
SECTION("Compare with different array") {
JsonArray array = doc.createNestedArray();
array.add(1);
array.add("hello1");
array.createNestedObject();
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello2");
array2.createNestedObject();
JsonVariantConst variant = array2;
CHECK(array != variant);
CHECK_FALSE(array == variant);
CHECK_FALSE(array > variant);
CHECK_FALSE(array < variant);
CHECK_FALSE(array <= variant);
CHECK_FALSE(array >= variant);
}
}
TEST_CASE("Compare JsonArray with JsonArrayConst") {
StaticJsonDocument<256> doc;
SECTION("Compare with unbound") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonArrayConst unbound;
CHECK(array != unbound);
CHECK_FALSE(array == unbound);
CHECK_FALSE(array <= unbound);
CHECK_FALSE(array >= unbound);
CHECK_FALSE(array > unbound);
CHECK_FALSE(array < unbound);
CHECK(unbound != array);
CHECK_FALSE(unbound == array);
CHECK_FALSE(unbound <= array);
CHECK_FALSE(unbound >= array);
CHECK_FALSE(unbound > array);
CHECK_FALSE(unbound < array);
}
SECTION("Compare with self") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonArrayConst carray = array;
CHECK(array == carray);
CHECK(array <= carray);
CHECK(array >= carray);
CHECK_FALSE(array != carray);
CHECK_FALSE(array > carray);
CHECK_FALSE(array < carray);
CHECK(carray == array);
CHECK(carray <= array);
CHECK(carray >= array);
CHECK_FALSE(carray != array);
CHECK_FALSE(carray > array);
CHECK_FALSE(carray < array);
}
SECTION("Compare with identical array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello");
array1.createNestedObject();
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello");
array2.createNestedObject();
JsonArrayConst carray2 = array2;
CHECK(array1 == carray2);
CHECK(array1 <= carray2);
CHECK(array1 >= carray2);
CHECK_FALSE(array1 != carray2);
CHECK_FALSE(array1 > carray2);
CHECK_FALSE(array1 < carray2);
CHECK(carray2 == array1);
CHECK(carray2 <= array1);
CHECK(carray2 >= array1);
CHECK_FALSE(carray2 != array1);
CHECK_FALSE(carray2 > array1);
CHECK_FALSE(carray2 < array1);
}
SECTION("Compare with different array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello1");
array1.createNestedObject();
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello2");
array2.createNestedObject();
JsonArrayConst carray2 = array2;
CHECK(array1 != carray2);
CHECK_FALSE(array1 == carray2);
CHECK_FALSE(array1 > carray2);
CHECK_FALSE(array1 < carray2);
CHECK_FALSE(array1 <= carray2);
CHECK_FALSE(array1 >= carray2);
CHECK(carray2 != array1);
CHECK_FALSE(carray2 == array1);
CHECK_FALSE(carray2 > array1);
CHECK_FALSE(carray2 < array1);
CHECK_FALSE(carray2 <= array1);
CHECK_FALSE(carray2 >= array1);
}
}
TEST_CASE("Compare JsonArrayConst with JsonArrayConst") {
StaticJsonDocument<256> doc;
SECTION("Compare with unbound") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonArrayConst carray = array;
JsonArrayConst unbound;
CHECK(carray != unbound);
CHECK_FALSE(carray == unbound);
CHECK_FALSE(carray <= unbound);
CHECK_FALSE(carray >= unbound);
CHECK_FALSE(carray > unbound);
CHECK_FALSE(carray < unbound);
CHECK(unbound != carray);
CHECK_FALSE(unbound == carray);
CHECK_FALSE(unbound <= carray);
CHECK_FALSE(unbound >= carray);
CHECK_FALSE(unbound > carray);
CHECK_FALSE(unbound < carray);
}
SECTION("Compare with self") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonArrayConst carray = array;
CHECK(carray == carray);
CHECK(carray <= carray);
CHECK(carray >= carray);
CHECK_FALSE(carray != carray);
CHECK_FALSE(carray > carray);
CHECK_FALSE(carray < carray);
}
SECTION("Compare with identical array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello");
array1.createNestedObject();
JsonArrayConst carray1 = array1;
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello");
array2.createNestedObject();
JsonArrayConst carray2 = array2;
CHECK(carray1 == carray2);
CHECK(carray1 <= carray2);
CHECK(carray1 >= carray2);
CHECK_FALSE(carray1 != carray2);
CHECK_FALSE(carray1 > carray2);
CHECK_FALSE(carray1 < carray2);
}
SECTION("Compare with different array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello1");
array1.createNestedObject();
JsonArrayConst carray1 = array1;
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello2");
array2.createNestedObject();
JsonArrayConst carray2 = array2;
CHECK(carray1 != carray2);
CHECK_FALSE(carray1 == carray2);
CHECK_FALSE(carray1 > carray2);
CHECK_FALSE(carray1 < carray2);
CHECK_FALSE(carray1 <= carray2);
CHECK_FALSE(carray1 >= carray2);
}
}
TEST_CASE("Compare JsonArrayConst with JsonVariant") {
StaticJsonDocument<256> doc;
SECTION("Compare with self") {
JsonArray array = doc.to<JsonArray>();
array.add(1);
array.add("hello");
JsonArrayConst carray = array;
JsonVariant variant = array;
CHECK(carray == variant);
CHECK(carray <= variant);
CHECK(carray >= variant);
CHECK_FALSE(carray != variant);
CHECK_FALSE(carray > variant);
CHECK_FALSE(carray < variant);
CHECK(variant == carray);
CHECK(variant <= carray);
CHECK(variant >= carray);
CHECK_FALSE(variant != carray);
CHECK_FALSE(variant > carray);
CHECK_FALSE(variant < carray);
}
SECTION("Compare with identical array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello");
array1.createNestedObject();
JsonArrayConst carray1 = array1;
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello");
array2.createNestedObject();
JsonVariant variant2 = array2;
CHECK(carray1 == variant2);
CHECK(carray1 <= variant2);
CHECK(carray1 >= variant2);
CHECK_FALSE(carray1 != variant2);
CHECK_FALSE(carray1 > variant2);
CHECK_FALSE(carray1 < variant2);
CHECK(variant2 == carray1);
CHECK(variant2 <= carray1);
CHECK(variant2 >= carray1);
CHECK_FALSE(variant2 != carray1);
CHECK_FALSE(variant2 > carray1);
CHECK_FALSE(variant2 < carray1);
}
SECTION("Compare with different array") {
JsonArray array1 = doc.createNestedArray();
array1.add(1);
array1.add("hello1");
array1.createNestedObject();
JsonArrayConst carray1 = array1;
JsonArray array2 = doc.createNestedArray();
array2.add(1);
array2.add("hello2");
array2.createNestedObject();
JsonVariant variant2 = array2;
CHECK(carray1 != variant2);
CHECK_FALSE(carray1 == variant2);
CHECK_FALSE(carray1 > variant2);
CHECK_FALSE(carray1 < variant2);
CHECK_FALSE(carray1 <= variant2);
CHECK_FALSE(carray1 >= variant2);
CHECK(variant2 != carray1);
CHECK_FALSE(variant2 == carray1);
CHECK_FALSE(variant2 > carray1);
CHECK_FALSE(variant2 < carray1);
CHECK_FALSE(variant2 <= carray1);
CHECK_FALSE(variant2 >= carray1);
}
}

@ -1,16 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::get()") {
DynamicJsonDocument doc(4096);
deserializeJson(doc, "[1,2,3]");
JsonArray array = doc.as<JsonArray>();
SECTION("Overflow") {
REQUIRE(array.getElement(3).isNull());
}
}

@ -7,7 +7,8 @@
static void eraseString(std::string& str) {
char* p = const_cast<char*>(str.c_str());
while (*p) *p++ = '*';
while (*p)
*p++ = '*';
}
TEST_CASE("std::string") {

@ -137,7 +137,7 @@ TEST_CASE("JsonArray::operator[]") {
SECTION("set(VLA)") {
size_t i = 16;
char vla[i];
strcpy(vla, "world");
strlcpy(vla, "world");
array.add("hello");
array[0].set(vla);
@ -148,7 +148,7 @@ TEST_CASE("JsonArray::operator[]") {
SECTION("operator=(VLA)") {
size_t i = 16;
char vla[i];
strcpy(vla, "world");
strlcpy(vla, "world");
array.add("hello");
array[0] = vla;

@ -71,6 +71,15 @@ TEST_CASE("Filtering") {
"{\"example\":null}",
JSON_OBJECT_SIZE(1) + 8
},
{
// Member is a number, but filter wants an array
"{\"example\":42}",
"{\"example\":[true]}",
10,
DeserializationError::Ok,
"{\"example\":null}",
JSON_OBJECT_SIZE(1) + 8
},
{
// Input is an array, but filter wants an object
"[\"hello\",\"world\"]",
@ -117,7 +126,7 @@ TEST_CASE("Filtering") {
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip a boolean
// skip false
"{\"a_bool\":false,example:42}",
"{\"example\":true}",
10,
@ -125,6 +134,24 @@ TEST_CASE("Filtering") {
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// skip true
"{\"a_bool\":true,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// skip null
"{\"a_bool\":null,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip a double-quoted string
"{\"a_double_quoted_string\":\"hello\",example:42}",
@ -618,7 +645,7 @@ TEST_CASE("Filtering") {
0
},
{
// incomplete after after key of a skipped object
// incomplete comment after key of a skipped object
"{\"example\"/*:2}",
"false",
10,
@ -636,7 +663,7 @@ TEST_CASE("Filtering") {
0
},
{
// incomplete after after value of a skipped object
// incomplete comment after value of a skipped object
"{\"example\":2/*}",
"false",
10,
@ -644,6 +671,15 @@ TEST_CASE("Filtering") {
"null",
0
},
{
// incomplete comment after comma in skipped object
"{\"example\":2,/*}",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
}; // clang-format on
for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) {
@ -710,7 +746,7 @@ TEST_CASE("Overloads") {
SECTION("char[n], Filter") {
size_t i = 4;
char vla[i];
strcpy(vla, "{}");
strlcpy(vla, "{}");
deserializeJson(doc, vla, Filter(filter));
}
#endif
@ -738,7 +774,7 @@ TEST_CASE("Overloads") {
SECTION("char[n], Filter, NestingLimit") {
size_t i = 4;
char vla[i];
strcpy(vla, "{}");
strlcpy(vla, "{}");
deserializeJson(doc, vla, Filter(filter), NestingLimit(5));
}
#endif
@ -766,7 +802,7 @@ TEST_CASE("Overloads") {
SECTION("char[n], NestingLimit, Filter") {
size_t i = 4;
char vla[i];
strcpy(vla, "{}");
strlcpy(vla, "{}");
deserializeJson(doc, vla, NestingLimit(5), Filter(filter));
}
#endif

@ -123,7 +123,7 @@ TEST_CASE("deserializeJson(std::istream&)") {
TEST_CASE("deserializeJson(VLA)") {
size_t i = 9;
char vla[i];
strcpy(vla, "{\"a\":42}");
strlcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeJson(doc, vla);

@ -9,7 +9,8 @@
TEST_CASE("Invalid JSON input") {
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'",
"'\\u000/'", "\\x1234", "6a9", "1,",
"2]", "3}"};
"nulL", "tru3", "fals3", "2]",
"3}"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
@ -23,9 +24,6 @@ TEST_CASE("Invalid JSON input") {
TEST_CASE("Invalid JSON input that should pass") {
const char* testCases[] = {
"nulL",
"tru3",
"fals3",
"'\\ud83d'", // leading surrogate without a trailing surrogate
"'\\udda4'", // trailing surrogate without a leading surrogate
"'\\ud83d\\ud83d'", // two leading surrogates

@ -5,12 +5,12 @@
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
typedef ARDUINOJSON_NAMESPACE::ElementProxy<JsonDocument&> ElementProxy;
TEST_CASE("ElementProxy::add()") {
DynamicJsonDocument doc(4096);
doc.addElement();
ElementProxy<JsonDocument &> ep = doc[0];
doc.add();
ElementProxy ep = doc[0];
SECTION("add(int)") {
ep.add(42);
@ -27,7 +27,7 @@ TEST_CASE("ElementProxy::add()") {
SECTION("set(char[])") {
char s[] = "world";
ep.add(s);
strcpy(s, "!!!!!");
strlcpy(s, "!!!!!");
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
}
@ -35,8 +35,8 @@ TEST_CASE("ElementProxy::add()") {
TEST_CASE("ElementProxy::clear()") {
DynamicJsonDocument doc(4096);
doc.addElement();
ElementProxy<JsonDocument &> ep = doc[0];
doc.add();
ElementProxy ep = doc[0];
SECTION("size goes back to zero") {
ep.add(42);
@ -95,8 +95,8 @@ TEST_CASE("ElementProxy::operator==()") {
TEST_CASE("ElementProxy::remove()") {
DynamicJsonDocument doc(4096);
doc.addElement();
ElementProxy<JsonDocument &> ep = doc[0];
doc.add();
ElementProxy ep = doc[0];
SECTION("remove(int)") {
ep.add(1);
@ -133,7 +133,7 @@ TEST_CASE("ElementProxy::remove()") {
size_t i = 4;
char vla[i];
strcpy(vla, "b");
strlcpy(vla, "b");
ep.remove(vla);
REQUIRE(ep.as<std::string>() == "{\"a\":1}");
@ -143,7 +143,7 @@ TEST_CASE("ElementProxy::remove()") {
TEST_CASE("ElementProxy::set()") {
DynamicJsonDocument doc(4096);
ElementProxy<JsonDocument &> ep = doc[0];
ElementProxy ep = doc[0];
SECTION("set(int)") {
ep.set(42);
@ -160,7 +160,7 @@ TEST_CASE("ElementProxy::set()") {
SECTION("set(char[])") {
char s[] = "world";
ep.set(s);
strcpy(s, "!!!!!");
strlcpy(s, "!!!!!");
REQUIRE(doc.as<std::string>() == "[\"world\"]");
}
@ -168,8 +168,8 @@ TEST_CASE("ElementProxy::set()") {
TEST_CASE("ElementProxy::size()") {
DynamicJsonDocument doc(4096);
doc.addElement();
ElementProxy<JsonDocument &> ep = doc[0];
doc.add();
ElementProxy ep = doc[0];
SECTION("returns 0") {
REQUIRE(ep.size() == 0);
@ -190,8 +190,8 @@ TEST_CASE("ElementProxy::size()") {
TEST_CASE("ElementProxy::memoryUsage()") {
DynamicJsonDocument doc(4096);
doc.addElement();
ElementProxy<JsonDocument &> ep = doc[0];
doc.add();
ElementProxy ep = doc[0];
SECTION("returns 0 for null") {
REQUIRE(ep.memoryUsage() == 0);
@ -205,7 +205,7 @@ TEST_CASE("ElementProxy::memoryUsage()") {
TEST_CASE("ElementProxy::operator[]") {
DynamicJsonDocument doc(4096);
ElementProxy<JsonDocument &> ep = doc[1];
ElementProxy ep = doc[1];
SECTION("set member") {
ep["world"] = 42;
@ -224,7 +224,7 @@ TEST_CASE("ElementProxy cast to JsonVariantConst") {
DynamicJsonDocument doc(4096);
doc[0] = "world";
const ElementProxy<JsonDocument &> ep = doc[0];
const ElementProxy ep = doc[0];
JsonVariantConst var = ep;
@ -235,7 +235,7 @@ TEST_CASE("ElementProxy cast to JsonVariant") {
DynamicJsonDocument doc(4096);
doc[0] = "world";
ElementProxy<JsonDocument &> ep = doc[0];
ElementProxy ep = doc[0];
JsonVariant var = ep;
@ -245,3 +245,11 @@ TEST_CASE("ElementProxy cast to JsonVariant") {
CHECK(doc.as<std::string>() == "[\"toto\"]");
}
TEST_CASE("ElementProxy::shallowCopy()") {
StaticJsonDocument<1024> doc1, doc2;
doc2["hello"] = "world";
doc1[0].shallowCopy(doc2);
CHECK(doc1.as<std::string>() == "[{\"hello\":\"world\"}]");
}

@ -5,11 +5,12 @@
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace ARDUINOJSON_NAMESPACE;
typedef ARDUINOJSON_NAMESPACE::MemberProxy<JsonDocument&, const char*>
MemberProxy;
TEST_CASE("MemberProxy::add()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("add(int)") {
mp.add(42);
@ -26,7 +27,7 @@ TEST_CASE("MemberProxy::add()") {
TEST_CASE("MemberProxy::clear()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("size goes back to zero") {
mp.add(42);
@ -85,7 +86,7 @@ TEST_CASE("MemberProxy::operator==()") {
TEST_CASE("MemberProxy::containsKey()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("containsKey(const char*)") {
mp["key"] = "value";
@ -136,7 +137,7 @@ TEST_CASE("MemberProxy::operator|()") {
TEST_CASE("MemberProxy::remove()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("remove(int)") {
mp.add(1);
@ -173,7 +174,7 @@ TEST_CASE("MemberProxy::remove()") {
size_t i = 4;
char vla[i];
strcpy(vla, "b");
strlcpy(vla, "b");
mp.remove(vla);
REQUIRE(mp.as<std::string>() == "{\"a\":1}");
@ -183,7 +184,7 @@ TEST_CASE("MemberProxy::remove()") {
TEST_CASE("MemberProxy::set()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("set(int)") {
mp.set(42);
@ -200,7 +201,7 @@ TEST_CASE("MemberProxy::set()") {
SECTION("set(char[])") { // issue #1191
char s[] = "world";
mp.set(s);
strcpy(s, "!!!!!");
strlcpy(s, "!!!!!");
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
}
@ -208,7 +209,7 @@ TEST_CASE("MemberProxy::set()") {
TEST_CASE("MemberProxy::size()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("returns 0") {
REQUIRE(mp.size() == 0);
@ -231,7 +232,7 @@ TEST_CASE("MemberProxy::size()") {
TEST_CASE("MemberProxy::memoryUsage()") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("returns 0 when null") {
REQUIRE(mp.memoryUsage() == 0);
@ -245,7 +246,7 @@ TEST_CASE("MemberProxy::memoryUsage()") {
TEST_CASE("MemberProxy::operator[]") {
DynamicJsonDocument doc(4096);
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
SECTION("set member") {
mp["world"] = 42;
@ -264,7 +265,7 @@ TEST_CASE("MemberProxy cast to JsonVariantConst") {
DynamicJsonDocument doc(4096);
doc["hello"] = "world";
const MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
const MemberProxy mp = doc["hello"];
JsonVariantConst var = mp;
@ -275,7 +276,7 @@ TEST_CASE("MemberProxy cast to JsonVariant") {
DynamicJsonDocument doc(4096);
doc["hello"] = "world";
MemberProxy<JsonDocument &, const char *> mp = doc["hello"];
MemberProxy mp = doc["hello"];
JsonVariant var = mp;
@ -285,3 +286,43 @@ TEST_CASE("MemberProxy cast to JsonVariant") {
CHECK(doc.as<std::string>() == "{\"hello\":\"toto\"}");
}
TEST_CASE("MemberProxy::createNestedArray()") {
StaticJsonDocument<1024> doc;
JsonArray arr = doc["items"].createNestedArray();
arr.add(42);
CHECK(doc["items"][0][0] == 42);
}
TEST_CASE("MemberProxy::createNestedArray(key)") {
StaticJsonDocument<1024> doc;
JsonArray arr = doc["weather"].createNestedArray("temp");
arr.add(42);
CHECK(doc["weather"]["temp"][0] == 42);
}
TEST_CASE("MemberProxy::createNestedObject()") {
StaticJsonDocument<1024> doc;
JsonObject obj = doc["items"].createNestedObject();
obj["value"] = 42;
CHECK(doc["items"][0]["value"] == 42);
}
TEST_CASE("MemberProxy::createNestedObject(key)") {
StaticJsonDocument<1024> doc;
JsonObject obj = doc["status"].createNestedObject("weather");
obj["temp"] = 42;
CHECK(doc["status"]["weather"]["temp"] == 42);
}
TEST_CASE("MemberProxy::shallowCopy()") {
StaticJsonDocument<1024> doc1, doc2;
doc2["hello"] = "world";
doc1["obj"].shallowCopy(doc2);
CHECK(doc1.as<std::string>() == "{\"obj\":{\"hello\":\"world\"}}");
}

@ -43,7 +43,7 @@ TEST_CASE("JsonDocument::remove()") {
size_t i = 4;
char vla[i];
strcpy(vla, "b");
strlcpy(vla, "b");
doc.remove(vla);
REQUIRE(doc.as<std::string>() == "{\"a\":1}");

@ -4,6 +4,7 @@
add_executable(JsonObjectTests
clear.cpp
compare.cpp
containsKey.cpp
copy.cpp
createNestedArray.cpp

@ -0,0 +1,512 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Compare JsonObject with JsonObject") {
StaticJsonDocument<512> doc;
SECTION("Compare with unbound") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonObject unbound;
CHECK(object != unbound);
CHECK_FALSE(object == unbound);
CHECK_FALSE(object <= unbound);
CHECK_FALSE(object >= unbound);
CHECK_FALSE(object > unbound);
CHECK_FALSE(object < unbound);
CHECK(unbound != object);
CHECK_FALSE(unbound == object);
CHECK_FALSE(unbound <= object);
CHECK_FALSE(unbound >= object);
CHECK_FALSE(unbound > object);
CHECK_FALSE(unbound < object);
}
SECTION("Compare with self") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
CHECK(object == object);
CHECK(object <= object);
CHECK(object >= object);
CHECK_FALSE(object != object);
CHECK_FALSE(object > object);
CHECK_FALSE(object < object);
}
SECTION("Compare with identical object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello";
object1["c"][0] = false;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello";
object2["c"][0] = false;
CHECK(object1 == object2);
CHECK(object1 <= object2);
CHECK(object1 >= object2);
CHECK_FALSE(object1 != object2);
CHECK_FALSE(object1 > object2);
CHECK_FALSE(object1 < object2);
}
SECTION("Compare with different object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello1";
object1["c"][0] = false;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello2";
object2["c"][0] = false;
CHECK(object1 != object2);
CHECK_FALSE(object1 == object2);
CHECK_FALSE(object1 > object2);
CHECK_FALSE(object1 < object2);
CHECK_FALSE(object1 <= object2);
CHECK_FALSE(object1 >= object2);
}
}
TEST_CASE("Compare JsonObject with JsonVariant") {
StaticJsonDocument<512> doc;
SECTION("Compare with self") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonVariant variant = object;
CHECK(object == variant);
CHECK(object <= variant);
CHECK(object >= variant);
CHECK_FALSE(object != variant);
CHECK_FALSE(object > variant);
CHECK_FALSE(object < variant);
CHECK(variant == object);
CHECK(variant <= object);
CHECK(variant >= object);
CHECK_FALSE(variant != object);
CHECK_FALSE(variant > object);
CHECK_FALSE(variant < object);
}
SECTION("Compare with identical object") {
JsonObject object = doc.createNestedObject();
object["a"] = 1;
object["b"] = "hello";
object["c"][0] = false;
JsonVariant variant = doc.createNestedObject();
variant["a"] = 1;
variant["b"] = "hello";
variant["c"][0] = false;
CHECK(object == variant);
CHECK(object <= variant);
CHECK(object >= variant);
CHECK_FALSE(object != variant);
CHECK_FALSE(object > variant);
CHECK_FALSE(object < variant);
CHECK(variant == object);
CHECK(variant <= object);
CHECK(variant >= object);
CHECK_FALSE(variant != object);
CHECK_FALSE(variant > object);
CHECK_FALSE(variant < object);
}
SECTION("Compare with different object") {
JsonObject object = doc.createNestedObject();
object["a"] = 1;
object["b"] = "hello1";
object["c"][0] = false;
JsonVariant variant = doc.createNestedObject();
variant["a"] = 1;
variant["b"] = "hello2";
variant["c"][0] = false;
CHECK(object != variant);
CHECK_FALSE(object == variant);
CHECK_FALSE(object > variant);
CHECK_FALSE(object < variant);
CHECK_FALSE(object <= variant);
CHECK_FALSE(object >= variant);
}
}
TEST_CASE("Compare JsonObject with JsonVariantConst") {
StaticJsonDocument<512> doc;
SECTION("Compare with unbound") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonVariantConst unbound;
CHECK(object != unbound);
CHECK_FALSE(object == unbound);
CHECK_FALSE(object <= unbound);
CHECK_FALSE(object >= unbound);
CHECK_FALSE(object > unbound);
CHECK_FALSE(object < unbound);
CHECK(unbound != object);
CHECK_FALSE(unbound == object);
CHECK_FALSE(unbound <= object);
CHECK_FALSE(unbound >= object);
CHECK_FALSE(unbound > object);
CHECK_FALSE(unbound < object);
}
SECTION("Compare with self") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonVariantConst variant = object;
CHECK(object == variant);
CHECK(object <= variant);
CHECK(object >= variant);
CHECK_FALSE(object != variant);
CHECK_FALSE(object > variant);
CHECK_FALSE(object < variant);
CHECK(variant == object);
CHECK(variant <= object);
CHECK(variant >= object);
CHECK_FALSE(variant != object);
CHECK_FALSE(variant > object);
CHECK_FALSE(variant < object);
}
SECTION("Compare with identical object") {
JsonObject object = doc.createNestedObject();
object["a"] = 1;
object["b"] = "hello";
object["c"][0] = false;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello";
object2["c"][0] = false;
JsonVariantConst variant = object2;
CHECK(object == variant);
CHECK(object <= variant);
CHECK(object >= variant);
CHECK_FALSE(object != variant);
CHECK_FALSE(object > variant);
CHECK_FALSE(object < variant);
CHECK(variant == object);
CHECK(variant <= object);
CHECK(variant >= object);
CHECK_FALSE(variant != object);
CHECK_FALSE(variant > object);
CHECK_FALSE(variant < object);
}
SECTION("Compare with different object") {
JsonObject object = doc.createNestedObject();
object["a"] = 1;
object["b"] = "hello1";
object["c"][0] = false;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello2";
object2["c"][0] = false;
JsonVariantConst variant = object2;
CHECK(object != variant);
CHECK_FALSE(object == variant);
CHECK_FALSE(object > variant);
CHECK_FALSE(object < variant);
CHECK_FALSE(object <= variant);
CHECK_FALSE(object >= variant);
}
}
TEST_CASE("Compare JsonObject with JsonObjectConst") {
StaticJsonDocument<512> doc;
SECTION("Compare with unbound") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonObjectConst unbound;
CHECK(object != unbound);
CHECK_FALSE(object == unbound);
CHECK_FALSE(object <= unbound);
CHECK_FALSE(object >= unbound);
CHECK_FALSE(object > unbound);
CHECK_FALSE(object < unbound);
CHECK(unbound != object);
CHECK_FALSE(unbound == object);
CHECK_FALSE(unbound <= object);
CHECK_FALSE(unbound >= object);
CHECK_FALSE(unbound > object);
CHECK_FALSE(unbound < object);
}
SECTION("Compare with self") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonObjectConst cobject = object;
CHECK(object == cobject);
CHECK(object <= cobject);
CHECK(object >= cobject);
CHECK_FALSE(object != cobject);
CHECK_FALSE(object > cobject);
CHECK_FALSE(object < cobject);
CHECK(cobject == object);
CHECK(cobject <= object);
CHECK(cobject >= object);
CHECK_FALSE(cobject != object);
CHECK_FALSE(cobject > object);
CHECK_FALSE(cobject < object);
}
SECTION("Compare with identical object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello";
object1["c"][0] = false;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello";
object2["c"][0] = false;
JsonObjectConst carray2 = object2;
CHECK(object1 == carray2);
CHECK(object1 <= carray2);
CHECK(object1 >= carray2);
CHECK_FALSE(object1 != carray2);
CHECK_FALSE(object1 > carray2);
CHECK_FALSE(object1 < carray2);
CHECK(carray2 == object1);
CHECK(carray2 <= object1);
CHECK(carray2 >= object1);
CHECK_FALSE(carray2 != object1);
CHECK_FALSE(carray2 > object1);
CHECK_FALSE(carray2 < object1);
}
SECTION("Compare with different object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello1";
object1["c"][0] = false;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello2";
object2["c"][0] = false;
JsonObjectConst carray2 = object2;
CHECK(object1 != carray2);
CHECK_FALSE(object1 == carray2);
CHECK_FALSE(object1 > carray2);
CHECK_FALSE(object1 < carray2);
CHECK_FALSE(object1 <= carray2);
CHECK_FALSE(object1 >= carray2);
CHECK(carray2 != object1);
CHECK_FALSE(carray2 == object1);
CHECK_FALSE(carray2 > object1);
CHECK_FALSE(carray2 < object1);
CHECK_FALSE(carray2 <= object1);
CHECK_FALSE(carray2 >= object1);
}
}
TEST_CASE("Compare JsonObjectConst with JsonObjectConst") {
StaticJsonDocument<512> doc;
SECTION("Compare with unbound") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonObjectConst cobject = object;
JsonObjectConst unbound;
CHECK(cobject != unbound);
CHECK_FALSE(cobject == unbound);
CHECK_FALSE(cobject <= unbound);
CHECK_FALSE(cobject >= unbound);
CHECK_FALSE(cobject > unbound);
CHECK_FALSE(cobject < unbound);
CHECK(unbound != cobject);
CHECK_FALSE(unbound == cobject);
CHECK_FALSE(unbound <= cobject);
CHECK_FALSE(unbound >= cobject);
CHECK_FALSE(unbound > cobject);
CHECK_FALSE(unbound < cobject);
}
SECTION("Compare with self") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonObjectConst cobject = object;
CHECK(cobject == cobject);
CHECK(cobject <= cobject);
CHECK(cobject >= cobject);
CHECK_FALSE(cobject != cobject);
CHECK_FALSE(cobject > cobject);
CHECK_FALSE(cobject < cobject);
}
SECTION("Compare with identical object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello";
object1["c"][0] = false;
JsonObjectConst carray1 = object1;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello";
object2["c"][0] = false;
JsonObjectConst carray2 = object2;
CHECK(carray1 == carray2);
CHECK(carray1 <= carray2);
CHECK(carray1 >= carray2);
CHECK_FALSE(carray1 != carray2);
CHECK_FALSE(carray1 > carray2);
CHECK_FALSE(carray1 < carray2);
}
SECTION("Compare with different object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello1";
object1["c"][0] = false;
JsonObjectConst carray1 = object1;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello2";
object2["c"][0] = false;
JsonObjectConst carray2 = object2;
CHECK(carray1 != carray2);
CHECK_FALSE(carray1 == carray2);
CHECK_FALSE(carray1 > carray2);
CHECK_FALSE(carray1 < carray2);
CHECK_FALSE(carray1 <= carray2);
CHECK_FALSE(carray1 >= carray2);
}
}
TEST_CASE("Compare JsonObjectConst with JsonVariant") {
StaticJsonDocument<512> doc;
SECTION("Compare with self") {
JsonObject object = doc.to<JsonObject>();
object["a"] = 1;
object["b"] = "hello";
JsonObjectConst cobject = object;
JsonVariant variant = object;
CHECK(cobject == variant);
CHECK(cobject <= variant);
CHECK(cobject >= variant);
CHECK_FALSE(cobject != variant);
CHECK_FALSE(cobject > variant);
CHECK_FALSE(cobject < variant);
CHECK(variant == cobject);
CHECK(variant <= cobject);
CHECK(variant >= cobject);
CHECK_FALSE(variant != cobject);
CHECK_FALSE(variant > cobject);
CHECK_FALSE(variant < cobject);
}
SECTION("Compare with identical object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello";
object1["c"][0] = false;
JsonObjectConst carray1 = object1;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello";
object2["c"][0] = false;
JsonVariant variant2 = object2;
CHECK(carray1 == variant2);
CHECK(carray1 <= variant2);
CHECK(carray1 >= variant2);
CHECK_FALSE(carray1 != variant2);
CHECK_FALSE(carray1 > variant2);
CHECK_FALSE(carray1 < variant2);
CHECK(variant2 == carray1);
CHECK(variant2 <= carray1);
CHECK(variant2 >= carray1);
CHECK_FALSE(variant2 != carray1);
CHECK_FALSE(variant2 > carray1);
CHECK_FALSE(variant2 < carray1);
}
SECTION("Compare with different object") {
JsonObject object1 = doc.createNestedObject();
object1["a"] = 1;
object1["b"] = "hello1";
object1["c"][0] = false;
JsonObjectConst carray1 = object1;
JsonObject object2 = doc.createNestedObject();
object2["a"] = 1;
object2["b"] = "hello2";
object2["c"][0] = false;
JsonVariant variant2 = object2;
CHECK(carray1 != variant2);
CHECK_FALSE(carray1 == variant2);
CHECK_FALSE(carray1 > variant2);
CHECK_FALSE(carray1 < variant2);
CHECK_FALSE(carray1 <= variant2);
CHECK_FALSE(carray1 >= variant2);
CHECK(variant2 != carray1);
CHECK_FALSE(variant2 == carray1);
CHECK_FALSE(variant2 > carray1);
CHECK_FALSE(variant2 < carray1);
CHECK_FALSE(variant2 <= carray1);
CHECK_FALSE(variant2 >= carray1);
}
}

@ -31,7 +31,7 @@ TEST_CASE("JsonObject::containsKey()") {
SECTION("key is a VLA") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
REQUIRE(true == obj.containsKey(vla));
}

@ -18,7 +18,7 @@ TEST_CASE("JsonObject::createNestedArray()") {
SECTION("key is a VLA") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
JsonArray arr = obj.createNestedArray(vla);
REQUIRE(arr.isNull() == false);

@ -17,7 +17,7 @@ TEST_CASE("JsonObject::createNestedObject()") {
SECTION("key is a VLA") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
obj.createNestedObject(vla);
}

@ -62,7 +62,7 @@ TEST_CASE("JsonObject::remove()") {
SECTION("key is a vla") {
size_t i = 16;
char vla[i];
strcpy(vla, "b");
strlcpy(vla, "b");
obj.remove(vla);
serializeJson(obj, result);

@ -7,7 +7,8 @@
static void eraseString(std::string& str) {
char* p = const_cast<char*>(str.c_str());
while (*p) *p++ = '*';
while (*p)
*p++ = '*';
}
TEST_CASE("std::string") {

@ -174,7 +174,7 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("obj[VLA] = str") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
obj[vla] = "world";
@ -184,7 +184,7 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("obj[str] = VLA") { // issue #416
size_t i = 32;
char vla[i];
strcpy(vla, "world");
strlcpy(vla, "world");
obj["hello"] = vla;
@ -194,7 +194,7 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("obj.set(VLA, str)") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
obj[vla] = "world";
@ -204,7 +204,7 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("obj.set(str, VLA)") {
size_t i = 32;
char vla[i];
strcpy(vla, "world");
strlcpy(vla, "world");
obj["hello"].set(vla);
@ -214,7 +214,7 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("obj[VLA]") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");

@ -8,8 +8,8 @@ add_executable(JsonVariantTests
clear.cpp
compare.cpp
containsKey.cpp
copy.cpp
converters.cpp
copy.cpp
createNested.cpp
is.cpp
isnull.cpp
@ -20,6 +20,8 @@ add_executable(JsonVariantTests
overflow.cpp
remove.cpp
set.cpp
shallowCopy.cpp
size.cpp
subscript.cpp
types.cpp
unbound.cpp

@ -10,7 +10,7 @@
TEST_CASE("Compare JsonVariant with value") {
StaticJsonDocument<256> doc;
JsonVariant a = doc.addElement();
JsonVariant a = doc.add();
SECTION("null vs (char*)0") {
char* b = 0;
@ -38,8 +38,8 @@ TEST_CASE("Compare JsonVariant with value") {
TEST_CASE("Compare JsonVariant with JsonVariant") {
StaticJsonDocument<256> doc;
JsonVariant a = doc.addElement();
JsonVariant b = doc.addElement();
JsonVariant a = doc.add();
JsonVariant b = doc.add();
SECTION("'abc' vs 'abc'") {
a.set("abc");

@ -12,14 +12,14 @@ TEST_CASE("JsonVariant::containsKey()") {
DynamicJsonDocument doc(4096);
JsonVariant var = doc.to<JsonVariant>();
SECTION("containsKey(const char*) returns true") {
SECTION("containsKey(const char*)") {
var["hello"] = "world";
REQUIRE(var.containsKey("hello") == true);
REQUIRE(var.containsKey("world") == false);
}
SECTION("containsKey(std::string) returns true") {
SECTION("containsKey(std::string)") {
var["hello"] = "world";
REQUIRE(var.containsKey(std::string("hello")) == true);

@ -91,16 +91,16 @@ class Complex {
namespace ARDUINOJSON_NAMESPACE {
template <>
struct Converter<Complex> {
static void toJson(const Complex& src, VariantRef dst) {
static void toJson(const Complex& src, JsonVariant dst) {
dst["real"] = src.real();
dst["imag"] = src.imag();
}
static Complex fromJson(VariantConstRef src) {
static Complex fromJson(JsonVariantConst src) {
return Complex(src["real"], src["imag"]);
}
static bool checkJson(VariantConstRef src) {
static bool checkJson(JsonVariantConst src) {
return src["real"].is<double>() && src["imag"].is<double>();
}
};
@ -140,3 +140,15 @@ TEST_CASE("Custom converter with specialization") {
REQUIRE(doc["value"]["imag"] == 3);
}
}
TEST_CASE("ConverterNeedsWriteableRef") {
using namespace ARDUINOJSON_NAMESPACE;
CHECK(ConverterNeedsWriteableRef<int>::value == false);
CHECK(ConverterNeedsWriteableRef<float>::value == false);
CHECK(ConverterNeedsWriteableRef<JsonVariant>::value == true);
CHECK(ConverterNeedsWriteableRef<JsonVariantConst>::value == false);
CHECK(ConverterNeedsWriteableRef<JsonObject>::value == true);
CHECK(ConverterNeedsWriteableRef<JsonObjectConst>::value == false);
CHECK(ConverterNeedsWriteableRef<JsonArray>::value == true);
CHECK(ConverterNeedsWriteableRef<JsonArrayConst>::value == false);
}

@ -18,13 +18,6 @@ TEST_CASE("JsonVariant::createNestedObject()") {
REQUIRE(variant[0]["value"] == 42);
REQUIRE(obj.isNull() == false);
}
SECTION("works on MemberProxy") {
JsonObject obj = variant["items"].createNestedObject();
obj["value"] = 42;
REQUIRE(variant["items"][0]["value"] == 42);
}
}
TEST_CASE("JsonVariant::createNestedArray()") {
@ -37,13 +30,6 @@ TEST_CASE("JsonVariant::createNestedArray()") {
REQUIRE(variant.is<JsonArray>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("works on MemberProxy") {
JsonArray arr = variant["items"].createNestedArray();
arr.add(42);
REQUIRE(variant["items"][0][0] == 42);
}
}
TEST_CASE("JsonVariant::createNestedObject(key)") {
@ -57,13 +43,6 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(variant["weather"]["temp"] == 42);
}
SECTION("works on MemberProxy") {
JsonObject obj = variant["status"].createNestedObject("weather");
obj["temp"] = 42;
REQUIRE(variant["status"]["weather"]["temp"] == 42);
}
}
TEST_CASE("JsonVariant::createNestedArray(key)") {
@ -76,11 +55,4 @@ TEST_CASE("JsonVariant::createNestedArray(key)") {
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("works on MemberProxy") {
JsonArray arr = variant["weather"].createNestedArray("temp");
arr.add(42);
REQUIRE(variant["weather"]["temp"][0] == 42);
}
}

@ -9,17 +9,17 @@ TEST_CASE("JsonVariant::isNull()") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("return true when Undefined") {
SECTION("returns true when Undefined") {
REQUIRE(variant.isNull() == true);
}
SECTION("return false when Integer") {
SECTION("returns false when Integer") {
variant.set(42);
REQUIRE(variant.isNull() == false);
}
SECTION("return false when EmptyArray") {
SECTION("returns false when EmptyArray") {
DynamicJsonDocument doc2(4096);
JsonArray array = doc2.to<JsonArray>();
@ -27,7 +27,7 @@ TEST_CASE("JsonVariant::isNull()") {
REQUIRE(variant.isNull() == false);
}
SECTION("return false when EmptyObject") {
SECTION("returns false when EmptyObject") {
DynamicJsonDocument doc2(4096);
JsonObject obj = doc2.to<JsonObject>();
@ -35,41 +35,54 @@ TEST_CASE("JsonVariant::isNull()") {
REQUIRE(variant.isNull() == false);
}
SECTION("return true after set(JsonArray())") {
SECTION("returns true after set(JsonArray())") {
variant.set(JsonArray());
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set(JsonObject())") {
SECTION("returns true after set(JsonObject())") {
variant.set(JsonObject());
REQUIRE(variant.isNull() == true);
}
SECTION("return false after set('hello')") {
SECTION("returns false after set('hello')") {
variant.set("hello");
REQUIRE(variant.isNull() == false);
}
SECTION("return true after set((char*)0)") {
SECTION("returns true after set((char*)0)") {
variant.set(static_cast<char*>(0));
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set((const char*)0)") {
SECTION("returns true after set((const char*)0)") {
variant.set(static_cast<const char*>(0));
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set(serialized((char*)0))") {
SECTION("returns true after set(serialized((char*)0))") {
variant.set(serialized(static_cast<char*>(0)));
REQUIRE(variant.isNull() == true);
}
SECTION("return true after set(serialized((const char*)0))") {
SECTION("returns true after set(serialized((const char*)0))") {
variant.set(serialized(static_cast<const char*>(0)));
REQUIRE(variant.isNull() == true);
}
SECTION("returns true for a shallow null copy") {
StaticJsonDocument<128> doc2;
variant.shallowCopy(doc2);
CHECK(variant.isNull() == true);
}
SECTION("returns false for a shallow array copy") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.shallowCopy(doc2);
CHECK(variant.isNull() == false);
}
SECTION("works with JsonVariantConst") {
variant.set(42);

@ -14,9 +14,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("const char*") {
char str[16];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(static_cast<const char*>(str));
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "world"); // stores by pointer
@ -32,9 +32,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("char*") {
char str[16];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(str);
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "hello"); // stores by copy
@ -50,9 +50,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("unsigned char*") {
char str[16];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(reinterpret_cast<unsigned char*>(str));
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "hello"); // stores by copy
@ -61,9 +61,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("signed char*") {
char str[16];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(reinterpret_cast<signed char*>(str));
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "hello"); // stores by copy
@ -74,9 +74,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
size_t n = 16;
char str[n];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(str);
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "hello"); // stores by copy
@ -97,9 +97,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("static JsonString") {
char str[16];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(JsonString(str, JsonString::Linked));
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "world"); // stores by pointer
@ -108,9 +108,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("non-static JsonString") {
char str[16];
strcpy(str, "hello");
strlcpy(str, "hello");
bool result = variant.set(JsonString(str, JsonString::Copied));
strcpy(str, "world");
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "hello"); // stores by copy

@ -0,0 +1,87 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonVariant::shallowCopy()") {
StaticJsonDocument<1024> doc1, doc2;
JsonVariant variant = doc1.to<JsonVariant>();
SECTION("JsonVariant::shallowCopy(JsonDocument&)") {
doc2["hello"] = "world";
variant.shallowCopy(doc2);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
// altering the linked document should change the result
doc2["hello"] = "WORLD!";
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("JsonVariant::shallowCopy(MemberProxy)") {
doc2["obj"]["hello"] = "world";
variant.shallowCopy(doc2["obj"]);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
// altering the linked document should change the result
doc2["obj"]["hello"] = "WORLD!";
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("JsonVariant::shallowCopy(ElementProxy)") {
doc2[0]["hello"] = "world";
variant.shallowCopy(doc2[0]);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
// altering the linked document should change the result
doc2[0]["hello"] = "WORLD!";
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("target is unbound") {
JsonVariant unbound;
variant["hello"] = "world";
variant.shallowCopy(unbound);
CHECK(variant.isUnbound() == false);
CHECK(variant.isNull() == true);
CHECK(variant.memoryUsage() == 0);
CHECK(variant.size() == 0);
}
SECTION("variant is unbound") {
JsonVariant unbound;
doc2["hello"] = "world";
unbound.shallowCopy(doc2);
CHECK(unbound.isUnbound() == true);
CHECK(unbound.isNull() == true);
CHECK(unbound.memoryUsage() == 0);
CHECK(unbound.size() == 0);
}
SECTION("preserves owned key bit") {
doc2.set(42);
doc1["a"].shallowCopy(doc2);
doc1[std::string("b")].shallowCopy(doc2);
JsonObject::iterator it = doc1.as<JsonObject>().begin();
CHECK(it->key().isLinked() == true);
++it;
CHECK(it->key().isLinked() == false);
}
}

@ -0,0 +1,36 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonVariant::size()") {
DynamicJsonDocument doc(4096);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("unbound reference") {
JsonVariant unbound;
CHECK(unbound.size() == 0);
}
SECTION("int") {
variant.set(42);
CHECK(variant.size() == 0);
}
SECTION("string") {
variant.set("hello");
CHECK(variant.size() == 0);
}
SECTION("object") {
variant["a"] = 1;
variant["b"] = 2;
CHECK(variant.size() == 2);
}
}

@ -110,7 +110,7 @@ TEST_CASE("JsonVariant::operator[]") {
SECTION("key is a VLA") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
JsonVariant variant = doc.as<JsonVariant>();
@ -121,7 +121,7 @@ TEST_CASE("JsonVariant::operator[]") {
SECTION("key is a VLA, const JsonVariant") {
size_t i = 16;
char vla[i];
strcpy(vla, "hello");
strlcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
const JsonVariant variant = doc.as<JsonVariant>();

@ -12,7 +12,7 @@ TEST_CASE("StringCopier") {
SECTION("Works when buffer is big enough") {
MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(5)));
StringCopier str(pool);
StringCopier str(&pool);
str.startString();
str.append("hello");
@ -24,7 +24,7 @@ TEST_CASE("StringCopier") {
SECTION("Returns null when too small") {
MemoryPool pool(buffer, sizeof(void*));
StringCopier str(pool);
StringCopier str(&pool);
str.startString();
str.append("hello world!");
@ -35,7 +35,7 @@ TEST_CASE("StringCopier") {
SECTION("Increases size of memory pool") {
MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6)));
StringCopier str(pool);
StringCopier str(&pool);
str.startString();
str.save();
@ -46,7 +46,7 @@ TEST_CASE("StringCopier") {
SECTION("Works when memory pool is 0 bytes") {
MemoryPool pool(buffer, 0);
StringCopier str(pool);
StringCopier str(&pool);
str.startString();
REQUIRE(str.isValid() == false);
@ -55,7 +55,7 @@ TEST_CASE("StringCopier") {
}
static const char* addStringToPool(MemoryPool& pool, const char* s) {
StringCopier str(pool);
StringCopier str(&pool);
str.startString();
str.append(s);
return str.save().c_str();

@ -25,7 +25,8 @@ TEST_CASE("MemoryPool::size()") {
SECTION("Doesn't grow when memory pool is full") {
const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot);
for (size_t i = 0; i < variantCount; i++) pool.allocVariant();
for (size_t i = 0; i < variantCount; i++)
pool.allocVariant();
size_t size = pool.size();
pool.allocVariant();

@ -5,7 +5,6 @@
add_executable(MiscTests
arithmeticCompare.cpp
conflicts.cpp
deprecated.cpp
FloatParts.cpp
JsonString.cpp
NoArduinoHeader.cpp

@ -8,6 +8,7 @@
#include "custom_string.hpp"
#include "weird_strcmp.hpp"
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <catch.hpp>
@ -85,30 +86,18 @@ TEST_CASE("custom_string") {
CHECK(s.size() == 5);
}
struct EmptyStruct {};
TEST_CASE("IsString<T>") {
SECTION("std::string") {
CHECK(IsString<std::string>::value == true);
}
SECTION("basic_string<wchar_t>") {
CHECK(IsString<std::basic_string<wchar_t> >::value == false);
}
SECTION("custom_string") {
CHECK(IsString<custom_string>::value == true);
}
SECTION("const __FlashStringHelper*") {
CHECK(IsString<const __FlashStringHelper*>::value == true);
}
SECTION("const char*") {
CHECK(IsString<const char*>::value == true);
}
SECTION("const char[]") {
CHECK(IsString<const char[8]>::value == true);
}
CHECK(IsString< ::String>::value == true);
CHECK(IsString< ::StringSumHelper>::value == true);
CHECK(IsString<const EmptyStruct*>::value == false);
}
TEST_CASE("stringCompare") {

@ -80,7 +80,7 @@ TEST_CASE("Polyfills/type_traits") {
CHECK(is_integral<const volatile unsigned long>::value == true);
CHECK(is_integral<const volatile unsigned short>::value == true);
CHECK(is_integral<UInt>::value == true);
CHECK(is_integral<JsonUInt>::value == true);
}
SECTION("is_signed") {
@ -177,6 +177,24 @@ TEST_CASE("Polyfills/type_traits") {
CHECK((is_convertible<EmptyEnum, int>::value == true));
CHECK((is_convertible<int*, int>::value == false));
CHECK((is_convertible<EmptyClass, int>::value == false));
CHECK((is_convertible<DeserializationError, JsonVariantConst>::value ==
false));
CHECK((is_convertible<JsonPair, JsonVariantConst>::value == false));
CHECK((is_convertible<JsonVariant, JsonVariantConst>::value == true));
CHECK((is_convertible<JsonVariantConst, JsonVariantConst>::value == true));
CHECK((is_convertible<JsonArray, JsonVariantConst>::value == true));
CHECK((is_convertible<ElementProxy<JsonArray>, JsonVariantConst>::value ==
true));
CHECK((is_convertible<JsonArrayConst, JsonVariantConst>::value == true));
CHECK((is_convertible<JsonObject, JsonVariantConst>::value == true));
CHECK((is_convertible<MemberProxy<JsonObject, const char*>,
JsonVariantConst>::value == true));
CHECK((is_convertible<JsonObjectConst, JsonVariantConst>::value == true));
CHECK(
(is_convertible<DynamicJsonDocument, JsonVariantConst>::value == true));
CHECK((is_convertible<StaticJsonDocument<10>, JsonVariantConst>::value ==
true));
}
SECTION("is_class") {
@ -194,19 +212,4 @@ TEST_CASE("Polyfills/type_traits") {
CHECK(is_enum<bool>::value == false);
CHECK(is_enum<double>::value == false);
}
SECTION("IsVisitable") {
CHECK(IsVisitable<DeserializationError>::value == false);
CHECK(IsVisitable<JsonPair>::value == false);
CHECK(IsVisitable<VariantRef>::value == true);
CHECK(IsVisitable<VariantConstRef>::value == true);
CHECK(IsVisitable<ArrayRef>::value == true);
CHECK(IsVisitable<ElementProxy<ArrayRef> >::value == true);
CHECK(IsVisitable<ArrayConstRef>::value == true);
CHECK(IsVisitable<ObjectRef>::value == true);
CHECK((IsVisitable<MemberProxy<ObjectRef, const char*> >::value == true));
CHECK(IsVisitable<ObjectConstRef>::value == true);
CHECK(IsVisitable<DynamicJsonDocument>::value == true);
CHECK(IsVisitable<StaticJsonDocument<10> >::value == true);
}
}

@ -12,7 +12,7 @@ using namespace ARDUINOJSON_NAMESPACE;
static void testCodepoint(uint32_t codepoint, std::string expected) {
char buffer[4096];
MemoryPool pool(buffer, 4096);
StringCopier str(pool);
StringCopier str(&pool);
str.startString();
CAPTURE(codepoint);

@ -1,115 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#define ARDUINOJSON_DEPRECATED(msg) // nothing
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Deprecated features") {
StaticJsonDocument<256> doc;
const char* s = "hello";
doc["s"] = s;
doc["c"] = 42;
doc["a"].add(s);
doc["a"].add(42);
SECTION("JsonVariant::add(char)") {
JsonVariant v = doc.to<JsonVariant>();
v.add('*');
REQUIRE(v[0] == 42);
}
SECTION("JsonVariant::as<char*>()") {
JsonVariant v = doc["s"];
REQUIRE(v.as<char*>() == s);
}
SECTION("JsonVariant::as<char>()") {
JsonVariant v = doc["c"];
REQUIRE(v.as<char>() == '*');
}
SECTION("JsonVariant::is<char*>()") {
JsonVariant v = doc["s"];
REQUIRE(v.is<char*>() == true);
}
SECTION("JsonVariant::is<char>()") {
JsonVariant v = doc["c"];
REQUIRE(v.is<char>() == true);
}
SECTION("JsonVariant::set(char)") {
JsonVariant v = doc.to<JsonVariant>();
v.set('*');
REQUIRE(v.as<unsigned char>() == 42);
}
SECTION("JsonVariantConst::as<char*>()") {
JsonVariantConst v = doc["s"];
REQUIRE(v.as<char*>() == s);
}
SECTION("JsonVariantConst::as<char>()") {
JsonVariantConst v = doc["c"];
REQUIRE(v.as<char>() == '*');
}
SECTION("JsonVariantConst::is<char*>()") {
JsonVariantConst v = doc["s"];
REQUIRE(v.is<char*>() == true);
}
SECTION("JsonVariantConst::is<char>()") {
JsonVariantConst v = doc["c"];
REQUIRE(v.is<char>() == true);
}
SECTION("MemberProxy::as<char*>()") {
REQUIRE(doc["s"].as<char*>() == s);
}
SECTION("MemberProxy::as<char>()") {
REQUIRE(doc["c"].as<char>() == '*');
}
SECTION("MemberProxy::as<char>()") {
doc["x"].set('*');
REQUIRE(doc["x"] == 42);
}
SECTION("MemberProxy::is<char*>()") {
REQUIRE(doc["s"].is<char*>() == true);
REQUIRE(doc["c"].is<char*>() == false);
}
SECTION("MemberProxy::is<char>()") {
REQUIRE(doc["c"].is<char>() == true);
REQUIRE(doc["s"].is<char>() == false);
}
SECTION("ElementProxy::as<char*>()") {
REQUIRE(doc["a"][0].as<char*>() == s);
}
SECTION("ElementProxy::as<char>()") {
REQUIRE(doc["a"][1].as<char>() == '*');
}
SECTION("ElementProxy::as<char>()") {
doc["a"][0].set('*');
REQUIRE(doc["a"][0] == 42);
}
SECTION("ElementProxy::is<char*>()") {
REQUIRE(doc["a"][0].is<char*>() == true);
REQUIRE(doc["a"][1].is<char*>() == false);
}
SECTION("ElementProxy::is<char>()") {
REQUIRE(doc["a"][1].is<char>() == true);
REQUIRE(doc["a"][0].is<char>() == false);
}
}

@ -1070,7 +1070,7 @@ TEST_CASE("Overloads") {
SECTION("char[n], Filter") {
size_t i = 4;
char vla[i];
strcpy(vla, "{}");
strlcpy(vla, "{}");
deserializeMsgPack(doc, vla, Filter(filter));
}
#endif
@ -1098,7 +1098,7 @@ TEST_CASE("Overloads") {
SECTION("char[n], Filter, NestingLimit") {
size_t i = 4;
char vla[i];
strcpy(vla, "{}");
strlcpy(vla, "{}");
deserializeMsgPack(doc, vla, Filter(filter), NestingLimit(5));
}
#endif
@ -1126,7 +1126,7 @@ TEST_CASE("Overloads") {
SECTION("char[n], NestingLimit, Filter") {
size_t i = 4;
char vla[i];
strcpy(vla, "{}");
strlcpy(vla, "{}");
deserializeMsgPack(doc, vla, NestingLimit(5), Filter(filter));
}
#endif

@ -41,7 +41,8 @@ TEST_CASE("serialize MsgPack array") {
}
SECTION("array 16") {
for (int i = 0; i < 16; i++) array.add(i);
for (int i = 0; i < 16; i++)
array.add(i);
check(array,
"\xDC\x00\x10\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D"
@ -50,7 +51,8 @@ TEST_CASE("serialize MsgPack array") {
SECTION("array 32") {
const char* nil = 0;
for (int i = 0; i < 65536; i++) array.add(nil);
for (int i = 0; i < 65536; i++)
array.add(nil);
check(array,
std::string("\xDD\x00\x01\x00\x00", 5) + std::string(65536, '\xc0'));

@ -109,6 +109,7 @@ TEST_CASE("serialize MsgPack value") {
SECTION("float 32") {
checkVariant(1.25, "\xCA\x3F\xA0\x00\x00");
checkVariant(9.22337204e+18f, "\xca\x5f\x00\x00\x00");
}
SECTION("float 64") {

@ -2,6 +2,9 @@
# Copyright © 2014-2022, Benoit BLANCHON
# MIT License
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED OFF)
add_executable(NumbersTests
convertNumber.cpp
parseFloat.cpp

@ -75,4 +75,62 @@ TEST_CASE("canConvertNumber<TOut, TIn>()") {
CHECK((canConvertNumber<uint16_t, uint8_t>(128)) == true);
CHECK((canConvertNumber<uint16_t, uint8_t>(255)) == true);
}
SECTION("float -> int32_t") {
CHECK((canConvertNumber<int32_t, float>(0)) == true);
CHECK((canConvertNumber<int32_t, float>(-2.147483904e9f)) == false);
CHECK((canConvertNumber<int32_t, float>(-2.147483648e+9f)) == true);
CHECK((canConvertNumber<int32_t, float>(2.14748352e+9f)) == true);
CHECK((canConvertNumber<int32_t, float>(2.14748365e+9f)) == false);
}
SECTION("double -> int32_t") {
CHECK((canConvertNumber<int32_t, double>(0)) == true);
CHECK((canConvertNumber<int32_t, double>(-2.147483649e+9)) == false);
CHECK((canConvertNumber<int32_t, double>(-2.147483648e+9)) == true);
CHECK((canConvertNumber<int32_t, double>(2.147483647e+9)) == true);
CHECK((canConvertNumber<int32_t, double>(2.147483648e+9)) == false);
}
SECTION("float -> uint32_t") {
CHECK((canConvertNumber<uint32_t, float>(0)) == true);
CHECK((canConvertNumber<uint32_t, float>(-1.401298e-45f)) == false);
CHECK((canConvertNumber<uint32_t, float>(4.29496704e+9f)) == true);
CHECK((canConvertNumber<uint32_t, float>(4.294967296e+9f)) == false);
}
#if ARDUINOJSON_HAS_LONG_LONG
SECTION("float -> int64_t") {
CHECK((canConvertNumber<int64_t, float>(0)) == true);
CHECK((canConvertNumber<int64_t, float>(-9.22337204e+18f)) == true);
CHECK((canConvertNumber<int64_t, float>(9.22337149e+18f)) == true);
CHECK((canConvertNumber<int64_t, float>(9.22337204e+18f)) == false);
}
SECTION("double -> int64_t") {
CHECK((canConvertNumber<int64_t, double>(0)) == true);
CHECK((canConvertNumber<int64_t, double>(-9.2233720368547758e+18)) == true);
CHECK((canConvertNumber<int64_t, double>(9.2233720368547748e+18)) == true);
CHECK((canConvertNumber<int64_t, double>(9.2233720368547758e+18)) == false);
}
SECTION("float -> uint64_t") {
CHECK((canConvertNumber<uint64_t, float>(0)) == true);
CHECK((canConvertNumber<uint64_t, float>(-1.401298e-45f)) == false);
CHECK((canConvertNumber<uint64_t, float>(1.844674297419792384e+19f)) ==
true);
CHECK((canConvertNumber<uint64_t, float>(1.8446744073709551616e+19f)) ==
false);
}
SECTION("double -> uint64_t") {
CHECK((canConvertNumber<uint64_t, double>(0)) == true);
CHECK((canConvertNumber<uint64_t, double>(-4.94065645841247e-324)) ==
false);
CHECK((canConvertNumber<uint64_t, double>(1.8446744073709549568e+19)) ==
true);
CHECK((canConvertNumber<uint64_t, double>(1.8446744073709551616e+19)) ==
false);
}
#endif
}

@ -13,7 +13,7 @@ TEST_CASE("Test unsigned integer overflow") {
second.init();
// Avoids MSVC warning C4127 (conditional expression is constant)
size_t integerSize = sizeof(Integer);
size_t integerSize = sizeof(JsonInteger);
if (integerSize == 8) {
parseNumber("18446744073709551615", first);
@ -33,7 +33,7 @@ TEST_CASE("Test signed integer overflow") {
second.init();
// Avoids MSVC warning C4127 (conditional expression is constant)
size_t integerSize = sizeof(Integer);
size_t integerSize = sizeof(JsonInteger);
if (integerSize == 8) {
parseNumber("-9223372036854775808", first);

@ -7,7 +7,7 @@
"type": "git",
"url": "https://github.com/bblanchon/ArduinoJson.git"
},
"version": "6.19.4",
"version": "6.20.0",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"

@ -1,5 +1,5 @@
name=ArduinoJson
version=6.19.4
version=6.20.0
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=A simple and efficient JSON library for embedded C++.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

@ -21,19 +21,19 @@
# endif
#endif
#include "ArduinoJson/Array/ArrayRef.hpp"
#include "ArduinoJson/Object/ObjectRef.hpp"
#include "ArduinoJson/Variant/VariantRef.hpp"
#include "ArduinoJson/Array/JsonArray.hpp"
#include "ArduinoJson/Object/JsonObject.hpp"
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
#include "ArduinoJson/Document/DynamicJsonDocument.hpp"
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
#include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Variant/ConverterImpl.hpp"
#include "ArduinoJson/Variant/VariantCompare.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp"
@ -47,25 +47,25 @@
#include "ArduinoJson/compatibility.hpp"
namespace ArduinoJson {
typedef ARDUINOJSON_NAMESPACE::ArrayConstRef JsonArrayConst;
typedef ARDUINOJSON_NAMESPACE::ArrayRef JsonArray;
typedef ARDUINOJSON_NAMESPACE::Float JsonFloat;
typedef ARDUINOJSON_NAMESPACE::Integer JsonInteger;
typedef ARDUINOJSON_NAMESPACE::ObjectConstRef JsonObjectConst;
typedef ARDUINOJSON_NAMESPACE::ObjectRef JsonObject;
typedef ARDUINOJSON_NAMESPACE::Pair JsonPair;
typedef ARDUINOJSON_NAMESPACE::PairConst JsonPairConst;
typedef ARDUINOJSON_NAMESPACE::String JsonString;
typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt;
typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst;
typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant;
using ARDUINOJSON_NAMESPACE::BasicJsonDocument;
using ARDUINOJSON_NAMESPACE::copyArray;
using ARDUINOJSON_NAMESPACE::DeserializationError;
using ARDUINOJSON_NAMESPACE::deserializeJson;
using ARDUINOJSON_NAMESPACE::deserializeMsgPack;
using ARDUINOJSON_NAMESPACE::DynamicJsonDocument;
using ARDUINOJSON_NAMESPACE::JsonArray;
using ARDUINOJSON_NAMESPACE::JsonArrayConst;
using ARDUINOJSON_NAMESPACE::JsonDocument;
using ARDUINOJSON_NAMESPACE::JsonFloat;
using ARDUINOJSON_NAMESPACE::JsonInteger;
using ARDUINOJSON_NAMESPACE::JsonObject;
using ARDUINOJSON_NAMESPACE::JsonObjectConst;
using ARDUINOJSON_NAMESPACE::JsonPair;
using ARDUINOJSON_NAMESPACE::JsonPairConst;
using ARDUINOJSON_NAMESPACE::JsonString;
using ARDUINOJSON_NAMESPACE::JsonUInt;
using ARDUINOJSON_NAMESPACE::JsonVariant;
using ARDUINOJSON_NAMESPACE::JsonVariantConst;
using ARDUINOJSON_NAMESPACE::measureJson;
using ARDUINOJSON_NAMESPACE::serialized;
using ARDUINOJSON_NAMESPACE::serializeJson;

@ -1,31 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
namespace ARDUINOJSON_NAMESPACE {
inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) {
return arr ? arr->addElement(pool) : 0;
}
template <typename TVisitor>
inline typename TVisitor::result_type arrayAccept(const CollectionData *arr,
TVisitor &visitor) {
if (arr)
return visitor.visitArray(*arr);
else
return visitor.visitNull();
}
inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {
if (lhs == rhs)
return true;
if (!lhs || !rhs)
return false;
return lhs->equalsArray(*rhs);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -1,28 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayRef.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TArray>
inline ArrayRef ArrayShortcuts<TArray>::createNestedArray() const {
return impl()->addElement().template to<ArrayRef>();
}
template <typename TArray>
inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const {
return impl()->addElement().template to<ObjectRef>();
}
template <typename TArray>
inline ElementProxy<TArray> ArrayShortcuts<TArray>::operator[](
size_t index) const {
return ElementProxy<TArray>(*impl(), index);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -1,121 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/SlotFunctions.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
namespace ARDUINOJSON_NAMESPACE {
class VariantPtr {
public:
VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {}
VariantRef *operator->() {
return &_variant;
}
VariantRef &operator*() {
return _variant;
}
private:
VariantRef _variant;
};
class ArrayIterator {
public:
ArrayIterator() : _slot(0) {}
explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot)
: _pool(pool), _slot(slot) {}
VariantRef operator*() const {
return VariantRef(_pool, _slot->data());
}
VariantPtr operator->() {
return VariantPtr(_pool, _slot->data());
}
bool operator==(const ArrayIterator &other) const {
return _slot == other._slot;
}
bool operator!=(const ArrayIterator &other) const {
return _slot != other._slot;
}
ArrayIterator &operator++() {
_slot = _slot->next();
return *this;
}
ArrayIterator &operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
VariantSlot *internal() {
return _slot;
}
private:
MemoryPool *_pool;
VariantSlot *_slot;
};
class VariantConstPtr {
public:
VariantConstPtr(const VariantData *data) : _variant(data) {}
VariantConstRef *operator->() {
return &_variant;
}
VariantConstRef &operator*() {
return _variant;
}
private:
VariantConstRef _variant;
};
class ArrayConstRefIterator {
public:
ArrayConstRefIterator() : _slot(0) {}
explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {}
VariantConstRef operator*() const {
return VariantConstRef(_slot->data());
}
VariantConstPtr operator->() {
return VariantConstPtr(_slot->data());
}
bool operator==(const ArrayConstRefIterator &other) const {
return _slot == other._slot;
}
bool operator!=(const ArrayConstRefIterator &other) const {
return _slot != other._slot;
}
ArrayConstRefIterator &operator++() {
_slot = _slot->next();
return *this;
}
ArrayConstRefIterator &operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
const VariantSlot *internal() {
return _slot;
}
private:
const VariantSlot *_slot;
};
} // namespace ARDUINOJSON_NAMESPACE

@ -1,213 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayFunctions.hpp>
#include <ArduinoJson/Array/ArrayIterator.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
// Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
namespace ARDUINOJSON_NAMESPACE {
class ObjectRef;
template <typename>
class ElementProxy;
template <typename TData>
class ArrayRefBase {
public:
operator VariantConstRef() const {
const void* data = _data; // prevent warning cast-align
return VariantConstRef(reinterpret_cast<const VariantData*>(data));
}
template <typename TVisitor>
FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const {
return arrayAccept(_data, visitor);
}
FORCE_INLINE bool isNull() const {
return _data == 0;
}
FORCE_INLINE operator bool() const {
return _data != 0;
}
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
FORCE_INLINE size_t nesting() const {
return _data ? _data->nesting() : 0;
}
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
protected:
ArrayRefBase(TData* data) : _data(data) {}
TData* _data;
};
class ArrayConstRef : public ArrayRefBase<const CollectionData>,
public Visitable {
friend class ArrayRef;
typedef ArrayRefBase<const CollectionData> base_type;
public:
typedef ArrayConstRefIterator iterator;
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_data->head());
}
FORCE_INLINE iterator end() const {
return iterator();
}
FORCE_INLINE ArrayConstRef() : base_type(0) {}
FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {}
FORCE_INLINE bool operator==(ArrayConstRef rhs) const {
return arrayEquals(_data, rhs._data);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return getElement(index);
}
FORCE_INLINE VariantConstRef getElement(size_t index) const {
return VariantConstRef(_data ? _data->getElement(index) : 0);
}
};
class ArrayRef : public ArrayRefBase<CollectionData>,
public ArrayShortcuts<ArrayRef>,
public Visitable {
typedef ArrayRefBase<CollectionData> base_type;
public:
typedef ArrayIterator iterator;
FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {}
FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data)
: base_type(data), _pool(pool) {}
operator VariantRef() {
void* data = _data; // prevent warning cast-align
return VariantRef(_pool, reinterpret_cast<VariantData*>(data));
}
operator ArrayConstRef() const {
return ArrayConstRef(_data);
}
VariantRef addElement() const {
return VariantRef(_pool, arrayAdd(_data, _pool));
}
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_pool, _data->head());
}
FORCE_INLINE iterator end() const {
return iterator();
}
// Copy a ArrayRef
FORCE_INLINE bool set(ArrayConstRef src) const {
if (!_data || !src._data)
return false;
return _data->copyFrom(*src._data, _pool);
}
FORCE_INLINE bool operator==(ArrayRef rhs) const {
return arrayEquals(_data, rhs._data);
}
// Internal use
FORCE_INLINE VariantRef getOrAddElement(size_t index) const {
return VariantRef(_pool, _data ? _data->getOrAddElement(index, _pool) : 0);
}
// Gets the value at the specified index.
FORCE_INLINE VariantRef getElement(size_t index) const {
return VariantRef(_pool, _data ? _data->getElement(index) : 0);
}
// Removes element at specified position.
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it.internal());
}
// Removes element at specified index.
FORCE_INLINE void remove(size_t index) const {
if (!_data)
return;
_data->removeElement(index);
}
void clear() const {
if (!_data)
return;
_data->clear();
}
private:
MemoryPool* _pool;
};
template <>
struct Converter<ArrayConstRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static ArrayConstRef fromJson(VariantConstRef src) {
return ArrayConstRef(variantAsArray(getData(src)));
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isArray();
}
};
template <>
struct Converter<ArrayRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static ArrayRef fromJson(VariantRef src) {
VariantData* data = getData(src);
MemoryPool* pool = getPool(src);
return ArrayRef(pool, data != 0 ? data->asArray() : 0);
}
static InvalidConversion<VariantConstRef, ArrayRef> fromJson(VariantConstRef);
static bool checkJson(VariantConstRef) {
return false;
}
static bool checkJson(VariantRef src) {
VariantData* data = getData(src);
return data && data->isArray();
}
};
} // namespace ARDUINOJSON_NAMESPACE

@ -1,49 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
// Forward declarations.
class ArrayRef;
class ObjectRef;
template <typename>
class ElementProxy;
template <typename TArray>
class ArrayShortcuts {
public:
// Returns the element at specified index if the variant is an array.
FORCE_INLINE ElementProxy<TArray> operator[](size_t index) const;
FORCE_INLINE ObjectRef createNestedObject() const;
FORCE_INLINE ArrayRef createNestedArray() const;
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ObjectRef
template <typename T>
FORCE_INLINE bool add(const T &value) const {
return impl()->addElement().set(value);
}
//
// bool add(TValue);
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE bool add(T *value) const {
return impl()->addElement().set(value);
}
private:
const TArray *impl() const {
return static_cast<const TArray *>(this);
}
};
} // namespace ARDUINOJSON_NAMESPACE

@ -4,194 +4,57 @@
#pragma once
#include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantShortcuts.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4522)
#endif
#include <ArduinoJson/Variant/VariantRefBase.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TArray>
class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
public VariantShortcuts<ElementProxy<TArray> >,
public Visitable,
public VariantTag {
typedef ElementProxy<TArray> this_type;
// A proxy class to get or set an element of an array.
// https://arduinojson.org/v6/api/jsonarray/subscript/
template <typename TUpstream>
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream> >,
public VariantOperators<ElementProxy<TUpstream> > {
friend class VariantAttorney;
public:
typedef VariantRef variant_type;
FORCE_INLINE ElementProxy(TArray array, size_t index)
: _array(array), _index(index) {}
ElementProxy(TUpstream upstream, size_t index)
: _upstream(upstream), _index(index) {}
FORCE_INLINE ElementProxy(const ElementProxy& src)
: _array(src._array), _index(src._index) {}
ElementProxy(const ElementProxy& src)
: _upstream(src._upstream), _index(src._index) {}
FORCE_INLINE this_type& operator=(const this_type& src) {
getOrAddUpstreamElement().set(src.as<VariantConstRef>());
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
this->set(src);
return *this;
}
// Replaces the value
//
// operator=(const TValue&)
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ArrayRef, ObjectRef
template <typename T>
FORCE_INLINE this_type& operator=(const T& src) {
getOrAddUpstreamElement().set(src);
FORCE_INLINE ElementProxy& operator=(const T& src) {
this->set(src);
return *this;
}
//
// operator=(TValue)
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE this_type& operator=(T* src) {
getOrAddUpstreamElement().set(src);
return *this;
}
FORCE_INLINE void clear() const {
getUpstreamElement().clear();
}
FORCE_INLINE bool isNull() const {
return getUpstreamElement().isNull();
}
template <typename T>
FORCE_INLINE typename enable_if<!is_same<T, char*>::value, T>::type as()
const {
return getUpstreamElement().template as<T>();
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char*>::value, const char*>::type
ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
as() const {
return as<const char*>();
}
template <typename T>
FORCE_INLINE operator T() const {
return getUpstreamElement();
}
template <typename T>
FORCE_INLINE bool is() const {
return getUpstreamElement().template is<T>();
}
template <typename T>
FORCE_INLINE typename VariantTo<T>::type to() const {
return getOrAddUpstreamElement().template to<T>();
}
// Replaces the value
//
// bool set(const TValue&)
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ArrayRef, ObjectRef
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) const {
return getOrAddUpstreamElement().set(value);
}
//
// bool set(TValue)
// TValue = char*, const char*, const __FlashStringHelper*
template <typename TValue>
FORCE_INLINE bool set(TValue* value) const {
return getOrAddUpstreamElement().set(value);
}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor& visitor) const {
return getUpstreamElement().accept(visitor);
}
FORCE_INLINE size_t size() const {
return getUpstreamElement().size();
}
FORCE_INLINE size_t memoryUsage() const {
return getUpstreamElement().memoryUsage();
}
template <typename TNestedKey>
VariantRef getMember(TNestedKey* key) const {
return getUpstreamElement().getMember(key);
}
template <typename TNestedKey>
VariantRef getMember(const TNestedKey& key) const {
return getUpstreamElement().getMember(key);
}
template <typename TNestedKey>
VariantRef getOrAddMember(TNestedKey* key) const {
return getOrAddUpstreamElement().getOrAddMember(key);
}
template <typename TNestedKey>
VariantRef getOrAddMember(const TNestedKey& key) const {
return getOrAddUpstreamElement().getOrAddMember(key);
}
VariantRef addElement() const {
return getOrAddUpstreamElement().addElement();
}
VariantRef getElement(size_t index) const {
return getOrAddUpstreamElement().getElement(index);
}
VariantRef getOrAddElement(size_t index) const {
return getOrAddUpstreamElement().getOrAddElement(index);
}
FORCE_INLINE void remove(size_t index) const {
getUpstreamElement().remove(index);
}
// remove(char*) const
// remove(const char*) const
// remove(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(
TChar* key) const {
getUpstreamElement().remove(key);
}
// remove(const std::string&) const
// remove(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString& key) const {
getUpstreamElement().remove(key);
FORCE_INLINE ElementProxy& operator=(T* src) {
this->set(src);
return *this;
}
private:
FORCE_INLINE VariantRef getUpstreamElement() const {
return _array.getElement(_index);
FORCE_INLINE MemoryPool* getPool() const {
return VariantAttorney::getPool(_upstream);
}
FORCE_INLINE VariantRef getOrAddUpstreamElement() const {
return _array.getOrAddElement(_index);
FORCE_INLINE VariantData* getData() const {
return variantGetElement(VariantAttorney::getData(_upstream), _index);
}
friend void convertToJson(const this_type& src, VariantRef dst) {
dst.set(src.getUpstreamElement());
FORCE_INLINE VariantData* getOrCreateData() const {
return variantGetOrAddElement(VariantAttorney::getOrCreateData(_upstream),
_index, VariantAttorney::getPool(_upstream));
}
TArray _array;
const size_t _index;
TUpstream _upstream;
size_t _index;
};
} // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER
# pragma warning(pop)
#endif

@ -0,0 +1,210 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ElementProxy.hpp>
#include <ArduinoJson/Array/JsonArrayConst.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonObject;
// A reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarray/
class JsonArray : public VariantOperators<JsonArray> {
friend class VariantAttorney;
public:
typedef JsonArrayIterator iterator;
// Constructs an unbound reference.
FORCE_INLINE JsonArray() : _data(0), _pool(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArray(MemoryPool* pool, CollectionData* data)
: _data(data), _pool(pool) {}
// Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v6/api/jsonvariant/
operator JsonVariant() {
void* data = _data; // prevent warning cast-align
return JsonVariant(_pool, reinterpret_cast<VariantData*>(data));
}
// Returns a read-only reference to the array.
// https://arduinojson.org/v6/api/jsonarrayconst/
operator JsonArrayConst() const {
return JsonArrayConst(_data);
}
// Appends a new (null) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonarray/add/
JsonVariant add() const {
if (!_data)
return JsonVariant();
return JsonVariant(_pool, _data->addElement(_pool));
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(const T& value) const {
return add().set(value);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(T* value) const {
return add().set(value);
}
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarray/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_pool, _data->head());
}
// Returns an iterator following the last element of the array.
// https://arduinojson.org/v6/api/jsonarray/end/
FORCE_INLINE iterator end() const {
return iterator();
}
// Copies an array.
// https://arduinojson.org/v6/api/jsonarray/set/
FORCE_INLINE bool set(JsonArrayConst src) const {
if (!_data || !src._data)
return false;
return _data->copyFrom(*src._data, _pool);
}
// Compares the content of two arrays.
FORCE_INLINE bool operator==(JsonArray rhs) const {
return JsonArrayConst(_data) == JsonArrayConst(rhs._data);
}
// Removes the element at the specified iterator.
// ⚠ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it._slot);
}
// Removes the element at the specified index.
// ⚠ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(size_t index) const {
if (!_data)
return;
_data->removeElement(index);
}
// Removes all the elements of the array.
// ⚠ Doesn't release the memory associated with the removed elements.
// https://arduinojson.org/v6/api/jsonarray/clear/
void clear() const {
if (!_data)
return;
_data->clear();
}
// Gets or sets the element at the specified index.
// https://arduinojson.org/v6/api/jsonarray/subscript/
FORCE_INLINE ElementProxy<JsonArray> operator[](size_t index) const {
return ElementProxy<JsonArray>(*this, index);
}
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const {
return add().to<JsonArray>();
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
private:
MemoryPool* getPool() const {
return _pool;
}
VariantData* getData() const {
return collectionToVariant(_data);
}
VariantData* getOrCreateData() const {
return collectionToVariant(_data);
}
CollectionData* _data;
MemoryPool* _pool;
};
template <>
struct Converter<JsonArray> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArray fromJson(JsonVariant src) {
VariantData* data = getData(src);
MemoryPool* pool = getPool(src);
return JsonArray(pool, data != 0 ? data->asArray() : 0);
}
static InvalidConversion<JsonVariantConst, JsonArray> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
VariantData* data = getData(src);
return data && data->isArray();
}
};
} // namespace ARDUINOJSON_NAMESPACE

@ -0,0 +1,134 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArrayIterator.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonObject;
// A read-only reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/
class JsonArrayConst : public VariantOperators<JsonArrayConst> {
friend class JsonArray;
friend class VariantAttorney;
public:
typedef JsonArrayConstIterator iterator;
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_data->head());
}
// Returns an iterator to the element following the last element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/end/
FORCE_INLINE iterator end() const {
return iterator();
}
// Creates an unbound reference.
FORCE_INLINE JsonArrayConst() : _data(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArrayConst(const CollectionData* data) : _data(data) {}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
if (_data == rhs._data)
return true;
if (!_data || !rhs._data)
return false;
iterator it1 = begin();
iterator it2 = rhs.begin();
for (;;) {
bool end1 = it1 == end();
bool end2 = it2 == rhs.end();
if (end1 && end2)
return true;
if (end1 || end2)
return false;
if (*it1 != *it2)
return false;
++it1;
++it2;
}
}
// Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(_data ? _data->getElement(index) : 0);
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
private:
const VariantData* getData() const {
return collectionToVariant(_data);
}
const CollectionData* _data;
};
template <>
struct Converter<JsonArrayConst> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArrayConst fromJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return data ? data->asArray() : 0;
}
static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return data && data->isArray();
}
};
} // namespace ARDUINOJSON_NAMESPACE

@ -0,0 +1,32 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
namespace ARDUINOJSON_NAMESPACE {
inline JsonObject JsonArray::createNestedObject() const {
return add().to<JsonObject>();
}
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
return add().template to<JsonArray>();
}
template <typename TDerived>
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
return add().template to<JsonObject>();
}
template <typename TDerived>
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
size_t index) const {
return ElementProxy<TDerived>(derived(), index);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -0,0 +1,117 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
namespace ARDUINOJSON_NAMESPACE {
class VariantPtr {
public:
VariantPtr(MemoryPool* pool, VariantData* data) : _variant(pool, data) {}
JsonVariant* operator->() {
return &_variant;
}
JsonVariant& operator*() {
return _variant;
}
private:
JsonVariant _variant;
};
class JsonArrayIterator {
friend class JsonArray;
public:
JsonArrayIterator() : _slot(0) {}
explicit JsonArrayIterator(MemoryPool* pool, VariantSlot* slot)
: _pool(pool), _slot(slot) {}
JsonVariant operator*() const {
return JsonVariant(_pool, _slot->data());
}
VariantPtr operator->() {
return VariantPtr(_pool, _slot->data());
}
bool operator==(const JsonArrayIterator& other) const {
return _slot == other._slot;
}
bool operator!=(const JsonArrayIterator& other) const {
return _slot != other._slot;
}
JsonArrayIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
private:
MemoryPool* _pool;
VariantSlot* _slot;
};
class VariantConstPtr {
public:
VariantConstPtr(const VariantData* data) : _variant(data) {}
JsonVariantConst* operator->() {
return &_variant;
}
JsonVariantConst& operator*() {
return _variant;
}
private:
JsonVariantConst _variant;
};
class JsonArrayConstIterator {
friend class JsonArray;
public:
JsonArrayConstIterator() : _slot(0) {}
explicit JsonArrayConstIterator(const VariantSlot* slot) : _slot(slot) {}
JsonVariantConst operator*() const {
return JsonVariantConst(_slot->data());
}
VariantConstPtr operator->() {
return VariantConstPtr(_slot->data());
}
bool operator==(const JsonArrayConstIterator& other) const {
return _slot == other._slot;
}
bool operator!=(const JsonArrayConstIterator& other) const {
return _slot != other._slot;
}
JsonArrayConstIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
private:
const VariantSlot* _slot;
};
} // namespace ARDUINOJSON_NAMESPACE

@ -4,19 +4,21 @@
#pragma once
#include <ArduinoJson/Array/ArrayRef.hpp>
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Document/JsonDocument.hpp>
namespace ARDUINOJSON_NAMESPACE {
// Trivial form to stop the recursion
// Copies a value to a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T>
inline typename enable_if<!is_array<T>::value, bool>::type copyArray(
const T& src, VariantRef dst) {
const T& src, JsonVariant dst) {
return dst.set(src);
}
// Copy array to a JsonArray/JsonVariant/MemberProxy/ElementProxy
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, size_t N, typename TDestination>
inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value,
bool>::type
@ -24,64 +26,72 @@ copyArray(T (&src)[N], const TDestination& dst) {
return copyArray(src, N, dst);
}
// Copy ptr+size to a JsonArray/JsonVariant/MemberProxy/ElementProxy
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, typename TDestination>
inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value,
bool>::type
copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true;
for (size_t i = 0; i < len; i++) {
ok &= copyArray(src[i], dst.addElement());
ok &= copyArray(src[i], dst.add());
}
return ok;
}
// Special case for char[] which much be treated as const char*
// Copies a string to a JsonVariant.
// This is a degenerated form of copyArray() to handle strings.
template <typename TDestination>
inline bool copyArray(const char* src, size_t, const TDestination& dst) {
return dst.set(src);
}
// Copy array to a JsonDocument
// Copies values from an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T>
inline bool copyArray(const T& src, JsonDocument& dst) {
return copyArray(src, dst.to<ArrayRef>());
return copyArray(src, dst.to<JsonArray>());
}
// Copy a ptr+size array to a JsonDocument
// Copies an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T>
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
return copyArray(src, len, dst.to<ArrayRef>());
return copyArray(src, len, dst.to<JsonArray>());
}
// Trivial case form to stop the recursion
// Copies a value from a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T>
inline typename enable_if<!is_array<T>::value, size_t>::type copyArray(
VariantConstRef src, T& dst) {
JsonVariantConst src, T& dst) {
dst = src.as<T>();
return 1;
}
// Copy a JsonArray to array
// Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, size_t N>
inline size_t copyArray(ArrayConstRef src, T (&dst)[N]) {
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
return copyArray(src, dst, N);
}
// Copy a JsonArray to ptr+size
// Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T>
inline size_t copyArray(ArrayConstRef src, T* dst, size_t len) {
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
size_t i = 0;
for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < len;
for (JsonArrayConst::iterator it = src.begin(); it != src.end() && i < len;
++it)
copyArray(*it, dst[i++]);
return i;
}
// Special case for char[] which must be treated as a string
// Copies a string from a JsonVariant.
// This is a degenerated form of copyArray() to handle strings.
template <size_t N>
inline size_t copyArray(VariantConstRef src, char (&dst)[N]) {
String s = src;
inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
JsonString s = src;
size_t len = N - 1;
if (len > s.size())
len = s.size();
@ -90,14 +100,14 @@ inline size_t copyArray(VariantConstRef src, char (&dst)[N]) {
return 1;
}
// Copy a JsonDocument to an array
// (JsonDocument doesn't implicitly convert to JsonArrayConst)
// Copies values from a JsonDocument to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename TSource, typename T>
inline typename enable_if<is_array<T>::value &&
is_base_of<JsonDocument, TSource>::value,
size_t>::type
copyArray(const TSource& src, T& dst) {
return copyArray(src.template as<ArrayConstRef>(), dst);
return copyArray(src.template as<JsonArrayConst>(), dst);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -36,19 +36,16 @@ class CollectionData {
void removeElement(size_t index);
bool equalsArray(const CollectionData &other) const;
// Object only
template <typename TAdaptedString, typename TStoragePolicy>
VariantData *addMember(TAdaptedString key, MemoryPool *pool, TStoragePolicy);
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString, typename TStoragePolicy>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool,
TStoragePolicy);
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
void removeMember(TAdaptedString key) {
@ -58,13 +55,10 @@ class CollectionData {
template <typename TAdaptedString>
bool containsKey(const TAdaptedString& key) const;
bool equalsObject(const CollectionData &other) const;
// Generic
void clear();
size_t memoryUsage() const;
size_t nesting() const;
size_t size() const;
VariantSlot* addSlot(MemoryPool*);
@ -86,4 +80,15 @@ class CollectionData {
VariantSlot* getPreviousSlot(VariantSlot*) const;
};
inline const VariantData* collectionToVariant(
const CollectionData* collection) {
const void* data = collection; // prevent warning cast-align
return reinterpret_cast<const VariantData*>(data);
}
inline VariantData* collectionToVariant(CollectionData* collection) {
void* data = collection; // prevent warning cast-align
return reinterpret_cast<VariantData*>(data);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -11,16 +11,13 @@
namespace ARDUINOJSON_NAMESPACE {
inline bool variantEquals(const VariantData* a, const VariantData* b) {
return variantCompare(a, b) == COMPARE_RESULT_EQUAL;
}
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
VariantSlot* slot = pool->allocVariant();
if (!slot)
return 0;
if (_tail) {
ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object
_tail->setNextNotNull(slot);
_tail = slot;
} else {
@ -36,12 +33,11 @@ inline VariantData* CollectionData::addElement(MemoryPool* pool) {
return slotData(addSlot(pool));
}
template <typename TAdaptedString, typename TStoragePolicy>
template <typename TAdaptedString>
inline VariantData* CollectionData::addMember(TAdaptedString key,
MemoryPool* pool,
TStoragePolicy storage) {
MemoryPool* pool) {
VariantSlot* slot = addSlot(pool);
if (!slotSetKey(slot, key, pool, storage)) {
if (!slotSetKey(slot, key, pool)) {
removeSlot(slot);
return 0;
}
@ -64,8 +60,9 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
for (VariantSlot* s = src._head; s; s = s->next()) {
VariantData* var;
if (s->key() != 0) {
String key(s->key(), s->ownsKey() ? String::Copied : String::Linked);
var = addMember(adaptString(key), pool, getStringStoragePolicy(key));
JsonString key(s->key(),
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
var = addMember(adaptString(key), pool);
} else {
var = addElement(pool);
}
@ -77,33 +74,6 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
return true;
}
inline bool CollectionData::equalsObject(const CollectionData& other) const {
size_t count = 0;
for (VariantSlot* slot = _head; slot; slot = slot->next()) {
VariantData* v1 = slot->data();
VariantData* v2 = other.getMember(adaptString(slot->key()));
if (!variantEquals(v1, v2))
return false;
count++;
}
return count == other.size();
}
inline bool CollectionData::equalsArray(const CollectionData& other) const {
VariantSlot* s1 = _head;
VariantSlot* s2 = other._head;
for (;;) {
if (s1 == s2)
return true;
if (!s1 || !s2)
return false;
if (!variantEquals(s1->data(), s2->data()))
return false;
s1 = s1->next();
s2 = s2->next();
}
}
template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull())
@ -140,9 +110,9 @@ inline VariantData* CollectionData::getMember(TAdaptedString key) const {
return slot ? slot->data() : 0;
}
template <typename TAdaptedString, typename TStoragePolicy>
inline VariantData* CollectionData::getOrAddMember(
TAdaptedString key, MemoryPool* pool, TStoragePolicy storage_policy) {
template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
MemoryPool* pool) {
// ignore null key
if (key.isNull())
return 0;
@ -152,7 +122,7 @@ inline VariantData* CollectionData::getOrAddMember(
if (slot)
return slot->data();
return addMember(key, pool, storage_policy);
return addMember(key, pool);
}
inline VariantData* CollectionData::getElement(size_t index) const {
@ -203,16 +173,6 @@ inline size_t CollectionData::memoryUsage() const {
return total;
}
inline size_t CollectionData::nesting() const {
size_t maxChildNesting = 0;
for (VariantSlot* s = _head; s; s = s->next()) {
size_t childNesting = s->data()->nesting();
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
}
inline size_t CollectionData::size() const {
return slotSize(_head);
}

@ -10,18 +10,18 @@ namespace ARDUINOJSON_NAMESPACE {
class Filter {
public:
explicit Filter(VariantConstRef v) : _variant(v) {}
explicit Filter(JsonVariantConst v) : _variant(v) {}
bool allow() const {
return _variant;
}
bool allowArray() const {
return _variant == true || _variant.is<ArrayConstRef>();
return _variant == true || _variant.is<JsonArrayConst>();
}
bool allowObject() const {
return _variant == true || _variant.is<ObjectConstRef>();
return _variant == true || _variant.is<JsonObjectConst>();
}
bool allowValue() const {
@ -32,12 +32,12 @@ class Filter {
Filter operator[](const TKey& key) const {
if (_variant == true) // "true" means "allow recursively"
return *this;
VariantConstRef member = _variant[key];
JsonVariantConst member = _variant[key];
return Filter(member.isNull() ? _variant["*"] : member);
}
private:
VariantConstRef _variant;
JsonVariantConst _variant;
};
struct AllowAllFilter {

@ -23,7 +23,8 @@ class IteratorReader {
size_t readBytes(char* buffer, size_t length) {
size_t i = 0;
while (i < length && _ptr < _end) buffer[i++] = *_ptr++;
while (i < length && _ptr < _end)
buffer[i++] = *_ptr++;
return i;
}
};

@ -32,7 +32,8 @@ struct Reader<TSource*,
}
size_t readBytes(char* buffer, size_t length) {
for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++;
for (size_t i = 0; i < length; i++)
buffer[i] = *_ptr++;
return length;
}
};

@ -5,30 +5,15 @@
#pragma once
#include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TArray>
struct Reader<ElementProxy<TArray>, void> : Reader<char*, void> {
explicit Reader(const ElementProxy<TArray>& x)
template <typename TVariant>
struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
: Reader<char*, void> {
explicit Reader(const TVariant& x)
: Reader<char*, void>(x.template as<const char*>()) {}
};
template <typename TObject, typename TStringRef>
struct Reader<MemberProxy<TObject, TStringRef>, void> : Reader<char*, void> {
explicit Reader(const MemberProxy<TObject, TStringRef>& x)
: Reader<char*, void>(x.template as<const char*>()) {}
};
template <>
struct Reader<VariantRef, void> : Reader<char*, void> {
explicit Reader(VariantRef x) : Reader<char*, void>(x.as<const char*>()) {}
};
template <>
struct Reader<VariantConstRef, void> : Reader<char*, void> {
explicit Reader(VariantConstRef x)
: Reader<char*, void>(x.as<const char*>()) {}
};
} // namespace ARDUINOJSON_NAMESPACE

@ -14,9 +14,10 @@ namespace ARDUINOJSON_NAMESPACE {
template <template <typename, typename> class TDeserializer, typename TReader,
typename TWriter>
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool,
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool,
TReader reader,
TWriter writer) {
ARDUINOJSON_ASSERT(pool != 0);
return TDeserializer<TReader, TWriter>(pool, reader, writer);
}
@ -31,11 +32,12 @@ typename enable_if<!is_array<TString>::value, DeserializationError>::type
deserialize(JsonDocument& doc, const TString& input, NestingLimit nestingLimit,
TFilter filter) {
Reader<TString> reader(input);
VariantData* data = VariantAttorney::getData(doc);
MemoryPool* pool = VariantAttorney::getPool(doc);
doc.clear();
return makeDeserializer<TDeserializer>(
doc.memoryPool(), reader,
makeStringStorage(input, doc.memoryPool()))
.parse(doc.data(), filter, nestingLimit);
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, filter, nestingLimit);
}
//
// deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter);
@ -47,11 +49,12 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input,
size_t inputSize, NestingLimit nestingLimit,
TFilter filter) {
BoundedReader<TChar*> reader(input, inputSize);
VariantData* data = VariantAttorney::getData(doc);
MemoryPool* pool = VariantAttorney::getPool(doc);
doc.clear();
return makeDeserializer<TDeserializer>(
doc.memoryPool(), reader,
makeStringStorage(input, doc.memoryPool()))
.parse(doc.data(), filter, nestingLimit);
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, filter, nestingLimit);
}
//
// deserialize(JsonDocument&, std::istream&, NestingLimit, Filter);
@ -61,11 +64,12 @@ template <template <typename, typename> class TDeserializer, typename TStream,
DeserializationError deserialize(JsonDocument& doc, TStream& input,
NestingLimit nestingLimit, TFilter filter) {
Reader<TStream> reader(input);
VariantData* data = VariantAttorney::getData(doc);
MemoryPool* pool = VariantAttorney::getPool(doc);
doc.clear();
return makeDeserializer<TDeserializer>(
doc.memoryPool(), reader,
makeStringStorage(input, doc.memoryPool()))
.parse(doc.data(), filter, nestingLimit);
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, filter, nestingLimit);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -37,6 +37,8 @@ class AllocatorOwner {
TAllocator _allocator;
};
// A JsonDocument that uses the provided allocator to allocate its memory pool.
// https://arduinojson.org/v6/api/basicjsondocument/
template <typename TAllocator>
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
public:
@ -65,16 +67,16 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
BasicJsonDocument(
const T& src,
typename enable_if<
is_same<T, VariantRef>::value || is_same<T, VariantConstRef>::value ||
is_same<T, ArrayRef>::value || is_same<T, ArrayConstRef>::value ||
is_same<T, ObjectRef>::value ||
is_same<T, ObjectConstRef>::value>::type* = 0)
is_same<T, JsonVariant>::value ||
is_same<T, JsonVariantConst>::value || is_same<T, JsonArray>::value ||
is_same<T, JsonArrayConst>::value || is_same<T, JsonObject>::value ||
is_same<T, JsonObjectConst>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
BasicJsonDocument(VariantRef src)
BasicJsonDocument(JsonVariant src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
@ -104,6 +106,8 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
return *this;
}
// Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/
void shrinkToFit() {
ptrdiff_t bytes_reclaimed = _pool.squash();
if (bytes_reclaimed == 0)
@ -119,6 +123,8 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
_data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
}
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
bool garbageCollect() {
// make a temporary clone and move assign
BasicJsonDocument tmp(*this);
@ -146,7 +152,7 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
}
void freePool() {
this->deallocate(memoryPool().buffer());
this->deallocate(getPool()->buffer());
}
void copyAssignFrom(const JsonDocument& src) {

@ -10,6 +10,7 @@
namespace ARDUINOJSON_NAMESPACE {
// The allocator of DynamicJsonDocument.
struct DefaultAllocator {
void* allocate(size_t size) {
return malloc(size);
@ -24,6 +25,8 @@ struct DefaultAllocator {
}
};
// A JsonDocument with a memory pool in the heap.
// https://arduinojson.org/v6/api/dynamicjsondocument/
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
} // namespace ARDUINOJSON_NAMESPACE

@ -6,152 +6,169 @@
#include <ArduinoJson/Array/ElementProxy.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
#include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonDocument : public Visitable,
public VariantOperators<const JsonDocument&> {
public:
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor& visitor) const {
return getVariant().accept(visitor);
}
// A JSON document.
// https://arduinojson.org/v6/api/jsondocument/
class JsonDocument : public VariantOperators<const JsonDocument&> {
friend class VariantAttorney;
public:
// Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/
template <typename T>
T as() {
return getVariant().template as<T>();
}
// Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/
template <typename T>
T as() const {
return getVariant().template as<T>();
}
// Empties the document and resets the memory pool
// https://arduinojson.org/v6/api/jsondocument/clear/
void clear() {
_pool.clear();
_data.init();
}
// Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/
template <typename T>
bool is() {
return getVariant().template is<T>();
}
// Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/
template <typename T>
bool is() const {
return getVariant().template is<T>();
}
// Returns true if the root is null.
// https://arduinojson.org/v6/api/jsondocument/isnull/
bool isNull() const {
return getVariant().isNull();
}
// Returns the number of used bytes in the memory pool.
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
size_t memoryUsage() const {
return _pool.size();
}
// Returns trues if the memory pool was too small.
// https://arduinojson.org/v6/api/jsondocument/overflowed/
bool overflowed() const {
return _pool.overflowed();
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsondocument/nesting/
size_t nesting() const {
return _data.nesting();
return variantNesting(&_data);
}
// Returns the capacity of the memory pool.
// https://arduinojson.org/v6/api/jsondocument/capacity/
size_t capacity() const {
return _pool.capacity();
}
// Returns the number of elements in the root array or object.
// https://arduinojson.org/v6/api/jsondocument/size/
size_t size() const {
return _data.size();
}
// Copies the specified document.
// https://arduinojson.org/v6/api/jsondocument/set/
bool set(const JsonDocument& src) {
return to<VariantRef>().set(src.as<VariantConstRef>());
return to<JsonVariant>().set(src.as<JsonVariantConst>());
}
// Replaces the root with the specified value.
// https://arduinojson.org/v6/api/jsondocument/set/
template <typename T>
typename enable_if<!is_base_of<JsonDocument, T>::value, bool>::type set(
const T& src) {
return to<VariantRef>().set(src);
return to<JsonVariant>().set(src);
}
// Clears the document and converts it to the specified type.
// https://arduinojson.org/v6/api/jsondocument/to/
template <typename T>
typename VariantTo<T>::type to() {
clear();
return getVariant().template to<T>();
}
// for internal use only
MemoryPool& memoryPool() {
return _pool;
// Creates an array and appends it to the root array.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
JsonArray createNestedArray() {
return add().to<JsonArray>();
}
// for internal use only
VariantData& data() {
return _data;
}
ArrayRef createNestedArray() {
return addElement().to<ArrayRef>();
}
// createNestedArray(char*)
// createNestedArray(const char*)
// createNestedArray(const __FlashStringHelper*)
// Creates an array and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TChar>
ArrayRef createNestedArray(TChar* key) {
return getOrAddMember(key).template to<ArrayRef>();
JsonArray createNestedArray(TChar* key) {
return operator[](key).template to<JsonArray>();
}
// createNestedArray(const std::string&)
// createNestedArray(const String&)
// Creates an array and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TString>
ArrayRef createNestedArray(const TString& key) {
return getOrAddMember(key).template to<ArrayRef>();
JsonArray createNestedArray(const TString& key) {
return operator[](key).template to<JsonArray>();
}
ObjectRef createNestedObject() {
return addElement().to<ObjectRef>();
// Creates an object and appends it to the root array.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
JsonObject createNestedObject() {
return add().to<JsonObject>();
}
// createNestedObject(char*)
// createNestedObject(const char*)
// createNestedObject(const __FlashStringHelper*)
// Creates an object and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TChar>
ObjectRef createNestedObject(TChar* key) {
return getOrAddMember(key).template to<ObjectRef>();
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>();
}
// createNestedObject(const std::string&)
// createNestedObject(const String&)
// Creates an object and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TString>
ObjectRef createNestedObject(const TString& key) {
return getOrAddMember(key).template to<ObjectRef>();
JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>();
}
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
// Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/
template <typename TChar>
bool containsKey(TChar* key) const {
return !getMember(key).isUnbound();
return _data.getMember(adaptString(key)) != 0;
}
// containsKey(const std::string&) const
// containsKey(const String&) const
// Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/
template <typename TString>
bool containsKey(const TString& key) const {
return !getMember(key).isUnbound();
return _data.getMember(adaptString(key)) != 0;
}
// operator[](const std::string&)
// operator[](const String&)
// Gets or sets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<JsonDocument&, TString> >::type
@ -159,9 +176,8 @@ class JsonDocument : public Visitable,
return MemberProxy<JsonDocument&, TString>(*this, key);
}
// operator[](char*)
// operator[](const char*)
// operator[](const __FlashStringHelper*)
// Gets or sets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value,
MemberProxy<JsonDocument&, TChar*> >::type
@ -169,138 +185,87 @@ class JsonDocument : public Visitable,
return MemberProxy<JsonDocument&, TChar*>(*this, key);
}
// operator[](const std::string&) const
// operator[](const String&) const
// Gets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
typename enable_if<IsString<TString>::value, JsonVariantConst>::type
operator[](const TString& key) const {
return getMember(key);
return JsonVariantConst(_data.getMember(adaptString(key)));
}
// operator[](char*) const
// operator[](const char*) const
// operator[](const __FlashStringHelper*) const
// Gets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
template <typename TChar>
FORCE_INLINE
typename enable_if<IsString<TChar*>::value, VariantConstRef>::type
typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type
operator[](TChar* key) const {
return getMember(key);
return JsonVariantConst(_data.getMember(adaptString(key)));
}
// Gets or sets a root array's element.
// https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) {
return ElementProxy<JsonDocument&>(*this, index);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return getElement(index);
}
FORCE_INLINE VariantRef getElement(size_t index) {
return VariantRef(&_pool, _data.getElement(index));
}
FORCE_INLINE VariantConstRef getElement(size_t index) const {
return VariantConstRef(_data.getElement(index));
// Gets a root array's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(_data.getElement(index));
}
FORCE_INLINE VariantRef getOrAddElement(size_t index) {
return VariantRef(&_pool, _data.getOrAddElement(index, &_pool));
}
// JsonVariantConst getMember(char*) const
// JsonVariantConst getMember(const char*) const
// JsonVariantConst getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMember(TChar* key) const {
return VariantConstRef(_data.getMember(adaptString(key)));
}
// JsonVariantConst getMember(const std::string&) const
// JsonVariantConst getMember(const String&) const
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
getMember(const TString& key) const {
return VariantConstRef(_data.getMember(adaptString(key)));
}
// JsonVariant getMember(char*)
// JsonVariant getMember(const char*)
// JsonVariant getMember(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE VariantRef getMember(TChar* key) {
return VariantRef(&_pool, _data.getMember(adaptString(key)));
}
// JsonVariant getMember(const std::string&)
// JsonVariant getMember(const String&)
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type
getMember(const TString& key) {
return VariantRef(&_pool, _data.getMember(adaptString(key)));
}
// getOrAddMember(char*)
// getOrAddMember(const char*)
// getOrAddMember(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar* key) {
return VariantRef(&_pool,
_data.getOrAddMember(adaptString(key), &_pool,
getStringStoragePolicy(key)));
}
// getOrAddMember(const std::string&)
// getOrAddMember(const String&)
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString& key) {
return VariantRef(&_pool,
_data.getOrAddMember(adaptString(key), &_pool,
getStringStoragePolicy(key)));
}
FORCE_INLINE VariantRef addElement() {
return VariantRef(&_pool, _data.addElement(&_pool));
// Appends a new (null) element to the root array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsondocument/add/
FORCE_INLINE JsonVariant add() {
return JsonVariant(&_pool, _data.addElement(&_pool));
}
// Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/
template <typename TValue>
FORCE_INLINE bool add(const TValue& value) {
return addElement().set(value);
return add().set(value);
}
// add(char*) const
// add(const char*) const
// add(const __FlashStringHelper*) const
// Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/
template <typename TChar>
FORCE_INLINE bool add(TChar* value) {
return addElement().set(value);
return add().set(value);
}
// Removes an element of the root array.
// ⚠ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
FORCE_INLINE void remove(size_t index) {
_data.remove(index);
}
// remove(char*)
// remove(const char*)
// remove(const __FlashStringHelper*)
// Removes a member of the root object.
// ⚠ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(
TChar* key) {
_data.remove(adaptString(key));
}
// remove(const std::string&)
// remove(const String&)
// Removes a member of the root object.
// ⚠ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString& key) {
_data.remove(adaptString(key));
}
FORCE_INLINE operator VariantRef() {
FORCE_INLINE operator JsonVariant() {
return getVariant();
}
FORCE_INLINE operator VariantConstRef() const {
FORCE_INLINE operator JsonVariantConst() const {
return getVariant();
}
@ -323,12 +288,12 @@ class JsonDocument : public Visitable,
_pool = pool;
}
VariantRef getVariant() {
return VariantRef(&_pool, &_data);
JsonVariant getVariant() {
return JsonVariant(&_pool, &_data);
}
VariantConstRef getVariant() const {
return VariantConstRef(&_data);
JsonVariantConst getVariant() const {
return JsonVariantConst(&_data);
}
MemoryPool _pool;
@ -337,10 +302,27 @@ class JsonDocument : public Visitable,
private:
JsonDocument(const JsonDocument&);
JsonDocument& operator=(const JsonDocument&);
protected:
MemoryPool* getPool() {
return &_pool;
}
VariantData* getData() {
return &_data;
}
const VariantData* getData() const {
return &_data;
}
VariantData* getOrCreateData() {
return &_data;
}
};
inline void convertToJson(const JsonDocument& src, VariantRef dst) {
dst.set(src.as<VariantConstRef>());
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
dst.set(src.as<JsonVariantConst>());
}
} // namespace ARDUINOJSON_NAMESPACE

@ -8,6 +8,7 @@
namespace ARDUINOJSON_NAMESPACE {
// A JsonDocument with a memory pool on the stack.
template <size_t desiredCapacity>
class StaticJsonDocument : public JsonDocument {
static const size_t _capacity =
@ -22,14 +23,15 @@ class StaticJsonDocument : public JsonDocument {
}
template <typename T>
StaticJsonDocument(const T& src,
typename enable_if<IsVisitable<T>::value>::type* = 0)
StaticJsonDocument(
const T& src,
typename enable_if<is_convertible<T, JsonVariantConst>::value>::type* = 0)
: JsonDocument(_buffer, _capacity) {
set(src);
}
// disambiguate
StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) {
StaticJsonDocument(JsonVariant src) : JsonDocument(_buffer, _capacity) {
set(src);
}
@ -44,6 +46,8 @@ class StaticJsonDocument : public JsonDocument {
return *this;
}
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
void garbageCollect() {
StaticJsonDocument tmp(*this);
set(tmp);

@ -20,25 +20,26 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TReader, typename TStringStorage>
class JsonDeserializer {
public:
JsonDeserializer(MemoryPool &pool, TReader reader,
JsonDeserializer(MemoryPool* pool, TReader reader,
TStringStorage stringStorage)
: _stringStorage(stringStorage),
_foundSomething(false),
_latch(reader),
_pool(&pool),
_error(DeserializationError::Ok) {}
_pool(pool) {}
template <typename TFilter>
DeserializationError parse(VariantData& variant, TFilter filter,
NestingLimit nestingLimit) {
parseVariant(variant, filter, nestingLimit);
DeserializationError::Code err;
if (!_error && _latch.last() != 0 && !variant.isEnclosed()) {
err = parseVariant(variant, filter, nestingLimit);
if (!err && _latch.last() != 0 && !variant.isEnclosed()) {
// We don't detect trailing characters earlier, so we need to check now
return DeserializationError::InvalidInput;
}
return _error;
return err;
}
private:
@ -58,10 +59,13 @@ class JsonDeserializer {
}
template <typename TFilter>
bool parseVariant(VariantData &variant, TFilter filter,
DeserializationError::Code parseVariant(VariantData& variant, TFilter filter,
NestingLimit nestingLimit) {
if (!skipSpacesAndComments())
return false;
DeserializationError::Code err;
err = skipSpacesAndComments();
if (err)
return err;
switch (current()) {
case '[':
@ -81,7 +85,22 @@ class JsonDeserializer {
if (filter.allowValue())
return parseStringValue(variant);
else
return skipString();
return skipQuotedString();
case 't':
if (filter.allowValue())
variant.setBoolean(true);
return skipKeyword("true");
case 'f':
if (filter.allowValue())
variant.setBoolean(false);
return skipKeyword("false");
case 'n':
// the variant should already by null, except if the same object key was
// used twice, as in {"a":1,"a":null}
return skipKeyword("null");
default:
if (filter.allowValue())
@ -91,9 +110,12 @@ class JsonDeserializer {
}
}
bool skipVariant(NestingLimit nestingLimit) {
if (!skipSpacesAndComments())
return false;
DeserializationError::Code skipVariant(NestingLimit nestingLimit) {
DeserializationError::Code err;
err = skipSpacesAndComments();
if (err)
return err;
switch (current()) {
case '[':
@ -104,7 +126,16 @@ class JsonDeserializer {
case '\"':
case '\'':
return skipString();
return skipQuotedString();
case 't':
return skipKeyword("true");
case 'f':
return skipKeyword("false");
case 'n':
return skipKeyword("null");
default:
return skipNumericValue();
@ -112,24 +143,25 @@ class JsonDeserializer {
}
template <typename TFilter>
bool parseArray(CollectionData &array, TFilter filter,
DeserializationError::Code parseArray(CollectionData& array, TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening braket
ARDUINOJSON_ASSERT(current() == '[');
move();
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Empty array?
if (eat(']'))
return true;
return DeserializationError::Ok;
TFilter memberFilter = filter[0UL];
@ -138,38 +170,37 @@ class JsonDeserializer {
if (memberFilter.allow()) {
// Allocate slot in array
VariantData* value = array.addElement(_pool);
if (!value) {
_error = DeserializationError::NoMemory;
return false;
}
if (!value)
return DeserializationError::NoMemory;
// 1 - Parse value
if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
return false;
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
if (err)
return err;
} else {
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
}
// 2 - Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// 3 - More values?
if (eat(']'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
}
}
bool skipArray(NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code skipArray(NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening braket
ARDUINOJSON_ASSERT(current() == '[');
@ -178,60 +209,61 @@ class JsonDeserializer {
// Read each value
for (;;) {
// 1 - Skip value
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
// 2 - Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// 3 - More values?
if (eat(']'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
}
}
template <typename TFilter>
bool parseObject(CollectionData &object, TFilter filter,
DeserializationError::Code parseObject(CollectionData& object, TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening brace
ARDUINOJSON_ASSERT(current() == '{');
move();
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Empty object?
if (eat('}'))
return true;
return DeserializationError::Ok;
// Read each key value pair
for (;;) {
// Parse key
if (!parseKey())
return false;
err = parseKey();
if (err)
return err;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Colon
if (!eat(':')) {
_error = DeserializationError::InvalidInput;
return false;
}
if (!eat(':'))
return DeserializationError::InvalidInput;
String key = _stringStorage.str();
JsonString key = _stringStorage.str();
TFilter memberFilter = filter[key.c_str()];
@ -244,10 +276,8 @@ class JsonDeserializer {
// Allocate slot in object
VariantSlot* slot = object.addSlot(_pool);
if (!slot) {
_error = DeserializationError::NoMemory;
return false;
}
if (!slot)
return DeserializationError::NoMemory;
slot->setKey(key);
@ -255,84 +285,91 @@ class JsonDeserializer {
}
// Parse value
if (!parseVariant(*variant, memberFilter, nestingLimit.decrement()))
return false;
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
if (err)
return err;
} else {
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
}
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// More keys/values?
if (eat('}'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
}
}
bool skipObject(NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code skipObject(NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening brace
ARDUINOJSON_ASSERT(current() == '{');
move();
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Empty object?
if (eat('}'))
return true;
return DeserializationError::Ok;
// Read each key value pair
for (;;) {
// Skip key
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipKey();
if (err)
return err;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Colon
if (!eat(':')) {
_error = DeserializationError::InvalidInput;
return false;
}
if (!eat(':'))
return DeserializationError::InvalidInput;
// Skip value
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// More keys/values?
if (eat('}'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
err = skipSpacesAndComments();
if (err)
return err;
}
}
bool parseKey() {
DeserializationError::Code parseKey() {
_stringStorage.startString();
if (isQuote(current())) {
return parseQuotedString();
@ -341,17 +378,24 @@ class JsonDeserializer {
}
}
bool parseStringValue(VariantData &variant) {
DeserializationError::Code parseStringValue(VariantData& variant) {
DeserializationError::Code err;
_stringStorage.startString();
if (!parseQuotedString())
return false;
err = parseQuotedString();
if (err)
return err;
variant.setString(_stringStorage.save());
return true;
return DeserializationError::Ok;
}
bool parseQuotedString() {
DeserializationError::Code parseQuotedString() {
#if ARDUINOJSON_DECODE_UNICODE
Utf16::Codepoint codepoint;
DeserializationError::Code err;
#endif
const char stopChar = current();
@ -362,25 +406,22 @@ class JsonDeserializer {
if (c == stopChar)
break;
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == 'u') {
#if ARDUINOJSON_DECODE_UNICODE
move();
uint16_t codeunit;
if (!parseHex4(codeunit))
return false;
err = parseHex4(codeunit);
if (err)
return err;
if (codepoint.append(codeunit))
Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
#else
@ -391,25 +432,21 @@ class JsonDeserializer {
// replace char
c = EscapeSequence::unescapeChar(c);
if (c == '\0') {
_error = DeserializationError::InvalidInput;
return false;
}
if (c == '\0')
return DeserializationError::InvalidInput;
move();
}
_stringStorage.append(c);
}
if (!_stringStorage.isValid()) {
_error = DeserializationError::NoMemory;
return false;
}
if (!_stringStorage.isValid())
return DeserializationError::NoMemory;
return true;
return DeserializationError::Ok;
}
bool parseNonQuotedString() {
DeserializationError::Code parseNonQuotedString() {
char c = current();
ARDUINOJSON_ASSERT(c);
@ -420,19 +457,24 @@ class JsonDeserializer {
c = current();
} while (canBeInNonQuotedString(c));
} else {
_error = DeserializationError::InvalidInput;
return false;
return DeserializationError::InvalidInput;
}
if (!_stringStorage.isValid()) {
_error = DeserializationError::NoMemory;
return false;
if (!_stringStorage.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
}
return true;
DeserializationError::Code skipKey() {
if (isQuote(current())) {
return skipQuotedString();
} else {
return skipNonQuotedString();
}
}
bool skipString() {
DeserializationError::Code skipQuotedString() {
const char stopChar = current();
move();
@ -441,99 +483,83 @@ class JsonDeserializer {
move();
if (c == stopChar)
break;
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '\\') {
if (current() != '\0')
move();
}
}
return true;
return DeserializationError::Ok;
}
DeserializationError::Code skipNonQuotedString() {
char c = current();
while (canBeInNonQuotedString(c)) {
move();
c = current();
}
return DeserializationError::Ok;
}
bool parseNumericValue(VariantData &result) {
DeserializationError::Code parseNumericValue(VariantData& result) {
uint8_t n = 0;
char c = current();
while (canBeInNonQuotedString(c) && n < 63) {
while (canBeInNumber(c) && n < 63) {
move();
_buffer[n++] = c;
c = current();
}
_buffer[n] = 0;
c = _buffer[0];
if (c == 't') { // true
result.setBoolean(true);
if (n != 4) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
}
if (c == 'f') { // false
result.setBoolean(false);
if (n != 5) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
}
if (c == 'n') { // null
// the variant is already null
if (n != 4) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
}
if (!parseNumber(_buffer, result)) {
_error = DeserializationError::InvalidInput;
return false;
}
if (!parseNumber(_buffer, result))
return DeserializationError::InvalidInput;
return true;
return DeserializationError::Ok;
}
bool skipNumericValue() {
DeserializationError::Code skipNumericValue() {
char c = current();
while (canBeInNonQuotedString(c)) {
while (canBeInNumber(c)) {
move();
c = current();
}
return true;
return DeserializationError::Ok;
}
bool parseHex4(uint16_t &result) {
DeserializationError::Code parseHex4(uint16_t& result) {
result = 0;
for (uint8_t i = 0; i < 4; ++i) {
char digit = current();
if (!digit) {
_error = DeserializationError::IncompleteInput;
return false;
}
if (!digit)
return DeserializationError::IncompleteInput;
uint8_t value = decodeHex(digit);
if (value > 0x0F) {
_error = DeserializationError::InvalidInput;
return false;
}
if (value > 0x0F)
return DeserializationError::InvalidInput;
result = uint16_t((result << 4) | value);
move();
}
return true;
return DeserializationError::Ok;
}
static inline bool isBetween(char c, char min, char max) {
return min <= c && c <= max;
}
static inline bool canBeInNumber(char c) {
return isBetween(c, '0', '9') || c == '+' || c == '-' || c == '.' ||
#if ARDUINOJSON_ENABLE_NAN || ARDUINOJSON_ENABLE_INFINITY
isBetween(c, 'A', 'Z') || isBetween(c, 'a', 'z');
#else
c == 'e' || c == 'E';
#endif
}
static inline bool canBeInNonQuotedString(char c) {
return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.';
isBetween(c, 'A', 'Z');
}
static inline bool isQuote(char c) {
@ -547,14 +573,13 @@ class JsonDeserializer {
return uint8_t(c - 'A' + 10);
}
bool skipSpacesAndComments() {
DeserializationError::Code skipSpacesAndComments() {
for (;;) {
switch (current()) {
// end of string
case '\0':
_error = _foundSomething ? DeserializationError::IncompleteInput
return _foundSomething ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput;
return false;
// spaces
case ' ':
@ -575,10 +600,8 @@ class JsonDeserializer {
bool wasStar = false;
for (;;) {
char c = current();
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '/' && wasStar) {
move();
break;
@ -595,10 +618,8 @@ class JsonDeserializer {
for (;;) {
move();
char c = current();
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '\n')
break;
}
@ -606,19 +627,31 @@ class JsonDeserializer {
// not a comment, just a '/'
default:
_error = DeserializationError::InvalidInput;
return false;
return DeserializationError::InvalidInput;
}
break;
#endif
default:
_foundSomething = true;
return true;
return DeserializationError::Ok;
}
}
}
DeserializationError::Code skipKeyword(const char* s) {
while (*s) {
char c = current();
if (c == '\0')
return DeserializationError::IncompleteInput;
if (*s != c)
return DeserializationError::InvalidInput;
++s;
move();
}
return DeserializationError::Ok;
}
TStringStorage _stringStorage;
bool _foundSomething;
Latch<TReader> _latch;
@ -626,13 +659,10 @@ class JsonDeserializer {
char _buffer[64]; // using a member instead of a local variable because it
// ended in the recursive path after compiler inlined the
// code
DeserializationError _error;
};
//
// deserializeJson(JsonDocument&, const std::string&, ...)
//
// ... = NestingLimit
// Parses a JSON input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TString>
DeserializationError deserializeJson(
JsonDocument& doc, const TString& input,
@ -640,24 +670,26 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TString>
DeserializationError deserializeJson(
JsonDocument& doc, const TString& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TString>
DeserializationError deserializeJson(JsonDocument& doc, const TString& input,
NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeJson(JsonDocument&, std::istream&, ...)
//
// ... = NestingLimit
// Parses a JSON input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TStream>
DeserializationError deserializeJson(
JsonDocument& doc, TStream& input,
@ -665,24 +697,26 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TStream>
DeserializationError deserializeJson(
JsonDocument& doc, TStream& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TStream>
DeserializationError deserializeJson(JsonDocument& doc, TStream& input,
NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeJson(JsonDocument&, char*, ...)
//
// ... = NestingLimit
// Parses a JSON input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar>
DeserializationError deserializeJson(
JsonDocument& doc, TChar* input,
@ -690,24 +724,26 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar>
DeserializationError deserializeJson(
JsonDocument& doc, TChar* input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar>
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeJson(JsonDocument&, char*, size_t, ...)
//
// ... = NestingLimit
// Parses a JSON input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar>
DeserializationError deserializeJson(
JsonDocument& doc, TChar* input, size_t inputSize,
@ -715,7 +751,9 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar>
DeserializationError deserializeJson(
JsonDocument& doc, TChar* input, size_t inputSize, Filter filter,
@ -723,7 +761,9 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
filter);
}
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar>
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
size_t inputSize,

@ -5,7 +5,6 @@
#pragma once
#include <ArduinoJson/Json/TextFormatter.hpp>
#include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Serialization/measure.hpp>
#include <ArduinoJson/Serialization/serialize.hpp>
#include <ArduinoJson/Variant/Visitor.hpp>
@ -22,7 +21,7 @@ class JsonSerializer : public Visitor<size_t> {
FORCE_INLINE size_t visitArray(const CollectionData& array) {
write('[');
VariantSlot *slot = array.head();
const VariantSlot* slot = array.head();
while (slot != 0) {
slot->data()->accept(*this);
@ -41,7 +40,7 @@ class JsonSerializer : public Visitor<size_t> {
size_t visitObject(const CollectionData& object) {
write('{');
VariantSlot *slot = object.head();
const VariantSlot* slot = object.head();
while (slot != 0) {
_formatter.writeString(slot->key());
@ -59,7 +58,7 @@ class JsonSerializer : public Visitor<size_t> {
return bytesWritten();
}
size_t visitFloat(Float value) {
size_t visitFloat(JsonFloat value) {
_formatter.writeFloat(value);
return bytesWritten();
}
@ -79,12 +78,12 @@ class JsonSerializer : public Visitor<size_t> {
return bytesWritten();
}
size_t visitSignedInteger(Integer value) {
size_t visitSignedInteger(JsonInteger value) {
_formatter.writeInteger(value);
return bytesWritten();
}
size_t visitUnsignedInteger(UInt value) {
size_t visitUnsignedInteger(JsonUInt value) {
_formatter.writeInteger(value);
return bytesWritten();
}
@ -116,24 +115,30 @@ class JsonSerializer : public Visitor<size_t> {
TextFormatter<TWriter> _formatter;
};
template <typename TSource, typename TDestination>
size_t serializeJson(const TSource &source, TDestination &destination) {
// Produces a minified JSON document.
// https://arduinojson.org/v6/api/json/serializejson/
template <typename TDestination>
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
return serialize<JsonSerializer>(source, destination);
}
template <typename TSource>
size_t serializeJson(const TSource &source, void *buffer, size_t bufferSize) {
// Produces a minified JSON document.
// https://arduinojson.org/v6/api/json/serializejson/
inline size_t serializeJson(JsonVariantConst source, void* buffer,
size_t bufferSize) {
return serialize<JsonSerializer>(source, buffer, bufferSize);
}
template <typename TSource>
size_t measureJson(const TSource &source) {
// Computes the length of the document that serializeJson() produces.
// https://arduinojson.org/v6/api/json/measurejson/
inline size_t measureJson(JsonVariantConst source) {
return measure<JsonSerializer>(source);
}
#if ARDUINOJSON_ENABLE_STD_STREAM
template <typename T>
inline typename enable_if<IsVisitable<T>::value, std::ostream &>::type
inline typename enable_if<is_convertible<T, JsonVariantConst>::value,
std::ostream&>::type
operator<<(std::ostream& os, const T& source) {
serializeJson(source, os);
return os;

@ -19,7 +19,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {}
size_t visitArray(const CollectionData& array) {
VariantSlot *slot = array.head();
const VariantSlot* slot = array.head();
if (slot) {
base::write("[\r\n");
_nesting++;
@ -40,7 +40,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
}
size_t visitObject(const CollectionData& object) {
VariantSlot *slot = object.head();
const VariantSlot* slot = object.head();
if (slot) {
base::write("{\r\n");
_nesting++;
@ -64,25 +64,30 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
private:
void indent() {
for (uint8_t i = 0; i < _nesting; i++) base::write(ARDUINOJSON_TAB);
for (uint8_t i = 0; i < _nesting; i++)
base::write(ARDUINOJSON_TAB);
}
uint8_t _nesting;
};
template <typename TSource, typename TDestination>
size_t serializeJsonPretty(const TSource &source, TDestination &destination) {
// Produces JsonDocument to create a prettified JSON document.
// https://arduinojson.org/v6/api/json/serializejsonpretty/
template <typename TDestination>
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
return serialize<PrettyJsonSerializer>(source, destination);
}
template <typename TSource>
size_t serializeJsonPretty(const TSource &source, void *buffer,
// Produces JsonDocument to create a prettified JSON document.
// https://arduinojson.org/v6/api/json/serializejsonpretty/
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
size_t bufferSize) {
return serialize<PrettyJsonSerializer>(source, buffer, bufferSize);
}
template <typename TSource>
size_t measureJsonPretty(const TSource &source) {
// Computes the length of the document that serializeJsonPretty() produces.
// https://arduinojson.org/v6/api/json/measurejsonpretty/
inline size_t measureJsonPretty(JsonVariantConst source) {
return measure<PrettyJsonSerializer>(source);
}

@ -9,7 +9,7 @@
#include <ArduinoJson/Json/EscapeSequence.hpp>
#include <ArduinoJson/Numbers/FloatParts.hpp>
#include <ArduinoJson/Numbers/Integer.hpp>
#include <ArduinoJson/Numbers/JsonInteger.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
@ -37,14 +37,16 @@ class TextFormatter {
void writeString(const char* value) {
ARDUINOJSON_ASSERT(value != NULL);
writeRaw('\"');
while (*value) writeChar(*value++);
while (*value)
writeChar(*value++);
writeRaw('\"');
}
void writeString(const char* value, size_t n) {
ARDUINOJSON_ASSERT(value != NULL);
writeRaw('\"');
while (n--) writeChar(*value++);
while (n--)
writeChar(*value++);
writeRaw('\"');
}

@ -14,6 +14,16 @@
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
// Computes the size required to store an array in a JsonDocument.
// https://arduinojson.org/v6/how-to/determine-the-capacity-of-the-jsondocument/
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
namespace ARDUINOJSON_NAMESPACE {
// _begin _end
@ -173,7 +183,8 @@ class MemoryPool {
return next;
// jump to next terminator
while (*next) ++next;
while (*next)
++next;
}
return 0;
}
@ -208,4 +219,35 @@ class MemoryPool {
bool _overflowed;
};
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::Copy, TCallback callback) {
const char* copy = pool->saveString(str);
JsonString storedString(copy, str.size(), JsonString::Copied);
callback(storedString);
return copy != 0;
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link,
TCallback callback) {
JsonString storedString(str.data(), str.size(), JsonString::Linked);
callback(storedString);
return !str.isNull();
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::LinkOrCopy policy, TCallback callback) {
if (policy.link)
return storeString(pool, str, StringStoragePolicy::Link(), callback);
else
return storeString(pool, str, StringStoragePolicy::Copy(), callback);
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
return storeString(pool, str, str.storagePolicy(), callback);
}
} // namespace ARDUINOJSON_NAMESPACE

@ -1,21 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
struct Visitable {
// template<Visitor>
// void accept(Visitor&) const;
};
template <typename T>
struct IsVisitable : is_base_of<Visitable, T> {};
template <typename T>
struct IsVisitable<T &> : IsVisitable<T> {};
} // namespace ARDUINOJSON_NAMESPACE

@ -16,33 +16,31 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TReader, typename TStringStorage>
class MsgPackDeserializer {
public:
MsgPackDeserializer(MemoryPool &pool, TReader reader,
MsgPackDeserializer(MemoryPool* pool, TReader reader,
TStringStorage stringStorage)
: _pool(&pool),
: _pool(pool),
_reader(reader),
_stringStorage(stringStorage),
_error(DeserializationError::Ok),
_foundSomething(false) {}
template <typename TFilter>
DeserializationError parse(VariantData& variant, TFilter filter,
NestingLimit nestingLimit) {
parseVariant(&variant, filter, nestingLimit);
return _foundSomething ? _error : DeserializationError::EmptyInput;
DeserializationError::Code err;
err = parseVariant(&variant, filter, nestingLimit);
return _foundSomething ? err : DeserializationError::EmptyInput;
}
private:
bool invalidInput() {
_error = DeserializationError::InvalidInput;
return false;
}
template <typename TFilter>
bool parseVariant(VariantData *variant, TFilter filter,
DeserializationError::Code parseVariant(VariantData* variant, TFilter filter,
NestingLimit nestingLimit) {
DeserializationError::Code err;
uint8_t code = 0; // TODO: why do we need to initialize this variable?
if (!readByte(code))
return false;
err = readByte(code);
if (err)
return err;
_foundSomething = true;
@ -56,20 +54,20 @@ class MsgPackDeserializer {
switch (code) {
case 0xc0:
// already null
return true;
return DeserializationError::Ok;
case 0xc1:
return invalidInput();
return DeserializationError::InvalidInput;
case 0xc2:
if (allowValue)
variant->setBoolean(false);
return true;
return DeserializationError::Ok;
case 0xc3:
if (allowValue)
variant->setBoolean(true);
return true;
return DeserializationError::Ok;
case 0xc4: // bin 8 (not supported)
return skipString<uint8_t>();
@ -221,157 +219,202 @@ class MsgPackDeserializer {
if (allowValue)
variant->setInteger(static_cast<int8_t>(code));
return true;
return DeserializationError::Ok;
}
bool readByte(uint8_t &value) {
DeserializationError::Code readByte(uint8_t& value) {
int c = _reader.read();
if (c < 0) {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c < 0)
return DeserializationError::IncompleteInput;
value = static_cast<uint8_t>(c);
return true;
return DeserializationError::Ok;
}
bool readBytes(uint8_t *p, size_t n) {
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
if (_reader.readBytes(reinterpret_cast<char*>(p), n) == n)
return true;
_error = DeserializationError::IncompleteInput;
return false;
return DeserializationError::Ok;
return DeserializationError::IncompleteInput;
}
template <typename T>
bool readBytes(T &value) {
DeserializationError::Code readBytes(T& value) {
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
bool skipBytes(size_t n) {
DeserializationError::Code skipBytes(size_t n) {
for (; n; --n) {
if (_reader.read() < 0) {
_error = DeserializationError::IncompleteInput;
return false;
if (_reader.read() < 0)
return DeserializationError::IncompleteInput;
}
}
return true;
return DeserializationError::Ok;
}
template <typename T>
bool readInteger(T &value) {
if (!readBytes(value))
return false;
DeserializationError::Code readInteger(T& value) {
DeserializationError::Code err;
err = readBytes(value);
if (err)
return err;
fixEndianess(value);
return true;
return DeserializationError::Ok;
}
template <typename T>
bool readInteger(VariantData *variant) {
DeserializationError::Code readInteger(VariantData* variant) {
DeserializationError::Code err;
T value;
if (!readInteger(value))
return false;
err = readInteger(value);
if (err)
return err;
variant->setInteger(value);
return true;
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 4, bool>::type readFloat(
VariantData *variant) {
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
readFloat(VariantData* variant) {
DeserializationError::Code err;
T value;
if (!readBytes(value))
return false;
err = readBytes(value);
if (err)
return err;
fixEndianess(value);
variant->setFloat(value);
return true;
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 8, bool>::type readDouble(
VariantData *variant) {
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
readDouble(VariantData* variant) {
DeserializationError::Code err;
T value;
if (!readBytes(value))
return false;
err = readBytes(value);
if (err)
return err;
fixEndianess(value);
variant->setFloat(value);
return true;
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 4, bool>::type readDouble(
VariantData *variant) {
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
readDouble(VariantData* variant) {
DeserializationError::Code err;
uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes
uint8_t* o = reinterpret_cast<uint8_t*>(&value);
if (!readBytes(i, 8))
return false;
err = readBytes(i, 8);
if (err)
return err;
doubleToFloat(i, o);
fixEndianess(value);
variant->setFloat(value);
return true;
return DeserializationError::Ok;
}
template <typename T>
bool readString(VariantData *variant) {
DeserializationError::Code readString(VariantData* variant) {
DeserializationError::Code err;
T size;
if (!readInteger(size))
return false;
err = readInteger(size);
if (err)
return err;
return readString(variant, size);
}
template <typename T>
bool readString() {
DeserializationError::Code readString() {
DeserializationError::Code err;
T size;
if (!readInteger(size))
return false;
err = readInteger(size);
if (err)
return err;
return readString(size);
}
template <typename T>
bool skipString() {
DeserializationError::Code skipString() {
DeserializationError::Code err;
T size;
if (!readInteger(size))
return false;
err = readInteger(size);
if (err)
return err;
return skipBytes(size);
}
bool readString(VariantData *variant, size_t n) {
if (!readString(n))
return false;
DeserializationError::Code readString(VariantData* variant, size_t n) {
DeserializationError::Code err;
err = readString(n);
if (err)
return err;
variant->setString(_stringStorage.save());
return true;
return DeserializationError::Ok;
}
bool readString(size_t n) {
DeserializationError::Code readString(size_t n) {
DeserializationError::Code err;
_stringStorage.startString();
for (; n; --n) {
uint8_t c;
if (!readBytes(c))
return false;
err = readBytes(c);
if (err)
return err;
_stringStorage.append(static_cast<char>(c));
}
if (!_stringStorage.isValid()) {
_error = DeserializationError::NoMemory;
return false;
}
return true;
if (!_stringStorage.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
}
template <typename TSize, typename TFilter>
bool readArray(VariantData *variant, TFilter filter,
DeserializationError::Code readArray(VariantData* variant, TFilter filter,
NestingLimit nestingLimit) {
DeserializationError::Code err;
TSize size;
if (!readInteger(size))
return false;
err = readInteger(size);
if (err)
return err;
return readArray(variant, size, filter, nestingLimit);
}
template <typename TFilter>
bool readArray(VariantData *variant, size_t n, TFilter filter,
DeserializationError::Code readArray(VariantData* variant, size_t n,
TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
bool allowArray = filter.allowArray();
@ -384,45 +427,50 @@ class MsgPackDeserializer {
if (memberFilter.allow()) {
value = array->addElement(_pool);
if (!value) {
_error = DeserializationError::NoMemory;
return false;
}
if (!value)
return DeserializationError::NoMemory;
} else {
value = 0;
}
if (!parseVariant(value, memberFilter, nestingLimit.decrement()))
return false;
err = parseVariant(value, memberFilter, nestingLimit.decrement());
if (err)
return err;
}
return true;
return DeserializationError::Ok;
}
template <typename TSize, typename TFilter>
bool readObject(VariantData *variant, TFilter filter,
DeserializationError::Code readObject(VariantData* variant, TFilter filter,
NestingLimit nestingLimit) {
DeserializationError::Code err;
TSize size;
if (!readInteger(size))
return false;
err = readInteger(size);
if (err)
return err;
return readObject(variant, size, filter, nestingLimit);
}
template <typename TFilter>
bool readObject(VariantData *variant, size_t n, TFilter filter,
DeserializationError::Code readObject(VariantData* variant, size_t n,
TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
CollectionData* object = filter.allowObject() ? &variant->toObject() : 0;
for (; n; --n) {
if (!readKey())
return false;
err = readKey();
if (err)
return err;
String key = _stringStorage.str();
JsonString key = _stringStorage.str();
TFilter memberFilter = filter[key.c_str()];
VariantData* member;
@ -434,10 +482,8 @@ class MsgPackDeserializer {
key = _stringStorage.save();
VariantSlot* slot = object->addSlot(_pool);
if (!slot) {
_error = DeserializationError::NoMemory;
return false;
}
if (!slot)
return DeserializationError::NoMemory;
slot->setKey(key);
@ -446,17 +492,21 @@ class MsgPackDeserializer {
member = 0;
}
if (!parseVariant(member, memberFilter, nestingLimit.decrement()))
return false;
err = parseVariant(member, memberFilter, nestingLimit.decrement());
if (err)
return err;
}
return true;
return DeserializationError::Ok;
}
bool readKey() {
DeserializationError::Code readKey() {
DeserializationError::Code err;
uint8_t code;
if (!readByte(code))
return false;
err = readByte(code);
if (err)
return err;
if ((code & 0xe0) == 0xa0)
return readString(code & 0x1f);
@ -472,29 +522,30 @@ class MsgPackDeserializer {
return readString<uint32_t>();
default:
return invalidInput();
return DeserializationError::InvalidInput;
}
}
template <typename T>
bool skipExt() {
DeserializationError::Code skipExt() {
DeserializationError::Code err;
T size;
if (!readInteger(size))
return false;
err = readInteger(size);
if (err)
return err;
return skipBytes(size + 1U);
}
MemoryPool* _pool;
TReader _reader;
TStringStorage _stringStorage;
DeserializationError _error;
bool _foundSomething;
};
//
// deserializeMsgPack(JsonDocument&, const std::string&, ...)
//
// ... = NestingLimit
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TString>
DeserializationError deserializeMsgPack(
JsonDocument& doc, const TString& input,
@ -502,14 +553,18 @@ DeserializationError deserializeMsgPack(
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TString>
DeserializationError deserializeMsgPack(
JsonDocument& doc, const TString& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TString>
DeserializationError deserializeMsgPack(JsonDocument& doc, const TString& input,
NestingLimit nestingLimit,
@ -517,10 +572,8 @@ DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input,
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeMsgPack(JsonDocument&, std::istream&, ...)
//
// ... = NestingLimit
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TStream>
DeserializationError deserializeMsgPack(
JsonDocument& doc, TStream& input,
@ -528,14 +581,18 @@ DeserializationError deserializeMsgPack(
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TStream>
DeserializationError deserializeMsgPack(
JsonDocument& doc, TStream& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TStream>
DeserializationError deserializeMsgPack(JsonDocument& doc, TStream& input,
NestingLimit nestingLimit,
@ -543,10 +600,8 @@ DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input,
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeMsgPack(JsonDocument&, char*, ...)
//
// ... = NestingLimit
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument& doc, TChar* input,
@ -554,14 +609,18 @@ DeserializationError deserializeMsgPack(
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument& doc, TChar* input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar>
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
NestingLimit nestingLimit,
@ -569,10 +628,8 @@ DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeMsgPack(JsonDocument&, char*, size_t, ...)
//
// ... = NestingLimit
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument& doc, TChar* input, size_t inputSize,
@ -580,7 +637,9 @@ DeserializationError deserializeMsgPack(
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument& doc, TChar* input, size_t inputSize, Filter filter,
@ -588,7 +647,9 @@ DeserializationError deserializeMsgPack(
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
filter);
}
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar>
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
size_t inputSize,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save