mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 02:35:45 +00:00
306 lines
9.8 KiB
C++
306 lines
9.8 KiB
C++
//
|
|
// CroissantSerializer.cpp
|
|
// eagle0_engine
|
|
//
|
|
// Created by Dan Crosby on 7/20/17.
|
|
// Copyright © 2017 none. All rights reserved.
|
|
//
|
|
|
|
#include "CroissantSerializer.hpp"
|
|
|
|
const byte_vector NULL_SVALUE = byte_vector{0x00};
|
|
const byte_vector TRUE_SVALUE = byte_vector{0x81};
|
|
const byte_vector FALSE_SVALUE = byte_vector{0x80};
|
|
const int32_t INT24_MAX = 0x007FFFFF;
|
|
const int32_t INT24_MIN = -INT24_MAX - 1;
|
|
|
|
static inline byte_vector serialized(const Serializable& object);
|
|
|
|
static inline byte_vector lengthBits(uint8_t type, size_t length) {
|
|
uint8_t firstByte = type;
|
|
if (length < 16) {
|
|
firstByte |= length;
|
|
return byte_vector{firstByte};
|
|
} else {
|
|
firstByte |= CroissantSerializer::EXTRA_LENGTH_MASK;
|
|
if (length < INT8_MAX) {
|
|
firstByte |= 0x01;
|
|
return byte_vector{firstByte, (uint8_t)length};
|
|
} else if (length < INT16_MAX) {
|
|
firstByte |= 0x02;
|
|
return byte_vector{firstByte, (uint8_t)((length >> 8) & 0xFF), (uint8_t)(length & 0xFF)};
|
|
} else if (length < INT32_MAX) {
|
|
firstByte |= 0x04;
|
|
return byte_vector{firstByte,
|
|
(uint8_t)((length >> 24) & 0xFF),
|
|
(uint8_t)((length >> 16) & 0xFF),
|
|
(uint8_t)((length >> 8) & 0xFF),
|
|
(uint8_t)(length & 0xFF)};
|
|
}
|
|
}
|
|
|
|
throw CroissantSerializationException("Unable to handle >4 length bytes for now, sorry");
|
|
return byte_vector{};
|
|
}
|
|
|
|
static inline byte_vector serializeString(const Serializable& stringObject) {
|
|
string toSerialize = stringObject.stringValue();
|
|
byte_vector startingBytes = lengthBits(CroissantSerializer::Type::stringType, toSerialize.length());
|
|
startingBytes.insert(startingBytes.end(), toSerialize.begin(), toSerialize.end());
|
|
return startingBytes;
|
|
}
|
|
|
|
static inline byte_vector serializeInteger(const Serializable& stringObject) {
|
|
int64_t toSerialize = stringObject.integerValue();
|
|
|
|
if (toSerialize > INT8_MIN && toSerialize < INT8_MAX) {
|
|
// one byte
|
|
byte_vector startingBytes = lengthBits(CroissantSerializer::Type::integerType, 1);
|
|
startingBytes.push_back(toSerialize & 0xFF);
|
|
return startingBytes;
|
|
} else if (toSerialize > INT16_MIN && toSerialize < INT16_MAX) {
|
|
// two bytes
|
|
byte_vector startingBytes = lengthBits(CroissantSerializer::Type::integerType, 2);
|
|
startingBytes.push_back((toSerialize >> 8) & 0xFF);
|
|
startingBytes.push_back(toSerialize & 0xFF);
|
|
return startingBytes;
|
|
} else if (toSerialize > INT24_MIN && toSerialize < INT24_MAX) {
|
|
// three bytes
|
|
byte_vector startingBytes = lengthBits(CroissantSerializer::Type::integerType, 3);
|
|
startingBytes.push_back((toSerialize >> 16) & 0xFF);
|
|
startingBytes.push_back((toSerialize >> 8) & 0xFF);
|
|
startingBytes.push_back(toSerialize & 0xFF);
|
|
return startingBytes;
|
|
} else if (toSerialize > INT32_MIN && toSerialize < INT32_MAX) {
|
|
// four bytes
|
|
byte_vector startingBytes = lengthBits(CroissantSerializer::Type::integerType, 4);
|
|
startingBytes.push_back((toSerialize >> 24) & 0xFF);
|
|
startingBytes.push_back((toSerialize >> 16) & 0xFF);
|
|
startingBytes.push_back((toSerialize >> 8) & 0xFF);
|
|
startingBytes.push_back(toSerialize & 0xFF);
|
|
return startingBytes;
|
|
}
|
|
|
|
throw CroissantSerializationException("Unable to handle >4 length bytes, sorry");
|
|
}
|
|
|
|
static inline byte_vector serializeFloat(const Serializable& floatObject) {
|
|
double toSerialize = floatObject.floatingValue();
|
|
|
|
byte_vector startingBytes = lengthBits(CroissantSerializer::Type::floatType, sizeof(double));
|
|
for (int i=0; i<sizeof(double); i++) {
|
|
startingBytes.push_back(((uint8_t*)(&toSerialize))[i]);
|
|
}
|
|
|
|
return startingBytes;
|
|
}
|
|
|
|
static inline byte_vector serializeArray(const Serializable& arrayObject) {
|
|
const auto objects = arrayObject.arrayValue();
|
|
|
|
byte_vector objectsData = lengthBits(CroissantSerializer::Type::arrayType, objects.size());
|
|
for (const Serializable& object : objects) {
|
|
objectsData += serialized(object);
|
|
}
|
|
|
|
return objectsData;
|
|
}
|
|
|
|
static inline byte_vector serializeMap(const Serializable& mapObject) {
|
|
const auto objectPairs = mapObject.mapValue();
|
|
|
|
byte_vector keyValueData = lengthBits(CroissantSerializer::Type::mapType, objectPairs.size());
|
|
for (auto pair : objectPairs) {
|
|
keyValueData += serialized(pair.first);
|
|
keyValueData += serialized(pair.second);
|
|
}
|
|
|
|
return keyValueData;
|
|
}
|
|
|
|
static inline byte_vector serialized(const Serializable& object) {
|
|
switch (object.GetType()) {
|
|
case Serializable::nullType:
|
|
return NULL_SVALUE;
|
|
break;
|
|
|
|
case Serializable::booleanType:
|
|
return object.booleanValue() ? TRUE_SVALUE : FALSE_SVALUE;
|
|
break;
|
|
|
|
case Serializable::integerType:
|
|
return serializeInteger(object);
|
|
break;
|
|
|
|
case Serializable::floatingType:
|
|
return serializeFloat(object);
|
|
break;
|
|
|
|
case Serializable::stringType:
|
|
return serializeString(object);
|
|
break;
|
|
|
|
case Serializable::arrayType:
|
|
return serializeArray(object);
|
|
break;
|
|
|
|
case Serializable::mapType:
|
|
return serializeMap(object);
|
|
break;
|
|
}
|
|
|
|
return byte_vector{};
|
|
}
|
|
|
|
byte_vector CroissantSerializer::serialize(const Serializable& object) const {
|
|
return serialized(object);
|
|
}
|
|
|
|
static inline Serializable deserialized(const uint8_t* &rawBytes);
|
|
|
|
static inline size_t parseLength(const uint8_t* &rawBytes) {
|
|
int inlineLength = rawBytes[0] & CroissantSerializer::LENGTH_MASK;
|
|
bool externalLength = rawBytes[0] & CroissantSerializer::EXTRA_LENGTH_MASK;
|
|
|
|
rawBytes++;
|
|
|
|
if (externalLength) {
|
|
if (inlineLength > 4) {
|
|
throw CroissantSerializationException("Unable to handle >4 byte length for now, sorry");
|
|
}
|
|
|
|
// TODO: handle first bit set
|
|
uint32_t total = 0;
|
|
for (int i=0; i<inlineLength; i++) {
|
|
total <<= 8;
|
|
total += *rawBytes;
|
|
rawBytes++;
|
|
}
|
|
|
|
return total;
|
|
} else {
|
|
return inlineLength;
|
|
}
|
|
}
|
|
|
|
static inline Serializable deserializeBoolean(const uint8_t* &rawBytes) {
|
|
bool truth = rawBytes[0] & 0x01;
|
|
rawBytes++;
|
|
return Serializable(truth);
|
|
}
|
|
|
|
static inline Serializable deserializeInteger(const uint8_t* &rawBytes) {
|
|
size_t length = parseLength(rawBytes);
|
|
if (length == 0) {
|
|
return Serializable(0);
|
|
}
|
|
int64_t total = 0;
|
|
bool negative = *rawBytes & 0x80;
|
|
int64_t mask = 0;
|
|
for (int i=0; i<length; i++) {
|
|
total <<= 8;
|
|
mask <<= 8;
|
|
total |= *rawBytes;
|
|
mask |= 0xFF;
|
|
rawBytes++;
|
|
}
|
|
if (negative) {
|
|
total |= ~mask;
|
|
}
|
|
|
|
return Serializable(total);
|
|
}
|
|
|
|
static inline Serializable deserializeFloat(const uint8_t* &rawBytes) {
|
|
// TODO: only works with Doubles
|
|
double deserialized;
|
|
size_t length = parseLength(rawBytes);
|
|
memcpy(&deserialized, rawBytes, length);
|
|
rawBytes += length;
|
|
return Serializable(deserialized);
|
|
}
|
|
|
|
static inline Serializable deserializeString(const uint8_t* &rawBytes) {
|
|
size_t length = parseLength(rawBytes);
|
|
string str(reinterpret_cast<char const*>(rawBytes), length);
|
|
rawBytes += length;
|
|
return Serializable(str);
|
|
}
|
|
|
|
static inline Serializable deserializeByteArray(const uint8_t* &rawBytes) {
|
|
return Serializable({0x01, 0x02, 0x03});
|
|
}
|
|
|
|
static inline Serializable deserializeMap(const uint8_t* &rawBytes) {
|
|
size_t length = parseLength(rawBytes);
|
|
|
|
Serializable map = Serializable::NewMap();
|
|
for (int i=0; i<length; i++) {
|
|
Serializable key = deserialized(rawBytes);
|
|
Serializable value = deserialized(rawBytes);
|
|
if (key.GetType() != Serializable::SerializableType::stringType) {
|
|
throw CroissantSerializationException("Only string keys are supported now");
|
|
}
|
|
map[key.stringValue()] = value;
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
static inline Serializable deserializeArray(const uint8_t* &rawBytes) {
|
|
size_t length = parseLength(rawBytes);
|
|
|
|
Serializable array = Serializable::NewArray();
|
|
for (int i=0; i<length; i++) {
|
|
array.Add(deserialized(rawBytes));
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
Serializable deserialized(const uint8_t* &rawBytes) {
|
|
uint8_t infoByte = rawBytes[0];
|
|
CroissantSerializer::Type type = CroissantSerializer::Type(infoByte & CroissantSerializer::TYPE_MASK);
|
|
|
|
switch (type) {
|
|
case CroissantSerializer::Type::nullType:
|
|
return Serializable();
|
|
break;
|
|
|
|
case CroissantSerializer::Type::booleanType:
|
|
return deserializeBoolean(rawBytes);
|
|
break;
|
|
|
|
case CroissantSerializer::Type::integerType:
|
|
return deserializeInteger(rawBytes);
|
|
break;
|
|
|
|
case CroissantSerializer::Type::floatType:
|
|
return deserializeFloat(rawBytes);
|
|
break;
|
|
|
|
case CroissantSerializer::Type::byteArrayType:
|
|
return deserializeByteArray(rawBytes);
|
|
break;
|
|
|
|
case CroissantSerializer::Type::stringType:
|
|
return deserializeString(rawBytes);
|
|
break;
|
|
|
|
case CroissantSerializer::Type::mapType:
|
|
return deserializeMap(rawBytes);
|
|
break;
|
|
|
|
case CroissantSerializer::Type::arrayType:
|
|
return deserializeArray(rawBytes);
|
|
break;
|
|
}
|
|
return Serializable();
|
|
}
|
|
|
|
|
|
Serializable CroissantSerializer::deserialize(const byte_vector& data) const {
|
|
const uint8_t* rawBytes = data.data();
|
|
return deserialized(rawBytes);
|
|
}
|