From 0a61b0df1224a5470bcddab302bc199ca5a9e356 Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Sun, 29 Aug 2010 16:58:15 +0000 Subject: propset svn:eol-style native git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@146 1a98c847-1fd6-4fd8-948a-caf3550aa51b --- serialize.h | 2370 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 1185 insertions(+), 1185 deletions(-) (limited to 'serialize.h') diff --git a/serialize.h b/serialize.h index d1dcea218d..3797159726 100644 --- a/serialize.h +++ b/serialize.h @@ -1,1185 +1,1185 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 int64; -typedef unsigned __int64 uint64; -#else -typedef long long int64; -typedef unsigned long long uint64; -#endif -#if defined(_MSC_VER) && _MSC_VER < 1300 -#define for if (false) ; else for -#endif -class CScript; -class CDataStream; -class CAutoFile; - -static const unsigned int MAX_SIZE = 0x02000000; - -static const int VERSION = 311; -static const char* pszSubVer = ".0"; - - - - - - -///////////////////////////////////////////////////////////////// -// -// Templates for serializing to anything that looks like a stream, -// i.e. anything that supports .read(char*, int) and .write(char*, int) -// - -enum -{ - // primary actions - SER_NETWORK = (1 << 0), - SER_DISK = (1 << 1), - SER_GETHASH = (1 << 2), - - // modifiers - SER_SKIPSIG = (1 << 16), - SER_BLOCKHEADERONLY = (1 << 17), -}; - -#define IMPLEMENT_SERIALIZE(statements) \ - unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \ - { \ - CSerActionGetSerializeSize ser_action; \ - const bool fGetSize = true; \ - const bool fWrite = false; \ - const bool fRead = false; \ - unsigned int nSerSize = 0; \ - ser_streamplaceholder s; \ - s.nType = nType; \ - s.nVersion = nVersion; \ - {statements} \ - return nSerSize; \ - } \ - template \ - void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \ - { \ - CSerActionSerialize ser_action; \ - const bool fGetSize = false; \ - const bool fWrite = true; \ - const bool fRead = false; \ - unsigned int nSerSize = 0; \ - {statements} \ - } \ - template \ - void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \ - { \ - CSerActionUnserialize ser_action; \ - const bool fGetSize = false; \ - const bool fWrite = false; \ - const bool fRead = true; \ - unsigned int nSerSize = 0; \ - {statements} \ - } - -#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) - -#define READWRITEVER(obj) \ - do { \ - READWRITE((obj)); \ - if ((obj) == 10300) \ - (obj) = 300; \ - } while (false) - - - - - - -// -// Basic types -// -#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) -#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) - -inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } -inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } - -template inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } -template inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } - -template inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } -template inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } - -inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } -template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } -template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } - - - - - - -// -// Compact size -// size < 253 -- 1 byte -// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) -// size <= UINT_MAX -- 5 bytes (254 + 4 bytes) -// size > UINT_MAX -- 9 bytes (255 + 8 bytes) -// -inline unsigned int GetSizeOfCompactSize(uint64 nSize) -{ - if (nSize < UCHAR_MAX-2) return sizeof(unsigned char); - else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short); - else if (nSize <= UINT_MAX) return sizeof(unsigned char) + sizeof(unsigned int); - else return sizeof(unsigned char) + sizeof(uint64); -} - -template -void WriteCompactSize(Stream& os, uint64 nSize) -{ - if (nSize < UCHAR_MAX-2) - { - unsigned char chSize = nSize; - WRITEDATA(os, chSize); - } - else if (nSize <= USHRT_MAX) - { - unsigned char chSize = UCHAR_MAX-2; - unsigned short xSize = nSize; - WRITEDATA(os, chSize); - WRITEDATA(os, xSize); - } - else if (nSize <= UINT_MAX) - { - unsigned char chSize = UCHAR_MAX-1; - unsigned int xSize = nSize; - WRITEDATA(os, chSize); - WRITEDATA(os, xSize); - } - else - { - unsigned char chSize = UCHAR_MAX; - WRITEDATA(os, chSize); - WRITEDATA(os, nSize); - } - return; -} - -template -uint64 ReadCompactSize(Stream& is) -{ - unsigned char chSize; - READDATA(is, chSize); - uint64 nSizeRet = 0; - if (chSize < UCHAR_MAX-2) - { - nSizeRet = chSize; - } - else if (chSize == UCHAR_MAX-2) - { - unsigned short nSize; - READDATA(is, nSize); - nSizeRet = nSize; - } - else if (chSize == UCHAR_MAX-1) - { - unsigned int nSize; - READDATA(is, nSize); - nSizeRet = nSize; - } - else - { - uint64 nSize; - READDATA(is, nSize); - nSizeRet = nSize; - } - if (nSizeRet > (uint64)MAX_SIZE) - throw std::ios_base::failure("ReadCompactSize() : size too large"); - return nSizeRet; -} - - - -// -// Wrapper for serializing arrays and POD -// There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it -// -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) -class CFlatData -{ -protected: - char* pbegin; - char* pend; -public: - CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } - char* begin() { return pbegin; } - const char* begin() const { return pbegin; } - char* end() { return pend; } - const char* end() const { return pend; } - - unsigned int GetSerializeSize(int, int=0) const - { - return pend - pbegin; - } - - template - void Serialize(Stream& s, int, int=0) const - { - s.write(pbegin, pend - pbegin); - } - - template - void Unserialize(Stream& s, int, int=0) - { - s.read(pbegin, pend - pbegin); - } -}; - - - -// -// string stored as a fixed length field -// -template -class CFixedFieldString -{ -protected: - const string* pcstr; - string* pstr; -public: - explicit CFixedFieldString(const string& str) : pcstr(&str), pstr(NULL) { } - explicit CFixedFieldString(string& str) : pcstr(&str), pstr(&str) { } - - unsigned int GetSerializeSize(int, int=0) const - { - return LEN; - } - - template - void Serialize(Stream& s, int, int=0) const - { - char pszBuf[LEN]; - strncpy(pszBuf, pcstr->c_str(), LEN); - s.write(pszBuf, LEN); - } - - template - void Unserialize(Stream& s, int, int=0) - { - if (pstr == NULL) - throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"); - char pszBuf[LEN+1]; - s.read(pszBuf, LEN); - pszBuf[LEN] = '\0'; - *pstr = pszBuf; - } -}; - - - - - -// -// Forward declarations -// - -// string -template unsigned int GetSerializeSize(const basic_string& str, int, int=0); -template void Serialize(Stream& os, const basic_string& str, int, int=0); -template void Unserialize(Stream& is, basic_string& str, int, int=0); - -// vector -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&); -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&); -template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion=VERSION); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&); -template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion=VERSION); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&); -template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion=VERSION); - -// others derived from vector -extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=VERSION); -template void Serialize(Stream& os, const CScript& v, int nType, int nVersion=VERSION); -template void Unserialize(Stream& is, CScript& v, int nType, int nVersion=VERSION); - -// pair -template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion=VERSION); -template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion=VERSION); -template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion=VERSION); - -// map -template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion=VERSION); -template void Serialize(Stream& os, const std::map& m, int nType, int nVersion=VERSION); -template void Unserialize(Stream& is, std::map& m, int nType, int nVersion=VERSION); - -// set -template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion=VERSION); -template void Serialize(Stream& os, const std::set& m, int nType, int nVersion=VERSION); -template void Unserialize(Stream& is, std::set& m, int nType, int nVersion=VERSION); - - - - - -// -// If none of the specialized versions above matched, default to calling member function. -// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. -// The compiler will only cast int to long if none of the other templates matched. -// Thanks to Boost serialization for this idea. -// -template -inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=VERSION) -{ - return a.GetSerializeSize((int)nType, nVersion); -} - -template -inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION) -{ - a.Serialize(os, (int)nType, nVersion); -} - -template -inline void Unserialize(Stream& is, T& a, long nType, int nVersion=VERSION) -{ - a.Unserialize(is, (int)nType, nVersion); -} - - - - - -// -// string -// -template -unsigned int GetSerializeSize(const basic_string& str, int, int) -{ - return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); -} - -template -void Serialize(Stream& os, const basic_string& str, int, int) -{ - WriteCompactSize(os, str.size()); - if (!str.empty()) - os.write((char*)&str[0], str.size() * sizeof(str[0])); -} - -template -void Unserialize(Stream& is, basic_string& str, int, int) -{ - unsigned int nSize = ReadCompactSize(is); - str.resize(nSize); - if (nSize != 0) - is.read((char*)&str[0], nSize * sizeof(str[0])); -} - - - -// -// vector -// -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&) -{ - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&) -{ - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) -{ - return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental()); -} - - -template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&) -{ - WriteCompactSize(os, v.size()); - if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); -} - -template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&) -{ - WriteCompactSize(os, v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); -} - -template -inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) -{ - Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); -} - - -template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&) -{ - //unsigned int nSize = ReadCompactSize(is); - //v.resize(nSize); - //is.read((char*)&v[0], nSize * sizeof(T)); - - // Limit size per read so bogus size value won't cause out of memory - v.clear(); - unsigned int nSize = ReadCompactSize(is); - unsigned int i = 0; - while (i < nSize) - { - unsigned int blk = min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); - v.resize(i + blk); - is.read((char*)&v[i], blk * sizeof(T)); - i += blk; - } -} - -template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&) -{ - //unsigned int nSize = ReadCompactSize(is); - //v.resize(nSize); - //for (std::vector::iterator vi = v.begin(); vi != v.end(); ++vi) - // Unserialize(is, (*vi), nType, nVersion); - - v.clear(); - unsigned int nSize = ReadCompactSize(is); - unsigned int i = 0; - unsigned int nMid = 0; - while (nMid < nSize) - { - nMid += 5000000 / sizeof(T); - if (nMid > nSize) - nMid = nSize; - v.resize(nMid); - for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); - } -} - -template -inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) -{ - Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); -} - - - -// -// others derived from vector -// -inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) -{ - return GetSerializeSize((const vector&)v, nType, nVersion); -} - -template -void Serialize(Stream& os, const CScript& v, int nType, int nVersion) -{ - Serialize(os, (const vector&)v, nType, nVersion); -} - -template -void Unserialize(Stream& is, CScript& v, int nType, int nVersion) -{ - Unserialize(is, (vector&)v, nType, nVersion); -} - - - -// -// pair -// -template -unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) -{ - return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); -} - -template -void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) -{ - Serialize(os, item.first, nType, nVersion); - Serialize(os, item.second, nType, nVersion); -} - -template -void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) -{ - Unserialize(is, item.first, nType, nVersion); - Unserialize(is, item.second, nType, nVersion); -} - - - -// -// map -// -template -unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - nSize += GetSerializeSize((*mi), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::map& m, int nType, int nVersion) -{ - WriteCompactSize(os, m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - Serialize(os, (*mi), nType, nVersion); -} - -template -void Unserialize(Stream& is, std::map& m, int nType, int nVersion) -{ - m.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::map::iterator mi = m.begin(); - for (unsigned int i = 0; i < nSize; i++) - { - pair item; - Unserialize(is, item, nType, nVersion); - mi = m.insert(mi, item); - } -} - - - -// -// set -// -template -unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream& os, const std::set& m, int nType, int nVersion) -{ - WriteCompactSize(os, m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - Serialize(os, (*it), nType, nVersion); -} - -template -void Unserialize(Stream& is, std::set& m, int nType, int nVersion) -{ - m.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::set::iterator it = m.begin(); - for (unsigned int i = 0; i < nSize; i++) - { - K key; - Unserialize(is, key, nType, nVersion); - it = m.insert(it, key); - } -} - - - -// -// Support for IMPLEMENT_SERIALIZE and READWRITE macro -// -class CSerActionGetSerializeSize { }; -class CSerActionSerialize { }; -class CSerActionUnserialize { }; - -template -inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) -{ - return ::GetSerializeSize(obj, nType, nVersion); -} - -template -inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) -{ - ::Serialize(s, obj, nType, nVersion); - return 0; -} - -template -inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) -{ - ::Unserialize(s, obj, nType, nVersion); - return 0; -} - -struct ser_streamplaceholder -{ - int nType; - int nVersion; -}; - - - - - - - - - -// -// Allocator that clears its contents before deletion -// -template -struct secure_allocator : public std::allocator -{ - // MSVC8 default copy constructor is broken - typedef std::allocator base; - typedef typename base::size_type size_type; - typedef typename base::difference_type difference_type; - typedef typename base::pointer pointer; - typedef typename base::const_pointer const_pointer; - typedef typename base::reference reference; - typedef typename base::const_reference const_reference; - typedef typename base::value_type value_type; - secure_allocator() throw() {} - secure_allocator(const secure_allocator& a) throw() : base(a) {} - ~secure_allocator() throw() {} - template struct rebind - { typedef secure_allocator<_Other> other; }; - - void deallocate(T* p, std::size_t n) - { - if (p != NULL) - memset(p, 0, sizeof(T) * n); - allocator::deallocate(p, n); - } -}; - - - -// -// Double ended buffer combining vector and stream-like interfaces. -// >> and << read and write unformatted data using the above serialization templates. -// Fills with data in linear time; some stringstream implementations take N^2 time. -// -class CDataStream -{ -protected: - typedef vector > vector_type; - vector_type vch; - unsigned int nReadPos; - short state; - short exceptmask; -public: - int nType; - int nVersion; - - typedef vector_type::allocator_type allocator_type; - typedef vector_type::size_type size_type; - typedef vector_type::difference_type difference_type; - typedef vector_type::reference reference; - typedef vector_type::const_reference const_reference; - typedef vector_type::value_type value_type; - typedef vector_type::iterator iterator; - typedef vector_type::const_iterator const_iterator; - typedef vector_type::reverse_iterator reverse_iterator; - - explicit CDataStream(int nTypeIn=0, int nVersionIn=VERSION) - { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend) - { - Init(nTypeIn, nVersionIn); - } - -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - CDataStream(const char* pbegin, const char* pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend) - { - Init(nTypeIn, nVersionIn); - } -#endif - - CDataStream(const vector_type& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end()) - { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const vector& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end()) - { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const vector& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) - { - Init(nTypeIn, nVersionIn); - } - - void Init(int nTypeIn=0, int nVersionIn=VERSION) - { - nReadPos = 0; - nType = nTypeIn; - nVersion = nVersionIn; - state = 0; - exceptmask = ios::badbit | ios::failbit; - } - - CDataStream& operator+=(const CDataStream& b) - { - vch.insert(vch.end(), b.begin(), b.end()); - return *this; - } - - friend CDataStream operator+(const CDataStream& a, const CDataStream& b) - { - CDataStream ret = a; - ret += b; - return (ret); - } - - string str() const - { - return (string(begin(), end())); - } - - - // - // Vector subset - // - const_iterator begin() const { return vch.begin() + nReadPos; } - iterator begin() { return vch.begin() + nReadPos; } - const_iterator end() const { return vch.end(); } - iterator end() { return vch.end(); } - size_type size() const { return vch.size() - nReadPos; } - bool empty() const { return vch.size() == nReadPos; } - void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } - void reserve(size_type n) { vch.reserve(n + nReadPos); } - const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } - reference operator[](size_type pos) { return vch[pos + nReadPos]; } - void clear() { vch.clear(); nReadPos = 0; } - iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } - void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } - - void insert(iterator it, const_iterator first, const_iterator last) - { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - - void insert(iterator it, vector::const_iterator first, vector::const_iterator last) - { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - void insert(iterator it, const char* first, const char* last) - { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } -#endif - - iterator erase(iterator it) - { - if (it == vch.begin() + nReadPos) - { - // special case for erasing from the front - if (++nReadPos >= vch.size()) - { - // whenever we reach the end, we take the opportunity to clear the buffer - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - return vch.begin() + nReadPos; - } - else - return vch.erase(it); - } - - iterator erase(iterator first, iterator last) - { - if (first == vch.begin() + nReadPos) - { - // special case for erasing from the front - if (last == vch.end()) - { - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - else - { - nReadPos = (last - vch.begin()); - return last; - } - } - else - return vch.erase(first, last); - } - - inline void Compact() - { - vch.erase(vch.begin(), vch.begin() + nReadPos); - nReadPos = 0; - } - - bool Rewind(size_type n) - { - // Rewind by n characters if the buffer hasn't been compacted yet - if (n > nReadPos) - return false; - nReadPos -= n; - return true; - } - - - // - // Stream subset - // - void setstate(short bits, const char* psz) - { - state |= bits; - if (state & exceptmask) - throw std::ios_base::failure(psz); - } - - bool eof() const { return size() == 0; } - bool fail() const { return state & (ios::badbit | ios::failbit); } - bool good() const { return !eof() && (state == 0); } - void clear(short n) { state = n; } // name conflict with vector clear() - short exceptions() { return exceptmask; } - short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } - CDataStream* rdbuf() { return this; } - int in_avail() { return size(); } - - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } - - CDataStream& read(char* pch, int nSize) - { - // Read from the beginning of the buffer - assert(nSize >= 0); - unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) - { - if (nReadPosNext > vch.size()) - { - setstate(ios::failbit, "CDataStream::read() : end of data"); - memset(pch, 0, nSize); - nSize = vch.size() - nReadPos; - } - memcpy(pch, &vch[nReadPos], nSize); - nReadPos = 0; - vch.clear(); - return (*this); - } - memcpy(pch, &vch[nReadPos], nSize); - nReadPos = nReadPosNext; - return (*this); - } - - CDataStream& ignore(int nSize) - { - // Ignore from the beginning of the buffer - assert(nSize >= 0); - unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) - { - if (nReadPosNext > vch.size()) - { - setstate(ios::failbit, "CDataStream::ignore() : end of data"); - nSize = vch.size() - nReadPos; - } - nReadPos = 0; - vch.clear(); - return (*this); - } - nReadPos = nReadPosNext; - return (*this); - } - - CDataStream& write(const char* pch, int nSize) - { - // Write to the end of the buffer - assert(nSize >= 0); - vch.insert(vch.end(), pch, pch + nSize); - return (*this); - } - - template - void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const - { - // Special case: stream << stream concatenates like stream += stream - if (!vch.empty()) - s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); - } - - template - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - - template - CDataStream& operator<<(const T& obj) - { - // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } - - template - CDataStream& operator>>(T& obj) - { - // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); - return (*this); - } -}; - -#ifdef TESTCDATASTREAM -// VC6sp6 -// CDataStream: -// n=1000 0 seconds -// n=2000 0 seconds -// n=4000 0 seconds -// n=8000 0 seconds -// n=16000 0 seconds -// n=32000 0 seconds -// n=64000 1 seconds -// n=128000 1 seconds -// n=256000 2 seconds -// n=512000 4 seconds -// n=1024000 8 seconds -// n=2048000 16 seconds -// n=4096000 32 seconds -// stringstream: -// n=1000 1 seconds -// n=2000 1 seconds -// n=4000 13 seconds -// n=8000 87 seconds -// n=16000 400 seconds -// n=32000 1660 seconds -// n=64000 6749 seconds -// n=128000 27241 seconds -// n=256000 109804 seconds -#include -int main(int argc, char *argv[]) -{ - vector vch(0xcc, 250); - printf("CDataStream:\n"); - for (int n = 1000; n <= 4500000; n *= 2) - { - CDataStream ss; - time_t nStart = time(NULL); - for (int i = 0; i < n; i++) - ss.write((char*)&vch[0], vch.size()); - printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); - } - printf("stringstream:\n"); - for (int n = 1000; n <= 4500000; n *= 2) - { - stringstream ss; - time_t nStart = time(NULL); - for (int i = 0; i < n; i++) - ss.write((char*)&vch[0], vch.size()); - printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); - } -} -#endif - - - - - - - - - - -// -// Automatic closing wrapper for FILE* -// - Will automatically close the file when it goes out of scope if not null. -// - If you're returning the file pointer, return file.release(). -// - If you need to close the file early, use file.fclose() instead of fclose(file). -// -class CAutoFile -{ -protected: - FILE* file; - short state; - short exceptmask; -public: - int nType; - int nVersion; - - typedef FILE element_type; - - CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=VERSION) - { - file = filenew; - nType = nTypeIn; - nVersion = nVersionIn; - state = 0; - exceptmask = ios::badbit | ios::failbit; - } - - ~CAutoFile() - { - fclose(); - } - - void fclose() - { - if (file != NULL && file != stdin && file != stdout && file != stderr) - ::fclose(file); - file = NULL; - } - - FILE* release() { FILE* ret = file; file = NULL; return ret; } - operator FILE*() { return file; } - FILE* operator->() { return file; } - FILE& operator*() { return *file; } - FILE** operator&() { return &file; } - FILE* operator=(FILE* pnew) { return file = pnew; } - bool operator!() { return (file == NULL); } - - - // - // Stream subset - // - void setstate(short bits, const char* psz) - { - state |= bits; - if (state & exceptmask) - throw std::ios_base::failure(psz); - } - - bool fail() const { return state & (ios::badbit | ios::failbit); } - bool good() const { return state == 0; } - void clear(short n = 0) { state = n; } - short exceptions() { return exceptmask; } - short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } - - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } - - CAutoFile& read(char* pch, int nSize) - { - if (!file) - throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); - if (fread(pch, 1, nSize, file) != nSize) - setstate(ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); - return (*this); - } - - CAutoFile& write(const char* pch, int nSize) - { - if (!file) - throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); - if (fwrite(pch, 1, nSize, file) != nSize) - setstate(ios::failbit, "CAutoFile::write : write failed"); - return (*this); - } - - template - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - - template - CAutoFile& operator<<(const T& obj) - { - // Serialize to this stream - if (!file) - throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } - - template - CAutoFile& operator>>(T& obj) - { - // Unserialize from this stream - if (!file) - throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); - ::Unserialize(*this, obj, nType, nVersion); - return (*this); - } -}; +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int64; +typedef unsigned long long uint64; +#endif +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define for if (false) ; else for +#endif +class CScript; +class CDataStream; +class CAutoFile; + +static const unsigned int MAX_SIZE = 0x02000000; + +static const int VERSION = 311; +static const char* pszSubVer = ".0"; + + + + + + +///////////////////////////////////////////////////////////////// +// +// Templates for serializing to anything that looks like a stream, +// i.e. anything that supports .read(char*, int) and .write(char*, int) +// + +enum +{ + // primary actions + SER_NETWORK = (1 << 0), + SER_DISK = (1 << 1), + SER_GETHASH = (1 << 2), + + // modifiers + SER_SKIPSIG = (1 << 16), + SER_BLOCKHEADERONLY = (1 << 17), +}; + +#define IMPLEMENT_SERIALIZE(statements) \ + unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \ + { \ + CSerActionGetSerializeSize ser_action; \ + const bool fGetSize = true; \ + const bool fWrite = false; \ + const bool fRead = false; \ + unsigned int nSerSize = 0; \ + ser_streamplaceholder s; \ + s.nType = nType; \ + s.nVersion = nVersion; \ + {statements} \ + return nSerSize; \ + } \ + template \ + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \ + { \ + CSerActionSerialize ser_action; \ + const bool fGetSize = false; \ + const bool fWrite = true; \ + const bool fRead = false; \ + unsigned int nSerSize = 0; \ + {statements} \ + } \ + template \ + void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \ + { \ + CSerActionUnserialize ser_action; \ + const bool fGetSize = false; \ + const bool fWrite = false; \ + const bool fRead = true; \ + unsigned int nSerSize = 0; \ + {statements} \ + } + +#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) + +#define READWRITEVER(obj) \ + do { \ + READWRITE((obj)); \ + if ((obj) == 10300) \ + (obj) = 300; \ + } while (false) + + + + + + +// +// Basic types +// +#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) +#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) + +inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } + +template inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } + +template inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } + +inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } +template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } +template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } + + + + + + +// +// Compact size +// size < 253 -- 1 byte +// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) +// size <= UINT_MAX -- 5 bytes (254 + 4 bytes) +// size > UINT_MAX -- 9 bytes (255 + 8 bytes) +// +inline unsigned int GetSizeOfCompactSize(uint64 nSize) +{ + if (nSize < UCHAR_MAX-2) return sizeof(unsigned char); + else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short); + else if (nSize <= UINT_MAX) return sizeof(unsigned char) + sizeof(unsigned int); + else return sizeof(unsigned char) + sizeof(uint64); +} + +template +void WriteCompactSize(Stream& os, uint64 nSize) +{ + if (nSize < UCHAR_MAX-2) + { + unsigned char chSize = nSize; + WRITEDATA(os, chSize); + } + else if (nSize <= USHRT_MAX) + { + unsigned char chSize = UCHAR_MAX-2; + unsigned short xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + else if (nSize <= UINT_MAX) + { + unsigned char chSize = UCHAR_MAX-1; + unsigned int xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + else + { + unsigned char chSize = UCHAR_MAX; + WRITEDATA(os, chSize); + WRITEDATA(os, nSize); + } + return; +} + +template +uint64 ReadCompactSize(Stream& is) +{ + unsigned char chSize; + READDATA(is, chSize); + uint64 nSizeRet = 0; + if (chSize < UCHAR_MAX-2) + { + nSizeRet = chSize; + } + else if (chSize == UCHAR_MAX-2) + { + unsigned short nSize; + READDATA(is, nSize); + nSizeRet = nSize; + } + else if (chSize == UCHAR_MAX-1) + { + unsigned int nSize; + READDATA(is, nSize); + nSizeRet = nSize; + } + else + { + uint64 nSize; + READDATA(is, nSize); + nSizeRet = nSize; + } + if (nSizeRet > (uint64)MAX_SIZE) + throw std::ios_base::failure("ReadCompactSize() : size too large"); + return nSizeRet; +} + + + +// +// Wrapper for serializing arrays and POD +// There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it +// +#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +class CFlatData +{ +protected: + char* pbegin; + char* pend; +public: + CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } + char* begin() { return pbegin; } + const char* begin() const { return pbegin; } + char* end() { return pend; } + const char* end() const { return pend; } + + unsigned int GetSerializeSize(int, int=0) const + { + return pend - pbegin; + } + + template + void Serialize(Stream& s, int, int=0) const + { + s.write(pbegin, pend - pbegin); + } + + template + void Unserialize(Stream& s, int, int=0) + { + s.read(pbegin, pend - pbegin); + } +}; + + + +// +// string stored as a fixed length field +// +template +class CFixedFieldString +{ +protected: + const string* pcstr; + string* pstr; +public: + explicit CFixedFieldString(const string& str) : pcstr(&str), pstr(NULL) { } + explicit CFixedFieldString(string& str) : pcstr(&str), pstr(&str) { } + + unsigned int GetSerializeSize(int, int=0) const + { + return LEN; + } + + template + void Serialize(Stream& s, int, int=0) const + { + char pszBuf[LEN]; + strncpy(pszBuf, pcstr->c_str(), LEN); + s.write(pszBuf, LEN); + } + + template + void Unserialize(Stream& s, int, int=0) + { + if (pstr == NULL) + throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"); + char pszBuf[LEN+1]; + s.read(pszBuf, LEN); + pszBuf[LEN] = '\0'; + *pstr = pszBuf; + } +}; + + + + + +// +// Forward declarations +// + +// string +template unsigned int GetSerializeSize(const basic_string& str, int, int=0); +template void Serialize(Stream& os, const basic_string& str, int, int=0); +template void Unserialize(Stream& is, basic_string& str, int, int=0); + +// vector +template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&); +template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion=VERSION); +template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&); +template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion=VERSION); +template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&); +template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion=VERSION); + +// others derived from vector +extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const CScript& v, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, CScript& v, int nType, int nVersion=VERSION); + +// pair +template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion=VERSION); + +// map +template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const std::map& m, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, std::map& m, int nType, int nVersion=VERSION); + +// set +template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion=VERSION); +template void Serialize(Stream& os, const std::set& m, int nType, int nVersion=VERSION); +template void Unserialize(Stream& is, std::set& m, int nType, int nVersion=VERSION); + + + + + +// +// If none of the specialized versions above matched, default to calling member function. +// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. +// The compiler will only cast int to long if none of the other templates matched. +// Thanks to Boost serialization for this idea. +// +template +inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=VERSION) +{ + return a.GetSerializeSize((int)nType, nVersion); +} + +template +inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION) +{ + a.Serialize(os, (int)nType, nVersion); +} + +template +inline void Unserialize(Stream& is, T& a, long nType, int nVersion=VERSION) +{ + a.Unserialize(is, (int)nType, nVersion); +} + + + + + +// +// string +// +template +unsigned int GetSerializeSize(const basic_string& str, int, int) +{ + return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); +} + +template +void Serialize(Stream& os, const basic_string& str, int, int) +{ + WriteCompactSize(os, str.size()); + if (!str.empty()) + os.write((char*)&str[0], str.size() * sizeof(str[0])); +} + +template +void Unserialize(Stream& is, basic_string& str, int, int) +{ + unsigned int nSize = ReadCompactSize(is); + str.resize(nSize); + if (nSize != 0) + is.read((char*)&str[0], nSize * sizeof(str[0])); +} + + + +// +// vector +// +template +unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); +} + +template +unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + unsigned int nSize = GetSizeOfCompactSize(v.size()); + for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + nSize += GetSerializeSize((*vi), nType, nVersion); + return nSize; +} + +template +inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) +{ + return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental()); +} + + +template +void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + WriteCompactSize(os, v.size()); + if (!v.empty()) + os.write((char*)&v[0], v.size() * sizeof(T)); +} + +template +void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + WriteCompactSize(os, v.size()); + for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + ::Serialize(os, (*vi), nType, nVersion); +} + +template +inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) +{ + Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); +} + + +template +void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + //unsigned int nSize = ReadCompactSize(is); + //v.resize(nSize); + //is.read((char*)&v[0], nSize * sizeof(T)); + + // Limit size per read so bogus size value won't cause out of memory + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + while (i < nSize) + { + unsigned int blk = min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + v.resize(i + blk); + is.read((char*)&v[i], blk * sizeof(T)); + i += blk; + } +} + +template +void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + //unsigned int nSize = ReadCompactSize(is); + //v.resize(nSize); + //for (std::vector::iterator vi = v.begin(); vi != v.end(); ++vi) + // Unserialize(is, (*vi), nType, nVersion); + + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + unsigned int nMid = 0; + while (nMid < nSize) + { + nMid += 5000000 / sizeof(T); + if (nMid > nSize) + nMid = nSize; + v.resize(nMid); + for (; i < nMid; i++) + Unserialize(is, v[i], nType, nVersion); + } +} + +template +inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) +{ + Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); +} + + + +// +// others derived from vector +// +inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) +{ + return GetSerializeSize((const vector&)v, nType, nVersion); +} + +template +void Serialize(Stream& os, const CScript& v, int nType, int nVersion) +{ + Serialize(os, (const vector&)v, nType, nVersion); +} + +template +void Unserialize(Stream& is, CScript& v, int nType, int nVersion) +{ + Unserialize(is, (vector&)v, nType, nVersion); +} + + + +// +// pair +// +template +unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) +{ + return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); +} + +template +void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) +{ + Serialize(os, item.first, nType, nVersion); + Serialize(os, item.second, nType, nVersion); +} + +template +void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) +{ + Unserialize(is, item.first, nType, nVersion); + Unserialize(is, item.second, nType, nVersion); +} + + + +// +// map +// +template +unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) +{ + unsigned int nSize = GetSizeOfCompactSize(m.size()); + for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) + nSize += GetSerializeSize((*mi), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const std::map& m, int nType, int nVersion) +{ + WriteCompactSize(os, m.size()); + for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) + Serialize(os, (*mi), nType, nVersion); +} + +template +void Unserialize(Stream& is, std::map& m, int nType, int nVersion) +{ + m.clear(); + unsigned int nSize = ReadCompactSize(is); + typename std::map::iterator mi = m.begin(); + for (unsigned int i = 0; i < nSize; i++) + { + pair item; + Unserialize(is, item, nType, nVersion); + mi = m.insert(mi, item); + } +} + + + +// +// set +// +template +unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) +{ + unsigned int nSize = GetSizeOfCompactSize(m.size()); + for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) + nSize += GetSerializeSize((*it), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const std::set& m, int nType, int nVersion) +{ + WriteCompactSize(os, m.size()); + for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) + Serialize(os, (*it), nType, nVersion); +} + +template +void Unserialize(Stream& is, std::set& m, int nType, int nVersion) +{ + m.clear(); + unsigned int nSize = ReadCompactSize(is); + typename std::set::iterator it = m.begin(); + for (unsigned int i = 0; i < nSize; i++) + { + K key; + Unserialize(is, key, nType, nVersion); + it = m.insert(it, key); + } +} + + + +// +// Support for IMPLEMENT_SERIALIZE and READWRITE macro +// +class CSerActionGetSerializeSize { }; +class CSerActionSerialize { }; +class CSerActionUnserialize { }; + +template +inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) +{ + return ::GetSerializeSize(obj, nType, nVersion); +} + +template +inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) +{ + ::Serialize(s, obj, nType, nVersion); + return 0; +} + +template +inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) +{ + ::Unserialize(s, obj, nType, nVersion); + return 0; +} + +struct ser_streamplaceholder +{ + int nType; + int nVersion; +}; + + + + + + + + + +// +// Allocator that clears its contents before deletion +// +template +struct secure_allocator : public std::allocator +{ + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + secure_allocator() throw() {} + secure_allocator(const secure_allocator& a) throw() : base(a) {} + ~secure_allocator() throw() {} + template struct rebind + { typedef secure_allocator<_Other> other; }; + + void deallocate(T* p, std::size_t n) + { + if (p != NULL) + memset(p, 0, sizeof(T) * n); + allocator::deallocate(p, n); + } +}; + + + +// +// Double ended buffer combining vector and stream-like interfaces. +// >> and << read and write unformatted data using the above serialization templates. +// Fills with data in linear time; some stringstream implementations take N^2 time. +// +class CDataStream +{ +protected: + typedef vector > vector_type; + vector_type vch; + unsigned int nReadPos; + short state; + short exceptmask; +public: + int nType; + int nVersion; + + typedef vector_type::allocator_type allocator_type; + typedef vector_type::size_type size_type; + typedef vector_type::difference_type difference_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + typedef vector_type::value_type value_type; + typedef vector_type::iterator iterator; + typedef vector_type::const_iterator const_iterator; + typedef vector_type::reverse_iterator reverse_iterator; + + explicit CDataStream(int nTypeIn=0, int nVersionIn=VERSION) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend) + { + Init(nTypeIn, nVersionIn); + } + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 + CDataStream(const char* pbegin, const char* pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend) + { + Init(nTypeIn, nVersionIn); + } +#endif + + CDataStream(const vector_type& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end()) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const vector& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end()) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const vector& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) + { + Init(nTypeIn, nVersionIn); + } + + void Init(int nTypeIn=0, int nVersionIn=VERSION) + { + nReadPos = 0; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = ios::badbit | ios::failbit; + } + + CDataStream& operator+=(const CDataStream& b) + { + vch.insert(vch.end(), b.begin(), b.end()); + return *this; + } + + friend CDataStream operator+(const CDataStream& a, const CDataStream& b) + { + CDataStream ret = a; + ret += b; + return (ret); + } + + string str() const + { + return (string(begin(), end())); + } + + + // + // Vector subset + // + const_iterator begin() const { return vch.begin() + nReadPos; } + iterator begin() { return vch.begin() + nReadPos; } + const_iterator end() const { return vch.end(); } + iterator end() { return vch.end(); } + size_type size() const { return vch.size() - nReadPos; } + bool empty() const { return vch.size() == nReadPos; } + void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } + void reserve(size_type n) { vch.reserve(n + nReadPos); } + const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } + reference operator[](size_type pos) { return vch[pos + nReadPos]; } + void clear() { vch.clear(); nReadPos = 0; } + iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } + void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } + + void insert(iterator it, const_iterator first, const_iterator last) + { + if (it == vch.begin() + nReadPos && last - first <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } + + void insert(iterator it, vector::const_iterator first, vector::const_iterator last) + { + if (it == vch.begin() + nReadPos && last - first <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 + void insert(iterator it, const char* first, const char* last) + { + if (it == vch.begin() + nReadPos && last - first <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } +#endif + + iterator erase(iterator it) + { + if (it == vch.begin() + nReadPos) + { + // special case for erasing from the front + if (++nReadPos >= vch.size()) + { + // whenever we reach the end, we take the opportunity to clear the buffer + nReadPos = 0; + return vch.erase(vch.begin(), vch.end()); + } + return vch.begin() + nReadPos; + } + else + return vch.erase(it); + } + + iterator erase(iterator first, iterator last) + { + if (first == vch.begin() + nReadPos) + { + // special case for erasing from the front + if (last == vch.end()) + { + nReadPos = 0; + return vch.erase(vch.begin(), vch.end()); + } + else + { + nReadPos = (last - vch.begin()); + return last; + } + } + else + return vch.erase(first, last); + } + + inline void Compact() + { + vch.erase(vch.begin(), vch.begin() + nReadPos); + nReadPos = 0; + } + + bool Rewind(size_type n) + { + // Rewind by n characters if the buffer hasn't been compacted yet + if (n > nReadPos) + return false; + nReadPos -= n; + return true; + } + + + // + // Stream subset + // + void setstate(short bits, const char* psz) + { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); + } + + bool eof() const { return size() == 0; } + bool fail() const { return state & (ios::badbit | ios::failbit); } + bool good() const { return !eof() && (state == 0); } + void clear(short n) { state = n; } // name conflict with vector clear() + short exceptions() { return exceptmask; } + short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } + CDataStream* rdbuf() { return this; } + int in_avail() { return size(); } + + void SetType(int n) { nType = n; } + int GetType() { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() { return nVersion; } + void ReadVersion() { *this >> nVersion; } + void WriteVersion() { *this << nVersion; } + + CDataStream& read(char* pch, int nSize) + { + // Read from the beginning of the buffer + assert(nSize >= 0); + unsigned int nReadPosNext = nReadPos + nSize; + if (nReadPosNext >= vch.size()) + { + if (nReadPosNext > vch.size()) + { + setstate(ios::failbit, "CDataStream::read() : end of data"); + memset(pch, 0, nSize); + nSize = vch.size() - nReadPos; + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = 0; + vch.clear(); + return (*this); + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = nReadPosNext; + return (*this); + } + + CDataStream& ignore(int nSize) + { + // Ignore from the beginning of the buffer + assert(nSize >= 0); + unsigned int nReadPosNext = nReadPos + nSize; + if (nReadPosNext >= vch.size()) + { + if (nReadPosNext > vch.size()) + { + setstate(ios::failbit, "CDataStream::ignore() : end of data"); + nSize = vch.size() - nReadPos; + } + nReadPos = 0; + vch.clear(); + return (*this); + } + nReadPos = nReadPosNext; + return (*this); + } + + CDataStream& write(const char* pch, int nSize) + { + // Write to the end of the buffer + assert(nSize >= 0); + vch.insert(vch.end(), pch, pch + nSize); + return (*this); + } + + template + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const + { + // Special case: stream << stream concatenates like stream += stream + if (!vch.empty()) + s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); + } + + template + unsigned int GetSerializeSize(const T& obj) + { + // Tells the size of the object if serialized to this stream + return ::GetSerializeSize(obj, nType, nVersion); + } + + template + CDataStream& operator<<(const T& obj) + { + // Serialize to this stream + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } + + template + CDataStream& operator>>(T& obj) + { + // Unserialize from this stream + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } +}; + +#ifdef TESTCDATASTREAM +// VC6sp6 +// CDataStream: +// n=1000 0 seconds +// n=2000 0 seconds +// n=4000 0 seconds +// n=8000 0 seconds +// n=16000 0 seconds +// n=32000 0 seconds +// n=64000 1 seconds +// n=128000 1 seconds +// n=256000 2 seconds +// n=512000 4 seconds +// n=1024000 8 seconds +// n=2048000 16 seconds +// n=4096000 32 seconds +// stringstream: +// n=1000 1 seconds +// n=2000 1 seconds +// n=4000 13 seconds +// n=8000 87 seconds +// n=16000 400 seconds +// n=32000 1660 seconds +// n=64000 6749 seconds +// n=128000 27241 seconds +// n=256000 109804 seconds +#include +int main(int argc, char *argv[]) +{ + vector vch(0xcc, 250); + printf("CDataStream:\n"); + for (int n = 1000; n <= 4500000; n *= 2) + { + CDataStream ss; + time_t nStart = time(NULL); + for (int i = 0; i < n; i++) + ss.write((char*)&vch[0], vch.size()); + printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); + } + printf("stringstream:\n"); + for (int n = 1000; n <= 4500000; n *= 2) + { + stringstream ss; + time_t nStart = time(NULL); + for (int i = 0; i < n; i++) + ss.write((char*)&vch[0], vch.size()); + printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); + } +} +#endif + + + + + + + + + + +// +// Automatic closing wrapper for FILE* +// - Will automatically close the file when it goes out of scope if not null. +// - If you're returning the file pointer, return file.release(). +// - If you need to close the file early, use file.fclose() instead of fclose(file). +// +class CAutoFile +{ +protected: + FILE* file; + short state; + short exceptmask; +public: + int nType; + int nVersion; + + typedef FILE element_type; + + CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=VERSION) + { + file = filenew; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = ios::badbit | ios::failbit; + } + + ~CAutoFile() + { + fclose(); + } + + void fclose() + { + if (file != NULL && file != stdin && file != stdout && file != stderr) + ::fclose(file); + file = NULL; + } + + FILE* release() { FILE* ret = file; file = NULL; return ret; } + operator FILE*() { return file; } + FILE* operator->() { return file; } + FILE& operator*() { return *file; } + FILE** operator&() { return &file; } + FILE* operator=(FILE* pnew) { return file = pnew; } + bool operator!() { return (file == NULL); } + + + // + // Stream subset + // + void setstate(short bits, const char* psz) + { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); + } + + bool fail() const { return state & (ios::badbit | ios::failbit); } + bool good() const { return state == 0; } + void clear(short n = 0) { state = n; } + short exceptions() { return exceptmask; } + short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } + + void SetType(int n) { nType = n; } + int GetType() { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() { return nVersion; } + void ReadVersion() { *this >> nVersion; } + void WriteVersion() { *this << nVersion; } + + CAutoFile& read(char* pch, int nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); + if (fread(pch, 1, nSize, file) != nSize) + setstate(ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); + return (*this); + } + + CAutoFile& write(const char* pch, int nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); + if (fwrite(pch, 1, nSize, file) != nSize) + setstate(ios::failbit, "CAutoFile::write : write failed"); + return (*this); + } + + template + unsigned int GetSerializeSize(const T& obj) + { + // Tells the size of the object if serialized to this stream + return ::GetSerializeSize(obj, nType, nVersion); + } + + template + CAutoFile& operator<<(const T& obj) + { + // Serialize to this stream + if (!file) + throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } + + template + CAutoFile& operator>>(T& obj) + { + // Unserialize from this stream + if (!file) + throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } +}; -- cgit v1.2.3