X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fserialize.h;h=8305dd079eae3750a5432b365fde5555a2989631;hp=85b48a26965e7d9e2dd9e3986fb5a4db32124898;hb=6aba6f08af53e3fa49ab4d1ef002e6771d0ce358;hpb=83e34b29071b58d6578b197430d12c55d277a515 diff --git a/src/serialize.h b/src/serialize.h index 85b48a2..8305dd0 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,7 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2012 The PPCoin developers -// Copyright (c) 2012-2013 The NovaCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SERIALIZE_H @@ -16,16 +14,21 @@ #include #include +#ifndef Q_MOC_RUN #include #include #include #include +#endif + +#if defined __USE_MINGW_ANSI_STDIO +#undef __USE_MINGW_ANSI_STDIO // This constant forces MinGW to conduct stupid behavior +#endif +#include #include "allocators.h" #include "version.h" -typedef long long int64; -typedef unsigned long long uint64; class CScript; class CDataStream; @@ -55,7 +58,8 @@ enum // modifiers SER_SKIPSIG = (1 << 16), - SER_BLOCKHEADERONLY = (1 << 17), + SER_BLOCKHEADERONLY = (1 << 17) + }; #define IMPLEMENT_SERIALIZE(statements) \ @@ -116,10 +120,10 @@ inline unsigned int GetSerializeSize(signed short a, int, int=0) { return size 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(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_t a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(uint64_t 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); } @@ -130,10 +134,10 @@ template inline void Serialize(Stream& s, signed short a, int 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, 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_t a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, uint64_t 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); } @@ -144,10 +148,10 @@ template inline void Unserialize(Stream& s, signed short& 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, 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_t& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, uint64_t& 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); } @@ -157,14 +161,8 @@ template inline void Unserialize(Stream& s, bool& a, int, int=0 -#ifndef THROW_WITH_STACKTRACE -#define THROW_WITH_STACKTRACE(exception) \ -{ \ - LogStackTrace(); \ - throw (exception); \ -} -void LogStackTrace(); -#endif + + // // Compact size @@ -173,40 +171,40 @@ void LogStackTrace(); // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) // size > UINT_MAX -- 9 bytes (255 + 8 bytes) // -inline unsigned int GetSizeOfCompactSize(uint64 nSize) +inline unsigned int GetSizeOfCompactSize(uint64_t nSize) { if (nSize < 253) return sizeof(unsigned char); else if (nSize <= std::numeric_limits::max()) return sizeof(unsigned char) + sizeof(unsigned short); else if (nSize <= std::numeric_limits::max()) return sizeof(unsigned char) + sizeof(unsigned int); - else return sizeof(unsigned char) + sizeof(uint64); + else return sizeof(unsigned char) + sizeof(uint64_t); } template -void WriteCompactSize(Stream& os, uint64 nSize) +void WriteCompactSize(Stream& os, uint64_t nSize) { if (nSize < 253) { - unsigned char chSize = nSize; + unsigned char chSize = (unsigned char)nSize; WRITEDATA(os, chSize); } else if (nSize <= std::numeric_limits::max()) { unsigned char chSize = 253; - unsigned short xSize = nSize; + unsigned short xSize = (unsigned short)nSize; WRITEDATA(os, chSize); WRITEDATA(os, xSize); } else if (nSize <= std::numeric_limits::max()) { unsigned char chSize = 254; - unsigned int xSize = nSize; + unsigned int xSize = (unsigned int)nSize; WRITEDATA(os, chSize); WRITEDATA(os, xSize); } else { unsigned char chSize = 255; - uint64 xSize = nSize; + uint64_t xSize = nSize; WRITEDATA(os, chSize); WRITEDATA(os, xSize); } @@ -214,11 +212,11 @@ void WriteCompactSize(Stream& os, uint64 nSize) } template -uint64 ReadCompactSize(Stream& is) +uint64_t ReadCompactSize(Stream& is) { unsigned char chSize; READDATA(is, chSize); - uint64 nSizeRet = 0; + uint64_t nSizeRet = 0; if (chSize < 253) { nSizeRet = chSize; @@ -237,21 +235,86 @@ uint64 ReadCompactSize(Stream& is) } else { - uint64 xSize; + uint64_t xSize; READDATA(is, xSize); nSizeRet = xSize; } - if (nSizeRet > (uint64)MAX_SIZE) - THROW_WITH_STACKTRACE(std::ios_base::failure("ReadCompactSize() : size too large")); + if (nSizeRet > (uint64_t)MAX_SIZE) + throw std::ios_base::failure("ReadCompactSize() : size too large"); return nSizeRet; } +// 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 encoding is one-to-one, one is subtracted from all but the last digit. +// Thus, the byte sequence a[] with length len, where all but the last byte +// has bit 128 set, encodes the number: +// +// (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) +// +// Properties: +// * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) +// * Every integer has exactly one encoding +// * Encoding does not depend on size of original integer type +// * No redundancy: every (infinite) byte sequence corresponds to a list +// of encoded integers. +// +// 0: [0x00] 256: [0x81 0x00] +// 1: [0x01] 16383: [0xFE 0x7F] +// 127: [0x7F] 16384: [0xFF 0x00] +// 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] +// 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] +// 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] + +template +inline unsigned int GetSizeOfVarInt(I n) +{ + int nRet = 0; + while(true) { + nRet++; + if (n <= 0x7F) + break; + n = (n >> 7) - 1; + } + return nRet; +} + +template +void WriteVarInt(Stream& os, I n) +{ + unsigned char tmp[(sizeof(n)*8+6)/7]; + int len=0; + while(true) { + tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); + if (n <= 0x7F) + break; + n = (n >> 7) - 1; + len++; + } + do { + WRITEDATA(os, tmp[len]); + } while(len--); +} +template +I ReadVarInt(Stream& is) +{ + I n = 0; + while(true) { + unsigned char chData; + READDATA(is, chData); + n = (n << 7) | (chData & 0x7F); + if (chData & 0x80) + n++; + else + return n; + } +} -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) +#define VARINT(obj) REF(WrapVarInt(REF(obj))) /** Wrapper for serializing arrays and POD. - * There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it. */ class CFlatData { @@ -267,13 +330,13 @@ public: unsigned int GetSerializeSize(int, int=0) const { - return pend - pbegin; + return (unsigned int)(pend - pbegin); } template void Serialize(Stream& s, int, int=0) const { - s.write(pbegin, pend - pbegin); + s.write(pbegin, (int)(pend - pbegin)); } template @@ -283,6 +346,32 @@ public: } }; +template +class CVarInt +{ +protected: + I &n; +public: + CVarInt(I& nIn) : n(nIn) { } + + unsigned int GetSerializeSize(int, int) const { + return GetSizeOfVarInt(n); + } + + template + void Serialize(Stream &s, int, int) const { + WriteVarInt(s, n); + } + + template + void Unserialize(Stream& s, int, int) { + n = ReadVarInt(s); + } +}; + +template +CVarInt WrapVarInt(I& n) { return CVarInt(n); } + // // Forward declarations // @@ -371,7 +460,7 @@ inline void Unserialize(Stream& is, T& a, long nType, int nVersion) template unsigned int GetSerializeSize(const std::basic_string& str, int, int) { - return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); + return (unsigned int)(GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0])); } template @@ -379,13 +468,13 @@ void Serialize(Stream& os, const std::basic_string& str, int, int) { WriteCompactSize(os, str.size()); if (!str.empty()) - os.write((char*)&str[0], str.size() * sizeof(str[0])); + os.write((char*)&str[0], (int)(str.size() * sizeof(str[0]))); } template void Unserialize(Stream& is, std::basic_string& str, int, int) { - unsigned int nSize = ReadCompactSize(is); + unsigned int nSize = (unsigned int)(ReadCompactSize(is)); str.resize(nSize); if (nSize != 0) is.read((char*)&str[0], nSize * sizeof(str[0])); @@ -399,7 +488,7 @@ void Unserialize(Stream& is, std::basic_string& str, int, int) 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)); + return (unsigned int)(GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); } template @@ -423,7 +512,7 @@ void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVers { WriteCompactSize(os, v.size()); if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); + os.write((char*)&v[0], (int)(v.size() * sizeof(T))); } template @@ -446,7 +535,7 @@ void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, { // Limit size per read so bogus size value won't cause out of memory v.clear(); - unsigned int nSize = ReadCompactSize(is); + unsigned int nSize = (unsigned int)(ReadCompactSize(is)); unsigned int i = 0; while (i < nSize) { @@ -461,7 +550,7 @@ template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&) { v.clear(); - unsigned int nSize = ReadCompactSize(is); + unsigned int nSize = (unsigned int)(ReadCompactSize(is)); unsigned int i = 0; unsigned int nMid = 0; while (nMid < nSize) @@ -619,7 +708,7 @@ template void Unserialize(Stream& is, std::map& m, int nType, int nVersion) { m.clear(); - unsigned int nSize = ReadCompactSize(is); + unsigned int nSize = (unsigned int)(ReadCompactSize(is)); typename std::map::iterator mi = m.begin(); for (unsigned int i = 0; i < nSize; i++) { @@ -710,6 +799,7 @@ struct ser_streamplaceholder +typedef std::vector > CSerializeData; /** Double ended buffer combining vector and stream-like interfaces. * @@ -719,7 +809,7 @@ struct ser_streamplaceholder class CDataStream { protected: - typedef std::vector > vector_type; + typedef CSerializeData vector_type; vector_type vch; unsigned int nReadPos; short state; @@ -765,7 +855,7 @@ public: Init(nTypeIn, nVersionIn); } - CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) + CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } @@ -815,21 +905,26 @@ public: 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); } +#ifdef _MSC_VER void insert(iterator it, const_iterator first, const_iterator last) { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) + assert(last - first >= 0); + if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room - nReadPos -= (last - first); + nReadPos -= (unsigned int)(last - first); memcpy(&vch[nReadPos], &first[0], last - first); } else vch.insert(it, first, last); } +#endif +#ifndef _MSC_VER void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) + assert(last - first >= 0); + if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room nReadPos -= (last - first); @@ -838,14 +933,16 @@ public: else vch.insert(it, first, last); } +#endif #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) + assert(last - first >= 0); + if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room - nReadPos -= (last - first); + nReadPos -= (unsigned int)(last - first); memcpy(&vch[nReadPos], &first[0], last - first); } else @@ -882,7 +979,7 @@ public: } else { - nReadPos = (last - vch.begin()); + nReadPos = (unsigned int)(last - vch.begin()); return last; } } @@ -901,7 +998,7 @@ public: // Rewind by n characters if the buffer hasn't been compacted yet if (n > nReadPos) return false; - nReadPos -= n; + nReadPos -= (unsigned int)n; return true; } @@ -913,17 +1010,17 @@ public: { state |= bits; if (state & exceptmask) - THROW_WITH_STACKTRACE(std::ios_base::failure(psz)); + throw std::ios_base::failure(psz); } bool eof() const { return size() == 0; } - bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } + bool fail() const { return (state & (std::ios::badbit | std::ios::failbit)) != 0; } 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(); } + int in_avail() { return (int)(size()); } void SetType(int n) { nType = n; } int GetType() { return nType; } @@ -943,7 +1040,7 @@ public: { setstate(std::ios::failbit, "CDataStream::read() : end of data"); memset(pch, 0, nSize); - nSize = vch.size() - nReadPos; + nSize = (int)(vch.size() - nReadPos); } memcpy(pch, &vch[nReadPos], nSize); nReadPos = 0; @@ -963,10 +1060,7 @@ public: if (nReadPosNext >= vch.size()) { if (nReadPosNext > vch.size()) - { setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); - nSize = vch.size() - nReadPos; - } nReadPos = 0; vch.clear(); return (*this); @@ -1013,58 +1107,12 @@ public: ::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); + void GetAndClear(CSerializeData &data) { + vch.swap(data); + CSerializeData().swap(vch); } -} -#endif +}; @@ -1128,10 +1176,10 @@ public: { state |= bits; if (state & exceptmask) - THROW_WITH_STACKTRACE(std::ios_base::failure(psz)); + throw std::ios_base::failure(psz); } - bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } + bool fail() const { return (state & (std::ios::badbit | std::ios::failbit)) != 0; } bool good() const { return state == 0; } void clear(short n = 0) { state = n; } short exceptions() { return exceptmask; } @@ -1190,4 +1238,148 @@ public: } }; +/** Wrapper around a FILE* that implements a ring buffer to + * deserialize from. It guarantees the ability to rewind + * a given number of bytes. */ +class CBufferedFile +{ +private: + FILE *src; // source file + uint64_t nSrcPos; // how many bytes have been read from source + uint64_t nReadPos; // how many bytes have been read from this + uint64_t nReadLimit; // up to which position we're allowed to read + uint64_t nRewind; // how many bytes we guarantee to rewind + std::vector vchBuf; // the buffer + + short state; + short exceptmask; + +protected: + void setstate(short bits, const char *psz) { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); + } + + // read data from the source to fill the buffer + bool Fill() { + unsigned int pos = (unsigned int)(nSrcPos % vchBuf.size()); + unsigned int readNow = (unsigned int)(vchBuf.size() - pos); + unsigned int nAvail = (unsigned int)(vchBuf.size() - (nSrcPos - nReadPos) - nRewind); + if (nAvail < readNow) + readNow = nAvail; + if (readNow == 0) + return false; + size_t read = fread((void*)&vchBuf[pos], 1, readNow, src); + if (read == 0) { + setstate(std::ios_base::failbit, feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed"); + return false; + } else { + nSrcPos += read; + return true; + } + } + +public: + int nType; + int nVersion; + + CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) : + src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0), + state(0), exceptmask(std::ios_base::badbit | std::ios_base::failbit), nType(nTypeIn), nVersion(nVersionIn) { + } + + // check whether no error occurred + bool good() const { + return state == 0; + } + + // check whether we're at the end of the source file + bool eof() const { + return nReadPos == nSrcPos && feof(src); + } + + // read a number of bytes + CBufferedFile& read(char *pch, size_t nSize) { + if (nSize + nReadPos > nReadLimit) + throw std::ios_base::failure("Read attempted past buffer limit"); + if (nSize + nRewind > vchBuf.size()) + throw std::ios_base::failure("Read larger than buffer size"); + while (nSize > 0) { + if (nReadPos == nSrcPos) + Fill(); + unsigned int pos = (unsigned int)(nReadPos % vchBuf.size()); + size_t nNow = nSize; + if (nNow + pos > vchBuf.size()) + nNow = vchBuf.size() - pos; + if (nNow + nReadPos > nSrcPos) + nNow = (size_t)(nSrcPos - nReadPos); + memcpy(pch, &vchBuf[pos], nNow); + nReadPos += nNow; + pch += nNow; + nSize -= nNow; + } + return (*this); + } + + // return the current reading position + uint64_t GetPos() { + return nReadPos; + } + + // rewind to a given reading position + bool SetPos(uint64_t nPos) { + nReadPos = nPos; + if (nReadPos + nRewind < nSrcPos) { + nReadPos = nSrcPos - nRewind; + return false; + } else if (nReadPos > nSrcPos) { + nReadPos = nSrcPos; + return false; + } else { + return true; + } + } + + bool Seek(uint64_t nPos) { + long nLongPos = (long)nPos; + if (nPos != (uint64_t)nLongPos) + return false; + if (fseek(src, nLongPos, SEEK_SET)) + return false; + nLongPos = ftell(src); + nSrcPos = nLongPos; + nReadPos = nLongPos; + state = 0; + return true; + } + + // prevent reading beyond a certain position + // no argument removes the limit + bool SetLimit(uint64_t nPos = std::numeric_limits::max()) { + if (nPos < nReadPos) + return false; + nReadLimit = nPos; + return true; + } + + template + CBufferedFile& operator>>(T& obj) { + // Unserialize from this stream + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } + + // search for a given byte in the stream, and remain positioned on it + void FindByte(char ch) { + for ( ; ; ) { + if (nReadPos == nSrcPos) + Fill(); + if (vchBuf[nReadPos % vchBuf.size()] == ch) + break; + nReadPos++; + } + } +}; + #endif