2015-04-23 16:07:22 +00:00
|
|
|
// Copyright (c) 2011-2015 The Cryptonote developers
|
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
#include "KVBinaryInputStreamSerializer.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
2015-05-27 12:08:46 +00:00
|
|
|
#include <stdexcept>
|
2015-07-30 15:22:07 +00:00
|
|
|
#include <Common/StreamTools.h>
|
2015-05-27 12:08:46 +00:00
|
|
|
#include "KVBinaryCommon.h"
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
using namespace Common;
|
2015-04-06 16:13:07 +00:00
|
|
|
using namespace CryptoNote;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename T>
|
2015-07-30 15:22:07 +00:00
|
|
|
T readPod(Common::IInputStream& s) {
|
2015-04-06 16:13:07 +00:00
|
|
|
T v;
|
2015-07-30 15:22:07 +00:00
|
|
|
read(s, &v, sizeof(T));
|
2015-04-06 16:13:07 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename JsonT = T>
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue readPodJson(Common::IInputStream& s) {
|
2015-05-27 12:08:46 +00:00
|
|
|
JsonValue jv;
|
2015-07-15 12:23:00 +00:00
|
|
|
jv = static_cast<JsonT>(readPod<T>(s));
|
2015-04-06 16:13:07 +00:00
|
|
|
return jv;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue readIntegerJson(Common::IInputStream& s) {
|
2015-04-06 16:13:07 +00:00
|
|
|
return readPodJson<T, int64_t>(s);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t readVarint(Common::IInputStream& s) {
|
|
|
|
uint8_t b = read<uint8_t>(s);
|
|
|
|
uint8_t size_mask = b & PORTABLE_RAW_SIZE_MARK_MASK;
|
|
|
|
size_t bytesLeft = 0;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
switch (size_mask){
|
2015-04-06 16:13:07 +00:00
|
|
|
case PORTABLE_RAW_SIZE_MARK_BYTE:
|
2015-07-30 15:22:07 +00:00
|
|
|
bytesLeft = 0;
|
2015-04-06 16:13:07 +00:00
|
|
|
break;
|
|
|
|
case PORTABLE_RAW_SIZE_MARK_WORD:
|
2015-07-30 15:22:07 +00:00
|
|
|
bytesLeft = 1;
|
2015-04-06 16:13:07 +00:00
|
|
|
break;
|
|
|
|
case PORTABLE_RAW_SIZE_MARK_DWORD:
|
2015-07-30 15:22:07 +00:00
|
|
|
bytesLeft = 3;
|
2015-04-06 16:13:07 +00:00
|
|
|
break;
|
|
|
|
case PORTABLE_RAW_SIZE_MARK_INT64:
|
2015-07-30 15:22:07 +00:00
|
|
|
bytesLeft = 7;
|
2015-04-06 16:13:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
size_t value = b;
|
|
|
|
|
|
|
|
for (size_t i = 1; i <= bytesLeft; ++i) {
|
|
|
|
size_t n = read<uint8_t>(s);
|
|
|
|
value |= n << (i * 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
value >>= 2;
|
|
|
|
return value;
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::string readString(Common::IInputStream& s) {
|
2015-04-06 16:13:07 +00:00
|
|
|
auto size = readVarint(s);
|
|
|
|
std::string str;
|
|
|
|
str.resize(size);
|
2015-07-15 12:23:00 +00:00
|
|
|
if (size) {
|
2015-07-30 15:22:07 +00:00
|
|
|
read(s, &str[0], size);
|
2015-07-15 12:23:00 +00:00
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue readStringJson(Common::IInputStream& s) {
|
2015-07-15 12:23:00 +00:00
|
|
|
return JsonValue(readString(s));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
void readName(Common::IInputStream& s, std::string& name) {
|
2015-04-06 16:13:07 +00:00
|
|
|
uint8_t len = readPod<uint8_t>(s);
|
2015-07-15 12:23:00 +00:00
|
|
|
if (len) {
|
|
|
|
name.resize(len);
|
2015-07-30 15:22:07 +00:00
|
|
|
read(s, &name[0], len);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue loadValue(Common::IInputStream& stream, uint8_t type);
|
|
|
|
JsonValue loadSection(Common::IInputStream& stream);
|
|
|
|
JsonValue loadEntry(Common::IInputStream& stream);
|
|
|
|
JsonValue loadArray(Common::IInputStream& stream, uint8_t itemType);
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue loadSection(Common::IInputStream& stream) {
|
2015-04-06 16:13:07 +00:00
|
|
|
JsonValue sec(JsonValue::OBJECT);
|
|
|
|
size_t count = readVarint(stream);
|
|
|
|
std::string name;
|
|
|
|
|
|
|
|
while (count--) {
|
|
|
|
readName(stream, name);
|
2015-07-15 12:23:00 +00:00
|
|
|
sec.insert(name, loadEntry(stream));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue loadValue(Common::IInputStream& stream, uint8_t type) {
|
2015-04-06 16:13:07 +00:00
|
|
|
switch (type) {
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_INT64: return readIntegerJson<int64_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_INT32: return readIntegerJson<int32_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_INT16: return readIntegerJson<int16_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_INT8: return readIntegerJson<int8_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_UINT64: return readIntegerJson<uint64_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_UINT32: return readIntegerJson<uint32_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_UINT16: return readIntegerJson<uint16_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_UINT8: return readIntegerJson<uint8_t>(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_DOUBLE: return readPodJson<double>(stream);
|
2015-07-30 15:22:07 +00:00
|
|
|
case BIN_KV_SERIALIZE_TYPE_BOOL: return JsonValue(read<uint8_t>(stream) != 0);
|
2015-04-06 16:13:07 +00:00
|
|
|
case BIN_KV_SERIALIZE_TYPE_STRING: return readStringJson(stream);
|
2015-07-15 12:23:00 +00:00
|
|
|
case BIN_KV_SERIALIZE_TYPE_OBJECT: return loadSection(stream);
|
|
|
|
case BIN_KV_SERIALIZE_TYPE_ARRAY: return loadArray(stream, type);
|
2015-04-06 16:13:07 +00:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("Unknown data type");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue loadEntry(Common::IInputStream& stream) {
|
2015-04-06 16:13:07 +00:00
|
|
|
uint8_t type = readPod<uint8_t>(stream);
|
|
|
|
|
|
|
|
if (type & BIN_KV_SERIALIZE_FLAG_ARRAY) {
|
|
|
|
type &= ~BIN_KV_SERIALIZE_FLAG_ARRAY;
|
2015-07-15 12:23:00 +00:00
|
|
|
return loadArray(stream, type);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
return loadValue(stream, type);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue loadArray(Common::IInputStream& stream, uint8_t itemType) {
|
2015-04-06 16:13:07 +00:00
|
|
|
JsonValue arr(JsonValue::ARRAY);
|
|
|
|
size_t count = readVarint(stream);
|
|
|
|
|
|
|
|
while (count--) {
|
2015-07-15 12:23:00 +00:00
|
|
|
arr.pushBack(loadValue(stream, itemType));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
JsonValue parseBinary(Common::IInputStream& stream) {
|
2015-07-15 12:23:00 +00:00
|
|
|
auto hdr = readPod<KVBinaryStorageBlockHeader>(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
KVBinaryInputStreamSerializer::KVBinaryInputStreamSerializer(Common::IInputStream& strm) : JsonInputValueSerializer(parseBinary(strm)) {
|
2015-07-15 12:23:00 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
bool KVBinaryInputStreamSerializer::binary(void* value, size_t size, Common::StringView name) {
|
2015-07-15 12:23:00 +00:00
|
|
|
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;
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
bool KVBinaryInputStreamSerializer::binary(std::string& value, Common::StringView name) {
|
|
|
|
return (*this)(value, name); // load as string
|
|
|
|
}
|
|
|
|
|