Added new ArduinoJson library.

Disabled drum menus when drums not enabled.
Replaced all strcpy(),strncpy(),strcat(),strncat() against strlcpy()/strlcat.
dev
Holger Wirtz 1 year ago
parent 70f5c12484
commit a0d3fee52f
  1. 18
      MicroDexed.ino
  2. 161
      UI.hpp
  3. 39
      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. 2
      third-party/ArduinoJson/extras/fuzzing/json_fuzzer.cpp
  16. 2
      third-party/ArduinoJson/extras/fuzzing/msgpack_fuzzer.cpp
  17. 0
      third-party/ArduinoJson/extras/scripts/build-arduino-package.sh
  18. 0
      third-party/ArduinoJson/extras/scripts/build-single-header.sh
  19. 0
      third-party/ArduinoJson/extras/scripts/get-release-body.sh
  20. 0
      third-party/ArduinoJson/extras/scripts/get-release-page.sh
  21. 0
      third-party/ArduinoJson/extras/scripts/publish-particle-library.sh
  22. 0
      third-party/ArduinoJson/extras/scripts/publish.sh
  23. 0
      third-party/ArduinoJson/extras/scripts/wandbox/publish.sh
  24. 6
      third-party/ArduinoJson/extras/tests/Cpp11/CMakeLists.txt
  25. 72
      third-party/ArduinoJson/extras/tests/Cpp11/stl_containers.cpp
  26. 2
      third-party/ArduinoJson/extras/tests/Helpers/api/String.h
  27. 4
      third-party/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt
  28. 2
      third-party/ArduinoJson/extras/tests/JsonArray/add.cpp
  29. 512
      third-party/ArduinoJson/extras/tests/JsonArray/compare.cpp
  30. 16
      third-party/ArduinoJson/extras/tests/JsonArray/get.cpp
  31. 7
      third-party/ArduinoJson/extras/tests/JsonArray/std_string.cpp
  32. 4
      third-party/ArduinoJson/extras/tests/JsonArray/subscript.cpp
  33. 48
      third-party/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp
  34. 2
      third-party/ArduinoJson/extras/tests/JsonDeserializer/input_types.cpp
  35. 6
      third-party/ArduinoJson/extras/tests/JsonDeserializer/invalid_input.cpp
  36. 44
      third-party/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp
  37. 71
      third-party/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp
  38. 2
      third-party/ArduinoJson/extras/tests/JsonDocument/remove.cpp
  39. 3
      third-party/ArduinoJson/extras/tests/JsonObject/CMakeLists.txt
  40. 512
      third-party/ArduinoJson/extras/tests/JsonObject/compare.cpp
  41. 2
      third-party/ArduinoJson/extras/tests/JsonObject/containsKey.cpp
  42. 2
      third-party/ArduinoJson/extras/tests/JsonObject/createNestedArray.cpp
  43. 2
      third-party/ArduinoJson/extras/tests/JsonObject/createNestedObject.cpp
  44. 2
      third-party/ArduinoJson/extras/tests/JsonObject/remove.cpp
  45. 7
      third-party/ArduinoJson/extras/tests/JsonObject/std_string.cpp
  46. 10
      third-party/ArduinoJson/extras/tests/JsonObject/subscript.cpp
  47. 10
      third-party/ArduinoJson/extras/tests/JsonSerializer/CustomWriter.cpp
  48. 2
      third-party/ArduinoJson/extras/tests/JsonSerializer/JsonArray.cpp
  49. 6
      third-party/ArduinoJson/extras/tests/JsonSerializer/JsonObject.cpp
  50. 4
      third-party/ArduinoJson/extras/tests/JsonSerializer/JsonVariant.cpp
  51. 4
      third-party/ArduinoJson/extras/tests/JsonVariant/CMakeLists.txt
  52. 6
      third-party/ArduinoJson/extras/tests/JsonVariant/compare.cpp
  53. 4
      third-party/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp
  54. 18
      third-party/ArduinoJson/extras/tests/JsonVariant/converters.cpp
  55. 28
      third-party/ArduinoJson/extras/tests/JsonVariant/createNested.cpp
  56. 40
      third-party/ArduinoJson/extras/tests/JsonVariant/is.cpp
  57. 35
      third-party/ArduinoJson/extras/tests/JsonVariant/isnull.cpp
  58. 38
      third-party/ArduinoJson/extras/tests/JsonVariant/set.cpp
  59. 87
      third-party/ArduinoJson/extras/tests/JsonVariant/shallowCopy.cpp
  60. 36
      third-party/ArduinoJson/extras/tests/JsonVariant/size.cpp
  61. 4
      third-party/ArduinoJson/extras/tests/JsonVariant/subscript.cpp
  62. 8
      third-party/ArduinoJson/extras/tests/JsonVariant/types.cpp
  63. 10
      third-party/ArduinoJson/extras/tests/MemoryPool/StringCopier.cpp
  64. 2
      third-party/ArduinoJson/extras/tests/MemoryPool/clear.cpp
  65. 40
      third-party/ArduinoJson/extras/tests/MemoryPool/saveString.cpp
  66. 3
      third-party/ArduinoJson/extras/tests/MemoryPool/size.cpp
  67. 1
      third-party/ArduinoJson/extras/tests/Misc/CMakeLists.txt
  68. 35
      third-party/ArduinoJson/extras/tests/Misc/StringAdapters.cpp
  69. 35
      third-party/ArduinoJson/extras/tests/Misc/TypeTraits.cpp
  70. 2
      third-party/ArduinoJson/extras/tests/Misc/Utf8.cpp
  71. 115
      third-party/ArduinoJson/extras/tests/Misc/deprecated.cpp
  72. 6
      third-party/ArduinoJson/extras/tests/MsgPackDeserializer/filter.cpp
  73. 2
      third-party/ArduinoJson/extras/tests/MsgPackSerializer/destination_types.cpp
  74. 2
      third-party/ArduinoJson/extras/tests/MsgPackSerializer/misc.cpp
  75. 6
      third-party/ArduinoJson/extras/tests/MsgPackSerializer/serializeArray.cpp
  76. 1
      third-party/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp
  77. 5
      third-party/ArduinoJson/extras/tests/Numbers/CMakeLists.txt
  78. 58
      third-party/ArduinoJson/extras/tests/Numbers/convertNumber.cpp
  79. 4
      third-party/ArduinoJson/extras/tests/Numbers/parseNumber.cpp
  80. 2
      third-party/ArduinoJson/library.json
  81. 2
      third-party/ArduinoJson/library.properties
  82. 1
      third-party/ArduinoJson/logo.svg
  83. 34
      third-party/ArduinoJson/src/ArduinoJson.hpp
  84. 31
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayFunctions.hpp
  85. 28
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayImpl.hpp
  86. 121
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayIterator.hpp
  87. 213
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayRef.hpp
  88. 49
      third-party/ArduinoJson/src/ArduinoJson/Array/ArrayShortcuts.hpp
  89. 191
      third-party/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp
  90. 210
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp
  91. 134
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp
  92. 32
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArrayImpl.hpp
  93. 117
      third-party/ArduinoJson/src/ArduinoJson/Array/JsonArrayIterator.hpp
  94. 58
      third-party/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp
  95. 53
      third-party/ArduinoJson/src/ArduinoJson/Collection/CollectionData.hpp
  96. 62
      third-party/ArduinoJson/src/ArduinoJson/Collection/CollectionImpl.hpp
  97. 10
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Filter.hpp
  98. 3
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp
  99. 3
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Readers/RamReader.hpp
  100. 25
      third-party/ArduinoJson/src/ArduinoJson/Deserialization/Readers/VariantReader.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];
}
#ifdef DEBUG
Serial.print(F("Get performance name for "));
Serial.print(number);
Serial.print(F(": "));
Serial.print(configuration.performance.name_temp);
Serial.println();
#endif
}
strlcpy(configuration.performance.name_temp, data_json["name"] | "NoName", sizeof(configuration.performance.name_temp));
#ifdef DEBUG
else {
Serial.print(F("Cannot get performance name for "));
Serial.print(number);
Serial.println();
}
Serial.print(F("Get performance name for "));
Serial.print(number);
Serial.print(F(": "));
Serial.print(configuration.performance.name_temp);
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);
}

