Added deserializeMsgPack() (issue #358)

This commit is contained in:
Benoit Blanchon
2018-04-10 17:43:27 +02:00
parent 923d3e8a84
commit cb723840d9
58 changed files with 1311 additions and 89 deletions

View File

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

View File

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

View File

@ -7,13 +7,15 @@
#include "ArduinoJson/DynamicJsonArray.hpp" #include "ArduinoJson/DynamicJsonArray.hpp"
#include "ArduinoJson/DynamicJsonObject.hpp" #include "ArduinoJson/DynamicJsonObject.hpp"
#include "ArduinoJson/DynamicJsonVariant.hpp" #include "ArduinoJson/DynamicJsonVariant.hpp"
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
#include "ArduinoJson/StaticJsonArray.hpp" #include "ArduinoJson/StaticJsonArray.hpp"
#include "ArduinoJson/StaticJsonObject.hpp" #include "ArduinoJson/StaticJsonObject.hpp"
#include "ArduinoJson/StaticJsonVariant.hpp" #include "ArduinoJson/StaticJsonVariant.hpp"
#include "ArduinoJson/deserializeJson.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/JsonArrayImpl.hpp"
#include "ArduinoJson/JsonObjectImpl.hpp" #include "ArduinoJson/JsonObjectImpl.hpp"
#include "ArduinoJson/JsonVariantImpl.hpp" #include "ArduinoJson/JsonVariantImpl.hpp"
#include "ArduinoJson/Serialization/JsonSerializerImpl.hpp"

View File

@ -144,3 +144,13 @@
#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64 #if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64
#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together #error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together
#endif #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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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