From 257a2bf339a77cd410fa5d84d16db405cbf35eb9 Mon Sep 17 00:00:00 2001 From: jezal Date: Mon, 15 Sep 2014 21:33:47 +0400 Subject: [PATCH] New JSON serialization --- CMakeLists.txt | 4 +- .../BinaryInputStreamSerializer.cpp | 242 +++++++ .../BinaryInputStreamSerializer.h | 66 ++ .../BinaryOutputStreamSerializer.cpp | 185 ++++++ .../BinaryOutputStreamSerializer.h | 65 ++ src/serialization/ISerializer.h | 135 ++++ .../JsonInputStreamSerializer.cpp | 33 + src/serialization/JsonInputStreamSerializer.h | 40 ++ .../JsonInputValueSerializer.cpp | 216 +++++++ src/serialization/JsonInputValueSerializer.h | 67 ++ .../JsonOutputStreamSerializer.cpp | 189 ++++++ .../JsonOutputStreamSerializer.h | 69 ++ .../JsonSerializationDispatcher.h | 65 ++ src/serialization/JsonValue.cpp | 612 ++++++++++++++++++ src/serialization/JsonValue.h | 103 +++ src/serialization/SerializationOverloads.cpp | 81 +++ src/serialization/SerializationOverloads.h | 78 +++ 17 files changed, 2248 insertions(+), 2 deletions(-) create mode 100644 src/serialization/BinaryInputStreamSerializer.cpp create mode 100644 src/serialization/BinaryInputStreamSerializer.h create mode 100644 src/serialization/BinaryOutputStreamSerializer.cpp create mode 100644 src/serialization/BinaryOutputStreamSerializer.h create mode 100644 src/serialization/ISerializer.h create mode 100644 src/serialization/JsonInputStreamSerializer.cpp create mode 100644 src/serialization/JsonInputStreamSerializer.h create mode 100644 src/serialization/JsonInputValueSerializer.cpp create mode 100644 src/serialization/JsonInputValueSerializer.h create mode 100644 src/serialization/JsonOutputStreamSerializer.cpp create mode 100644 src/serialization/JsonOutputStreamSerializer.h create mode 100644 src/serialization/JsonSerializationDispatcher.h create mode 100644 src/serialization/JsonValue.cpp create mode 100644 src/serialization/JsonValue.h create mode 100644 src/serialization/SerializationOverloads.cpp create mode 100644 src/serialization/SerializationOverloads.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 09493a73..c2794e7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,9 +31,9 @@ else() else() set(ARCH_FLAG "-march=${ARCH}") endif() - set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Werror -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized") + set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Werror -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized -Wno-error=unused-result") if(CMAKE_C_COMPILER_ID STREQUAL "Clang") - set(WARNINGS "${WARNINGS} -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration") + set(WARNINGS "${WARNINGS} -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration -Wno-error=unused-function") else() set(WARNINGS "${WARNINGS} -Wlogical-op -Wno-error=maybe-uninitialized") endif() diff --git a/src/serialization/BinaryInputStreamSerializer.cpp b/src/serialization/BinaryInputStreamSerializer.cpp new file mode 100644 index 00000000..31a85b32 --- /dev/null +++ b/src/serialization/BinaryInputStreamSerializer.cpp @@ -0,0 +1,242 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "BinaryInputStreamSerializer.h" +#include "SerializationOverloads.h" + +#include +#include +#include + +namespace { + +void deserialize(std::istream& stream, uint8_t& v) { + char c; + stream.get(c); + v = static_cast(c); +} + +void deserialize(std::istream& stream, int8_t& v) { + uint8_t val; + deserialize(stream, val); + v = val; +} + +void deserialize(std::istream& stream, bool& v) { + uint8_t val; + deserialize(stream, val); + + v = val; +} + +void deserialize(std::istream& stream, uint32_t& v) { + char c; + + stream.get(c); + v = static_cast(c); + + stream.get(c); + v += static_cast(c) << 8; + + stream.get(c); + v += static_cast(c) << 16; + + stream.get(c); + v += static_cast(c) << 24; +} + +void deserialize(std::istream& stream, int32_t& v) { + uint32_t val; + deserialize(stream, val); + v = val; +} + +void deserialize(std::istream& stream, uint64_t& v) { + char c; + uint64_t uc; + + stream.get(c); + uc = static_cast(c); + v = uc; + + stream.get(c); + uc = static_cast(c); + v += (uc << 8); + + stream.get(c); + uc = static_cast(c); + v += (uc << 16); + + stream.get(c); + uc = static_cast(c); + v += (uc << 24); + + stream.get(c); + uc = static_cast(c); + v += (uc << 32); + + stream.get(c); + uc = static_cast(c); + v += (uc << 40); + + stream.get(c); + uc = static_cast(c); + v += (uc << 48); + + stream.get(c); + uc = static_cast(c); + v += (uc << 56); +} + +void deserialize(std::istream& stream, int64_t& v) { + uint64_t val; + deserialize(stream, val); + v = val; +} + +void deserialize(std::istream& stream, char* buf, size_t len) { + const size_t chunk = 1000; + +// stream.read(buf, len); + +// looks redundant, but i had a bug with it + while (len && stream) { + size_t toRead = std::min(len, chunk); + stream.read(buf, toRead); + len -= toRead; + buf += toRead; + } +} + +} + +namespace cryptonote { + +ISerializer::SerializerType BinaryInputStreamSerializer::type() const { + return ISerializer::INPUT; +} + +ISerializer& BinaryInputStreamSerializer::beginObject(const std::string& name) { + return *this; +} + +ISerializer& BinaryInputStreamSerializer::endObject() { + return *this; +} + +ISerializer& BinaryInputStreamSerializer::beginArray(std::size_t& size, const std::string& name) { + uint64_t val; + serializeVarint(val, name, *this); + size = val; + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::endArray() { + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(uint8_t& value, const std::string& name) { + deserialize(stream, value); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(uint32_t& value, const std::string& name) { + deserialize(stream, value); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(int32_t& value, const std::string& name) { + uint32_t v; + operator()(v, name); + value = v; + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(int64_t& value, const std::string& name) { + deserialize(stream, value); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(uint64_t& value, const std::string& name) { + deserialize(stream, value); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(bool& value, const std::string& name) { + deserialize(stream, value); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(std::string& value, const std::string& name) { + uint64_t size; + serializeVarint(size, name, *this); + + std::vector temp; + temp.resize(size); + + deserialize(stream, &temp[0], size); + + value.reserve(size); + value.assign(&temp[0], size); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::operator()(char* value, std::size_t size, const std::string& name) { + stream.read(value, size); + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::tag(const std::string& name) { + return *this; +} + +ISerializer& BinaryInputStreamSerializer::untagged(uint8_t& value) { + char v; + stream.get(v); + value = v; + + return *this; +} + +ISerializer& BinaryInputStreamSerializer::endTag() { + return *this; +} + +bool BinaryInputStreamSerializer::hasObject(const std::string& name) { + assert(false); //the method is not supported for this type of serialization + throw std::runtime_error("hasObject method is not supported in BinaryInputStreamSerializer"); + + return false; +} + +ISerializer& BinaryInputStreamSerializer::operator()(double& value, const std::string& name) { + assert(false); //the method is not supported for this type of serialization + throw std::runtime_error("double serialization is not supported in BinaryInputStreamSerializer"); + + return *this; +} + +} diff --git a/src/serialization/BinaryInputStreamSerializer.h b/src/serialization/BinaryInputStreamSerializer.h new file mode 100644 index 00000000..50ee18e8 --- /dev/null +++ b/src/serialization/BinaryInputStreamSerializer.h @@ -0,0 +1,66 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include "ISerializer.h" +#include "SerializationOverloads.h" + +#include + +namespace cryptonote { + +class BinaryInputStreamSerializer : public ISerializer { +public: + BinaryInputStreamSerializer(std::istream& strm) : stream(strm) {} + virtual ~BinaryInputStreamSerializer() {} + + virtual ISerializer::SerializerType type() const; + + virtual ISerializer& beginObject(const std::string& name) override; + virtual ISerializer& endObject() override; + + virtual ISerializer& beginArray(std::size_t& size, const std::string& name) override; + virtual ISerializer& endArray() override; + + virtual ISerializer& operator()(uint8_t& value, const std::string& name) override; + virtual ISerializer& operator()(int32_t& value, const std::string& name) override; + + virtual ISerializer& operator()(uint32_t& value, const std::string& name) override; + virtual ISerializer& operator()(int64_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint64_t& value, const std::string& name) override; + virtual ISerializer& operator()(double& value, const std::string& name) override; + virtual ISerializer& operator()(bool& value, const std::string& name) override; + virtual ISerializer& operator()(std::string& value, const std::string& name) override; + virtual ISerializer& operator()(char* value, std::size_t size, const std::string& name); + + virtual ISerializer& tag(const std::string& name) override; + virtual ISerializer& untagged(uint8_t& value) override; + virtual ISerializer& endTag() override; + + virtual bool hasObject(const std::string& name) override; + + template + ISerializer& operator()(T& value, const std::string& name) { + return ISerializer::operator()(value, name); + } + +private: + std::istream& stream; +}; + +} diff --git a/src/serialization/BinaryOutputStreamSerializer.cpp b/src/serialization/BinaryOutputStreamSerializer.cpp new file mode 100644 index 00000000..eba6bba3 --- /dev/null +++ b/src/serialization/BinaryOutputStreamSerializer.cpp @@ -0,0 +1,185 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "BinaryOutputStreamSerializer.h" + +#include +#include + +namespace { + +void serializeInteger(std::ostream& stream, uint8_t v) { + stream.put(static_cast(v)); +} + +void serializeBool(std::ostream& stream, bool v) { + serializeInteger(stream, static_cast(v)); +} + +void serializeInteger(std::ostream& stream, uint32_t v) { + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); +} + +void serializeInteger(std::ostream& stream, uint64_t v) { + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); + v >>= 8; + + stream.put(static_cast(v & 0xff)); +} + +void serializeInteger(std::ostream& stream, int64_t v) { + serializeInteger(stream, static_cast(v)); +} + +void serializeData(std::ostream& stream, const char* buf, size_t len) { + stream.write(buf, len); +} + +} + +namespace cryptonote { + +ISerializer::SerializerType BinaryOutputStreamSerializer::type() const { + return ISerializer::OUTPUT; +} + +ISerializer& BinaryOutputStreamSerializer::beginObject(const std::string& name) { + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::endObject() { + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::beginArray(std::size_t& size, const std::string& name) { + uint64_t size64 = size; + serializeVarint(size64, name, *this); + size = size64; + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::endArray() { + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(uint8_t& value, const std::string& name) { + serializeInteger(stream, value); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(uint32_t& value, const std::string& name) { + serializeInteger(stream, value); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(int32_t& value, const std::string& name) { + uint32_t v = value; + operator()(v, name); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(int64_t& value, const std::string& name) { + serializeInteger(stream, value); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(uint64_t& value, const std::string& name) { + serializeInteger(stream, value); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(bool& value, const std::string& name) { + serializeBool(stream, value); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(std::string& value, const std::string& name) { + uint64_t size = value.size(); + serializeVarint(size, name, *this); + serializeData(stream, value.c_str(), value.size()); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(char* value, std::size_t size, const std::string& name) { + serializeData(stream, value, size); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::tag(const std::string& name) { + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::untagged(uint8_t& value) { + stream.put(value); + + return *this; +} + +ISerializer& BinaryOutputStreamSerializer::endTag() { + return *this; +} + +bool BinaryOutputStreamSerializer::hasObject(const std::string& name) { + assert(false); //the method is not supported for this type of serialization + throw std::runtime_error("hasObject method is not supported in BinaryOutputStreamSerializer"); + + return false; +} + +ISerializer& BinaryOutputStreamSerializer::operator()(double& value, const std::string& name) { + assert(false); //the method is not supported for this type of serialization + throw std::runtime_error("double serialization is not supported in BinaryOutputStreamSerializer"); + + return *this; +} + +} diff --git a/src/serialization/BinaryOutputStreamSerializer.h b/src/serialization/BinaryOutputStreamSerializer.h new file mode 100644 index 00000000..dc4bf80f --- /dev/null +++ b/src/serialization/BinaryOutputStreamSerializer.h @@ -0,0 +1,65 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include "ISerializer.h" +#include "SerializationOverloads.h" + +#include + +namespace cryptonote { + +class BinaryOutputStreamSerializer : public ISerializer { +public: + BinaryOutputStreamSerializer(std::ostream& strm) : stream(strm) {} + virtual ~BinaryOutputStreamSerializer() {} + + virtual ISerializer::SerializerType type() const; + + virtual ISerializer& beginObject(const std::string& name) override; + virtual ISerializer& endObject() override; + + virtual ISerializer& beginArray(std::size_t& size, const std::string& name) override; + virtual ISerializer& endArray() override; + + virtual ISerializer& operator()(uint8_t& value, const std::string& name) override; + virtual ISerializer& operator()(int32_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint32_t& value, const std::string& name) override; + virtual ISerializer& operator()(int64_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint64_t& value, const std::string& name) override; + virtual ISerializer& operator()(double& value, const std::string& name) override; + virtual ISerializer& operator()(bool& value, const std::string& name) override; + virtual ISerializer& operator()(std::string& value, const std::string& name) override; + virtual ISerializer& operator()(char* value, std::size_t size, const std::string& name) override; + + virtual ISerializer& tag(const std::string& name) override; + virtual ISerializer& untagged(uint8_t& value) override; + virtual ISerializer& endTag() override; + + virtual bool hasObject(const std::string& name) override; + + template + ISerializer& operator()(T& value, const std::string& name) { + return ISerializer::operator()(value, name); + } + +private: + std::ostream& stream; +}; + +} diff --git a/src/serialization/ISerializer.h b/src/serialization/ISerializer.h new file mode 100644 index 00000000..fe83f7b0 --- /dev/null +++ b/src/serialization/ISerializer.h @@ -0,0 +1,135 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include +#include + +namespace cryptonote { + +class ISerializer { +public: + + enum SerializerType { + INPUT, + OUTPUT + }; + + virtual ~ISerializer() {} + + virtual SerializerType type() const = 0; + + virtual ISerializer& beginObject(const std::string& name) = 0; + virtual ISerializer& endObject() = 0; + virtual ISerializer& beginArray(std::size_t& size, const std::string& name) = 0; + virtual ISerializer& endArray() = 0; + + virtual ISerializer& operator()(uint8_t& value, const std::string& name) = 0; + virtual ISerializer& operator()(int32_t& value, const std::string& name) = 0; + virtual ISerializer& operator()(uint32_t& value, const std::string& name) = 0; + virtual ISerializer& operator()(int64_t& value, const std::string& name) = 0; + virtual ISerializer& operator()(uint64_t& value, const std::string& name) = 0; + virtual ISerializer& operator()(double& value, const std::string& name) = 0; + virtual ISerializer& operator()(bool& value, const std::string& name) = 0; + virtual ISerializer& operator()(char* value, std::size_t size, const std::string& name) = 0; + virtual ISerializer& operator()(std::string& value, const std::string& name) = 0; + + virtual ISerializer& tag(const std::string& name) = 0; + virtual ISerializer& untagged(uint8_t& value) = 0; + virtual ISerializer& endTag() = 0; + + virtual bool hasObject(const std::string& name) = 0; + + template + ISerializer& operator()(T& value, const std::string& name); +}; + +template +ISerializer& ISerializer::operator()(T& value, const std::string& name) { + serialize(value, name, *this); + return *this; +} + +template +void serialize(T& value, const std::string& name, ISerializer& serializer) { + value.serialize(serializer, name); + return; +} + +/* +template +void serialize(std::vector& value, const std::string& name); + +template +void serialize(std::unordered_map& value, const std::string& name); + + + +template +void ISerializer::serialize(std::vector& value, const std::string& name) { + std::size_t size = value.size(); + beginArray(size, name); + value.resize(size); + + for (size_t i = 0; i < size; ++i) { + serialize(value[i], ""); + } + + endArray(); + + return *this; +} + +template +void ISerializer::serialize(std::unordered_map& value, const std::string& name) { + std::size_t size; + size = value.size(); + + beginArray(size, name); + + if (type() == INPUT) { + value.reserve(size); + + for (size_t i = 0; i < size; ++i) { + K key; + V v; + beginObject(""); + serialize(key, ""); + serialize(v, ""); + endObject(); + + value[key] = v; + } + } else { + for (auto kv: value) { + K key; + key = kv.first; + beginObject(""); + serialize(key, ""); + serialize(kv.second, ""); + endObject(); + } + } + + endArray(); + + return *this; +} +*/ + +} diff --git a/src/serialization/JsonInputStreamSerializer.cpp b/src/serialization/JsonInputStreamSerializer.cpp new file mode 100644 index 00000000..124b172a --- /dev/null +++ b/src/serialization/JsonInputStreamSerializer.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "serialization/JsonInputStreamSerializer.h" + +#include +#include + +namespace cryptonote { + +JsonInputStreamSerializer::JsonInputStreamSerializer(std::istream& stream) { + stream >> root; + JsonInputValueSerializer::setJsonValue(&root); +} + +JsonInputStreamSerializer::~JsonInputStreamSerializer() { +} + +} //namespace cryptonote diff --git a/src/serialization/JsonInputStreamSerializer.h b/src/serialization/JsonInputStreamSerializer.h new file mode 100644 index 00000000..ff67f951 --- /dev/null +++ b/src/serialization/JsonInputStreamSerializer.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include +#include +#include + +//#include "serialization/Enumerator.h" +#include "serialization/JsonInputValueSerializer.h" +#include "serialization/JsonValue.h" + +namespace cryptonote { + +//deserialization +class JsonInputStreamSerializer : public JsonInputValueSerializer { +public: + JsonInputStreamSerializer(std::istream& stream); + virtual ~JsonInputStreamSerializer(); + +private: + JsonValue root; +}; + +} diff --git a/src/serialization/JsonInputValueSerializer.cpp b/src/serialization/JsonInputValueSerializer.cpp new file mode 100644 index 00000000..7a1d385a --- /dev/null +++ b/src/serialization/JsonInputValueSerializer.cpp @@ -0,0 +1,216 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "serialization/JsonInputValueSerializer.h" + +#include +#include + +namespace cryptonote { + +JsonInputValueSerializer::JsonInputValueSerializer() : root(nullptr) { +} + +JsonInputValueSerializer::~JsonInputValueSerializer() { +} + +void JsonInputValueSerializer::setJsonValue(const JsonValue* value) { + root = value; +} + +ISerializer::SerializerType JsonInputValueSerializer::type() const { + return ISerializer::INPUT; +} + +ISerializer& JsonInputValueSerializer::beginObject(const std::string& name) { + assert(root); + + if (chain.size() == 0) { + chain.push_back(root); + return *this; + } + + const JsonValue* parent = chain.back(); + if (parent->isArray()) { + const JsonValue& v = (*parent)[idxs.back()++]; + chain.push_back(&v); + } else { + const JsonValue& v = (*parent)(name); + chain.push_back(&v); + } + + return *this; +} + +ISerializer& JsonInputValueSerializer::endObject() { + assert(root); + + chain.pop_back(); + return *this; +} + +ISerializer& JsonInputValueSerializer::beginArray(std::size_t& size, const std::string& name) { + assert(root); + + const JsonValue* parent = chain.back(); + + const JsonValue& arr = (*parent)(name); + size = arr.size(); + + chain.push_back(&arr); + idxs.push_back(0); + return *this; +} + +ISerializer& JsonInputValueSerializer::endArray() { + assert(root); + + chain.pop_back(); + idxs.pop_back(); + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(uint32_t& value, const std::string& name) { + assert(root); + + int64_t v = static_cast(value); + operator()(v, name); + value = static_cast(v); + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(int32_t& value, const std::string& name) { + assert(root); + + int64_t v = static_cast(value); + operator()(v, name); + value = static_cast(v); + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(int64_t& value, const std::string& name) { + assert(root); + + const JsonValue* val = chain.back(); + + if (val->isArray()) { + const JsonValue& v = (*val)[idxs.back()++]; + value = v.getNumber(); + } else { + const JsonValue& v = (*val)(name); + value = v.getNumber(); + } + + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(uint64_t& value, const std::string& name) { + assert(root); + + int64_t v = static_cast(value); + operator()(v, name); + value = static_cast(v); + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(double& value, const std::string& name) { + assert(root); + + const JsonValue* val = chain.back(); + + if (val->isArray()) { + value = (*val)[idxs.back()++].getDouble(); + } else { + value = (*val)(name).getDouble(); + } + + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(std::string& value, const std::string& name) { + assert(root); + + const JsonValue* val = chain.back(); + + if (val->isArray()) { + value = (*val)[idxs.back()++].getString(); + } else { + value = (*val)(name).getString(); + } + + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(uint8_t& value, const std::string& name) { + assert(root); + + uint64_t v = static_cast(value); + operator()(v, name); + value = static_cast(value); + + return *this; +} + +ISerializer& JsonInputValueSerializer::operator()(bool& value, const std::string& name) { + assert(root); + + const JsonValue* val = chain.back(); + + if (val->isArray()) { + value = (*val)[idxs.back()++].getBool(); + } else { + value = (*val)(name).getBool(); + } + + return *this; +} + +bool JsonInputValueSerializer::hasObject(const std::string& name) { + const JsonValue* val = chain.back(); + + return val->count(name) != 0; +} + +ISerializer& JsonInputValueSerializer::operator()(char* value, std::size_t size, const std::string& name) { + assert(false); + throw std::runtime_error("JsonInputValueSerializer doesn't support this type of serialization"); + + return *this; +} + +ISerializer& JsonInputValueSerializer::tag(const std::string& name) { + assert(false); + throw std::runtime_error("JsonInputValueSerializer doesn't support this type of serialization"); + + return *this; +} + +ISerializer& JsonInputValueSerializer::untagged(uint8_t& value) { + assert(false); + throw std::runtime_error("JsonInputValueSerializer doesn't support this type of serialization"); + + return *this; +} + +ISerializer& JsonInputValueSerializer::endTag() { + assert(false); + throw std::runtime_error("JsonInputValueSerializer doesn't support this type of serialization"); + + return *this; +} + +} diff --git a/src/serialization/JsonInputValueSerializer.h b/src/serialization/JsonInputValueSerializer.h new file mode 100644 index 00000000..04647fdd --- /dev/null +++ b/src/serialization/JsonInputValueSerializer.h @@ -0,0 +1,67 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include "serialization/ISerializer.h" +#include "serialization/JsonValue.h" + +namespace cryptonote { + +//deserialization +class JsonInputValueSerializer : public ISerializer { +public: + JsonInputValueSerializer(); + virtual ~JsonInputValueSerializer(); + + void setJsonValue(const JsonValue* value); + SerializerType type() const; + + virtual ISerializer& beginObject(const std::string& name) override; + virtual ISerializer& endObject() override; + + virtual ISerializer& beginArray(std::size_t& size, const std::string& name) override; + virtual ISerializer& endArray() override; + + virtual ISerializer& operator()(int32_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint32_t& value, const std::string& name) override; + virtual ISerializer& operator()(int64_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint64_t& value, const std::string& name) override; + virtual ISerializer& operator()(double& value, const std::string& name) override; + virtual ISerializer& operator()(std::string& value, const std::string& name) override; + virtual ISerializer& operator()(uint8_t& value, const std::string& name) override; + virtual ISerializer& operator()(bool& value, const std::string& name) override; + virtual ISerializer& operator()(char* value, std::size_t size, const std::string& name) override; + + virtual ISerializer& tag(const std::string& name) override; + virtual ISerializer& untagged(uint8_t& value) override; + virtual ISerializer& endTag() override; + + virtual bool hasObject(const std::string& name) override; + + template + ISerializer& operator()(T& value, const std::string& name) { + return ISerializer::operator()(value, name); + } + +private: + const JsonValue* root; + std::vector chain; + std::vector idxs; +}; + +} diff --git a/src/serialization/JsonOutputStreamSerializer.cpp b/src/serialization/JsonOutputStreamSerializer.cpp new file mode 100644 index 00000000..bb470295 --- /dev/null +++ b/src/serialization/JsonOutputStreamSerializer.cpp @@ -0,0 +1,189 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "serialization/JsonOutputStreamSerializer.h" + +#include +#include + +namespace cryptonote { + +JsonOutputStreamSerializer::JsonOutputStreamSerializer() : root(JsonValue::OBJECT) { +} + +JsonOutputStreamSerializer::~JsonOutputStreamSerializer() { +} + +std::ostream& operator<<(std::ostream& out, const JsonOutputStreamSerializer& enumerator) { + out << enumerator.root; + return out; +} + +JsonValue JsonOutputStreamSerializer::getJsonValue() const { + return root; +} + +ISerializer::SerializerType JsonOutputStreamSerializer::type() const { + return ISerializer::OUTPUT; +} + +ISerializer& JsonOutputStreamSerializer::beginObject(const std::string& name) { + if (chain.size() == 0) { + chain.push_back(&root); + return *this; + } + + JsonValue* parent = chain.back(); + JsonValue obj(JsonValue::OBJECT); + + if (parent->isObject()) { + JsonValue& res = parent->insert(name, obj); + chain.push_back(&res); + } else { + JsonValue& res = parent->pushBack(obj); + chain.push_back(&res); + } + + return *this; +} + +ISerializer& JsonOutputStreamSerializer::endObject() { + chain.pop_back(); + return *this; +} + +ISerializer& JsonOutputStreamSerializer::beginArray(std::size_t& size, const std::string& name) { + JsonValue val(JsonValue::ARRAY); + JsonValue& res = chain.back()->insert(name, val); + chain.push_back(&res); + return *this; +} + +ISerializer& JsonOutputStreamSerializer::endArray() { + chain.pop_back(); + return *this; +} + +ISerializer& JsonOutputStreamSerializer::operator()(uint64_t& value, const std::string& name) { + int64_t v = static_cast(value); + return operator()(v, name); +} + +ISerializer& JsonOutputStreamSerializer::operator()(uint32_t& value, const std::string& name) { + uint64_t v = static_cast(value); + return operator()(v, name); +} + +ISerializer& JsonOutputStreamSerializer::operator()(int32_t& value, const std::string& name) { + int64_t v = static_cast(value); + return operator()(v, name); +} + +ISerializer& JsonOutputStreamSerializer::operator()(int64_t& value, const std::string& name) { + JsonValue* val = chain.back(); + JsonValue v; + v = static_cast(value); + if (val->isArray()) { + val->pushBack(v); + } else { + val->insert(name, v); + } + return *this; +} + +ISerializer& JsonOutputStreamSerializer::operator()(double& value, const std::string& name) { + JsonValue* val = chain.back(); + JsonValue v; + v = static_cast(value); + + if (val->isArray()) { + val->pushBack(v); + } else { + val->insert(name, v); + } + return *this; +} + +ISerializer& JsonOutputStreamSerializer::operator()(std::string& value, const std::string& name) { + JsonValue* val = chain.back(); + JsonValue v; + v = value; + + if (val->isArray()) { + val->pushBack(v); + } else { + val->insert(name, v); + } + return *this; +} + +ISerializer& JsonOutputStreamSerializer::operator()(uint8_t& value, const std::string& name) { + uint64_t v = static_cast(value); + return operator()(v, name); +} + +ISerializer& JsonOutputStreamSerializer::operator()(bool& value, const std::string& name) { + JsonValue* val = chain.back(); + JsonValue v; + v = static_cast(value); + if (val->isArray()) { + val->pushBack(v); + } else { + val->insert(name, v); + } + + return *this; +} + +ISerializer& JsonOutputStreamSerializer::operator()(char* value, std::size_t size, const std::string& name) { + assert(false); + throw std::runtime_error("JsonOutputStreamSerializer doesn't support \"char *\" type of serialization"); + + return *this; +} + +ISerializer& JsonOutputStreamSerializer::tag(const std::string& name) { + assert(false); + throw std::runtime_error("JsonOutputStreamSerializer doesn't support this type of serialization"); + + return *this; +} + +ISerializer& JsonOutputStreamSerializer::untagged(uint8_t& value) { + assert(false); + throw std::runtime_error("JsonOutputStreamSerializer doesn't support this type of serialization"); + + return *this; +} + +ISerializer& JsonOutputStreamSerializer::endTag() { + assert(false); + throw std::runtime_error("JsonOutputStreamSerializer doesn't support this type of serialization"); + + return *this; +} + +bool JsonOutputStreamSerializer::hasObject(const std::string& name) { + assert(false); + throw std::runtime_error("JsonOutputStreamSerializer doesn't support this type of serialization"); + + return false; +} + +} + + diff --git a/src/serialization/JsonOutputStreamSerializer.h b/src/serialization/JsonOutputStreamSerializer.h new file mode 100644 index 00000000..fd6ebff7 --- /dev/null +++ b/src/serialization/JsonOutputStreamSerializer.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include "serialization/ISerializer.h" +#include "serialization/JsonValue.h" + +#include + +namespace cryptonote { + +class JsonOutputStreamSerializer : public ISerializer { +public: + JsonOutputStreamSerializer(); + virtual ~JsonOutputStreamSerializer(); + + JsonValue getJsonValue() const; + SerializerType type() const; + + virtual ISerializer& beginObject(const std::string& name) override; + virtual ISerializer& endObject() override; + + virtual ISerializer& beginArray(std::size_t& size, const std::string& name) override; + virtual ISerializer& endArray() override; + + virtual ISerializer& operator()(int32_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint32_t& value, const std::string& name) override; + virtual ISerializer& operator()(int64_t& value, const std::string& name) override; + virtual ISerializer& operator()(uint64_t& value, const std::string& name) override; + virtual ISerializer& operator()(double& value, const std::string& name) override; + virtual ISerializer& operator()(std::string& value, const std::string& name) override; + virtual ISerializer& operator()(uint8_t& value, const std::string& name) override; + virtual ISerializer& operator()(bool& value, const std::string& name) override; + virtual ISerializer& operator()(char* value, std::size_t size, const std::string& name) override; + + virtual ISerializer& tag(const std::string& name) override; + virtual ISerializer& untagged(uint8_t& value) override; + virtual ISerializer& endTag() override; + + virtual bool hasObject(const std::string& name) override; + + template + ISerializer& operator()(T& value, const std::string& name) { + return ISerializer::operator()(value, name); + } + + friend std::ostream& operator<<(std::ostream& out, const JsonOutputStreamSerializer& enumerator); + +private: + JsonValue root; + std::vector chain; +}; + +} // namespace cryptonote diff --git a/src/serialization/JsonSerializationDispatcher.h b/src/serialization/JsonSerializationDispatcher.h new file mode 100644 index 00000000..94f26e2e --- /dev/null +++ b/src/serialization/JsonSerializationDispatcher.h @@ -0,0 +1,65 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include +#include +#include + +#include "serialization/JsonOutputStreamSerializer.h" +#include "serialization/JsonInputStreamSerializer.h" +#include "storages/portable_storage_template_helper.h" + +namespace { +BOOST_TTI_HAS_MEMBER_FUNCTION(serialize) +} //namespace + +namespace cryptonote { + +template +inline typename std::enable_if::value, void>::type SerializeToJson(T& obj, std::string& jsonBuff) { + std::stringstream stream; + JsonOutputStreamSerializer serializer; + + obj.serialize(serializer, ""); + + stream << serializer; + jsonBuff = stream.str(); +} + +template +inline typename std::enable_if::value, void>::type LoadFromJson(T& obj, const std::string& jsonBuff) { + std::stringstream stream(jsonBuff); + JsonInputStreamSerializer serializer(stream); + + obj.serialize(serializer, ""); +} + +//old epee serialization + +template +inline typename std::enable_if::value, void>::type SerializeToJson(T& obj, std::string& jsonBuff) { + epee::serialization::store_t_to_json(obj, jsonBuff); +} + +template +inline typename std::enable_if::value, void>::type LoadFromJson(T& obj, const std::string& jsonBuff) { + epee::serialization::load_t_from_json(obj, jsonBuff); +} + +} //namespace cryptonote diff --git a/src/serialization/JsonValue.cpp b/src/serialization/JsonValue.cpp new file mode 100644 index 00000000..c9ef17ba --- /dev/null +++ b/src/serialization/JsonValue.cpp @@ -0,0 +1,612 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "JsonValue.h" +#include +#include +#include + +namespace cryptonote { + +JsonValue::JsonValue() : d_type(NIL) { +} + +JsonValue::JsonValue(JsonValue::Type type) { + switch(type) { + case OBJECT: + new(d_valueObject)JsonValue::Object(); + break; + case ARRAY: + new(d_valueArray)JsonValue::Array(); + break; + default: + throw std::runtime_error("Wrong JsonValue type. Object or Array are possible only"); + } + + d_type = type; +} + +JsonValue::JsonValue(const JsonValue& other) : d_type(other.d_type) { + switch (d_type) { + case ARRAY: + new(d_valueArray)JsonValue::Array(*reinterpret_cast(other.d_valueArray)); + break; + case BOOL: + d_valueBool = other.d_valueBool; + break; + case INT64: + d_valueInt64 = other.d_valueInt64; + break; + case NIL: + break; + case OBJECT: + new(d_valueObject)JsonValue::Object(*reinterpret_cast(other.d_valueObject)); + break; + case DOUBLE: + d_valueDouble = other.d_valueDouble; + break; + case STRING: + new(d_valueString)std::string(*reinterpret_cast(other.d_valueString)); + break; + default: + throw(std::runtime_error("Invalid type")); + } +} + +JsonValue::~JsonValue() { + destructValue(); +} + +bool JsonValue::isArray() const { + return d_type == ARRAY; +} + +bool JsonValue::isBool() const { + return d_type == BOOL; +} + +bool JsonValue::isInt64() const { + return d_type == INT64; +} + +bool JsonValue::isNil() const { + return d_type == NIL; +} + +bool JsonValue::isObject() const { + return d_type == OBJECT; +} + +bool JsonValue::isDouble() const { + return d_type == DOUBLE; +} + +bool JsonValue::isString() const { + return d_type == STRING; +} + +bool JsonValue::getBool() const { + assert(d_type == BOOL); + if (d_type != BOOL) { + throw(std::runtime_error("Value type is not BOOL")); + } + + return d_valueBool; +} + +int64_t JsonValue::getNumber() const { + assert(d_type == INT64); + if (d_type != INT64) { + throw(std::runtime_error("Value type is not INT64")); + } + + return d_valueInt64; +} + +const JsonValue::Object& JsonValue::getObject() const { + assert(d_type == OBJECT); + if (d_type != OBJECT) { + throw(std::runtime_error("Value type is not OBJECT")); + } + + return *reinterpret_cast(d_valueObject); +} + +double JsonValue::getDouble() const { + assert(d_type == DOUBLE); + if (d_type != DOUBLE) { + throw(std::runtime_error("Value type is not DOUBLE")); + } + + return d_valueDouble; +} + +std::string JsonValue::getString() const { + assert(d_type == STRING); + if (d_type != STRING) { + throw(std::runtime_error("Value type is not STRING")); + } + + return *reinterpret_cast(d_valueString); +} + +const JsonValue& JsonValue::operator()(const std::string& name) const { + assert(d_type == OBJECT); + assert(reinterpret_cast(d_valueObject)->count(name) > 0); + if (d_type != OBJECT) { + throw(std::runtime_error("Value type is not OBJECT")); + } + + return reinterpret_cast(d_valueObject)->at(name); +} + +size_t JsonValue::count(const std::string& name) const { + assert(d_type == OBJECT); + if (d_type != OBJECT) { + throw(std::runtime_error("Value type is not OBJECT")); + } + + return reinterpret_cast(d_valueObject)->count(name); +} + +const JsonValue& JsonValue::operator[](size_t index) const { + assert(d_type == ARRAY); + if (d_type != ARRAY) { + throw(std::runtime_error("Value type is not ARRAY")); + } + + return reinterpret_cast(d_valueArray)->at(index); +} + +size_t JsonValue::size() const { + assert(d_type == ARRAY || d_type == OBJECT); + switch (d_type) { + case OBJECT: + return reinterpret_cast(d_valueString)->size(); + case ARRAY: + return reinterpret_cast(d_valueString)->size(); + default: + throw(std::runtime_error("Value type is not ARRAY or OBJECT")); + } +} + +JsonValue::Array::const_iterator JsonValue::begin() const { + assert(d_type == ARRAY); + if (d_type != ARRAY) { + throw(std::runtime_error("Value type is not ARRAY")); + } + + return reinterpret_cast(d_valueArray)->begin(); +} + +JsonValue::Array::const_iterator JsonValue::end() const { + assert(d_type == ARRAY); + if (d_type != ARRAY) { + throw(std::runtime_error("Value type is not ARRAY")); + } + + return reinterpret_cast(d_valueArray)->end(); +} + +void JsonValue::readArray(std::istream& in) { + char c; + JsonValue::Array value; + + c = in.peek(); + while (true) { + if (!isspace(in.peek())) break; + in.read(&c, 1); + } + + if (c != ']') { + for (;;) { + value.resize(value.size() + 1); + in >> value.back(); + in >> c; + while (isspace(c)) in >> c; + if (c == ']') { + break; + } + + if (c != ',') { + throw(std::runtime_error("Unable to parse")); + } + } + } + + if (d_type != JsonValue::ARRAY) { + destructValue(); + d_type = JsonValue::NIL; + new(d_valueArray)JsonValue::Array; + d_type = JsonValue::ARRAY; + } + + reinterpret_cast(d_valueArray)->swap(value); +} + +void JsonValue::readTrue(std::istream& in) { + char data[3]; + in.read(data, 3); + if (data[0] != 'r' || data[1] != 'u' || data[2] != 'e') { + throw(std::runtime_error("Unable to parse")); + } + + if (d_type != JsonValue::BOOL) { + destructValue(); + d_type = JsonValue::BOOL; + } + + d_valueBool = true; +} + +void JsonValue::readFalse(std::istream& in) { + char data[4]; + in.read(data, 4); + if (data[0] != 'a' || data[1] != 'l' || data[2] != 's' || data[3] != 'e') { + throw(std::runtime_error("Unable to parse")); + } + + if (d_type != JsonValue::BOOL) { + destructValue(); + d_type = JsonValue::BOOL; + } + + d_valueBool = false; +} + +void JsonValue::readNumber(std::istream& in, char c) { + std::string text; + text += c; + size_t dots = 0; + for (;;) { + int i = in.peek(); + if (i >= '0' && i <= '9') { + in.read(&c, 1); + text += c; + } else if (i == '.') { + in.read(&c, 1); + text += '.'; + ++dots; + } else { + break; + } + } + + if (dots > 0) { + if (dots > 1) { + throw(std::runtime_error("Unable to parse")); + } + + int i = in.peek(); + if (in.peek() == 'e') { + in.read(&c, 1); + text += c; + i = in.peek(); + if (i == '+') { + in.read(&c, 1); + text += c; + i = in.peek(); + } else if (i == '-') { + in.read(&c, 1); + text += c; + i = in.peek(); + } + + if (i < '0' || i > '9') { + throw(std::runtime_error("Unable to parse")); + } + + do { + in.read(&c, 1); + text += c; + i = in.peek(); + } while (i >= '0' && i <= '9'); + } + + double value; + std::istringstream(text) >> value; + if (d_type != JsonValue::DOUBLE) { + destructValue(); + d_type = JsonValue::DOUBLE; + } + + d_valueDouble = value; + } else { + if (text.size() > 1 && ((text[0] == '0') || (text[0] == '-' && text[1] == '0'))) { + throw(std::runtime_error("Unable to parse")); + } + + int64_t value; + std::istringstream(text) >> value; + if (d_type != JsonValue::INT64) { + destructValue(); + d_type = JsonValue::INT64; + } + + d_valueInt64 = value; + } +} + +void JsonValue::readNull(std::istream& in) { + char data[3]; + in.read(data, 3); + if (data[0] != 'u' || data[1] != 'l' || data[2] != 'l') { + throw(std::runtime_error("Unable to parse")); + } + + if (d_type != JsonValue::NIL) { + destructValue(); + d_type = JsonValue::NIL; + } +} + +void JsonValue::readObject(std::istream& in) { + char c; + JsonValue::Object value; + in >> c; + while (isspace(c)) in >> c; + + if (c != '}') { + std::string name; + for (;;) { + if (c != '"') { + throw(std::runtime_error("Unable to parse")); + } + + name.clear(); + for (;;) { + in >> c; + if (c == '"') { + break; + } + + if (c == '\\') { + name += c; + in >> c; + } + + name += c; + } + + in >> c; + while (isspace(c)) in >> c; + if (c != ':') { + throw(std::runtime_error("Unable to parse")); + } + + in >> value[name]; + in >> c; + while (isspace(c)) in >> c; + if (c == '}') { + break; + } + + if (c != ',') { + throw(std::runtime_error("Unable to parse")); + } + in >> c; + while (isspace(c)) in >> c; + } + } + + if (d_type != JsonValue::OBJECT) { + destructValue(); + d_type = JsonValue::NIL; + new(d_valueObject)JsonValue::Object; + d_type = JsonValue::OBJECT; + } + + reinterpret_cast(d_valueObject)->swap(value); +} + +void JsonValue::readString(std::istream& in) { + char c; + std::string value; + + for (;;) { + in.read(&c, 1); + if (c == '"') { + break; + } + + if (c == '\\') { + value += c; + in >> c; + } + + value += c; + } + + if (d_type != JsonValue::STRING) { + destructValue(); + d_type = JsonValue::NIL; + new(d_valueString)std::string; + d_type = JsonValue::STRING; + } + + reinterpret_cast(d_valueString)->swap(value); +} + +std::istream& operator>>(std::istream& in, JsonValue& jsonValue) { + char c; + in >> c; + while (isspace(c)) in >> c; + if (c == '[') { + jsonValue.readArray(in); + } else if (c == 't') { + jsonValue.readTrue(in); + } else if (c == 'f') { + jsonValue.readFalse(in); + } else if ((c == '-') || (c >= '0' && c <= '9')) { + jsonValue.readNumber(in, c); + } else if (c == 'n') { + jsonValue.readNull(in); + } else if (c == '{') { + jsonValue.readObject(in); + } else if (c == '"') { + jsonValue.readString(in); + } else { + throw(std::runtime_error("Unable to parse")); + } + + return in; +} + +std::ostream& operator<<(std::ostream& out, const JsonValue& jsonValue) { + if (jsonValue.d_type == JsonValue::ARRAY) { + const JsonValue::Array& array = *reinterpret_cast(jsonValue.d_valueArray); + out << '['; + if (array.size() > 0) { + out << array[0]; + for (size_t i = 1; i < array.size(); ++i) { + out << ',' << array[i]; + } + } + + out << ']'; + } else if (jsonValue.d_type == JsonValue::BOOL) { + out << (jsonValue.d_valueBool ? "true" : "false"); + } else if (jsonValue.d_type == JsonValue::INT64) { + out << jsonValue.d_valueInt64; + } else if (jsonValue.d_type == JsonValue::NIL) { + out << "null"; + } else if (jsonValue.d_type == JsonValue::OBJECT) { + const JsonValue::Object& object = *reinterpret_cast(jsonValue.d_valueObject); + out << '{'; + auto iter = object.begin(); + if (iter != object.end()) { + out << '"' << iter->first << "\":" << iter->second; + ++iter; + for (; iter != object.end(); ++iter) { + out << ",\"" << iter->first << "\":" << iter->second; + } + } + + out << '}'; + } else if (jsonValue.d_type == JsonValue::DOUBLE) { + std::ostringstream stream; + stream << std::fixed << std::setprecision(11) << jsonValue.d_valueDouble; + std::string value = stream.str(); + while (value.size() > 1 && value[value.size() - 2] != '.' && value[value.size() - 1] == '0') { + value.resize(value.size() - 1); + } + + out << value; + } else if (jsonValue.d_type == JsonValue::STRING) { + out << '"' << *reinterpret_cast(jsonValue.d_valueString) << '"'; + } else { + throw(std::runtime_error("Invalid type")); + } + + return out; +} + +void JsonValue::destructValue() { + switch (d_type) { + case ARRAY: + reinterpret_cast(d_valueArray)->~Array(); + break; + case OBJECT: + reinterpret_cast(d_valueObject)->~Object(); + break; + case STRING: + reinterpret_cast(d_valueString)->~basic_string(); + break; + default: + break; + } +} + +JsonValue& JsonValue::pushBack(const JsonValue& val) { + if (d_type != ARRAY) { + throw std::runtime_error("JsonValue error. pushBack is only possible for arrays"); + } + + Array* array = reinterpret_cast(d_valueArray); + array->push_back(val); + + return array->back(); +} + +JsonValue& JsonValue::insert(const std::string key, const JsonValue& value) { + if (d_type != OBJECT) { + throw std::runtime_error("JsonValue error. insert is only possible for objects"); + } + + Object* obj = reinterpret_cast(d_valueObject); + + auto res = obj->insert(std::make_pair(key, value)); + return res.first->second; +} + +JsonValue& JsonValue::operator=(bool value) { + if (d_type != BOOL) { + destructValue(); + d_type = BOOL; + } + + d_valueBool = value; + + return *this; +} + +JsonValue& JsonValue::operator=(int64_t value) { + if (d_type != INT64) { + destructValue(); + d_type = INT64; + } + + d_valueInt64 = value; + + return *this; +} + +//JsonValue& JsonValue::operator=(NilType value) { +// if (d_type != NIL) { +// destructValue(); +// d_type = NIL; +// } +//} + +JsonValue& JsonValue::operator=(double value) { + if (d_type != DOUBLE) { + destructValue(); + d_type = DOUBLE; + } + + d_valueDouble = value; + + return *this; +} + +JsonValue& JsonValue::operator=(const std::string& value) { + if (d_type != STRING) { + destructValue(); + new(d_valueString)std::string; + d_type = STRING; + } + + reinterpret_cast(d_valueString)->assign(value.data(), value.size()); + + return *this; +} + +JsonValue& JsonValue::operator=(const char* value) { + return operator=(std::string(value)); +} + +} //namespace cryptonote diff --git a/src/serialization/JsonValue.h b/src/serialization/JsonValue.h new file mode 100644 index 00000000..53a82f82 --- /dev/null +++ b/src/serialization/JsonValue.h @@ -0,0 +1,103 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include +#include +#include + +#include + +namespace cryptonote { + +class JsonValue { +public: + typedef std::vector Array; + typedef std::map Object; + + enum Type { + ARRAY, + BOOL, + INT64, + NIL, + OBJECT, + DOUBLE, + STRING + }; + + JsonValue(); + JsonValue(Type type); + JsonValue(const JsonValue& other); + ~JsonValue(); + JsonValue& operator=(const JsonValue& other) = delete; + bool isArray() const; + bool isBool() const; + bool isInt64() const; + bool isNil() const; + bool isObject() const; + bool isDouble() const; + bool isString() const; + bool getBool() const; + int64_t getNumber() const; + const Object& getObject() const; + double getDouble() const; + std::string getString() const; + const JsonValue& operator()(const std::string& name) const; + size_t count(const std::string& name) const; + const JsonValue& operator[](size_t index) const; + size_t size() const; + Array::const_iterator begin() const; + Array::const_iterator end() const; + + JsonValue& pushBack(const JsonValue& val); + JsonValue& insert(const std::string key, const JsonValue& value); + + JsonValue& operator=(bool value); + JsonValue& operator=(int64_t value); +// JsonValue& operator=(NilType value); + JsonValue& operator=(double value); + JsonValue& operator=(const std::string& value); + JsonValue& operator=(const char* value); + + + friend std::istream& operator>>(std::istream& in, JsonValue& jsonValue); + friend std::ostream& operator<<(std::ostream& out, const JsonValue& jsonValue); + +private: + size_t d_type; + union { + uint8_t d_valueArray[sizeof(Array)]; + bool d_valueBool; + int64_t d_valueInt64; + uint8_t d_valueObject[sizeof(Object)]; + double d_valueDouble; + uint8_t d_valueString[sizeof(std::string)]; + }; + + void destructValue(); + + void readArray(std::istream& in); + void readTrue(std::istream& in); + void readFalse(std::istream& in); + void readNumber(std::istream& in, char c); + void readNull(std::istream& in); + void readObject(std::istream& in); + void readString(std::istream& in); +}; + +} //namespace cryptonote diff --git a/src/serialization/SerializationOverloads.cpp b/src/serialization/SerializationOverloads.cpp new file mode 100644 index 00000000..ffd5e296 --- /dev/null +++ b/src/serialization/SerializationOverloads.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "SerializationOverloads.h" + +#include + +namespace cryptonote { + +void readVarint(uint64_t& value, cryptonote::ISerializer& serializer) { + const int bits = std::numeric_limits::digits; + + uint64_t v = 0; + for (int shift = 0;; shift += 7) { + uint8_t b; + serializer.untagged(b); + + if (shift + 7 >= bits && b >= 1 << (bits - shift)) { + throw std::runtime_error("Varint overflow"); + } + + if (b == 0 && shift != 0) { + throw std::runtime_error("Non-canonical varint representation"); + } + + v |= static_cast(b & 0x7f) << shift; + if ((b & 0x80) == 0) { + break; + } + } + + value = v; +} + +void writeVarint(uint64_t& value, cryptonote::ISerializer& serializer) { + uint64_t v = value; + + while (v >= 0x80) { + uint8_t b = (static_cast(v) & 0x7f) | 0x80; + serializer.untagged(b); + v >>= 7; + } + + uint8_t b = static_cast(v); + serializer.untagged(b); +} + + +void serializeVarint(uint64_t& value, const std::string& name, cryptonote::ISerializer& serializer) { + serializer.tag(name); + + if (serializer.type() == cryptonote::ISerializer::INPUT) { + readVarint(value, serializer); + } else { + writeVarint(value, serializer); + } + + serializer.endTag(); +} + +void serializeVarint(uint32_t& value, const std::string& name, cryptonote::ISerializer& serializer) { + uint64_t v = value; + serializeVarint(v, name, serializer); + value = static_cast(v); +} + +} diff --git a/src/serialization/SerializationOverloads.h b/src/serialization/SerializationOverloads.h new file mode 100644 index 00000000..a4a58384 --- /dev/null +++ b/src/serialization/SerializationOverloads.h @@ -0,0 +1,78 @@ +// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include "ISerializer.h" + +#include +#include +#include + +namespace cryptonote { + +void serializeVarint(uint64_t& value, const std::string& name, cryptonote::ISerializer& serializer); +void serializeVarint(uint32_t& value, const std::string& name, cryptonote::ISerializer& serializer); + +template +void serialize(std::vector& value, const std::string& name, cryptonote::ISerializer& serializer) { + std::size_t size = value.size(); + serializer.beginArray(size, name); + value.resize(size); + + for (size_t i = 0; i < size; ++i) { + serializer(value[i], ""); + } + + serializer.endArray(); +} + +template +void serialize(std::unordered_map& value, const std::string& name, cryptonote::ISerializer& serializer) { + std::size_t size; + size = value.size(); + + serializer.beginArray(size, name); + + if (serializer.type() == cryptonote::ISerializer::INPUT) { + value.reserve(size); + + for (size_t i = 0; i < size; ++i) { + K key; + V v; + serializer.beginObject(""); + serializer(key, ""); + serializer(v, ""); + serializer.endObject(); + + value[key] = v; + } + } else { + for (auto kv: value) { + K key; + key = kv.first; + serializer.beginObject(""); + serializer(key, ""); + serializer(kv.second, ""); + serializer.endObject(); + } + } + + serializer.endArray(); +} + +}