@ -1,6 +1,6 @@
#include <ArduinoJson.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
DynamicJsonDocument doc(4096);
DeserializationError error = deserializeJson(doc, data, size);
if (!error) {

@ -1,6 +1,6 @@
#include <ArduinoJson.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
DynamicJsonDocument doc(4096);
DeserializationError error = deserializeMsgPack(doc, data, size);
if (!error) {

@ -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()
@ -28,5 +32,5 @@ add_test(Cpp11 Cpp11Tests)
set_tests_properties(Cpp11
PROPERTIES
LABELS "Catch"
LABELS "Catch"
)

@ -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();

@ -2,13 +2,13 @@
# Copyright © 2014-2022, Benoit BLANCHON
# MIT License
add_executable(JsonArrayTests
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());
}
}

@ -5,9 +5,10 @@
#include <ArduinoJson.h>
#include <catch.hpp>
static void eraseString(std::string &str) {
char *p = const_cast<char *>(str.c_str());
while (*p) *p++ = '*';
static void eraseString(std::string& str) {
char* p = const_cast<char*>(str.c_str());
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";
@ -115,9 +116,9 @@ TEST_CASE("MemberProxy::operator|()") {
SECTION("Issue #1411") {
doc["sensor"] = "gps";
const char *test = "test"; // <- the literal must be captured in a variable
const char* test = "test"; // <- the literal must be captured in a variable
// to trigger the bug
const char *sensor = doc["sensor"] | test; // "gps"
const char* sensor = doc["sensor"] | test; // "gps"
REQUIRE(sensor == std::string("gps"));
}
@ -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}");

@ -2,8 +2,9 @@
# Copyright © 2014-2022, Benoit BLANCHON
# MIT License
add_executable(JsonObjectTests
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);

@ -5,9 +5,10 @@
#include <ArduinoJson.h>
#include <catch.hpp>
static void eraseString(std::string &str) {
char *p = const_cast<char *>(str.c_str());
while (*p) *p++ = '*';
static void eraseString(std::string& str) {
char* p = const_cast<char*>(str.c_str());
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\"}");

@ -14,18 +14,18 @@ class CustomWriter {
return 1;
}
size_t write(const uint8_t *s, size_t n) {
_str.append(reinterpret_cast<const char *>(s), n);
size_t write(const uint8_t* s, size_t n) {
_str.append(reinterpret_cast<const char*>(s), n);
return n;
}
const std::string &str() const {
const std::string& str() const {
return _str;
}
private:
CustomWriter(const CustomWriter &); // non-copiable
CustomWriter &operator=(const CustomWriter &);
CustomWriter(const CustomWriter&); // non-copiable
CustomWriter& operator=(const CustomWriter&);
std::string _str;
};

@ -23,7 +23,7 @@ TEST_CASE("serializeJson(JsonArray)") {
}
SECTION("Null") {
array.add(static_cast<char *>(0));
array.add(static_cast<char*>(0));
check(array, "[null]");
}

@ -6,7 +6,7 @@
#include <catch.hpp>
#include <string>
static void checkObject(const JsonObject obj, const std::string &expected) {
static void checkObject(const JsonObject obj, const std::string& expected) {
char actual[256];
memset(actual, '!', sizeof(actual));
@ -84,8 +84,8 @@ TEST_CASE("serializeJson(JsonObject)") {
}
SECTION("TwoNull") {
obj["a"] = static_cast<char *>(0);
obj["b"] = static_cast<char *>(0);
obj["a"] = static_cast<char*>(0);
obj["b"] = static_cast<char*>(0);
checkObject(obj, "{\"a\":null,\"b\":null}");
}

@ -7,7 +7,7 @@
#include <limits>
template <typename T>
void check(T value, const std::string &expected) {
void check(T value, const std::string& expected) {
DynamicJsonDocument doc(4096);
doc.to<JsonVariant>().set(value);
char buffer[256] = "";
@ -22,7 +22,7 @@ TEST_CASE("serializeJson(JsonVariant)") {
}
SECTION("Null string") {
check(static_cast<char *>(0), "null");
check(static_cast<char*>(0), "null");
}
SECTION("const char*") {

@ -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);
}
}

@ -19,7 +19,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariant>() == false);
CHECK(variant.is<JsonVariantConst>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<JsonString>() == false);
@ -34,7 +34,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<JsonString>() == false);
@ -50,7 +50,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<JsonString>() == false);
@ -66,7 +66,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<JsonString>() == false);
@ -88,7 +88,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<bool>() == false);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<JsonString>() == false);
}
@ -103,7 +103,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<bool>() == false);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<std::string>() == false);
CHECK(variant.is<JsonString>() == false);
@ -113,8 +113,8 @@ TEST_CASE("JsonVariant::is<T>()") {
SECTION("const char*") {
variant.set("4.2");
CHECK(variant.is<const char *>() == true);
CHECK(variant.is<const char *>() == true);
CHECK(variant.is<const char*>() == true);
CHECK(variant.is<const char*>() == true);
CHECK(variant.is<std::string>() == true);
CHECK(variant.is<JsonString>() == true);
CHECK(variant.is<JsonVariant>() == true);
@ -140,7 +140,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<MYENUM2>() == false);
}
@ -156,7 +156,7 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<const char*>() == false);
CHECK(variant.is<MYENUM2>() == false);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
@ -178,7 +178,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonVariantConst>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<JsonString>() == false);
@ -192,7 +192,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<JsonString>() == false);
@ -208,7 +208,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<JsonString>() == false);
@ -224,7 +224,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<JsonString>() == false);
@ -246,7 +246,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<JsonString>() == false);
}
@ -261,7 +261,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<std::string>() == false);
CHECK(cvariant.is<JsonString>() == false);
@ -271,8 +271,8 @@ TEST_CASE("JsonVariantConst::is<T>()") {
SECTION("const char*") {
variant.set("4.2");
CHECK(cvariant.is<const char *>() == true);
CHECK(cvariant.is<const char *>() == true);
CHECK(cvariant.is<const char*>() == true);
CHECK(cvariant.is<const char*>() == true);
CHECK(cvariant.is<std::string>() == true);
CHECK(cvariant.is<JsonString>() == true);
CHECK(cvariant.is<double>() == false);
@ -297,7 +297,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
@ -313,7 +313,7 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<const char*>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
}

@ -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,16 +14,16 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("const char*") {
char str[16];
strcpy(str, "hello");
bool result = variant.set(static_cast<const char *>(str));
strcpy(str, "world");
strlcpy(str, "hello");
bool result = variant.set(static_cast<const char*>(str));
strlcpy(str, "world");
REQUIRE(result == true);
REQUIRE(variant == "world"); // stores by pointer
}
SECTION("(const char*)0") {
bool result = variant.set(static_cast<const char *>(0));
bool result = variant.set(static_cast<const char*>(0));
REQUIRE(result == true);
REQUIRE(variant.isNull());
@ -32,16 +32,16 @@ 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
}
SECTION("(char*)0") {
bool result = variant.set(static_cast<char *>(0));
bool result = variant.set(static_cast<char*>(0));
REQUIRE(result == true);
REQUIRE(variant.isNull());
@ -50,9 +50,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
SECTION("unsigned char*") {
char str[16];
strcpy(str, "hello");
bool result = variant.set(reinterpret_cast<unsigned char *>(str));
strcpy(str, "world");
strlcpy(str, "hello");
bool result = variant.set(reinterpret_cast<unsigned char*>(str));
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");
bool result = variant.set(reinterpret_cast<signed char *>(str));
strcpy(str, "world");
strlcpy(str, "hello");
bool result = variant.set(reinterpret_cast<signed char*>(str));
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>();

@ -17,9 +17,9 @@ void checkValue(T expected) {
}
template <typename T>
void checkReference(T &expected) {
void checkReference(T& expected) {
JsonVariant variant = expected;
REQUIRE(expected == variant.as<T &>());
REQUIRE(expected == variant.as<T&>());
}
template <typename T>
@ -46,10 +46,10 @@ TEST_CASE("JsonVariant set()/get()") {
#endif
SECTION("Null") {
checkValue<const char *>(NULL);
checkValue<const char*>(NULL);
}
SECTION("const char*") {
checkValue<const char *>("hello");
checkValue<const char*>("hello");
}
SECTION("std::string") {
checkValue<std::string>("hello");

@ -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();

@ -22,7 +22,7 @@ TEST_CASE("MemoryPool::clear()") {
}
SECTION("Discards allocated strings") {
pool.saveString(adaptString(const_cast<char *>("123456789")));
pool.saveString(adaptString(const_cast<char*>("123456789")));
REQUIRE(pool.size() == 10);
pool.clear();

@ -8,11 +8,11 @@
using namespace ARDUINOJSON_NAMESPACE;
static const char *saveString(MemoryPool &pool, const char *s) {
return pool.saveString(adaptString(const_cast<char *>(s)));
static const char* saveString(MemoryPool& pool, const char* s) {
return pool.saveString(adaptString(const_cast<char*>(s)));
}
static const char *saveString(MemoryPool &pool, const char *s, size_t n) {
static const char* saveString(MemoryPool& pool, const char* s, size_t n) {
return pool.saveString(adaptString(s, n));
}
@ -21,36 +21,36 @@ TEST_CASE("MemoryPool::saveString()") {
MemoryPool pool(buffer, 32);
SECTION("Duplicates different strings") {
const char *a = saveString(pool, "hello");
const char *b = saveString(pool, "world");
const char* a = saveString(pool, "hello");
const char* b = saveString(pool, "world");
REQUIRE(a != b);
REQUIRE(pool.size() == 6 + 6);
}
SECTION("Deduplicates identical strings") {
const char *a = saveString(pool, "hello");
const char *b = saveString(pool, "hello");
const char* a = saveString(pool, "hello");
const char* b = saveString(pool, "hello");
REQUIRE(a == b);
REQUIRE(pool.size() == 6);
}
SECTION("Deduplicates identical strings that contain NUL") {
const char *a = saveString(pool, "hello\0world", 11);
const char *b = saveString(pool, "hello\0world", 11);
const char* a = saveString(pool, "hello\0world", 11);
const char* b = saveString(pool, "hello\0world", 11);
REQUIRE(a == b);
REQUIRE(pool.size() == 12);
}
SECTION("Reuse part of a string if it ends with NUL") {
const char *a = saveString(pool, "hello\0world", 11);
const char *b = saveString(pool, "hello");
const char* a = saveString(pool, "hello\0world", 11);
const char* b = saveString(pool, "hello");
REQUIRE(a == b);
REQUIRE(pool.size() == 12);
}
SECTION("Don't stop on first NUL") {
const char *a = saveString(pool, "hello");
const char *b = saveString(pool, "hello\0world", 11);
const char* a = saveString(pool, "hello");
const char* b = saveString(pool, "hello\0world", 11);
REQUIRE(a != b);
REQUIRE(pool.size() == 18);
}
@ -58,16 +58,16 @@ TEST_CASE("MemoryPool::saveString()") {
SECTION("Returns NULL when full") {
REQUIRE(pool.capacity() == 32);
const void *p1 = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
const void* p1 = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
REQUIRE(p1 != 0);
REQUIRE(pool.size() == 32);
const void *p2 = saveString(pool, "b");
const void* p2 = saveString(pool, "b");
REQUIRE(p2 == 0);
}
SECTION("Returns NULL when pool is too small") {
const void *p = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
const void* p = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
REQUIRE(0 == p);
}
@ -82,15 +82,15 @@ TEST_CASE("MemoryPool::saveString()") {
}
SECTION("Returns same address after clear()") {
const void *a = saveString(pool, "hello");
const void* a = saveString(pool, "hello");
pool.clear();
const void *b = saveString(pool, "world");
const void* b = saveString(pool, "world");
REQUIRE(a == b);
}
SECTION("Can use full capacity when fresh") {
const void *a = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
const void* a = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
REQUIRE(a != 0);
}
@ -99,7 +99,7 @@ TEST_CASE("MemoryPool::saveString()") {
saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
pool.clear();
const void *a = saveString(pool, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
const void* a = saveString(pool, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
REQUIRE(a != 0);
}

@ -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);
}
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);
}
struct EmptyStruct {};
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);
}
TEST_CASE("IsString<T>") {
CHECK(IsString<std::string>::value == true);
CHECK(IsString<std::basic_string<wchar_t> >::value == false);
CHECK(IsString<custom_string>::value == true);
CHECK(IsString<const __FlashStringHelper*>::value == true);
CHECK(IsString<const char*>::value == true);
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

@ -9,7 +9,7 @@ TEST_CASE("serialize MsgPack to various destination types") {
DynamicJsonDocument doc(4096);
JsonObject object = doc.to<JsonObject>();
object["hello"] = "world";
const char *expected_result = "\x81\xA5hello\xA5world";
const char* expected_result = "\x81\xA5hello\xA5world";
const size_t expected_length = 13;
SECTION("std::string") {

@ -3,7 +3,7 @@
#include <limits>
template <typename T>
void check(T value, const std::string &expected) {
void check(T value, const std::string& expected) {
DynamicJsonDocument doc(4096);
doc.to<JsonVariant>().set(value);
char buffer[256] = "";

@ -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,7 +2,10 @@
# Copyright © 2014-2022, Benoit BLANCHON
# MIT License
add_executable(NumbersTests
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED OFF)
add_executable(NumbersTests
convertNumber.cpp
parseFloat.cpp
parseDouble.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

@ -16,8 +16,8 @@ class VariantData;
class VariantSlot;
class CollectionData {
VariantSlot *_head;
VariantSlot *_tail;
VariantSlot* _head;
VariantSlot* _tail;
public:
// Must be a POD!
@ -28,27 +28,24 @@ class CollectionData {
// Array only
VariantData *addElement(MemoryPool *pool);
VariantData* addElement(MemoryPool* pool);
VariantData *getElement(size_t index) const;
VariantData* getElement(size_t index) const;
VariantData *getOrAddElement(size_t index, MemoryPool *pool);
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
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;
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) {
@ -56,34 +53,42 @@ class CollectionData {
}
template <typename TAdaptedString>
bool containsKey(const TAdaptedString &key) const;
bool equalsObject(const CollectionData &other) const;
bool containsKey(const TAdaptedString& key) const;
// Generic
void clear();
size_t memoryUsage() const;
size_t nesting() const;
size_t size() const;
VariantSlot *addSlot(MemoryPool *);
void removeSlot(VariantSlot *slot);
VariantSlot* addSlot(MemoryPool*);
void removeSlot(VariantSlot* slot);
bool copyFrom(const CollectionData &src, MemoryPool *pool);
bool copyFrom(const CollectionData& src, MemoryPool* pool);
VariantSlot *head() const {
VariantSlot* head() const {
return _head;
}
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
private:
VariantSlot *getSlot(size_t index) const;
VariantSlot* getSlot(size_t index) const;
template <typename TAdaptedString>
VariantSlot *getSlot(TAdaptedString key) const;
VariantSlot* getSlot(TAdaptedString key) const;
VariantSlot *getPreviousSlot(VariantSlot *) const;
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

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

Loading…
Cancel
Save