Просмотр исходного кода

Added `deserializeMsgPack()` (issue #358)

Benoit Blanchon 7 лет назад
Родитель
Сommit
cb723840d9
58 измененных файлов с 1311 добавлено и 89 удалено
  1. 0 6
      .travis.yml
  2. 1 0
      CHANGELOG.md
  3. 4 2
      src/ArduinoJson.hpp
  4. 10 0
      src/ArduinoJson/Configuration.hpp
  5. 1 1
      src/ArduinoJson/Data/ValueSaver.hpp
  6. 0 0
      src/ArduinoJson/Json/Deserialization/Comments.hpp
  7. 5 5
      src/ArduinoJson/Json/Deserialization/JsonParser.hpp
  8. 1 1
      src/ArduinoJson/Json/Deserialization/JsonParserImpl.hpp
  9. 0 0
      src/ArduinoJson/Json/Encoding.hpp
  10. 5 5
      src/ArduinoJson/Json/Serialization/FloatParts.hpp
  11. 0 0
      src/ArduinoJson/Json/Serialization/IndentedPrint.hpp
  12. 7 7
      src/ArduinoJson/Json/Serialization/JsonSerializer.hpp
  13. 5 5
      src/ArduinoJson/Json/Serialization/JsonSerializerImpl.hpp
  14. 4 4
      src/ArduinoJson/Json/Serialization/JsonWriter.hpp
  15. 0 0
      src/ArduinoJson/Json/Serialization/Prettyfier.hpp
  16. 1 1
      src/ArduinoJson/JsonArray.hpp
  17. 2 15
      src/ArduinoJson/JsonError.hpp
  18. 1 1
      src/ArduinoJson/JsonObject.hpp
  19. 3 3
      src/ArduinoJson/JsonVariantComparisons.hpp
  20. 4 4
      src/ArduinoJson/JsonVariantImpl.hpp
  21. 3 3
      src/ArduinoJson/JsonVariantSubscripts.hpp
  22. 328 0
      src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
  23. 67 0
      src/ArduinoJson/MsgPack/MsgPackError.hpp
  24. 47 0
      src/ArduinoJson/MsgPack/endianess.hpp
  25. 18 0
      src/ArduinoJson/MsgPack/ieee754.hpp
  26. 0 0
      src/ArduinoJson/Print/DummyPrint.hpp
  27. 3 3
      src/ArduinoJson/Print/DynamicStringBuilder.hpp
  28. 0 0
      src/ArduinoJson/Print/StaticStringBuilder.hpp
  29. 0 0
      src/ArduinoJson/Print/StreamPrintAdapter.hpp
  30. 0 0
      src/ArduinoJson/Strings/ArduinoStream.hpp
  31. 0 0
      src/ArduinoJson/Strings/CharPointer.hpp
  32. 0 0
      src/ArduinoJson/Strings/FlashString.hpp
  33. 0 0
      src/ArduinoJson/Strings/StdStream.hpp
  34. 0 0
      src/ArduinoJson/Strings/StdString.hpp
  35. 0 0
      src/ArduinoJson/Strings/StringTraits.hpp
  36. 0 0
      src/ArduinoJson/Strings/StringWriter.hpp
  37. 3 3
      src/ArduinoJson/Text/isFloat.hpp
  38. 3 3
      src/ArduinoJson/Text/isInteger.hpp
  39. 4 4
      src/ArduinoJson/Text/parseFloat.hpp
  40. 3 3
      src/ArduinoJson/Text/parseInteger.hpp
  41. 1 1
      src/ArduinoJson/deserializeJson.hpp
  42. 49 0
      src/ArduinoJson/deserializeMsgPack.hpp
  43. 1 0
      test/CMakeLists.txt
  44. 2 2
      test/JsonWriter/writeFloat.cpp
  45. 2 2
      test/JsonWriter/writeString.cpp
  46. 1 1
      test/Misc/FloatParts.cpp
  47. 16 0
      test/MsgPack/CMakeLists.txt
  48. 40 0
      test/MsgPack/MsgPackError.cpp
  49. 58 0
      test/MsgPack/deserializationErrors.cpp
  50. 85 0
      test/MsgPack/deserializeArray.cpp
  51. 86 0
      test/MsgPack/deserializeObject.cpp
  52. 131 0
      test/MsgPack/deserializeStaticVariant.cpp
  53. 277 0
      test/MsgPack/deserializeVariant.cpp
  54. 25 0
      test/MsgPack/doubleToFloat.cpp
  55. 1 1
      test/Polyfills/isFloat.cpp
  56. 1 1
      test/Polyfills/isInteger.cpp
  57. 1 1
      test/Polyfills/parseFloat.cpp
  58. 1 1
      test/Polyfills/parseInteger.cpp

+ 0 - 6
.travis.yml

@@ -2,12 +2,6 @@ sudo: false
 language: cpp
 matrix:
   include:
-    - compiler: gcc
-      addons:
-        apt:
-          sources: ['ubuntu-toolchain-r-test']
-          packages: ['g++-4.4']
-      env: SCRIPT=cmake GCC=4.4
     - compiler: gcc
       addons:
         apt:

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@ HEAD
 * Added `deserializeJson()`
 * Added `serializeJson()` and `serializeJsonPretty()`
 * Added `measureJson()` and `measureJsonPretty()`
+* Added `deserializeMsgPack()` (issue #358)
 * Removed `JsonBuffer::parseArray()`, `parseObject()` and `parse()`
 * Removed `JsonBuffer::createArray()` and `createObject()`
 * Removed `printTo()` and `prettyPrintTo()`

+ 4 - 2
src/ArduinoJson.hpp

@@ -7,13 +7,15 @@
 #include "ArduinoJson/DynamicJsonArray.hpp"
 #include "ArduinoJson/DynamicJsonObject.hpp"
 #include "ArduinoJson/DynamicJsonVariant.hpp"
+#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
 #include "ArduinoJson/StaticJsonArray.hpp"
 #include "ArduinoJson/StaticJsonObject.hpp"
 #include "ArduinoJson/StaticJsonVariant.hpp"
 #include "ArduinoJson/deserializeJson.hpp"
+#include "ArduinoJson/deserializeMsgPack.hpp"
 
-#include "ArduinoJson/Deserialization/JsonParserImpl.hpp"
+#include "ArduinoJson/Json/Deserialization/JsonParserImpl.hpp"
+#include "ArduinoJson/Json/Serialization/JsonSerializerImpl.hpp"
 #include "ArduinoJson/JsonArrayImpl.hpp"
 #include "ArduinoJson/JsonObjectImpl.hpp"
 #include "ArduinoJson/JsonVariantImpl.hpp"
-#include "ArduinoJson/Serialization/JsonSerializerImpl.hpp"

+ 10 - 0
src/ArduinoJson/Configuration.hpp

@@ -144,3 +144,13 @@
 #if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64
 #error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together
 #endif
+
+#ifndef ARDUINOJSON_LITTLE_ENDIAN
+#if defined(_MSC_VER) ||                                                      \
+    (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
+    (defined(__LITTLE_ENDIAN__))
+#define ARDUINOJSON_LITTLE_ENDIAN 1
+#else
+#define ARDUINOJSON_LITTLE_ENDIAN 0
+#endif
+#endif

+ 1 - 1
src/ArduinoJson/Data/ValueSaver.hpp

@@ -6,7 +6,7 @@
 
 #include "../JsonVariant.hpp"
 #include "../Memory/JsonBuffer.hpp"
-#include "../StringTraits/StringTraits.hpp"
+#include "../Strings/StringTraits.hpp"
 #include "../TypeTraits/EnableIf.hpp"
 
 namespace ArduinoJson {

+ 0 - 0
src/ArduinoJson/Deserialization/Comments.hpp → src/ArduinoJson/Json/Deserialization/Comments.hpp


+ 5 - 5
src/ArduinoJson/Deserialization/JsonParser.hpp → src/ArduinoJson/Json/Deserialization/JsonParser.hpp

@@ -4,11 +4,11 @@
 
 #pragma once
 
-#include "../JsonError.hpp"
-#include "../JsonVariant.hpp"
-#include "../Memory/JsonBuffer.hpp"
-#include "../TypeTraits/IsConst.hpp"
-#include "StringWriter.hpp"
+#include "../../JsonError.hpp"
+#include "../../JsonVariant.hpp"
+#include "../../Memory/JsonBuffer.hpp"
+#include "../../Strings/StringWriter.hpp"
+#include "../../TypeTraits/IsConst.hpp"
 
 namespace ArduinoJson {
 namespace Internals {

+ 1 - 1
src/ArduinoJson/Deserialization/JsonParserImpl.hpp → src/ArduinoJson/Json/Deserialization/JsonParserImpl.hpp

@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "../Data/Encoding.hpp"
+#include "../Encoding.hpp"
 #include "Comments.hpp"
 #include "JsonParser.hpp"
 

+ 0 - 0
src/ArduinoJson/Data/Encoding.hpp → src/ArduinoJson/Json/Encoding.hpp


+ 5 - 5
src/ArduinoJson/Serialization/FloatParts.hpp → src/ArduinoJson/Json/Serialization/FloatParts.hpp

@@ -4,9 +4,9 @@
 
 #pragma once
 
-#include "../Configuration.hpp"
-#include "../Polyfills/math.hpp"
-#include "../TypeTraits/FloatTraits.hpp"
+#include "../../Configuration.hpp"
+#include "../../Polyfills/math.hpp"
+#include "../../TypeTraits/FloatTraits.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -85,5 +85,5 @@ struct FloatParts {
     return powersOf10;
   }
 };
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 0 - 0
src/ArduinoJson/Serialization/IndentedPrint.hpp → src/ArduinoJson/Json/Serialization/IndentedPrint.hpp


+ 7 - 7
src/ArduinoJson/Serialization/JsonSerializer.hpp → src/ArduinoJson/Json/Serialization/JsonSerializer.hpp

@@ -4,15 +4,15 @@
 
 #pragma once
 
-#include "DummyPrint.hpp"
-#include "DynamicStringBuilder.hpp"
-#include "IndentedPrint.hpp"
-#include "JsonWriter.hpp"
-#include "Prettyfier.hpp"
-#include "StaticStringBuilder.hpp"
+#include "../../Print/DummyPrint.hpp"
+#include "../../Print/DynamicStringBuilder.hpp"
+#include "../../Print/StaticStringBuilder.hpp"
+#include "./IndentedPrint.hpp"
+#include "./JsonWriter.hpp"
+#include "./Prettyfier.hpp"
 
 #if ARDUINOJSON_ENABLE_STD_STREAM
-#include "StreamPrintAdapter.hpp"
+#include "../../Print/StreamPrintAdapter.hpp"
 #endif
 
 namespace ArduinoJson {

+ 5 - 5
src/ArduinoJson/Serialization/JsonSerializerImpl.hpp → src/ArduinoJson/Json/Serialization/JsonSerializerImpl.hpp

@@ -4,11 +4,11 @@
 
 #pragma once
 
-#include "../JsonArray.hpp"
-#include "../JsonArraySubscript.hpp"
-#include "../JsonObject.hpp"
-#include "../JsonObjectSubscript.hpp"
-#include "../JsonVariant.hpp"
+#include "../../JsonArray.hpp"
+#include "../../JsonArraySubscript.hpp"
+#include "../../JsonObject.hpp"
+#include "../../JsonObjectSubscript.hpp"
+#include "../../JsonVariant.hpp"
 #include "JsonSerializer.hpp"
 
 template <typename Writer>

+ 4 - 4
src/ArduinoJson/Serialization/JsonWriter.hpp → src/ArduinoJson/Json/Serialization/JsonWriter.hpp

@@ -5,10 +5,10 @@
 #pragma once
 
 #include <stdint.h>
-#include "../Data/Encoding.hpp"
-#include "../Data/JsonInteger.hpp"
-#include "../Polyfills/attributes.hpp"
-#include "../Serialization/FloatParts.hpp"
+#include "../../Data/JsonInteger.hpp"
+#include "../../Polyfills/attributes.hpp"
+#include "../Encoding.hpp"
+#include "./FloatParts.hpp"
 
 namespace ArduinoJson {
 namespace Internals {

+ 0 - 0
src/ArduinoJson/Serialization/Prettyfier.hpp → src/ArduinoJson/Json/Serialization/Prettyfier.hpp


+ 1 - 1
src/ArduinoJson/JsonArray.hpp

@@ -9,7 +9,7 @@
 #include "Data/ValueSaver.hpp"
 #include "JsonVariant.hpp"
 #include "Memory/JsonBufferAllocated.hpp"
-#include "StringTraits/StringTraits.hpp"
+#include "Strings/StringTraits.hpp"
 #include "TypeTraits/EnableIf.hpp"
 #include "TypeTraits/IsArray.hpp"
 #include "TypeTraits/IsFloatingPoint.hpp"

+ 2 - 15
src/ArduinoJson/JsonError.hpp

@@ -42,15 +42,7 @@ class JsonError {
   }
 
   const char* c_str() const {
-    return to_string(_code);
-  }
-
-  friend const char* to_string(const JsonError err) {
-    return to_string(err._code);
-  }
-
-  friend const char* to_string(JsonError::Code code) {
-    switch (code) {
+    switch (_code) {
       case Ok:
         return "Ok";
       case OpeningBraceExpected:
@@ -78,12 +70,7 @@ class JsonError {
 
 #if ARDUINOJSON_ENABLE_STD_STREAM
 inline std::ostream& operator<<(std::ostream& s, const JsonError& e) {
-  s << to_string(e);
-  return s;
-}
-
-inline std::ostream& operator<<(std::ostream& s, JsonError::Code e) {
-  s << to_string(e);
+  s << e.c_str();
   return s;
 }
 #endif

+ 1 - 1
src/ArduinoJson/JsonObject.hpp

@@ -9,7 +9,7 @@
 #include "Data/ValueSaver.hpp"
 #include "JsonPair.hpp"
 #include "Memory/JsonBufferAllocated.hpp"
-#include "StringTraits/StringTraits.hpp"
+#include "Strings/StringTraits.hpp"
 #include "TypeTraits/EnableIf.hpp"
 #include "TypeTraits/IsArray.hpp"
 #include "TypeTraits/IsFloatingPoint.hpp"

+ 3 - 3
src/ArduinoJson/JsonVariantComparisons.hpp

@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "StringTraits/StringTraits.hpp"
+#include "Strings/StringTraits.hpp"
 #include "TypeTraits/EnableIf.hpp"
 #include "TypeTraits/IsVariant.hpp"
 
@@ -134,5 +134,5 @@ class JsonVariantComparisons {
     return false;
   }
 };
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 4 - 4
src/ArduinoJson/JsonVariantImpl.hpp

@@ -8,10 +8,10 @@
 #include "JsonArray.hpp"
 #include "JsonObject.hpp"
 #include "JsonVariant.hpp"
-#include "Polyfills/isFloat.hpp"
-#include "Polyfills/isInteger.hpp"
-#include "Polyfills/parseFloat.hpp"
-#include "Polyfills/parseInteger.hpp"
+#include "Text/isFloat.hpp"
+#include "Text/isInteger.hpp"
+#include "Text/parseFloat.hpp"
+#include "Text/parseInteger.hpp"
 
 #include <string.h>  // for strcmp
 

+ 3 - 3
src/ArduinoJson/JsonVariantSubscripts.hpp

@@ -6,7 +6,7 @@
 
 #include "Data/JsonVariantAs.hpp"
 #include "Polyfills/attributes.hpp"
-#include "StringTraits/StringTraits.hpp"
+#include "Strings/StringTraits.hpp"
 #include "TypeTraits/EnableIf.hpp"
 
 namespace ArduinoJson {
@@ -82,5 +82,5 @@ class JsonVariantSubscripts {
     return static_cast<const TImpl *>(this);
   }
 };
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 328 - 0
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

@@ -0,0 +1,328 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonVariant.hpp"
+#include "../Memory/JsonBuffer.hpp"
+#include "../Strings/StringWriter.hpp"
+#include "../TypeTraits/IsConst.hpp"
+#include "./MsgPackError.hpp"
+#include "./endianess.hpp"
+#include "./ieee754.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Parse JSON string to create JsonArrays and JsonObjects
+// This internal class is not indended to be used directly.
+// Instead, use JsonBuffer.parseArray() or .parseObject()
+template <typename TReader, typename TWriter>
+class MsgPackDeserializer {
+ public:
+  MsgPackDeserializer(JsonBuffer *buffer, TReader reader, TWriter writer,
+                      uint8_t nestingLimit)
+      : _buffer(buffer),
+        _reader(reader),
+        _writer(writer),
+        _nestingLimit(nestingLimit) {}
+
+  MsgPackError parse(JsonArray &array) {
+    uint8_t c = readOne();
+    size_t n;
+
+    if ((c & 0xF0) == 0x90) {
+      n = c & 0x0F;
+    } else if (c == 0xdc) {
+      n = readInteger<uint16_t>();
+    } else if (c == 0xdd) {
+      n = readInteger<uint32_t>();
+    } else {
+      return MsgPackError::NotAnArray;
+    }
+
+    return readArray(array, n);
+  }
+
+  MsgPackError parse(JsonObject &object) {
+    uint8_t c = readOne();
+    size_t n;
+
+    if ((c & 0xf0) == 0x80) {
+      n = c & 0x0f;
+    } else if (c == 0xde) {
+      n = readInteger<uint16_t>();
+    } else if (c == 0xdf) {
+      n = readInteger<uint32_t>();
+    } else {
+      return MsgPackError::NotAnObject;
+    }
+
+    return readObject(object, n);
+  }
+
+  MsgPackError parse(JsonVariant &variant) {
+    uint8_t c = readOne();
+
+    if ((c & 0x80) == 0) {
+      variant = c;
+      return MsgPackError::Ok;
+    }
+
+    if ((c & 0xe0) == 0xe0) {
+      variant = static_cast<int8_t>(c);
+      return MsgPackError::Ok;
+    }
+
+    if ((c & 0xe0) == 0xa0) {
+      return readString(variant, c & 0x1f);
+    }
+
+    if ((c & 0xf0) == 0x90) return readArray(variant, c & 0x0F);
+
+    if ((c & 0xf0) == 0x80) return readObject(variant, c & 0x0F);
+
+    switch (c) {
+      case 0xc0:
+        variant = static_cast<char *>(0);
+        return MsgPackError::Ok;
+
+      case 0xc2:
+        variant = false;
+        return MsgPackError::Ok;
+
+      case 0xc3:
+        variant = true;
+        return MsgPackError::Ok;
+
+      case 0xcc:
+        variant = readInteger<uint8_t>();
+        return MsgPackError::Ok;
+
+      case 0xcd:
+        variant = readInteger<uint16_t>();
+        return MsgPackError::Ok;
+
+      case 0xce:
+        variant = readInteger<uint32_t>();
+        return MsgPackError::Ok;
+
+      case 0xcf:
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+        variant = readInteger<uint64_t>();
+#else
+        readInteger<uint32_t>();
+        variant = readInteger<uint32_t>();
+#endif
+        return MsgPackError::Ok;
+
+      case 0xd0:
+        variant = readInteger<int8_t>();
+        return MsgPackError::Ok;
+
+      case 0xd1:
+        variant = readInteger<int16_t>();
+        return MsgPackError::Ok;
+
+      case 0xd2:
+        variant = readInteger<int32_t>();
+        return MsgPackError::Ok;
+
+      case 0xd3:
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+        variant = readInteger<int64_t>();
+#else
+        readInteger<int32_t>();
+        variant = readInteger<int32_t>();
+#endif
+        return MsgPackError::Ok;
+
+      case 0xca:
+        variant = readFloat<float>();
+        return MsgPackError::Ok;
+
+      case 0xcb:
+        variant = readDouble<double>();
+        return MsgPackError::Ok;
+
+      case 0xd9: {
+        uint8_t n = readInteger<uint8_t>();
+        return readString(variant, n);
+      }
+
+      case 0xda: {
+        uint16_t n = readInteger<uint16_t>();
+        return readString(variant, n);
+      }
+
+      case 0xdb: {
+        uint32_t n = readInteger<uint32_t>();
+        return readString(variant, n);
+      }
+
+      case 0xdc:
+        return readArray(variant, readInteger<uint16_t>());
+
+      case 0xdd:
+        return readArray(variant, readInteger<uint32_t>());
+
+      case 0xde:
+        return readObject(variant, readInteger<uint16_t>());
+
+      case 0xdf:
+        return readObject(variant, readInteger<uint32_t>());
+
+      default:
+        return MsgPackError::NotSupported;
+    }
+  }
+
+ private:
+  // Prevent VS warning "assignment operator could not be generated"
+  MsgPackDeserializer &operator=(const MsgPackDeserializer &);
+
+  uint8_t readOne() {
+    char c = _reader.current();
+    _reader.move();
+    return static_cast<uint8_t>(c);
+  }
+
+  void read(uint8_t *p, size_t n) {
+    for (size_t i = 0; i < n; i++) p[i] = readOne();
+  }
+
+  template <typename T>
+  void read(T &value) {
+    read(reinterpret_cast<uint8_t *>(&value), sizeof(value));
+  }
+
+  template <typename T>
+  T readInteger() {
+    T value;
+    read(value);
+    fixEndianess(value);
+    return value;
+  }
+
+  template <typename T>
+  typename EnableIf<sizeof(T) == 4, T>::type readFloat() {
+    T value;
+    read(value);
+    fixEndianess(value);
+    return value;
+  }
+
+  template <typename T>
+  typename EnableIf<sizeof(T) == 8, T>::type readDouble() {
+    T value;
+    read(value);
+    fixEndianess(value);
+    return value;
+  }
+
+  template <typename T>
+  typename EnableIf<sizeof(T) == 4, T>::type readDouble() {
+    uint8_t i[8];  // input is 8 bytes
+    T value;       // output is 4 bytes
+    uint8_t *o = reinterpret_cast<uint8_t *>(&value);
+    read(i, 8);
+    doubleToFloat(i, o);
+    fixEndianess(value);
+    return value;
+  }
+
+  MsgPackError readString(JsonVariant &variant, size_t n) {
+    typename RemoveReference<TWriter>::type::String str = _writer.startString();
+    for (; n; --n) str.append(static_cast<char>(readOne()));
+    const char *s = str.c_str();
+    if (s == NULL) return MsgPackError::NoMemory;
+    variant = s;
+    return MsgPackError::Ok;
+  }
+
+  MsgPackError readArray(JsonVariant &variant, size_t n) {
+    JsonArray *array = new (_buffer) JsonArray(_buffer);
+    if (!array) return MsgPackError::NoMemory;
+    variant = array;
+    return readArray(*array, n);
+  }
+
+  MsgPackError readArray(JsonArray &array, size_t n) {
+    if (_nestingLimit == 0) return MsgPackError::TooDeep;
+    --_nestingLimit;
+    for (; n; --n) {
+      JsonVariant variant;
+      MsgPackError err = parse(variant);
+      if (err) return err;
+      if (!array.add(variant)) return MsgPackError::NoMemory;
+    }
+    ++_nestingLimit;
+    return MsgPackError::Ok;
+  }
+
+  MsgPackError readObject(JsonVariant &variant, size_t n) {
+    JsonObject *object = new (_buffer) JsonObject(_buffer);
+    if (!object) return MsgPackError::NoMemory;
+    variant = object;
+    return readObject(*object, n);
+  }
+
+  MsgPackError readObject(JsonObject &object, size_t n) {
+    if (_nestingLimit == 0) return MsgPackError::TooDeep;
+    --_nestingLimit;
+    for (; n; --n) {
+      MsgPackError err;
+      JsonVariant variant;
+      err = parse(variant);
+      if (err) return err;
+      const char *key = variant.as<char *>();
+      if (!key) return MsgPackError::NotSupported;
+      err = parse(variant);
+      if (err) return err;
+      if (!object.set(key, variant)) return MsgPackError::NoMemory;
+    }
+    ++_nestingLimit;
+    return MsgPackError::Ok;
+  }
+
+  JsonBuffer *_buffer;
+  TReader _reader;
+  TWriter _writer;
+  uint8_t _nestingLimit;
+};
+
+template <typename TJsonBuffer, typename TString, typename Enable = void>
+struct MsgPackDeserializerBuilder {
+  typedef typename StringTraits<TString>::Reader InputReader;
+  typedef MsgPackDeserializer<InputReader, TJsonBuffer &> TParser;
+
+  static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json,
+                                         uint8_t nestingLimit) {
+    return TParser(buffer, InputReader(json), *buffer, nestingLimit);
+  }
+};
+
+template <typename TJsonBuffer, typename TChar>
+struct MsgPackDeserializerBuilder<
+    TJsonBuffer, TChar *, typename EnableIf<!IsConst<TChar>::value>::type> {
+  typedef typename StringTraits<TChar *>::Reader TReader;
+  typedef StringWriter<TChar> TWriter;
+  typedef MsgPackDeserializer<TReader, TWriter> TParser;
+
+  static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TChar *json,
+                                         uint8_t nestingLimit) {
+    return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
+  }
+};
+
+template <typename TJsonBuffer, typename TString>
+inline typename MsgPackDeserializerBuilder<TJsonBuffer, TString>::TParser
+makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json,
+                        uint8_t nestingLimit) {
+  return MsgPackDeserializerBuilder<
+      TJsonBuffer, TString>::makeMsgPackDeserializer(buffer, json,
+                                                     nestingLimit);
+}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 67 - 0
src/ArduinoJson/MsgPack/MsgPackError.hpp

@@ -0,0 +1,67 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+
+class MsgPackError {
+ public:
+  enum Code { Ok, NotSupported, NoMemory, NotAnArray, NotAnObject, TooDeep };
+
+  MsgPackError() {}
+
+  MsgPackError(Code code) : _code(code) {}
+
+  operator bool() const {
+    return _code != Ok;
+  }
+
+  friend bool operator==(const MsgPackError& err, Code code) {
+    return err._code == code;
+  }
+
+  friend bool operator==(Code code, const MsgPackError& err) {
+    return err._code == code;
+  }
+
+  friend bool operator!=(const MsgPackError& err, Code code) {
+    return err._code != code;
+  }
+
+  friend bool operator!=(Code code, const MsgPackError& err) {
+    return err._code != code;
+  }
+
+  const char* c_str() const {
+    switch (_code) {
+      case Ok:
+        return "Ok";
+      case NotSupported:
+        return "NotSupported";
+      case NoMemory:
+        return "NoMemory";
+      case NotAnArray:
+        return "NotAnArray";
+      case NotAnObject:
+        return "NotAnObject";
+      case TooDeep:
+        return "TooDeep";
+      default:
+        return "???";
+    }
+  }
+
+ private:
+  Code _code;
+};
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+inline std::ostream& operator<<(std::ostream& os, const MsgPackError& err) {
+  os << err.c_str();
+  return os;
+}
+#endif
+
+}  // namespace ArduinoJson

+ 47 - 0
src/ArduinoJson/MsgPack/endianess.hpp

@@ -0,0 +1,47 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <class T, T v>
+struct integral_constant {};
+
+template <typename T>
+inline void swap(T& a, T& b) {
+  T t(a);
+  a = b;
+  b = t;
+}
+
+inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) {
+  swap(p[0], p[7]);
+  swap(p[1], p[6]);
+  swap(p[2], p[5]);
+  swap(p[3], p[4]);
+}
+
+inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) {
+  swap(p[0], p[3]);
+  swap(p[1], p[2]);
+}
+
+inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) {
+  swap(p[0], p[1]);
+}
+
+inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {}
+
+template <typename T>
+inline void fixEndianess(T& value) {
+#if ARDUINOJSON_LITTLE_ENDIAN
+  fixEndianess(reinterpret_cast<uint8_t*>(&value),
+               integral_constant<size_t, sizeof(T)>());
+#endif
+}
+
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 18 - 0
src/ArduinoJson/MsgPack/ieee754.hpp

@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) {
+  f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5));
+  f[1] = uint8_t((d[1] << 3) | (d[2] >> 5));
+  f[2] = uint8_t((d[2] << 3) | (d[3] >> 5));
+  f[3] = uint8_t((d[3] << 3) | (d[4] >> 5));
+}
+
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 0 - 0
src/ArduinoJson/Serialization/DummyPrint.hpp → src/ArduinoJson/Print/DummyPrint.hpp


