From 61a94025554ddd04d75635597444a4606fa9f81b Mon Sep 17 00:00:00 2001 From: svost Date: Fri, 11 Feb 2022 12:11:33 +0300 Subject: [PATCH] Create streams files --- CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + src/addrman.cpp | 1 + src/allocators.h | 4 + src/db.h | 1 + src/key.cpp | 1 + src/net.h | 1 + src/serialize.h | 599 +--------------------------------------------------- src/streams.cpp | 255 ++++++++++++++++++++++ src/streams.h | 357 +++++++++++++++++++++++++++++++ src/txdb-leveldb.h | 1 + 11 files changed, 626 insertions(+), 596 deletions(-) create mode 100644 src/streams.cpp create mode 100644 src/streams.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 93e35d6..b92cd42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(generic_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/ntp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/key.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/script.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/streams.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/miner.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/init.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c81ca14..91626be 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,6 +113,7 @@ set(generic_sources ${CMAKE_CURRENT_SOURCE_DIR}/rpcrawtransaction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rpcwallet.cpp ${CMAKE_CURRENT_SOURCE_DIR}/script.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/streams.cpp ${CMAKE_CURRENT_SOURCE_DIR}/stun.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sync.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timedata.cpp diff --git a/src/addrman.cpp b/src/addrman.cpp index f24e7e7..a754926 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -4,6 +4,7 @@ #include "addrman.h" #include "hash.h" +#include "streams.h" using namespace std; diff --git a/src/allocators.h b/src/allocators.h index fc95452..c787b35 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef WIN32 #ifdef _WIN32_WINNT @@ -257,4 +258,7 @@ struct zero_after_free_allocator : public std::allocator // This is exactly like std::string, but with a custom allocator. typedef std::basic_string, secure_allocator > SecureString; +// Byte-vector that clears its contents before deletion. +typedef std::vector > CSerializeData; + #endif diff --git a/src/db.h b/src/db.h index 2cccbc6..e1e3c93 100644 --- a/src/db.h +++ b/src/db.h @@ -8,6 +8,7 @@ #include "sync.h" #include "serialize.h" #include "script.h" +#include "streams.h" #include diff --git a/src/key.cpp b/src/key.cpp index 9038342..2df613b 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -9,6 +9,7 @@ #include "key.h" #include "base58.h" +#include "streams.h" // Generate a private key from just the secret parameter int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) diff --git a/src/net.h b/src/net.h index bede389..11963b0 100644 --- a/src/net.h +++ b/src/net.h @@ -9,6 +9,7 @@ #include "netbase.h" #include "addrman.h" #include "hash.h" +#include "streams.h" #include diff --git a/src/serialize.h b/src/serialize.h index 23e8be3..f24fd5c 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -5,9 +5,9 @@ #ifndef BITCOIN_SERIALIZE_H #define BITCOIN_SERIALIZE_H -#include "allocators.h" #include "version.h" +#include #include #include #include @@ -16,6 +16,7 @@ #include #include #include +#include #if defined __USE_MINGW_ANSI_STDIO #undef __USE_MINGW_ANSI_STDIO // This constant forces MinGW to conduct stupid behavior @@ -23,8 +24,7 @@ class CScript; -class CDataStream; -class CAutoFile; + static const unsigned int MAX_SIZE = 0x02000000; // Used to bypass the rule against non-const reference to temporary @@ -781,597 +781,4 @@ struct ser_streamplaceholder int nVersion; }; - - - - - - - - - - -typedef std::vector > CSerializeData; - -/** 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 CSerializeData 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, int nVersionIn) - { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) - { - Init(nTypeIn, nVersionIn); - } - -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) - { - Init(nTypeIn, nVersionIn); - } -#endif - - CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) - { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) - { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) - { - Init(nTypeIn, nVersionIn); - } - - void Init(int nTypeIn, int nVersionIn) - { - nReadPos = 0; - nType = nTypeIn; - nVersion = nVersionIn; - state = 0; - exceptmask = std::ios::badbit | std::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); - } - - std::string str() const - { - return (std::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); } - -#ifdef _MSC_VER - void insert(iterator it, const_iterator first, const_iterator last) - { - 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 -= (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) - { - 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); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } -#endif - -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - void insert(iterator it, const char* first, const char* last) - { - 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 -= (unsigned int)(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 = (unsigned int)(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 -= (unsigned int)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 & (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 (int)(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(std::ios::failbit, "CDataStream::read() : end of data"); - memset(pch, 0, nSize); - nSize = (int)(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(std::ios::failbit, "CDataStream::ignore() : end of data"); - 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, int nVersion) 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); - } - - void GetAndClear(CSerializeData &data) { - vch.swap(data); - CSerializeData().swap(vch); - } -}; - - - - - - - - - - -/** RAII 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; - - CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) - { - file = filenew; - nType = nTypeIn; - nVersion = nVersionIn; - state = 0; - exceptmask = std::ios::badbit | std::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 & (std::ios::badbit | std::ios::failbit)) != 0; } - 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, size_t nSize) - { - if (!file) - throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); - if (fread(pch, 1, nSize, file) != nSize) - setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); - return (*this); - } - - CAutoFile& write(const char* pch, size_t nSize) - { - if (!file) - throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); - if (fwrite(pch, 1, nSize, file) != nSize) - setstate(std::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); - } -}; - -/** 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 diff --git a/src/streams.cpp b/src/streams.cpp new file mode 100644 index 0000000..2fd351c --- /dev/null +++ b/src/streams.cpp @@ -0,0 +1,255 @@ +#include "streams.h" + +CDataStream::CDataStream(int nTypeIn, int nVersionIn) +{ + Init(nTypeIn, nVersionIn); +} + +CDataStream::CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) +{ + Init(nTypeIn, nVersionIn); +} + +CDataStream::CDataStream(const char *pbegin, const char *pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) +{ + Init(nTypeIn, nVersionIn); +} + +CDataStream::CDataStream(const vector_type &vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) +{ + Init(nTypeIn, nVersionIn); +} + +CDataStream::CDataStream(const std::vector &vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) +{ + Init(nTypeIn, nVersionIn); +} + +CDataStream::CDataStream(const std::vector &vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) +{ + Init(nTypeIn, nVersionIn); +} + +void CDataStream::Init(int nTypeIn, int nVersionIn) +{ + nReadPos = 0; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = std::ios::badbit | std::ios::failbit; +} + +CDataStream &CDataStream::operator+=(const CDataStream &b) +{ + vch.insert(vch.end(), b.begin(), b.end()); + return *this; +} + +std::string CDataStream::str() const +{ + return std::string(begin(), end()); +} + +bool CDataStream::Rewind(size_type n) +{ + // Rewind by n characters if the buffer hasn't been compacted yet + if (n > nReadPos) + return false; + nReadPos -= (unsigned int)n; + return true; +} + +void CDataStream::setstate(short bits, const char *psz) +{ + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); +} + +CDataStream &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(std::ios::failbit, "CDataStream::read() : end of data"); + memset(pch, 0, nSize); + nSize = (int)(vch.size() - nReadPos); + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = 0; + vch.clear(); + return (*this); + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = nReadPosNext; + return (*this); +} + +CDataStream &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(std::ios::failbit, "CDataStream::ignore() : end of data"); + nReadPos = 0; + vch.clear(); + return (*this); + } + nReadPos = nReadPosNext; + return (*this); +} + +CDataStream &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); +} + +void CDataStream::GetAndClear(CSerializeData &data) { + vch.swap(data); + CSerializeData().swap(vch); +} + +CAutoFile::CAutoFile(FILE *filenew, int nTypeIn, int nVersionIn) +{ + file = filenew; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = std::ios::badbit | std::ios::failbit; +} + +CAutoFile::~CAutoFile() +{ + fclose(); +} + +void CAutoFile::fclose() +{ + if (file != NULL && file != stdin && file != stdout && file != stderr) + ::fclose(file); + file = NULL; +} + +void CAutoFile::setstate(short bits, const char *psz) +{ + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); +} + +CAutoFile &CAutoFile::read(char *pch, size_t nSize) +{ + if (!file) + throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); + if (fread(pch, 1, nSize, file) != nSize) + setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); + return (*this); +} + +CAutoFile &CAutoFile::write(const char *pch, size_t nSize) +{ + if (!file) + throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); + if (fwrite(pch, 1, nSize, file) != nSize) + setstate(std::ios::failbit, "CAutoFile::write : write failed"); + return (*this); +} + +void CBufferedFile::setstate(short bits, const char *psz) { + state |= bits; + if (state & exceptmask) + throw std::ios_base::failure(psz); +} + +bool CBufferedFile::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; + } +} + +CBufferedFile &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); +} + +bool CBufferedFile::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 CBufferedFile::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; +} + +bool CBufferedFile::SetLimit(uint64_t nPos) { + if (nPos < nReadPos) + return false; + nReadLimit = nPos; + return true; +} + +void CBufferedFile::FindByte(char ch) { + for ( ; ; ) { + if (nReadPos == nSrcPos) + Fill(); + if (vchBuf[nReadPos % vchBuf.size()] == ch) + break; + nReadPos++; + } +} diff --git a/src/streams.h b/src/streams.h new file mode 100644 index 0000000..99ba125 --- /dev/null +++ b/src/streams.h @@ -0,0 +1,357 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_STREAMS_H +#define BITCOIN_STREAMS_H + +#include "allocators.h" +#include "serialize.h" + +#include +#include +#include + +/** 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 CSerializeData 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, int nVersionIn); + + CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn); + CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn); + CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn); + CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn); + CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn); + + void Init(int nTypeIn, int nVersionIn); + + CDataStream& operator+=(const CDataStream& b); + + friend CDataStream operator+(const CDataStream& a, const CDataStream& b) + { + CDataStream ret = a; + ret += b; + return (ret); + } + + std::string str() const; + + // + // 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, std::vector::const_iterator first, std::vector::const_iterator last) + { + 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); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } + + void insert(iterator it, const char* first, const char* last) + { + 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 -= (unsigned int)(last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } + + 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 = (unsigned int)(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); + + // + // Stream subset + // + void setstate(short bits, const char* psz); + + bool eof() const { return size() == 0; } + 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 (int)(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); + CDataStream& ignore(int nSize); + CDataStream& write(const char* pch, int nSize); + + template + void Serialize(Stream& s, int nType, int nVersion) 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); + } + + void GetAndClear(CSerializeData &data); +}; + + +/** RAII 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; + + CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn); + ~CAutoFile(); + void fclose(); + + 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); + 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; } + 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, size_t nSize); + CAutoFile& write(const char* pch, size_t nSize); + + 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); + } +}; + +/** 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); + + // read data from the source to fill the buffer + bool Fill(); + +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); + + // return the current reading position + uint64_t GetPos() { + return nReadPos; + } + + // rewind to a given reading position + bool SetPos(uint64_t nPos); + bool Seek(uint64_t nPos); + + // prevent reading beyond a certain position + // no argument removes the limit + bool SetLimit(uint64_t nPos = std::numeric_limits::max()); + + 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); +}; + +#endif // BITCOIN_STREAMS_H diff --git a/src/txdb-leveldb.h b/src/txdb-leveldb.h index 8f0c995..50b390b 100644 --- a/src/txdb-leveldb.h +++ b/src/txdb-leveldb.h @@ -7,6 +7,7 @@ #define BITCOIN_LEVELDB_H #include "serialize.h" +#include "streams.h" #include #include -- 1.7.1