Changeset View
Changeset View
Standalone View
Standalone View
src/serialize.h
Show All 17 Lines | |||||
#include <limits> | #include <limits> | ||||
#include <map> | #include <map> | ||||
#include <memory> | #include <memory> | ||||
#include <set> | #include <set> | ||||
#include <string> | #include <string> | ||||
#include <utility> | #include <utility> | ||||
#include <vector> | #include <vector> | ||||
static const uint64_t MAX_SIZE = 0x02000000; | /** | ||||
* The maximum size of a serialized object in bytes or number of elements | |||||
* (for eg vectors) when the size is encoded as CompactSize. | |||||
*/ | |||||
static constexpr uint64_t MAX_SIZE = 0x02000000; | |||||
/** | /** | ||||
* Maximum amount of memory (in bytes) to allocate at once when deserializing | * Maximum amount of memory (in bytes) to allocate at once when deserializing | ||||
* vectors. | * vectors. | ||||
*/ | */ | ||||
static const unsigned int MAX_VECTOR_ALLOCATE = 5000000; | static const unsigned int MAX_VECTOR_ALLOCATE = 5000000; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 405 Lines • ▼ Show 20 Lines | if (nSize < 253) { | ||||
ser_writedata32(os, nSize); | ser_writedata32(os, nSize); | ||||
} else { | } else { | ||||
ser_writedata8(os, 255); | ser_writedata8(os, 255); | ||||
ser_writedata64(os, nSize); | ser_writedata64(os, nSize); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
template <typename Stream> uint64_t ReadCompactSize(Stream &is) { | /** | ||||
* Decode a CompactSize-encoded variable-length integer. | |||||
* | |||||
* As these are primarily used to encode the size of vector-like serializations, | |||||
* by default a range check is performed. When used as a generic number | |||||
* encoding, range_check should be set to false. | |||||
*/ | |||||
template <typename Stream> | |||||
uint64_t ReadCompactSize(Stream &is, bool range_check = true) { | |||||
uint8_t chSize = ser_readdata8(is); | uint8_t chSize = ser_readdata8(is); | ||||
uint64_t nSizeRet = 0; | uint64_t nSizeRet = 0; | ||||
if (chSize < 253) { | if (chSize < 253) { | ||||
nSizeRet = chSize; | nSizeRet = chSize; | ||||
} else if (chSize == 253) { | } else if (chSize == 253) { | ||||
nSizeRet = ser_readdata16(is); | nSizeRet = ser_readdata16(is); | ||||
if (nSizeRet < 253) { | if (nSizeRet < 253) { | ||||
throw std::ios_base::failure("non-canonical ReadCompactSize()"); | throw std::ios_base::failure("non-canonical ReadCompactSize()"); | ||||
} | } | ||||
} else if (chSize == 254) { | } else if (chSize == 254) { | ||||
nSizeRet = ser_readdata32(is); | nSizeRet = ser_readdata32(is); | ||||
if (nSizeRet < 0x10000u) { | if (nSizeRet < 0x10000u) { | ||||
throw std::ios_base::failure("non-canonical ReadCompactSize()"); | throw std::ios_base::failure("non-canonical ReadCompactSize()"); | ||||
} | } | ||||
} else { | } else { | ||||
nSizeRet = ser_readdata64(is); | nSizeRet = ser_readdata64(is); | ||||
if (nSizeRet < 0x100000000ULL) { | if (nSizeRet < 0x100000000ULL) { | ||||
throw std::ios_base::failure("non-canonical ReadCompactSize()"); | throw std::ios_base::failure("non-canonical ReadCompactSize()"); | ||||
} | } | ||||
} | } | ||||
if (nSizeRet > MAX_SIZE) { | if (range_check && nSizeRet > MAX_SIZE) { | ||||
throw std::ios_base::failure("ReadCompactSize(): size too large"); | throw std::ios_base::failure("ReadCompactSize(): size too large"); | ||||
} | } | ||||
return nSizeRet; | return nSizeRet; | ||||
} | } | ||||
/** | /** | ||||
* Variable-length integers: bytes are a MSB base-128 encoding of the number. | * Variable-length integers: bytes are a MSB base-128 encoding of the number. | ||||
* The high bit in each byte signifies whether another digit follows. To make | * The high bit in each byte signifies whether another digit follows. To make | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
template <typename Formatter, typename T> | template <typename Formatter, typename T> | ||||
static inline Wrapper<Formatter, T &> Using(T &&t) { | static inline Wrapper<Formatter, T &> Using(T &&t) { | ||||
return Wrapper<Formatter, T &>(t); | return Wrapper<Formatter, T &>(t); | ||||
} | } | ||||
#define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj) | #define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj) | ||||
#define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) | #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) | ||||
#define COMPACTSIZE(obj) Using<CompactSizeFormatter>(obj) | #define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj) | ||||
#define LIMITED_STRING(obj, n) LimitedString<n>(REF(obj)) | #define LIMITED_STRING(obj, n) LimitedString<n>(REF(obj)) | ||||
/** | /** | ||||
* Serialization wrapper class for integers in VarInt format. | * Serialization wrapper class for integers in VarInt format. | ||||
*/ | */ | ||||
template <VarIntMode Mode> struct VarIntFormatter { | template <VarIntMode Mode> struct VarIntFormatter { | ||||
template <typename Stream, typename I> void Ser(Stream &s, I v) { | template <typename Stream, typename I> void Ser(Stream &s, I v) { | ||||
WriteVarInt<Stream, Mode, typename std::remove_cv<I>::type>(s, v); | WriteVarInt<Stream, Mode, typename std::remove_cv<I>::type>(s, v); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | template <typename Stream, typename I> void Unser(Stream &s, I &v) { | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
template <int Bytes> | template <int Bytes> | ||||
using BigEndianFormatter = CustomUintFormatter<Bytes, true>; | using BigEndianFormatter = CustomUintFormatter<Bytes, true>; | ||||
/** Formatter for integers in CompactSize format. */ | /** Formatter for integers in CompactSize format. */ | ||||
struct CompactSizeFormatter { | template <bool RangeCheck> struct CompactSizeFormatter { | ||||
template <typename Stream, typename I> void Unser(Stream &s, I &v) { | template <typename Stream, typename I> void Unser(Stream &s, I &v) { | ||||
uint64_t n = ReadCompactSize<Stream>(s); | uint64_t n = ReadCompactSize<Stream>(s, RangeCheck); | ||||
if (n < std::numeric_limits<I>::min() || | if (n < std::numeric_limits<I>::min() || | ||||
n > std::numeric_limits<I>::max()) { | n > std::numeric_limits<I>::max()) { | ||||
throw std::ios_base::failure("CompactSize exceeds limit of type"); | throw std::ios_base::failure("CompactSize exceeds limit of type"); | ||||
} | } | ||||
v = n; | v = n; | ||||
} | } | ||||
template <typename Stream, typename I> void Ser(Stream &s, I v) { | template <typename Stream, typename I> void Ser(Stream &s, I v) { | ||||
▲ Show 20 Lines • Show All 528 Lines • Show Last 20 Lines |