+ 3 - 3
src/ArduinoJson/Serialization/DynamicStringBuilder.hpp → src/ArduinoJson/Print/DynamicStringBuilder.hpp

@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "../StringTraits/StringTraits.hpp"
+#include "../Strings/StringTraits.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -31,5 +31,5 @@ class DynamicStringBuilder {
 
   TString &_str;
 };
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 0 - 0
src/ArduinoJson/Serialization/StaticStringBuilder.hpp → src/ArduinoJson/Print/StaticStringBuilder.hpp


+ 0 - 0
src/ArduinoJson/Serialization/StreamPrintAdapter.hpp → src/ArduinoJson/Print/StreamPrintAdapter.hpp


+ 0 - 0
src/ArduinoJson/StringTraits/ArduinoStream.hpp → src/ArduinoJson/Strings/ArduinoStream.hpp


+ 0 - 0
src/ArduinoJson/StringTraits/CharPointer.hpp → src/ArduinoJson/Strings/CharPointer.hpp


+ 0 - 0
src/ArduinoJson/StringTraits/FlashString.hpp → src/ArduinoJson/Strings/FlashString.hpp


+ 0 - 0
src/ArduinoJson/StringTraits/StdStream.hpp → src/ArduinoJson/Strings/StdStream.hpp


+ 0 - 0
src/ArduinoJson/StringTraits/StdString.hpp → src/ArduinoJson/Strings/StdString.hpp


