LCOV - code coverage report
Current view: top level - src - streams.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 353 482 73.2 %
Date: 2020-06-05 16:23:38 Functions: 278 392 70.9 %
Legend: Lines: hit, modifiedhit, not modified not hit, modifiednot hit, not modified

          Line data    Source code
#       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
#       2             : // Copyright (c) 2009-2019 The Bitcoin Core developers
#       3             : // Distributed under the MIT software license, see the accompanying
#       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5             : 
#       6             : #ifndef BITCOIN_STREAMS_H
#       7             : #define BITCOIN_STREAMS_H
#       8             : 
#       9             : #include <support/allocators/zeroafterfree.h>
#      10             : #include <serialize.h>
#      11             : 
#      12             : #include <algorithm>
#      13             : #include <assert.h>
#      14             : #include <ios>
#      15             : #include <limits>
#      16             : #include <stdint.h>
#      17             : #include <stdio.h>
#      18             : #include <string>
#      19             : #include <string.h>
#      20             : #include <utility>
#      21             : #include <vector>
#      22             : 
#      23             : template<typename Stream>
#      24             : class OverrideStream
#      25             : {
#      26             :     Stream* stream;
#      27             : 
#      28             :     const int nType;
#      29             :     const int nVersion;
#      30             : 
#      31             : public:
#      32           3 :     OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
#      33             : 
#      34             :     template<typename T>
#      35             :     OverrideStream<Stream>& operator<<(const T& obj)
#      36           8 :     {
#      37           8 :         // Serialize to this stream
#      38           8 :         ::Serialize(*this, obj);
#      39           8 :         return (*this);
#      40           8 :     }
#      41             : 
#      42             :     template<typename T>
#      43             :     OverrideStream<Stream>& operator>>(T&& obj)
#      44           4 :     {
#      45           4 :         // Unserialize from this stream
#      46           4 :         ::Unserialize(*this, obj);
#      47           4 :         return (*this);
#      48           4 :     }
#      49             : 
#      50             :     void write(const char* pch, size_t nSize)
#      51          35 :     {
#      52          35 :         stream->write(pch, nSize);
#      53          35 :     }
#      54             : 
#      55             :     void read(char* pch, size_t nSize)
#      56          19 :     {
#      57          19 :         stream->read(pch, nSize);
#      58          19 :     }
#      59             : 
#      60           5 :     int GetVersion() const { return nVersion; }
#      61             :     int GetType() const { return nType; }
#      62           2 :     size_t size() const { return stream->size(); }
#      63             : };
#      64             : 
#      65             : /* Minimal stream for overwriting and/or appending to an existing byte vector
#      66             :  *
#      67             :  * The referenced vector will grow as necessary
#      68             :  */
#      69             : class CVectorWriter
#      70             : {
#      71             :  public:
#      72             : 
#      73             : /*
#      74             :  * @param[in]  nTypeIn Serialization Type
#      75             :  * @param[in]  nVersionIn Serialization Version (including any flags)
#      76             :  * @param[in]  vchDataIn  Referenced byte vector to overwrite/append
#      77             :  * @param[in]  nPosIn Starting position. Vector index where writes should start. The vector will initially
#      78             :  *                    grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().
#      79             : */
#      80             :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
#      81         577 :     {
#      82         577 :         if(nPos > vchData.size())
#      83           2 :             vchData.resize(nPos);
#      84         577 :     }
#      85             : /*
#      86             :  * (other params same as above)
#      87             :  * @param[in]  args  A list of items to serialize starting at nPosIn.
#      88             : */
#      89             :     template <typename... Args>
#      90             :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
#      91          94 :     {
#      92          94 :         ::SerializeMany(*this, std::forward<Args>(args)...);
#      93          94 :     }
#      94             :     void write(const char* pch, size_t nSize)
#      95        2854 :     {
#      96        2854 :         assert(nPos <= vchData.size());
#      97        2854 :         size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
#      98        2854 :         if (nOverwrite) {
#      99          38 :             memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
#     100          38 :         }
#     101        2854 :         if (nOverwrite < nSize) {
#     102        2818 :             vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
#     103        2818 :         }
#     104        2854 :         nPos += nSize;
#     105        2854 :     }
#     106             :     template<typename T>
#     107             :     CVectorWriter& operator<<(const T& obj)
#     108        1921 :     {
#     109        1921 :         // Serialize to this stream
#     110        1921 :         ::Serialize(*this, obj);
#     111        1921 :         return (*this);
#     112        1921 :     }
#     113             :     int GetVersion() const
#     114          88 :     {
#     115          88 :         return nVersion;
#     116          88 :     }
#     117             :     int GetType() const
#     118          88 :     {
#     119          88 :         return nType;
#     120          88 :     }
#     121             : private:
#     122             :     const int nType;
#     123             :     const int nVersion;
#     124             :     std::vector<unsigned char>& vchData;
#     125             :     size_t nPos;
#     126             : };
#     127             : 
#     128             : /** Minimal stream for reading from an existing vector by reference
#     129             :  */
#     130             : class VectorReader
#     131             : {
#     132             : private:
#     133             :     const int m_type;
#     134             :     const int m_version;
#     135             :     const std::vector<unsigned char>& m_data;
#     136             :     size_t m_pos = 0;
#     137             : 
#     138             : public:
#     139             : 
#     140             :     /**
#     141             :      * @param[in]  type Serialization Type
#     142             :      * @param[in]  version Serialization Version (including any flags)
#     143             :      * @param[in]  data Referenced byte vector to overwrite/append
#     144             :      * @param[in]  pos Starting position. Vector index where reads should start.
#     145             :      */
#     146             :     VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
#     147             :         : m_type(type), m_version(version), m_data(data), m_pos(pos)
#     148        1091 :     {
#     149        1091 :         if (m_pos > m_data.size()) {
#     150           0 :             throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
#     151           0 :         }
#     152        1091 :     }
#     153             : 
#     154             :     /**
#     155             :      * (other params same as above)
#     156             :      * @param[in]  args  A list of items to deserialize starting at pos.
#     157             :      */
#     158             :     template <typename... Args>
#     159             :     VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,
#     160             :                   Args&&... args)
#     161             :         : VectorReader(type, version, data, pos)
#     162             :     {
#     163             :         ::UnserializeMany(*this, std::forward<Args>(args)...);
#     164             :     }
#     165             : 
#     166             :     template<typename T>
#     167             :     VectorReader& operator>>(T& obj)
#     168       29135 :     {
#     169       29135 :         // Unserialize from this stream
#     170       29135 :         ::Unserialize(*this, obj);
#     171       29135 :         return (*this);
#     172       29135 :     }
#     173             : 
#     174           0 :     int GetVersion() const { return m_version; }
#     175           0 :     int GetType() const { return m_type; }
#     176             : 
#     177          10 :     size_t size() const { return m_data.size() - m_pos; }
#     178         678 :     bool empty() const { return m_data.size() == m_pos; }
#     179             : 
#     180             :     void read(char* dst, size_t n)
#     181       30226 :     {
#     182       30226 :         if (n == 0) {
#     183           0 :             return;
#     184           0 :         }
#     185       30226 : 
#     186       30226 :         // Read from the beginning of the buffer
#     187       30226 :         size_t pos_next = m_pos + n;
#     188       30226 :         if (pos_next > m_data.size()) {
#     189           4 :             throw std::ios_base::failure("VectorReader::read(): end of data");
#     190           4 :         }
#     191       30222 :         memcpy(dst, m_data.data() + m_pos, n);
#     192       30222 :         m_pos = pos_next;
#     193       30222 :     }
#     194             : };
#     195             : 
#     196             : /** Double ended buffer combining vector and stream-like interfaces.
#     197             :  *
#     198             :  * >> and << read and write unformatted data using the above serialization templates.
#     199             :  * Fills with data in linear time; some stringstream implementations take N^2 time.
#     200             :  */
#     201             : class CDataStream
#     202             : {
#     203             : protected:
#     204             :     typedef CSerializeData vector_type;
#     205             :     vector_type vch;
#     206             :     unsigned int nReadPos;
#     207             : 
#     208             :     int nType;
#     209             :     int nVersion;
#     210             : public:
#     211             : 
#     212             :     typedef vector_type::allocator_type   allocator_type;
#     213             :     typedef vector_type::size_type        size_type;
#     214             :     typedef vector_type::difference_type  difference_type;
#     215             :     typedef vector_type::reference        reference;
#     216             :     typedef vector_type::const_reference  const_reference;
#     217             :     typedef vector_type::value_type       value_type;
#     218             :     typedef vector_type::iterator         iterator;
#     219             :     typedef vector_type::const_iterator   const_iterator;
#     220             :     typedef vector_type::reverse_iterator reverse_iterator;
#     221             : 
#     222             :     explicit CDataStream(int nTypeIn, int nVersionIn)
#     223    11359357 :     {
#     224    11359357 :         Init(nTypeIn, nVersionIn);
#     225    11359357 :     }
#     226             : 
#     227             :     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
#     228           0 :     {
#     229           0 :         Init(nTypeIn, nVersionIn);
#     230           0 :     }
#     231             : 
#     232             :     CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
#     233      153278 :     {
#     234      153278 :         Init(nTypeIn, nVersionIn);
#     235      153278 :     }
#     236             : 
#     237             :     CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
#     238           0 :     {
#     239           0 :         Init(nTypeIn, nVersionIn);
#     240           0 :     }
#     241             : 
#     242             :     CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
#     243           2 :     {
#     244           2 :         Init(nTypeIn, nVersionIn);
#     245           2 :     }
#     246             : 
#     247             :     CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
#     248        1508 :     {
#     249        1508 :         Init(nTypeIn, nVersionIn);
#     250        1508 :     }
#     251             : 
#     252             :     template <typename... Args>
#     253             :     CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
#     254           2 :     {
#     255           2 :         Init(nTypeIn, nVersionIn);
#     256           2 :         ::SerializeMany(*this, std::forward<Args>(args)...);
#     257           2 :     }
#     258             : 
#     259             :     void Init(int nTypeIn, int nVersionIn)
#     260    11514147 :     {
#     261    11514147 :         nReadPos = 0;
#     262    11514147 :         nType = nTypeIn;
#     263    11514147 :         nVersion = nVersionIn;
#     264    11514147 :     }
#     265             : 
#     266             :     CDataStream& operator+=(const CDataStream& b)
#     267           0 :     {
#     268           0 :         vch.insert(vch.end(), b.begin(), b.end());
#     269           0 :         return *this;
#     270           0 :     }
#     271             : 
#     272             :     friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
#     273           0 :     {
#     274           0 :         CDataStream ret = a;
#     275           0 :         ret += b;
#     276           0 :         return (ret);
#     277           0 :     }
#     278             : 
#     279             :     std::string str() const
#     280          22 :     {
#     281          22 :         return (std::string(begin(), end()));
#     282          22 :     }
#     283             : 
#     284             : 
#     285             :     //
#     286             :     // Vector subset
#     287             :     //
#     288          58 :     const_iterator begin() const                     { return vch.begin() + nReadPos; }
#     289         285 :     iterator begin()                                 { return vch.begin() + nReadPos; }
#     290          58 :     const_iterator end() const                       { return vch.end(); }
#     291         251 :     iterator end()                                   { return vch.end(); }
#     292    33929078 :     size_type size() const                           { return vch.size() - nReadPos; }
#     293          12 :     bool empty() const                               { return vch.size() == nReadPos; }
#     294          34 :     void resize(size_type n, value_type c=0)         { vch.resize(n + nReadPos, c); }
#     295    10418138 :     void reserve(size_type n)                        { vch.reserve(n + nReadPos); }
#     296           0 :     const_reference operator[](size_type pos) const  { return vch[pos + nReadPos]; }
#     297    28105878 :     reference operator[](size_type pos)              { return vch[pos + nReadPos]; }
#     298      138918 :     void clear()                                     { vch.clear(); nReadPos = 0; }
#     299           6 :     iterator insert(iterator it, const char x=char()) { return vch.insert(it, x); }
#     300           0 :     void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
#     301    10418138 :     value_type* data()                               { return vch.data() + nReadPos; }
#     302           0 :     const value_type* data() const                   { return vch.data() + nReadPos; }
#     303             : 
#     304             :     void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
#     305           4 :     {
#     306           4 :         if (last == first) return;
#     307           4 :         assert(last - first > 0);
#     308           4 :         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
#     309           0 :         {
#     310           0 :             // special case for inserting at the front when there's room
#     311           0 :             nReadPos -= (last - first);
#     312           0 :             memcpy(&vch[nReadPos], &first[0], last - first);
#     313           0 :         }
#     314           4 :         else
#     315           4 :             vch.insert(it, first, last);
#     316           4 :     }
#     317             : 
#     318             :     void insert(iterator it, const char* first, const char* last)
#     319           0 :     {
#     320           0 :         if (last == first) return;
#     321           0 :         assert(last - first > 0);
#     322           0 :         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
#     323           0 :         {
#     324           0 :             // special case for inserting at the front when there's room
#     325           0 :             nReadPos -= (last - first);
#     326           0 :             memcpy(&vch[nReadPos], &first[0], last - first);
#     327           0 :         }
#     328           0 :         else
#     329           0 :             vch.insert(it, first, last);
#     330           0 :     }
#     331             : 
#     332             :     iterator erase(iterator it)
#     333           6 :     {
#     334           6 :         if (it == vch.begin() + nReadPos)
#     335           2 :         {
#     336           2 :             // special case for erasing from the front
#     337           2 :             if (++nReadPos >= vch.size())
#     338           0 :             {
#     339           0 :                 // whenever we reach the end, we take the opportunity to clear the buffer
#     340           0 :                 nReadPos = 0;
#     341           0 :                 return vch.erase(vch.begin(), vch.end());
#     342           0 :             }
#     343           2 :             return vch.begin() + nReadPos;
#     344           2 :         }
#     345           4 :         else
#     346           4 :             return vch.erase(it);
#     347           6 :     }
#     348             : 
#     349             :     iterator erase(iterator first, iterator last)
#     350           0 :     {
#     351           0 :         if (first == vch.begin() + nReadPos)
#     352           0 :         {
#     353           0 :             // special case for erasing from the front
#     354           0 :             if (last == vch.end())
#     355           0 :             {
#     356           0 :                 nReadPos = 0;
#     357           0 :                 return vch.erase(vch.begin(), vch.end());
#     358           0 :             }
#     359           0 :             else
#     360           0 :             {
#     361           0 :                 nReadPos = (last - vch.begin());
#     362           0 :                 return last;
#     363           0 :             }
#     364           0 :         }
#     365           0 :         else
#     366           0 :             return vch.erase(first, last);
#     367           0 :     }
#     368             : 
#     369             :     inline void Compact()
#     370           0 :     {
#     371           0 :         vch.erase(vch.begin(), vch.begin() + nReadPos);
#     372           0 :         nReadPos = 0;
#     373           0 :     }
#     374             : 
#     375             :     bool Rewind(size_type n)
#     376           0 :     {
#     377           0 :         // Rewind by n characters if the buffer hasn't been compacted yet
#     378           0 :         if (n > nReadPos)
#     379           0 :             return false;
#     380           0 :         nReadPos -= n;
#     381           0 :         return true;
#     382           0 :     }
#     383             : 
#     384             : 
#     385             :     //
#     386             :     // Stream subset
#     387             :     //
#     388           8 :     bool eof() const             { return size() == 0; }
#     389           0 :     CDataStream* rdbuf()         { return this; }
#     390           0 :     int in_avail() const         { return size(); }
#     391             : 
#     392       24070 :     void SetType(int n)          { nType = n; }
#     393        9319 :     int GetType() const          { return nType; }
#     394          50 :     void SetVersion(int n)       { nVersion = n; }
#     395       14051 :     int GetVersion() const       { return nVersion; }
#     396             : 
#     397             :     void read(char* pch, size_t nSize)
#     398     2176597 :     {
#     399     2176597 :         if (nSize == 0) return;
#     400     2174061 : 
#     401     2174061 :         // Read from the beginning of the buffer
#     402     2174061 :         unsigned int nReadPosNext = nReadPos + nSize;
#     403     2174061 :         if (nReadPosNext > vch.size()) {
#     404         314 :             throw std::ios_base::failure("CDataStream::read(): end of data");
#     405         314 :         }
#     406     2173747 :         memcpy(pch, &vch[nReadPos], nSize);
#     407     2173747 :         if (nReadPosNext == vch.size())
#     408      179348 :         {
#     409      179348 :             nReadPos = 0;
#     410      179348 :             vch.clear();
#     411      179348 :             return;
#     412      179348 :         }
#     413     1994399 :         nReadPos = nReadPosNext;
#     414     1994399 :     }
#     415             : 
#     416             :     void ignore(int nSize)
#     417           2 :     {
#     418           2 :         // Ignore from the beginning of the buffer
#     419           2 :         if (nSize < 0) {
#     420           2 :             throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
#     421           2 :         }
#     422           0 :         unsigned int nReadPosNext = nReadPos + nSize;
#     423           0 :         if (nReadPosNext >= vch.size())
#     424           0 :         {
#     425           0 :             if (nReadPosNext > vch.size())
#     426           0 :                 throw std::ios_base::failure("CDataStream::ignore(): end of data");
#     427           0 :             nReadPos = 0;
#     428           0 :             vch.clear();
#     429           0 :             return;
#     430           0 :         }
#     431           0 :         nReadPos = nReadPosNext;
#     432           0 :     }
#     433             : 
#     434             :     void write(const char* pch, size_t nSize)
#     435    58252285 :     {
#     436    58252285 :         // Write to the end of the buffer
#     437    58252285 :         vch.insert(vch.end(), pch, pch + nSize);
#     438    58252285 :     }
#     439             : 
#     440             :     template<typename Stream>
#     441             :     void Serialize(Stream& s) const
#     442           0 :     {
#     443           0 :         // Special case: stream << stream concatenates like stream += stream
#     444           0 :         if (!vch.empty())
#     445           0 :             s.write((char*)vch.data(), vch.size() * sizeof(value_type));
#     446           0 :     }
#     447             : 
#     448             :     template<typename T>
#     449             :     CDataStream& operator<<(const T& obj)
#     450    11855949 :     {
#     451    11855949 :         // Serialize to this stream
#     452    11855949 :         ::Serialize(*this, obj);
#     453    11855949 :         return (*this);
#     454    11855949 :     }
#     455             : 
#     456             :     template<typename T>
#     457             :     CDataStream& operator>>(T&& obj)
#     458      924392 :     {
#     459      924392 :         // Unserialize from this stream
#     460      924392 :         ::Unserialize(*this, obj);
#     461      924392 :         return (*this);
#     462      924392 :     }
#     463             : 
#     464           2 :     void GetAndClear(CSerializeData &d) {
#     465           2 :         d.insert(d.end(), begin(), end());
#     466           2 :         clear();
#     467           2 :     }
#     468             : 
#     469             :     /**
#     470             :      * XOR the contents of this stream with a certain key.
#     471             :      *
#     472             :      * @param[in] key    The key used to XOR the data in this stream.
#     473             :      */
#     474             :     void Xor(const std::vector<unsigned char>& key)
#     475      194026 :     {
#     476      194026 :         if (key.size() == 0) {
#     477           0 :             return;
#     478           0 :         }
#     479      194026 : 
#     480     7719332 :         for (size_type i = 0, j = 0; i != size(); i++) {
#     481     7525306 :             vch[i] ^= key[j++];
#     482     7525306 : 
#     483     7525306 :             // This potentially acts on very many bytes of data, so it's
#     484     7525306 :             // important that we calculate `j`, i.e. the `key` index in this
#     485     7525306 :             // way instead of doing a %, which would effectively be a division
#     486     7525306 :             // for each byte Xor'd -- much slower than need be.
#     487     7525306 :             if (j == key.size())
#     488      856008 :                 j = 0;
#     489     7525306 :         }
#     490      194026 :     }
#     491             : };
#     492             : 
#     493             : template <typename IStream>
#     494             : class BitStreamReader
#     495             : {
#     496             : private:
#     497             :     IStream& m_istream;
#     498             : 
#     499             :     /// Buffered byte read in from the input stream. A new byte is read into the
#     500             :     /// buffer when m_offset reaches 8.
#     501             :     uint8_t m_buffer{0};
#     502             : 
#     503             :     /// Number of high order bits in m_buffer already returned by previous
#     504             :     /// Read() calls. The next bit to be returned is at this offset from the
#     505             :     /// most significant bit position.
#     506             :     int m_offset{8};
#     507             : 
#     508             : public:
#     509        1088 :     explicit BitStreamReader(IStream& istream) : m_istream(istream) {}
#     510             : 
#     511             :     /** Read the specified number of bits from the stream. The data is returned
#     512             :      * in the nbits least significant bits of a 64-bit uint.
#     513             :      */
#     514       48302 :     uint64_t Read(int nbits) {
#     515       48302 :         if (nbits < 0 || nbits > 64) {
#     516           0 :             throw std::out_of_range("nbits must be between 0 and 64");
#     517           0 :         }
#     518       48302 : 
#     519       48302 :         uint64_t data = 0;
#     520      119834 :         while (nbits > 0) {
#     521       71532 :             if (m_offset == 8) {
#     522       29136 :                 m_istream >> m_buffer;
#     523       29136 :                 m_offset = 0;
#     524       29136 :             }
#     525       71532 : 
#     526       71532 :             int bits = std::min(8 - m_offset, nbits);
#     527       71532 :             data <<= bits;
#     528       71532 :             data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
#     529       71532 :             m_offset += bits;
#     530       71532 :             nbits -= bits;
#     531       71532 :         }
#     532       48302 :         return data;
#     533       48302 :     }
#     534             : };
#     535             : 
#     536             : template <typename OStream>
#     537             : class BitStreamWriter
#     538             : {
#     539             : private:
#     540             :     OStream& m_ostream;
#     541             : 
#     542             :     /// Buffered byte waiting to be written to the output stream. The byte is
#     543             :     /// written buffer when m_offset reaches 8 or Flush() is called.
#     544             :     uint8_t m_buffer{0};
#     545             : 
#     546             :     /// Number of high order bits in m_buffer already written by previous
#     547             :     /// Write() calls and not yet flushed to the stream. The next bit to be
#     548             :     /// written to is at this offset from the most significant bit position.
#     549             :     int m_offset{0};
#     550             : 
#     551             : public:
#     552         472 :     explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
#     553             : 
#     554             :     ~BitStreamWriter()
#     555         472 :     {
#     556         472 :         Flush();
#     557         472 :     }
#     558             : 
#     559             :     /** Write the nbits least significant bits of a 64-bit int to the output
#     560             :      * stream. Data is buffered until it completes an octet.
#     561             :      */
#     562        1786 :     void Write(uint64_t data, int nbits) {
#     563        1786 :         if (nbits < 0 || nbits > 64) {
#     564           0 :             throw std::out_of_range("nbits must be between 0 and 64");
#     565           0 :         }
#     566        1786 : 
#     567        4914 :         while (nbits > 0) {
#     568        3128 :             int bits = std::min(8 - m_offset, nbits);
#     569        3128 :             m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
#     570        3128 :             m_offset += bits;
#     571        3128 :             nbits -= bits;
#     572        3128 : 
#     573        3128 :             if (m_offset == 8) {
#     574        1418 :                 Flush();
#     575        1418 :             }
#     576        3128 :         }
#     577        1786 :     }
#     578             : 
#     579             :     /** Flush any unwritten bits to the output stream, padding with 0's to the
#     580             :      * next byte boundary.
#     581             :      */
#     582        2362 :     void Flush() {
#     583        2362 :         if (m_offset == 0) {
#     584         474 :             return;
#     585         474 :         }
#     586        1888 : 
#     587        1888 :         m_ostream << m_buffer;
#     588        1888 :         m_buffer = 0;
#     589        1888 :         m_offset = 0;
#     590        1888 :     }
#     591             : };
#     592             : 
#     593             : 
#     594             : 
#     595             : /** Non-refcounted RAII wrapper for FILE*
#     596             :  *
#     597             :  * Will automatically close the file when it goes out of scope if not null.
#     598             :  * If you're returning the file pointer, return file.release().
#     599             :  * If you need to close the file early, use file.fclose() instead of fclose(file).
#     600             :  */
#     601             : class CAutoFile
#     602             : {
#     603             : private:
#     604             :     const int nType;
#     605             :     int nVersion;
#     606             : 
#     607             :     FILE* file;
#     608             : 
#     609             : public:
#     610             :     CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
#     611       13477 :     {
#     612       13477 :         file = filenew;
#     613       13477 :     }
#     614             : 
#     615             :     ~CAutoFile()
#     616       13477 :     {
#     617       13477 :         fclose();
#     618       13477 :     }
#     619             : 
#     620             :     // Disallow copies
#     621             :     CAutoFile(const CAutoFile&) = delete;
#     622             :     CAutoFile& operator=(const CAutoFile&) = delete;
#     623             : 
#     624             :     void fclose()
#     625       13666 :     {
#     626       13666 :         if (file) {
#     627       13224 :             ::fclose(file);
#     628       13224 :             file = nullptr;
#     629       13224 :         }
#     630       13666 :     }
#     631             : 
#     632             :     /** Get wrapped FILE* with transfer of ownership.
#     633             :      * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
#     634             :      * of this function to clean up the returned FILE*.
#     635             :      */
#     636           0 :     FILE* release()             { FILE* ret = file; file = nullptr; return ret; }
#     637             : 
#     638             :     /** Get wrapped FILE* without transfer of ownership.
#     639             :      * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
#     640             :      * CAutoFile outlives use of the passed pointer.
#     641             :      */
#     642        9661 :     FILE* Get() const           { return file; }
#     643             : 
#     644             :     /** Return true if the wrapped FILE* is nullptr, false otherwise.
#     645             :      */
#     646       13465 :     bool IsNull() const         { return (file == nullptr); }
#     647             : 
#     648             :     //
#     649             :     // Stream subset
#     650             :     //
#     651         880 :     int GetType() const          { return nType; }
#     652       16914 :     int GetVersion() const       { return nVersion; }
#     653           0 :     void SetVersion(int n)       { nVersion = n; }
#     654             : 
#     655             :     void read(char* pch, size_t nSize)
#     656       54034 :     {
#     657       54034 :         if (!file)
#     658           0 :             throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
#     659       54034 :         if (fread(pch, 1, nSize, file) != nSize)
#     660           2 :             throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
#     661       54034 :     }
#     662             : 
#     663             :     void ignore(size_t nSize)
#     664           0 :     {
#     665           0 :         if (!file)
#     666           0 :             throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
#     667           0 :         unsigned char data[4096];
#     668           0 :         while (nSize > 0) {
#     669           0 :             size_t nNow = std::min<size_t>(nSize, sizeof(data));
#     670           0 :             if (fread(data, 1, nNow, file) != nNow)
#     671           0 :                 throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
#     672           0 :             nSize -= nNow;
#     673           0 :         }
#     674           0 :     }
#     675             : 
#     676             :     void write(const char* pch, size_t nSize)
#     677      138988 :     {
#     678      138988 :         if (!file)
#     679           0 :             throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
#     680      138988 :         if (fwrite(pch, 1, nSize, file) != nSize)
#     681           2 :             throw std::ios_base::failure("CAutoFile::write: write failed");
#     682      138988 :     }
#     683             : 
#     684             :     template<typename T>
#     685             :     CAutoFile& operator<<(const T& obj)
#     686       54946 :     {
#     687       54946 :         // Serialize to this stream
#     688       54946 :         if (!file)
#     689           0 :             throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
#     690       54946 :         ::Serialize(*this, obj);
#     691       54946 :         return (*this);
#     692       54946 :     }
#     693             : 
#     694             :     template<typename T>
#     695             :     CAutoFile& operator>>(T&& obj)
#     696       15028 :     {
#     697       15028 :         // Unserialize from this stream
#     698       15028 :         if (!file)
#     699           0 :             throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
#     700       15028 :         ::Unserialize(*this, obj);
#     701       15028 :         return (*this);
#     702       15028 :     }
#     703             : };
#     704             : 
#     705             : /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
#     706             :  *  deserialize from. It guarantees the ability to rewind a given number of bytes.
#     707             :  *
#     708             :  *  Will automatically close the file when it goes out of scope if not null.
#     709             :  *  If you need to close the file early, use file.fclose() instead of fclose(file).
#     710             :  */
#     711             : class CBufferedFile
#     712             : {
#     713             : private:
#     714             :     const int nType;
#     715             :     const int nVersion;
#     716             : 
#     717             :     FILE *src;            //!< source file
#     718             :     uint64_t nSrcPos;     //!< how many bytes have been read from source
#     719             :     uint64_t nReadPos;    //!< how many bytes have been read from this
#     720             :     uint64_t nReadLimit;  //!< up to which position we're allowed to read
#     721             :     uint64_t nRewind;     //!< how many bytes we guarantee to rewind
#     722             :     std::vector<char> vchBuf; //!< the buffer
#     723             : 
#     724             : protected:
#     725             :     //! read data from the source to fill the buffer
#     726         612 :     bool Fill() {
#     727         612 :         unsigned int pos = nSrcPos % vchBuf.size();
#     728         612 :         unsigned int readNow = vchBuf.size() - pos;
#     729         612 :         unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
#     730         612 :         if (nAvail < readNow)
#     731         538 :             readNow = nAvail;
#     732         612 :         if (readNow == 0)
#     733           0 :             return false;
#     734         612 :         size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
#     735         612 :         if (nBytes == 0) {
#     736           2 :             throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
#     737           2 :         }
#     738         610 :         nSrcPos += nBytes;
#     739         610 :         return true;
#     740         610 :     }
#     741             : 
#     742             : public:
#     743             :     CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
#     744             :         nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0)
#     745         104 :     {
#     746         104 :         if (nRewindIn >= nBufSize)
#     747           2 :             throw std::ios_base::failure("Rewind limit must be less than buffer size");
#     748         102 :         src = fileIn;
#     749         102 :     }
#     750             : 
#     751             :     ~CBufferedFile()
#     752         102 :     {
#     753         102 :         fclose();
#     754         102 :     }
#     755             : 
#     756             :     // Disallow copies
#     757             :     CBufferedFile(const CBufferedFile&) = delete;
#     758             :     CBufferedFile& operator=(const CBufferedFile&) = delete;
#     759             : 
#     760           2 :     int GetVersion() const { return nVersion; }
#     761           2 :     int GetType() const { return nType; }
#     762             : 
#     763             :     void fclose()
#     764         104 :     {
#     765         104 :         if (src) {
#     766         102 :             ::fclose(src);
#     767         102 :             src = nullptr;
#     768         102 :         }
#     769         104 :     }
#     770             : 
#     771             :     //! check whether we're at the end of the source file
#     772        7348 :     bool eof() const {
#     773        7348 :         return nReadPos == nSrcPos && feof(src);
#     774        7348 :     }
#     775             : 
#     776             :     //! read a number of bytes
#     777        5972 :     void read(char *pch, size_t nSize) {
#     778        5972 :         if (nSize + nReadPos > nReadLimit)
#     779           2 :             throw std::ios_base::failure("Read attempted past buffer limit");
#     780       12196 :         while (nSize > 0) {
#     781        6226 :             if (nReadPos == nSrcPos)
#     782         416 :                 Fill();
#     783        6226 :             unsigned int pos = nReadPos % vchBuf.size();
#     784        6226 :             size_t nNow = nSize;
#     785        6226 :             if (nNow + pos > vchBuf.size())
#     786          74 :                 nNow = vchBuf.size() - pos;
#     787        6226 :             if (nNow + nReadPos > nSrcPos)
#     788         196 :                 nNow = nSrcPos - nReadPos;
#     789        6226 :             memcpy(pch, &vchBuf[pos], nNow);
#     790        6226 :             nReadPos += nNow;
#     791        6226 :             pch += nNow;
#     792        6226 :             nSize -= nNow;
#     793        6226 :         }
#     794        5970 :     }
#     795             : 
#     796             :     //! return the current reading position
#     797       10236 :     uint64_t GetPos() const {
#     798       10236 :         return nReadPos;
#     799       10236 :     }
#     800             : 
#     801             :     //! rewind to a given reading position
#     802        1396 :     bool SetPos(uint64_t nPos) {
#     803        1396 :         size_t bufsize = vchBuf.size();
#     804        1396 :         if (nPos + bufsize < nSrcPos) {
#     805         102 :             // rewinding too far, rewind as far as possible
#     806         102 :             nReadPos = nSrcPos - bufsize;
#     807         102 :             return false;
#     808         102 :         }
#     809        1294 :         if (nPos > nSrcPos) {
#     810          36 :             // can't go this far forward, go as far as possible
#     811          36 :             nReadPos = nSrcPos;
#     812          36 :             return false;
#     813          36 :         }
#     814        1258 :         nReadPos = nPos;
#     815        1258 :         return true;
#     816        1258 :     }
#     817             : 
#     818           0 :     bool Seek(uint64_t nPos) {
#     819           0 :         long nLongPos = nPos;
#     820           0 :         if (nPos != (uint64_t)nLongPos)
#     821           0 :             return false;
#     822           0 :         if (fseek(src, nLongPos, SEEK_SET))
#     823           0 :             return false;
#     824           0 :         nLongPos = ftell(src);
#     825           0 :         nSrcPos = nLongPos;
#     826           0 :         nReadPos = nLongPos;
#     827           0 :         return true;
#     828           0 :     }
#     829             : 
#     830             :     //! prevent reading beyond a certain position
#     831             :     //! no argument removes the limit
#     832        5940 :     bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
#     833        5940 :         if (nPos < nReadPos)
#     834           0 :             return false;
#     835        5940 :         nReadLimit = nPos;
#     836        5940 :         return true;
#     837        5940 :     }
#     838             : 
#     839             :     template<typename T>
#     840        5972 :     CBufferedFile& operator>>(T&& obj) {
#     841        5972 :         // Unserialize from this stream
#     842        5972 :         ::Unserialize(*this, obj);
#     843        5972 :         return (*this);
#     844        5972 :     }
#     845             : 
#     846             :     //! search for a given byte in the stream, and remain positioned on it
#     847        1492 :     void FindByte(char ch) {
#     848        6642 :         while (true) {
#     849        6642 :             if (nReadPos == nSrcPos)
#     850         196 :                 Fill();
#     851        6642 :             if (vchBuf[nReadPos % vchBuf.size()] == ch)
#     852        1492 :                 break;
#     853        5150 :             nReadPos++;
#     854        5150 :         }
#     855        1492 :     }
#     856             : };
#     857             : 
#     858             : #endif // BITCOIN_STREAMS_H

Generated by: LCOV version 1.14