Files
eagle0/CroissantSerializer.cpp
T
2017-09-13 09:33:29 -07:00

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