+ 0 - 0
src/ArduinoJson/StringTraits/StringTraits.hpp → src/ArduinoJson/Strings/StringTraits.hpp


+ 0 - 0
src/ArduinoJson/Deserialization/StringWriter.hpp → src/ArduinoJson/Strings/StringWriter.hpp


+ 3 - 3
src/ArduinoJson/Polyfills/isFloat.hpp → src/ArduinoJson/Text/isFloat.hpp

@@ -5,7 +5,7 @@
 #pragma once
 
 #include <string.h>  // for strcmp
-#include "./ctype.hpp"
+#include "../Polyfills/ctype.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -34,5 +34,5 @@ inline bool isFloat(const char* s) {
 
   return *s == '\0';
 }
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 3 - 3
src/ArduinoJson/Polyfills/isInteger.hpp → src/ArduinoJson/Text/isInteger.hpp

@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "./ctype.hpp"
+#include "../Polyfills/ctype.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -15,5 +15,5 @@ inline bool isInteger(const char* s) {
   while (isdigit(*s)) s++;
   return *s == '\0';
 }
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 4 - 4
src/ArduinoJson/Polyfills/parseFloat.hpp → src/ArduinoJson/Text/parseFloat.hpp

@@ -4,9 +4,9 @@
 
 #pragma once
 
