// Copyright (c) 2012-2015, 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 "KVBinaryInputStreamSerializer.h" #include #include #include #include #include "KVBinaryCommon.h" using Common::JsonValue; using namespace CryptoNote; namespace { void strictRead(std::istream& s, void* ptr, size_t size) { if (s.read(reinterpret_cast(ptr), size).gcount() != size) { throw std::runtime_error("read error"); } } template T readPod(std::istream& s) { T v; strictRead(s, &v, sizeof(T)); return v; } template JsonValue readPodJson(std::istream& s) { JsonValue jv; jv = static_cast(readPod(s)); return jv; } template JsonValue readIntegerJson(std::istream& s) { return readPodJson(s); } size_t readVarint(std::istream& s) { size_t v = 0; uint8_t size_mask = uint8_t(s.peek()) & PORTABLE_RAW_SIZE_MARK_MASK; switch (size_mask) { case PORTABLE_RAW_SIZE_MARK_BYTE: v = readPod(s); break; case PORTABLE_RAW_SIZE_MARK_WORD: v = readPod(s); break; case PORTABLE_RAW_SIZE_MARK_DWORD: v = readPod(s); break; case PORTABLE_RAW_SIZE_MARK_INT64: v = readPod(s); break; default: throw std::runtime_error("unknown varint size_mask"); } v >>= 2; return v; } std::string readString(std::istream& s) { auto size = readVarint(s); std::string str; str.resize(size); if (size) { strictRead(s, &str[0], size); } return str; } JsonValue readStringJson(std::istream& s) { return JsonValue(readString(s)); } void readName(std::istream& s, std::string& name) { uint8_t len = readPod(s); if (len) { name.resize(len); strictRead(s, &name[0], len); } } JsonValue loadValue(std::istream& stream, uint8_t type); JsonValue loadSection(std::istream& stream); JsonValue loadEntry(std::istream& stream); JsonValue loadArray(std::istream& stream, uint8_t itemType); JsonValue loadSection(std::istream& stream) { JsonValue sec(JsonValue::OBJECT); size_t count = readVarint(stream); std::string name; while (count--) { readName(stream, name); sec.insert(name, loadEntry(stream)); } return sec; } JsonValue loadValue(std::istream& stream, uint8_t type) { switch (type) { case BIN_KV_SERIALIZE_TYPE_INT64: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_INT32: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_INT16: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_INT8: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_UINT64: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_UINT32: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_UINT16: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_UINT8: return readIntegerJson(stream); case BIN_KV_SERIALIZE_TYPE_DOUBLE: return readPodJson(stream); case BIN_KV_SERIALIZE_TYPE_BOOL: return JsonValue(stream.get() != 0); case BIN_KV_SERIALIZE_TYPE_STRING: return readStringJson(stream); case BIN_KV_SERIALIZE_TYPE_OBJECT: return loadSection(stream); case BIN_KV_SERIALIZE_TYPE_ARRAY: return loadArray(stream, type); default: throw std::runtime_error("Unknown data type"); break; } } JsonValue loadEntry(std::istream& stream) { uint8_t type = readPod(stream); if (type & BIN_KV_SERIALIZE_FLAG_ARRAY) { type &= ~BIN_KV_SERIALIZE_FLAG_ARRAY; return loadArray(stream, type); } return loadValue(stream, type); } JsonValue loadArray(std::istream& stream, uint8_t itemType) { JsonValue arr(JsonValue::ARRAY); size_t count = readVarint(stream); while (count--) { arr.pushBack(loadValue(stream, itemType)); } return arr; } JsonValue parseBinary(std::istream& stream) { auto hdr = readPod(stream); if ( hdr.m_signature_a != PORTABLE_STORAGE_SIGNATUREA || hdr.m_signature_b != PORTABLE_STORAGE_SIGNATUREB) { throw std::runtime_error("Invalid binary storage signature"); } if (hdr.m_ver != PORTABLE_STORAGE_FORMAT_VER) { throw std::runtime_error("Unknown binary storage format version"); } return loadSection(stream); } } KVBinaryInputStreamSerializer::KVBinaryInputStreamSerializer(std::istream& strm) : value(parseBinary(strm)), JsonInputValueSerializer(value) { } bool KVBinaryInputStreamSerializer::binary(void* value, std::size_t size, Common::StringView name) { std::string str; if (!(*this)(str, name)) { return false; } if (str.size() != size) { throw std::runtime_error("Binary block size mismatch"); } memcpy(value, str.data(), size); return true; } bool KVBinaryInputStreamSerializer::binary(std::string& value, Common::StringView name) { return (*this)(value, name); // load as string }