初始化提交
This commit is contained in:
@@ -0,0 +1,637 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2020
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Deserialization/deserialize.hpp>
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||
#include <ArduinoJson/MsgPack/ieee754.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename TReader, typename TStringStorage>
|
||||
class MsgPackDeserializer {
|
||||
public:
|
||||
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
||||
TStringStorage stringStorage)
|
||||
: _pool(&pool),
|
||||
_reader(reader),
|
||||
_stringStorage(stringStorage),
|
||||
_error(DeserializationError::Ok),
|
||||
_foundSomething(false) {}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parse(VariantData &variant, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
parseVariant(variant, filter, nestingLimit);
|
||||
return _foundSomething ? _error : DeserializationError::EmptyInput;
|
||||
}
|
||||
|
||||
private:
|
||||
// Prevent VS warning "assignment operator could not be generated"
|
||||
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
|
||||
|
||||
bool invalidInput() {
|
||||
_error = DeserializationError::InvalidInput;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool notSupported() {
|
||||
_error = DeserializationError::NotSupported;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
bool parseVariant(VariantData &variant, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
uint8_t code = 0; // TODO: why do we need to initialize this variable?
|
||||
if (!readByte(code))
|
||||
return false;
|
||||
|
||||
_foundSomething = true;
|
||||
|
||||
bool allowValue = filter.allowValue();
|
||||
|
||||
switch (code) {
|
||||
case 0xc0:
|
||||
// already null
|
||||
return true;
|
||||
|
||||
case 0xc1:
|
||||
return invalidInput();
|
||||
|
||||
case 0xc2:
|
||||
if (allowValue)
|
||||
variant.setBoolean(false);
|
||||
return true;
|
||||
|
||||
case 0xc3:
|
||||
if (allowValue)
|
||||
variant.setBoolean(true);
|
||||
return true;
|
||||
|
||||
case 0xc4: // bin 8
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipString<uint8_t>();
|
||||
|
||||
case 0xc5: // bin 16
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipString<uint16_t>();
|
||||
|
||||
case 0xc6: // bin 32
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipString<uint32_t>();
|
||||
|
||||
case 0xc7: // ext 8
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipExt<uint8_t>();
|
||||
|
||||
case 0xc8: // ext 16
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipExt<uint16_t>();
|
||||
|
||||
case 0xc9: // ext 32
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipExt<uint32_t>();
|
||||
|
||||
case 0xca:
|
||||
if (allowValue)
|
||||
return readFloat<float>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xcb:
|
||||
if (allowValue)
|
||||
return readDouble<double>(variant);
|
||||
else
|
||||
return skipBytes(8);
|
||||
|
||||
case 0xcc:
|
||||
if (allowValue)
|
||||
return readInteger<uint8_t>(variant);
|
||||
else
|
||||
return skipBytes(1);
|
||||
|
||||
case 0xcd:
|
||||
if (allowValue)
|
||||
return readInteger<uint16_t>(variant);
|
||||
else
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xce:
|
||||
if (allowValue)
|
||||
return readInteger<uint32_t>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xcf:
|
||||
if (allowValue)
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
return readInteger<uint64_t>(variant);
|
||||
#else
|
||||
return notSupported();
|
||||
#endif
|
||||
else
|
||||
return skipBytes(8);
|
||||
|
||||
case 0xd0:
|
||||
if (allowValue)
|
||||
return readInteger<int8_t>(variant);
|
||||
else
|
||||
return skipBytes(1);
|
||||
|
||||
case 0xd1:
|
||||
if (allowValue)
|
||||
return readInteger<int16_t>(variant);
|
||||
else
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xd2:
|
||||
if (allowValue)
|
||||
return readInteger<int32_t>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xd3:
|
||||
if (allowValue)
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
return readInteger<int64_t>(variant);
|
||||
#else
|
||||
return notSupported();
|
||||
#endif
|
||||
else
|
||||
return skipBytes(8);
|
||||
|
||||
case 0xd4: // fixext 1
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xd5: // fixext 2
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipBytes(3);
|
||||
|
||||
case 0xd6: // fixext 4
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipBytes(5);
|
||||
|
||||
case 0xd7: // fixext 8
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipBytes(9);
|
||||
|
||||
case 0xd8: // fixext 16
|
||||
if (allowValue)
|
||||
return notSupported();
|
||||
else
|
||||
return skipBytes(17);
|
||||
|
||||
case 0xd9:
|
||||
if (allowValue)
|
||||
return readString<uint8_t>(variant);
|
||||
else
|
||||
return skipString<uint8_t>();
|
||||
|
||||
case 0xda:
|
||||
if (allowValue)
|
||||
return readString<uint16_t>(variant);
|
||||
else
|
||||
return skipString<uint16_t>();
|
||||
|
||||
case 0xdb:
|
||||
if (allowValue)
|
||||
return readString<uint32_t>(variant);
|
||||
else
|
||||
return skipString<uint32_t>();
|
||||
|
||||
case 0xdc:
|
||||
return readArray<uint16_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xdd:
|
||||
return readArray<uint32_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xde:
|
||||
return readObject<uint16_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xdf:
|
||||
return readObject<uint32_t>(variant, filter, nestingLimit);
|
||||
}
|
||||
|
||||
switch (code & 0xf0) {
|
||||
case 0x80:
|
||||
return readObject(variant, code & 0x0F, filter, nestingLimit);
|
||||
|
||||
case 0x90:
|
||||
return readArray(variant, code & 0x0F, filter, nestingLimit);
|
||||
}
|
||||
|
||||
if ((code & 0xe0) == 0xa0) {
|
||||
if (allowValue)
|
||||
return readString(variant, code & 0x1f);
|
||||
else
|
||||
return skipBytes(code & 0x1f);
|
||||
}
|
||||
|
||||
if (allowValue)
|
||||
variant.setInteger(static_cast<int8_t>(code));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readByte(uint8_t &value) {
|
||||
int c = _reader.read();
|
||||
if (c < 0) {
|
||||
_error = DeserializationError::IncompleteInput;
|
||||
return false;
|
||||
}
|
||||
value = static_cast<uint8_t>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readBytes(uint8_t *p, size_t n) {
|
||||
if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n)
|
||||
return true;
|
||||
_error = DeserializationError::IncompleteInput;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool readBytes(T &value) {
|
||||
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
bool skipBytes(size_t n) {
|
||||
for (; n; --n) {
|
||||
if (_reader.read() < 0) {
|
||||
_error = DeserializationError::IncompleteInput;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool readInteger(T &value) {
|
||||
if (!readBytes(value))
|
||||
return false;
|
||||
fixEndianess(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool readInteger(VariantData &variant) {
|
||||
T value;
|
||||
if (!readInteger(value))
|
||||
return false;
|
||||
variant.setInteger(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, bool>::type readFloat(
|
||||
VariantData &variant) {
|
||||
T value;
|
||||
if (!readBytes(value))
|
||||
return false;
|
||||
fixEndianess(value);
|
||||
variant.setFloat(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8, bool>::type readDouble(
|
||||
VariantData &variant) {
|
||||
T value;
|
||||
if (!readBytes(value))
|
||||
return false;
|
||||
fixEndianess(value);
|
||||
variant.setFloat(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, bool>::type readDouble(
|
||||
VariantData &variant) {
|
||||
uint8_t i[8]; // input is 8 bytes
|
||||
T value; // output is 4 bytes
|
||||
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
||||
if (!readBytes(i, 8))
|
||||
return false;
|
||||
doubleToFloat(i, o);
|
||||
fixEndianess(value);
|
||||
variant.setFloat(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool readString(VariantData &variant) {
|
||||
T size;
|
||||
if (!readInteger(size))
|
||||
return false;
|
||||
return readString(variant, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool readString() {
|
||||
T size;
|
||||
if (!readInteger(size))
|
||||
return false;
|
||||
return readString(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool skipString() {
|
||||
T size;
|
||||
if (!readInteger(size))
|
||||
return false;
|
||||
return skipBytes(size);
|
||||
}
|
||||
|
||||
bool readString(VariantData &variant, size_t n) {
|
||||
if (!readString(n))
|
||||
return false;
|
||||
variant.setStringPointer(_stringStorage.save(),
|
||||
typename TStringStorage::storage_policy());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readString(size_t n) {
|
||||
_stringStorage.startString();
|
||||
for (; n; --n) {
|
||||
uint8_t c;
|
||||
if (!readBytes(c))
|
||||
return false;
|
||||
_stringStorage.append(static_cast<char>(c));
|
||||
}
|
||||
_stringStorage.append('\0');
|
||||
if (!_stringStorage.isValid()) {
|
||||
_error = DeserializationError::NoMemory;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TSize, typename TFilter>
|
||||
bool readArray(VariantData &variant, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
TSize size;
|
||||
if (!readInteger(size))
|
||||
return false;
|
||||
return readArray(variant, size, filter, nestingLimit);
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
bool readArray(VariantData &variant, size_t n, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) {
|
||||
_error = DeserializationError::TooDeep;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allowArray = filter.allowArray();
|
||||
|
||||
CollectionData *array = allowArray ? &variant.toArray() : 0;
|
||||
|
||||
TFilter memberFilter = filter[0U];
|
||||
|
||||
for (; n; --n) {
|
||||
VariantData *value;
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
value = array->addElement(_pool);
|
||||
if (!value) {
|
||||
_error = DeserializationError::NoMemory;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TSize, typename TFilter>
|
||||
bool readObject(VariantData &variant, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
TSize size;
|
||||
if (!readInteger(size))
|
||||
return false;
|
||||
return readObject(variant, size, filter, nestingLimit);
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
bool readObject(VariantData &variant, size_t n, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) {
|
||||
_error = DeserializationError::TooDeep;
|
||||
return false;
|
||||
}
|
||||
|
||||
CollectionData *object = filter.allowObject() ? &variant.toObject() : 0;
|
||||
|
||||
for (; n; --n) {
|
||||
if (!readKey())
|
||||
return false;
|
||||
|
||||
const char *key = _stringStorage.c_str();
|
||||
TFilter memberFilter = filter[key];
|
||||
VariantData *member;
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
// Save key in memory pool.
|
||||
// This MUST be done before adding the slot.
|
||||
key = _stringStorage.save();
|
||||
|
||||
VariantSlot *slot = object->addSlot(_pool);
|
||||
if (!slot) {
|
||||
_error = DeserializationError::NoMemory;
|
||||
return false;
|
||||
}
|
||||
|
||||
slot->setKey(key, typename TStringStorage::storage_policy());
|
||||
|
||||
member = slot->data();
|
||||
} else {
|
||||
member = 0;
|
||||
}
|
||||
|
||||
if (!parseVariant(*member, memberFilter, nestingLimit.decrement()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readKey() {
|
||||
uint8_t code;
|
||||
if (!readByte(code))
|
||||
return false;
|
||||
|
||||
if ((code & 0xe0) == 0xa0)
|
||||
return readString(code & 0x1f);
|
||||
|
||||
switch (code) {
|
||||
case 0xd9:
|
||||
return readString<uint8_t>();
|
||||
|
||||
case 0xda:
|
||||
return readString<uint16_t>();
|
||||
|
||||
case 0xdb:
|
||||
return readString<uint32_t>();
|
||||
|
||||
default:
|
||||
return notSupported();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool skipExt() {
|
||||
T size;
|
||||
if (!readInteger(size))
|
||||
return false;
|
||||
return skipBytes(size + 1);
|
||||
}
|
||||
|
||||
MemoryPool *_pool;
|
||||
TReader _reader;
|
||||
TStringStorage _stringStorage;
|
||||
DeserializationError _error;
|
||||
bool _foundSomething;
|
||||
};
|
||||
|
||||
//
|
||||
// deserializeMsgPack(JsonDocument&, const std::string&, ...)
|
||||
//
|
||||
// ... = NestingLimit
|
||||
template <typename TString>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, const TString &input,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
||||
AllowAllFilter());
|
||||
}
|
||||
// ... = Filter, NestingLimit
|
||||
template <typename TString>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, const TString &input, Filter filter,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||
}
|
||||
// ... = NestingLimit, Filter
|
||||
template <typename TString>
|
||||
DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input,
|
||||
NestingLimit nestingLimit,
|
||||
Filter filter) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||
}
|
||||
|
||||
//
|
||||
// deserializeMsgPack(JsonDocument&, std::istream&, ...)
|
||||
//
|
||||
// ... = NestingLimit
|
||||
template <typename TStream>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, TStream &input,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
||||
AllowAllFilter());
|
||||
}
|
||||
// ... = Filter, NestingLimit
|
||||
template <typename TStream>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, TStream &input, Filter filter,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||
}
|
||||
// ... = NestingLimit, Filter
|
||||
template <typename TStream>
|
||||
DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input,
|
||||
NestingLimit nestingLimit,
|
||||
Filter filter) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||
}
|
||||
|
||||
//
|
||||
// deserializeMsgPack(JsonDocument&, char*, ...)
|
||||
//
|
||||
// ... = NestingLimit
|
||||
template <typename TChar>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, TChar *input,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
||||
AllowAllFilter());
|
||||
}
|
||||
// ... = Filter, NestingLimit
|
||||
template <typename TChar>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, TChar *input, Filter filter,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||
}
|
||||
// ... = NestingLimit, Filter
|
||||
template <typename TChar>
|
||||
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
|
||||
NestingLimit nestingLimit,
|
||||
Filter filter) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||
}
|
||||
|
||||
//
|
||||
// deserializeMsgPack(JsonDocument&, char*, size_t, ...)
|
||||
//
|
||||
// ... = NestingLimit
|
||||
template <typename TChar>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, TChar *input, size_t inputSize,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
||||
AllowAllFilter());
|
||||
}
|
||||
// ... = Filter, NestingLimit
|
||||
template <typename TChar>
|
||||
DeserializationError deserializeMsgPack(
|
||||
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
|
||||
NestingLimit nestingLimit = NestingLimit()) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
||||
filter);
|
||||
}
|
||||
// ... = NestingLimit, Filter
|
||||
template <typename TChar>
|
||||
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
|
||||
size_t inputSize,
|
||||
NestingLimit nestingLimit,
|
||||
Filter filter) {
|
||||
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
||||
filter);
|
||||
}
|
||||
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
@@ -0,0 +1,203 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2020
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||
#include <ArduinoJson/Serialization/measure.hpp>
|
||||
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename TWriter>
|
||||
class MsgPackSerializer : public Visitor<size_t> {
|
||||
public:
|
||||
MsgPackSerializer(TWriter writer) : _writer(writer) {}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) {
|
||||
writeByte(0xCA);
|
||||
writeInteger(value32);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
|
||||
typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) {
|
||||
float value32 = float(value64);
|
||||
if (value32 == value64) {
|
||||
writeByte(0xCA);
|
||||
writeInteger(value32);
|
||||
} else {
|
||||
writeByte(0xCB);
|
||||
writeInteger(value64);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitArray(const CollectionData& array) {
|
||||
size_t n = array.size();
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x90 + array.size()));
|
||||
} else if (n < 0x10000) {
|
||||
writeByte(0xDC);
|
||||
writeInteger(uint16_t(n));
|
||||
} else {
|
||||
writeByte(0xDD);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (VariantSlot* slot = array.head(); slot; slot = slot->next()) {
|
||||
slot->data()->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitObject(const CollectionData& object) {
|
||||
size_t n = object.size();
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x80 + n));
|
||||
} else if (n < 0x10000) {
|
||||
writeByte(0xDE);
|
||||
writeInteger(uint16_t(n));
|
||||
} else {
|
||||
writeByte(0xDF);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (VariantSlot* slot = object.head(); slot; slot = slot->next()) {
|
||||
visitString(slot->key());
|
||||
slot->data()->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitString(const char* value) {
|
||||
ARDUINOJSON_ASSERT(value != NULL);
|
||||
|
||||
size_t n = strlen(value);
|
||||
|
||||
if (n < 0x20) {
|
||||
writeByte(uint8_t(0xA0 + n));
|
||||
} else if (n < 0x100) {
|
||||
writeByte(0xD9);
|
||||
writeInteger(uint8_t(n));
|
||||
} else if (n < 0x10000) {
|
||||
writeByte(0xDA);
|
||||
writeInteger(uint16_t(n));
|
||||
} else {
|
||||
writeByte(0xDB);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitRawJson(const char* data, size_t size) {
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitNegativeInteger(UInt value) {
|
||||
UInt negated = UInt(~value + 1);
|
||||
if (value <= 0x20) {
|
||||
writeInteger(int8_t(negated));
|
||||
} else if (value <= 0x80) {
|
||||
writeByte(0xD0);
|
||||
writeInteger(int8_t(negated));
|
||||
} else if (value <= 0x8000) {
|
||||
writeByte(0xD1);
|
||||
writeInteger(int16_t(negated));
|
||||
} else if (value <= 0x80000000) {
|
||||
writeByte(0xD2);
|
||||
writeInteger(int32_t(negated));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else {
|
||||
writeByte(0xD3);
|
||||
writeInteger(int64_t(negated));
|
||||
}
|
||||
#endif
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitPositiveInteger(UInt value) {
|
||||
if (value <= 0x7F) {
|
||||
writeInteger(uint8_t(value));
|
||||
} else if (value <= 0xFF) {
|
||||
writeByte(0xCC);
|
||||
writeInteger(uint8_t(value));
|
||||
} else if (value <= 0xFFFF) {
|
||||
writeByte(0xCD);
|
||||
writeInteger(uint16_t(value));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else if (value <= 0xFFFFFFFF)
|
||||
#else
|
||||
else
|
||||
#endif
|
||||
{
|
||||
writeByte(0xCE);
|
||||
writeInteger(uint32_t(value));
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else {
|
||||
writeByte(0xCF);
|
||||
writeInteger(uint64_t(value));
|
||||
}
|
||||
#endif
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitBoolean(bool value) {
|
||||
writeByte(value ? 0xC3 : 0xC2);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitNull() {
|
||||
writeByte(0xC0);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t bytesWritten() const {
|
||||
return _writer.count();
|
||||
}
|
||||
|
||||
void writeByte(uint8_t c) {
|
||||
_writer.write(c);
|
||||
}
|
||||
|
||||
void writeBytes(const uint8_t* p, size_t n) {
|
||||
_writer.write(p, n);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writeInteger(T value) {
|
||||
fixEndianess(value);
|
||||
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
CountingDecorator<TWriter> _writer;
|
||||
};
|
||||
|
||||
template <typename TSource, typename TDestination>
|
||||
inline size_t serializeMsgPack(const TSource& source, TDestination& output) {
|
||||
return serialize<MsgPackSerializer>(source, output);
|
||||
}
|
||||
|
||||
template <typename TSource>
|
||||
inline size_t serializeMsgPack(const TSource& source, void* output,
|
||||
size_t size) {
|
||||
return serialize<MsgPackSerializer>(source, output, size);
|
||||
}
|
||||
|
||||
template <typename TSource>
|
||||
inline size_t measureMsgPack(const TSource& source) {
|
||||
return measure<MsgPackSerializer>(source);
|
||||
}
|
||||
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
@@ -0,0 +1,41 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2020
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
#if ARDUINOJSON_LITTLE_ENDIAN
|
||||
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) {
|
||||
fixEndianess(reinterpret_cast<uint8_t *>(&value),
|
||||
integral_constant<size_t, sizeof(T)>());
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
inline void fixEndianess(T &) {}
|
||||
#endif
|
||||
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
@@ -0,0 +1,18 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2020
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
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 ARDUINOJSON_NAMESPACE
|
||||
Reference in New Issue
Block a user