+#include "../Polyfills/ctype.hpp"
+#include "../Polyfills/math.hpp"
 #include "../TypeTraits/FloatTraits.hpp"
-#include "./ctype.hpp"
-#include "./math.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -86,5 +86,5 @@ inline T parseFloat(const char* s) {
 
   return negative_result ? -result : result;
 }
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 3 - 3
src/ArduinoJson/Polyfills/parseInteger.hpp → src/ArduinoJson/Text/parseInteger.hpp

@@ -7,7 +7,7 @@
 #include <stdlib.h>
 
 #include "../Configuration.hpp"
-#include "./ctype.hpp"
+#include "../Polyfills/ctype.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -37,5 +37,5 @@ T parseInteger(const char *s) {
 
   return negative_result ? T(~result + 1) : result;
 }
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 1 - 1
src/ArduinoJson/deserializeJson.hpp

@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "Deserialization/JsonParser.hpp"
+#include "Json/Deserialization/JsonParser.hpp"
 
 namespace ArduinoJson {
 // JsonError deserializeJson(TDestination& destination, TString json);

+ 49 - 0
src/ArduinoJson/deserializeMsgPack.hpp

@@ -0,0 +1,49 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "MsgPack/MsgPackDeserializer.hpp"
+
+namespace ArduinoJson {
+// MsgPackError deserializeMsgPack(TDestination& destination, TString json);
+// TDestination = JsonArray, JsonObject, JsonVariant
+// TString = const std::string&, const String&
+template <typename TDestination, typename TString>
+typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                             MsgPackError>::type
+deserializeMsgPack(TDestination &destination, const TString &json,
+                   uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+  destination.clear();
+  return Internals::makeMsgPackDeserializer(&destination.buffer(), json,
+                                            nestingLimit)
+      .parse(destination);
+}
+//
+// MsgPackError deserializeMsgPack(TDestination& destination, TString json);
+// TDestination = JsonArray, JsonObject, JsonVariant
+// TString = const char*, const char[N], const FlashStringHelper*
+template <typename TDestination, typename TString>
+MsgPackError deserializeMsgPack(
+    TDestination &destination, TString *json,
+    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+  destination.clear();
+  return Internals::makeMsgPackDeserializer(&destination.buffer(), json,
+                                            nestingLimit)
+      .parse(destination);
+}
+//
+// MsgPackError deserializeMsgPack(TDestination& destination, TString json);
+// TDestination = JsonArray, JsonObject, JsonVariant
+// TString = std::istream&, Stream&
+template <typename TDestination, typename TString>
+MsgPackError deserializeMsgPack(
+    TDestination &destination, TString &json,
+    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+  destination.clear();
+  return Internals::makeMsgPackDeserializer(&destination.buffer(), json,
+                                            nestingLimit)
+      .parse(destination);
+}
+}  // namespace ArduinoJson

+ 1 - 0
test/CMakeLists.txt

@@ -73,5 +73,6 @@ add_subdirectory(JsonSerializer)
 add_subdirectory(JsonVariant)
 add_subdirectory(JsonWriter)
 add_subdirectory(Misc)
+add_subdirectory(MsgPack)
 add_subdirectory(Polyfills)
 add_subdirectory(StaticJsonBuffer)

+ 2 - 2
test/JsonWriter/writeFloat.cpp

@@ -6,8 +6,8 @@
 #include <limits>
 #include <string>
 
-#include <ArduinoJson/Serialization/DynamicStringBuilder.hpp>
-#include <ArduinoJson/Serialization/JsonWriter.hpp>
+#include <ArduinoJson/Json/Serialization/JsonWriter.hpp>
+#include <ArduinoJson/Print/DynamicStringBuilder.hpp>
 
 using namespace ArduinoJson::Internals;
 

+ 2 - 2
test/JsonWriter/writeString.cpp

@@ -4,8 +4,8 @@
 
 #include <catch.hpp>
 
-#include <ArduinoJson/Serialization/JsonWriter.hpp>
-#include <ArduinoJson/Serialization/StaticStringBuilder.hpp>
+#include <ArduinoJson/Json/Serialization/JsonWriter.hpp>
+#include <ArduinoJson/Print/StaticStringBuilder.hpp>
 
 using namespace ArduinoJson::Internals;
 

+ 1 - 1
test/Misc/FloatParts.cpp

@@ -2,7 +2,7 @@
 // Copyright Benoit Blanchon 2014-2018
 // MIT License
 
-#include <ArduinoJson/Serialization/FloatParts.hpp>
+#include <ArduinoJson/Json/Serialization/FloatParts.hpp>
 #include <catch.hpp>
 
 using namespace ArduinoJson::Internals;

+ 16 - 0
test/MsgPack/CMakeLists.txt

@@ -0,0 +1,16 @@
+# ArduinoJson - arduinojson.org
+# Copyright Benoit Blanchon 2014-2018
+# MIT License
+
+add_executable(MsgPackTests
+	deserializationErrors.cpp
+	deserializeArray.cpp
+	deserializeObject.cpp
+	deserializeVariant.cpp
+	deserializeStaticVariant.cpp
+	doubleToFloat.cpp
+	MsgPackError.cpp
+)
+
+target_link_libraries(MsgPackTests catch)
+add_test(MsgPack MsgPackTests)

+ 40 - 0
test/MsgPack/MsgPackError.cpp

@@ -0,0 +1,40 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+void testStringification(MsgPackError error, std::string expected) {
+  REQUIRE(error.c_str() == expected);
+}
+
+void testBoolification(MsgPackError error, bool expected) {
+  CHECK(error == expected);
+}
+
+#define TEST_STRINGIFICATION(symbol) \
+  testStringification(MsgPackError::symbol, #symbol)
+
+#define TEST_BOOLIFICATION(symbol, expected) \
+  testBoolification(MsgPackError::symbol, expected)
+
+TEST_CASE("MsgPackError") {
+  SECTION("c_str()") {
+    TEST_STRINGIFICATION(Ok);
+    TEST_STRINGIFICATION(NotSupported);
+    TEST_STRINGIFICATION(NoMemory);
+    TEST_STRINGIFICATION(NotAnArray);
+    TEST_STRINGIFICATION(NotAnObject);
+    TEST_STRINGIFICATION(TooDeep);
+  }
+
+  SECTION("as boolean") {
+    TEST_BOOLIFICATION(Ok, false);
+    TEST_BOOLIFICATION(NotSupported, true);
+    TEST_BOOLIFICATION(NoMemory, true);
+    TEST_BOOLIFICATION(NotAnArray, true);
+    TEST_BOOLIFICATION(NotAnObject, true);
+    TEST_BOOLIFICATION(TooDeep, true);
+  }
+}

+ 58 - 0
test/MsgPack/deserializationErrors.cpp

@@ -0,0 +1,58 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+static void check(const char* input, MsgPackError expected,
+                  uint8_t nestingLimit = 10) {
+  DynamicJsonVariant variant;
+
+  MsgPackError error = deserializeMsgPack(variant, input, nestingLimit);
+
+  REQUIRE(error == expected);
+}
+
+TEST_CASE("Errors returned by deserializeMsgPack()") {
+  SECTION("unsupported") {
+    check("\xc4", MsgPackError::NotSupported);  // bin 8
+    check("\xc5", MsgPackError::NotSupported);  // bin 16
+    check("\xc6", MsgPackError::NotSupported);  // bin 32
+    check("\xc7", MsgPackError::NotSupported);  // ext 8
+    check("\xc8", MsgPackError::NotSupported);  // ext 16
+    check("\xc9", MsgPackError::NotSupported);  // ext 32
+    check("\xd4", MsgPackError::NotSupported);  // fixext 1
+    check("\xd5", MsgPackError::NotSupported);  // fixext 2
+    check("\xd6", MsgPackError::NotSupported);  // fixext 4
+    check("\xd7", MsgPackError::NotSupported);  // fixext 8
+    check("\xd8", MsgPackError::NotSupported);  // fixext 16
+  }
+
+  SECTION("unsupported in array") {
+    check("\x91\xc4", MsgPackError::NotSupported);
+  }
+
+  SECTION("unsupported in map") {
+    check("\x81\xc4\x00\xA1H", MsgPackError::NotSupported);
+    check("\x81\xA1H\xc4\x00", MsgPackError::NotSupported);
+  }
+
+  SECTION("integer as key") {
+    check("\x81\x01\xA1H", MsgPackError::NotSupported);
+  }
+
+  SECTION("object too deep") {
+    check("\x80", MsgPackError::TooDeep, 0);           // {}
+    check("\x80", MsgPackError::Ok, 1);                // {}
+    check("\x81\xA1H\x80", MsgPackError::TooDeep, 1);  // {H:{}}
+    check("\x81\xA1H\x80", MsgPackError::Ok, 2);       // {H:{}}
+  }
+
+  SECTION("array too deep") {
+    check("\x90", MsgPackError::TooDeep, 0);      // []
+    check("\x90", MsgPackError::Ok, 1);           // []
+    check("\x91\x90", MsgPackError::TooDeep, 1);  // [[]]
+    check("\x91\x90", MsgPackError::Ok, 2);       // [[]]
+  }
+}

+ 85 - 0
test/MsgPack/deserializeArray.cpp

@@ -0,0 +1,85 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+TEST_CASE("deserializeMsgPack(JsonArray&)") {
+  DynamicJsonArray array;
+
+  SECTION("not an array") {
+    const char* input = "\xA0";
+
+    MsgPackError error = deserializeMsgPack(array, input);
+
+    REQUIRE(error == MsgPackError::NotAnArray);
+  }
+
+  SECTION("fixarray") {
+    SECTION("empty") {
+      const char* input = "\x90";
+
+      MsgPackError error = deserializeMsgPack(array, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(array.size() == 0);
+    }
+
+    SECTION("two integers") {
+      const char* input = "\x92\x01\x02";
+
+      MsgPackError error = deserializeMsgPack(array, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(array.size() == 2);
+      REQUIRE(array[0] == 1);
+      REQUIRE(array[1] == 2);
+    }
+  }
+
+  SECTION("array 16") {
+    SECTION("empty") {
+      const char* input = "\xDC\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(array, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(array.size() == 0);
+    }
+
+    SECTION("two strings") {
+      const char* input = "\xDC\x00\x02\xA5hello\xA5world";
+
+      MsgPackError error = deserializeMsgPack(array, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(array.size() == 2);
+      REQUIRE(array[0] == "hello");
+      REQUIRE(array[1] == "world");
+    }
+  }
+
+  SECTION("array 32") {
+    SECTION("empty") {
+      const char* input = "\xDD\x00\x00\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(array, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(array.size() == 0);
+    }
+
+    SECTION("two floats") {
+      const char* input =
+          "\xDD\x00\x00\x00\x02\xCA\x00\x00\x00\x00\xCA\x40\x48\xF5\xC3";
+
+      MsgPackError error = deserializeMsgPack(array, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(array.size() == 2);
+      REQUIRE(array[0] == 0.0f);
+      REQUIRE(array[1] == 3.14f);
+    }
+  }
+}

+ 86 - 0
test/MsgPack/deserializeObject.cpp

@@ -0,0 +1,86 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+TEST_CASE("deserializeMsgPack(JsonObject&)") {
+  DynamicJsonObject object;
+
+  SECTION("not an object") {
+    const char* input = "\xA0";
+
+    MsgPackError error = deserializeMsgPack(object, input);
+
+    REQUIRE(error == MsgPackError::NotAnObject);
+  }
+
+  SECTION("fixmap") {
+    SECTION("empty") {
+      const char* input = "\x80";
+
+      MsgPackError error = deserializeMsgPack(object, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(object.size() == 0);
+    }
+
+    SECTION("two integers") {
+      const char* input = "\x82\xA3one\x01\xA3two\x02";
+
+      MsgPackError error = deserializeMsgPack(object, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(object.size() == 2);
+      REQUIRE(object["one"] == 1);
+      REQUIRE(object["two"] == 2);
+    }
+  }
+
+  SECTION("map 16") {
+    SECTION("empty") {
+      const char* input = "\xDE\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(object, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(object.size() == 0);
+    }
+
+    SECTION("two strings") {
+      const char* input = "\xDE\x00\x02\xA1H\xA5hello\xA1W\xA5world";
+
+      MsgPackError error = deserializeMsgPack(object, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(object.size() == 2);
+      REQUIRE(object["H"] == "hello");
+      REQUIRE(object["W"] == "world");
+    }
+  }
+
+  SECTION("map 32") {
+    SECTION("empty") {
+      const char* input = "\xDF\x00\x00\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(object, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(object.size() == 0);
+    }
+
+    SECTION("two floats") {
+      const char* input =
+          "\xDF\x00\x00\x00\x02\xA4zero\xCA\x00\x00\x00\x00\xA2pi\xCA\x40\x48"
+          "\xF5\xC3";
+
+      MsgPackError error = deserializeMsgPack(object, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(object.size() == 2);
+      REQUIRE(object["zero"] == 0.0f);
+      REQUIRE(object["pi"] == 3.14f);
+    }
+  }
+}

+ 131 - 0
test/MsgPack/deserializeStaticVariant.cpp

@@ -0,0 +1,131 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+static const size_t epsilon = sizeof(void*);
+
+template <size_t Capacity>
+static void check(const char* input, MsgPackError expected) {
+  StaticJsonVariant<Capacity> variant;
+
+  MsgPackError error = deserializeMsgPack(variant, input);
+
+  REQUIRE(error == expected);
+}
+
+TEST_CASE("deserializeMsgPack(StaticJsonVariant&)") {
+  SECTION("single values always fit") {
+    check<0>("\xc0", MsgPackError::Ok);                  // nil
+    check<0>("\xc2", MsgPackError::Ok);                  // false
+    check<0>("\xc3", MsgPackError::Ok);                  // true
+    check<0>("\xcc\x00", MsgPackError::Ok);              // uint 8
+    check<0>("\xcd\x30\x39", MsgPackError::Ok);          // uint 16
+    check<0>("\xCE\x12\x34\x56\x78", MsgPackError::Ok);  // uint 32
+  }
+
+  SECTION("fixstr") {
+    check<0>("\xA0", MsgPackError::Ok);
+    check<0>("\xA1H", MsgPackError::NoMemory);
+    check<4>("\xA1H", MsgPackError::Ok);
+    check<4>("\xA5Hello", MsgPackError::NoMemory);
+  }
+
+  SECTION("str 8") {
+    check<0>("\xD9\x00", MsgPackError::Ok);
+    check<0>("\xD9\x01H", MsgPackError::NoMemory);
+    check<4>("\xD9\x01H", MsgPackError::Ok);
+    check<4>("\xD9\x05Hello", MsgPackError::NoMemory);
+  }
+
+  SECTION("str 16") {
+    check<0>("\xDA\x00\x00", MsgPackError::Ok);
+    check<0>("\xDA\x00\x01H", MsgPackError::NoMemory);
+    check<4>("\xDA\x00\x01H", MsgPackError::Ok);
+    check<4>("\xDA\x00\x05Hello", MsgPackError::NoMemory);
+  }
+
+  SECTION("str 32") {
+    check<0>("\xDB\x00\x00\x00\x00", MsgPackError::Ok);
+    check<0>("\xDB\x00\x00\x00\x01H", MsgPackError::NoMemory);
+    check<4>("\xDB\x00\x00\x00\x01H", MsgPackError::Ok);
+    check<4>("\xDB\x00\x00\x00\x05Hello", MsgPackError::NoMemory);
+  }
+
+  SECTION("fixarray") {
+    check<JSON_ARRAY_SIZE(0)>("\x90", MsgPackError::Ok);                // []
+    check<JSON_ARRAY_SIZE(0)>("\x91\x01", MsgPackError::NoMemory);      // [1]
+    check<JSON_ARRAY_SIZE(1)>("\x91\x01", MsgPackError::Ok);            // [1]
+    check<JSON_ARRAY_SIZE(1)>("\x92\x01\x02", MsgPackError::NoMemory);  // [1,2]
+  }
+
+  SECTION("array 16") {
+    check<JSON_ARRAY_SIZE(0)>("\xDC\x00\x00", MsgPackError::Ok);
+    check<JSON_ARRAY_SIZE(0)>("\xDC\x00\x01\x01", MsgPackError::NoMemory);
+    check<JSON_ARRAY_SIZE(1)>("\xDC\x00\x01\x01", MsgPackError::Ok);
+    check<JSON_ARRAY_SIZE(1)>("\xDC\x00\x02\x01\x02", MsgPackError::NoMemory);
+  }
+
+  SECTION("array 32") {
+    check<JSON_ARRAY_SIZE(0)>("\xDD\x00\x00\x00\x00", MsgPackError::Ok);
+    check<JSON_ARRAY_SIZE(0)>("\xDD\x00\x00\x00\x01\x01",
+                              MsgPackError::NoMemory);
+    check<JSON_ARRAY_SIZE(1)>("\xDD\x00\x00\x00\x01\x01", MsgPackError::Ok);
+    check<JSON_ARRAY_SIZE(1)>("\xDD\x00\x00\x00\x02\x01\x02",
+                              MsgPackError::NoMemory);
+  }
+
+  SECTION("fixmap") {
+    SECTION("{}") {
+      check<JSON_OBJECT_SIZE(0)>("\x80", MsgPackError::Ok);
+    }
+    SECTION("{H:1}") {
+      check<JSON_OBJECT_SIZE(0)>("\x81\xA1H\x01",
+                                 MsgPackError::NoMemory);
+      check<JSON_OBJECT_SIZE(1) + epsilon>("\x81\xA1H\x01", MsgPackError::Ok);
+    }
+    SECTION("{H:1,W:2}") {
+      check<JSON_OBJECT_SIZE(1) + epsilon>("\x82\xA1H\x01\xA1W\x02",
+                                     MsgPackError::NoMemory);
+      check<JSON_OBJECT_SIZE(2) + 2*epsilon>("\x82\xA1H\x01\xA1W\x02",
+                                     MsgPackError::Ok);
+    }
+  }
+
+  SECTION("map 16") {
+    SECTION("{}") {
+      check<JSON_OBJECT_SIZE(0)>("\xDE\x00\x00", MsgPackError::Ok);
+    }
+    SECTION("{H:1}") {
+      check<JSON_OBJECT_SIZE(0)>("\xDE\x00\x01\xA1H\x01",
+                                 MsgPackError::NoMemory);
+      check<JSON_OBJECT_SIZE(1) + epsilon>("\xDE\x00\x01\xA1H\x01", MsgPackError::Ok);
+    }
+    SECTION("{H:1,W:2}") {
+      check<JSON_OBJECT_SIZE(1) + epsilon>("\xDE\x00\x02\xA1H\x01\xA1W\x02",
+                                     MsgPackError::NoMemory);
+      check<JSON_OBJECT_SIZE(2) + 2*epsilon>("\xDE\x00\x02\xA1H\x01\xA1W\x02",
+                                     MsgPackError::Ok);
+    }
+  }
+
+  SECTION("map 32") {
+    SECTION("{}") {
+      check<JSON_OBJECT_SIZE(0)>("\xDF\x00\x00\x00\x00", MsgPackError::Ok);
+    }
+    SECTION("{H:1}") {
+      check<JSON_OBJECT_SIZE(0)>("\xDF\x00\x00\x00\x01\xA1H\x01",
+                                 MsgPackError::NoMemory);
+      check<JSON_OBJECT_SIZE(1) + epsilon>("\xDF\x00\x00\x00\x01\xA1H\x01",
+                                     MsgPackError::Ok);
+    }
+    SECTION("{H:1,W:2}") {
+      check<JSON_OBJECT_SIZE(1) + epsilon>("\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
+                                     MsgPackError::NoMemory);
+      check<JSON_OBJECT_SIZE(2) + 2*epsilon>("\xDF\x00\x00\x00\x02\xA1H\x01\xA1W\x02",
+                                     MsgPackError::Ok);
+    }
+  }
+}

+ 277 - 0
test/MsgPack/deserializeVariant.cpp

@@ -0,0 +1,277 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+template <typename T, typename U>
+static void check(const char* input, U expected) {
+  DynamicJsonVariant variant;
+
+  MsgPackError error = deserializeMsgPack(variant, input);
+
+  REQUIRE(error == MsgPackError::Ok);
+  REQUIRE(variant.is<T>());
+  REQUIRE(variant.as<T>() == expected);
+}
+
+TEST_CASE("deserializeMsgPack(JsonVariant&)") {
+  SECTION("nil") {
+    const char* nil = 0;  // ArduinoJson uses a string for null
+    check<const char*>("\xc0", nil);
+  }
+
+  SECTION("bool") {
+    check<bool>("\xc2", false);
+    check<bool>("\xc3", true);
+  }
+
+  SECTION("positive fixint") {
+    check<int>("\x00", 0);
+    check<int>("\x7F", 127);
+  }
+
+  SECTION("negative fixint") {
+    check<int>("\xe0", -32);
+    check<int>("\xff", -1);
+  }
+
+  SECTION("uint 8") {
+    check<int>("\xcc\x00", 0);
+    check<int>("\xcc\xff", 255);
+  }
+
+  SECTION("uint 16") {
+    check<int>("\xcd\x00\x00", 0);
+    check<int>("\xcd\xFF\xFF", 65535);
+    check<int>("\xcd\x30\x39", 12345);
+  }
+
+  SECTION("uint 32") {
+    check<uint32_t>("\xCE\x00\x00\x00\x00", 0x00000000U);
+    check<uint32_t>("\xCE\xFF\xFF\xFF\xFF", 0xFFFFFFFFU);
+    check<uint32_t>("\xCE\x12\x34\x56\x78", 0x12345678U);
+  }
+
+  SECTION("uint 64") {
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+    check<uint64_t>("\xCF\x00\x00\x00\x00\x00\x00\x00\x00", 0U);
+    check<uint64_t>("\xCF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
+                    0xFFFFFFFFFFFFFFFFU);
+    check<uint64_t>("\xCF\x12\x34\x56\x78\x9A\xBC\xDE\xF0",
+                    0x123456789ABCDEF0U);
+#else
+    check<uint32_t>("\xCF\x00\x00\x00\x00\x00\x00\x00\x00", 0U);
+    check<uint32_t>("\xCF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0xFFFFFFFF);
+    check<uint32_t>("\xCF\x12\x34\x56\x78\x9A\xBC\xDE\xF0", 0x9ABCDEF0);
+#endif
+  }
+
+  SECTION("int 8") {
+    check<int>("\xd0\x00", 0);
+    check<int>("\xd0\xff", -1);
+  }
+
+  SECTION("int 16") {
+    check<int>("\xD1\x00\x00", 0);
+    check<int>("\xD1\xFF\xFF", -1);
+    check<int>("\xD1\xCF\xC7", -12345);
+  }
+
+  SECTION("int 32") {
+    check<int>("\xD2\x00\x00\x00\x00", 0);
+    check<int>("\xD2\xFF\xFF\xFF\xFF", -1);
+    check<int>("\xD2\xB6\x69\xFD\x2E", -1234567890);
+  }
+
+  SECTION("int 64") {
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+    check<uint64_t>("\xD3\x00\x00\x00\x00\x00\x00\x00\x00", 0U);
+    check<uint64_t>("\xD3\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
+                    0xFFFFFFFFFFFFFFFFU);
+    check<uint64_t>("\xD3\x12\x34\x56\x78\x9A\xBC\xDE\xF0",
+                    0x123456789ABCDEF0U);
+#else
+    check<uint32_t>("\xD3\x00\x00\x00\x00\x00\x00\x00\x00", 0U);
+    check<uint32_t>("\xD3\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0xFFFFFFFF);
+    check<uint32_t>("\xD3\x12\x34\x56\x78\x9A\xBC\xDE\xF0", 0x9ABCDEF0);
+#endif
+  }
+
+  SECTION("float 32") {
+    check<double>("\xCA\x00\x00\x00\x00", 0.0f);
+    check<double>("\xCA\x40\x48\xF5\xC3", 3.14f);
+  }
+
+  SECTION("float 64") {
+    check<double>("\xCB\x00\x00\x00\x00\x00\x00\x00\x00", 0.0);
+    check<double>("\xCB\x40\x09\x21\xCA\xC0\x83\x12\x6F", 3.1415);
+  }
+
+  SECTION("fixstr") {
+    check<const char*>("\xA0", std::string(""));
+    check<const char*>("\xABhello world", std::string("hello world"));
+    check<const char*>("\xBFhello world hello world hello !",
+                       std::string("hello world hello world hello !"));
+  }
+
+  SECTION("str 8") {
+    check<const char*>("\xd9\x05hello", std::string("hello"));
+  }
+
+  SECTION("str 16") {
+    check<const char*>("\xda\x00\x05hello", std::string("hello"));
+  }
+
+  SECTION("str 32") {
+    check<const char*>("\xdb\x00\x00\x00\x05hello", std::string("hello"));
+  }
+
+  SECTION("fixarray") {
+    DynamicJsonVariant variant;
+
+    SECTION("empty") {
+      const char* input = "\x90";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 0);
+    }
+
+    SECTION("two integers") {
+      const char* input = "\x92\x01\x02";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 2);
+      REQUIRE(variant[0] == 1);
+      REQUIRE(variant[1] == 2);
+    }
+  }
+
+  SECTION("array 16") {
+    DynamicJsonVariant variant;
+
+    SECTION("empty") {
+      const char* input = "\xDC\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 0);
+    }
+
+    SECTION("two strings") {
+      const char* input = "\xDC\x00\x02\xA5hello\xA5world";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 2);
+      REQUIRE(variant[0] == "hello");
+      REQUIRE(variant[1] == "world");
+    }
+  }
+
+  SECTION("array 32") {
+    DynamicJsonVariant variant;
+
+    SECTION("empty") {
+      const char* input = "\xDD\x00\x00\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 0);
+    }
+
+    SECTION("two floats") {
+      const char* input =
+          "\xDD\x00\x00\x00\x02\xCA\x00\x00\x00\x00\xCA\x40\x48\xF5\xC3";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 2);
+      REQUIRE(variant[0] == 0.0f);
+      REQUIRE(variant[1] == 3.14f);
+    }
+  }
+
+  SECTION("fixmap") {
+    DynamicJsonVariant variant;
+
+    SECTION("empty") {
+      const char* input = "\x80";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 0);
+    }
+
+    SECTION("two integers") {
+      const char* input = "\x82\xA3one\x01\xA3two\x02";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 2);
+      REQUIRE(variant["one"] == 1);
+      REQUIRE(variant["two"] == 2);
+    }
+  }
+
+  SECTION("map 16") {
+    DynamicJsonVariant variant;
+
+    SECTION("empty") {
+      const char* input = "\xDE\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 0);
+    }
+
+    SECTION("two strings") {
+      const char* input = "\xDE\x00\x02\xA1H\xA5hello\xA1W\xA5world";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 2);
+      REQUIRE(variant["H"] == "hello");
+      REQUIRE(variant["W"] == "world");
+    }
+  }
+
+  SECTION("map 32") {
+    DynamicJsonVariant variant;
+
+    SECTION("empty") {
+      const char* input = "\xDF\x00\x00\x00\x00";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 0);
+    }
+
+    SECTION("two floats") {
+      const char* input =
+          "\xDF\x00\x00\x00\x02\xA4zero\xCA\x00\x00\x00\x00\xA2pi\xCA\x40\x48"
+          "\xF5\xC3";
+
+      MsgPackError error = deserializeMsgPack(variant, input);
+
+      REQUIRE(error == MsgPackError::Ok);
+      REQUIRE(variant.size() == 2);
+      REQUIRE(variant["zero"] == 0.0f);
+      REQUIRE(variant["pi"] == 3.14f);
+    }
+  }
+}

+ 25 - 0
test/MsgPack/doubleToFloat.cpp

@@ -0,0 +1,25 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+using namespace ArduinoJson::Internals;
+
+template <typename T>
+static void check(const char* input, T expected) {
+  T actual;
+  uint8_t* f = reinterpret_cast<uint8_t*>(&actual);
+  const uint8_t* d = reinterpret_cast<const uint8_t*>(input);
+  doubleToFloat(d, f);
+  fixEndianess(actual);
+  CHECK(actual == expected);
+}
+
+TEST_CASE("Internals::doubleToFloat()") {
+  check("\x40\x09\x21\xCA\xC0\x83\x12\x6F", 3.1415f);
+  check("\x00\x00\x00\x00\x00\x00\x00\x00", 0.0f);
+  check("\x80\x00\x00\x00\x00\x00\x00\x00", -0.0f);
+  check("\xC0\x5E\xDC\xCC\xCC\xCC\xCC\xCD", -123.45f);
+}

+ 1 - 1
test/Polyfills/isFloat.cpp

@@ -2,7 +2,7 @@
 // Copyright Benoit Blanchon 2014-2018
 // MIT License
 
-#include <ArduinoJson/Polyfills/isFloat.hpp>
+#include <ArduinoJson/Text/isFloat.hpp>
 #include <catch.hpp>
 
 using namespace ArduinoJson::Internals;

+ 1 - 1
test/Polyfills/isInteger.cpp

@@ -2,7 +2,7 @@
 // Copyright Benoit Blanchon 2014-2018
 // MIT License
 
-#include <ArduinoJson/Polyfills/isInteger.hpp>
+#include <ArduinoJson/Text/isInteger.hpp>
 #include <catch.hpp>
 
 using namespace ArduinoJson::Internals;

+ 1 - 1
test/Polyfills/parseFloat.cpp

@@ -2,7 +2,7 @@
 // Copyright Benoit Blanchon 2014-2018
 // MIT License
 
-#include <ArduinoJson/Polyfills/parseFloat.hpp>
+#include <ArduinoJson/Text/parseFloat.hpp>
 #include <catch.hpp>
 
 using namespace ArduinoJson::Internals;

+ 1 - 1
test/Polyfills/parseInteger.cpp

@@ -3,7 +3,7 @@
 // MIT License
 
 #include <stdint.h>
-#include <ArduinoJson/Polyfills/parseInteger.hpp>
+#include <ArduinoJson/Text/parseInteger.hpp>
 #include <catch.hpp>
 
 using namespace ArduinoJson::Internals;