LCOV - code coverage report
Current view: top level - src - streams.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 315 343 91.8 %
Date: 2020-09-26 01:30:44 Functions: 394 405 97.3 %

          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        2194 :     OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
      33             : 
      34             :     template<typename T>
      35        2128 :     OverrideStream<Stream>& operator<<(const T& obj)
      36             :     {
      37             :         // Serialize to this stream
      38        2128 :         ::Serialize(*this, obj);
      39        2128 :         return (*this);
      40             :     }
      41             : 
      42             :     template<typename T>
      43        2292 :     OverrideStream<Stream>& operator>>(T&& obj)
      44             :     {
      45             :         // Unserialize from this stream
      46        2292 :         ::Unserialize(*this, obj);
      47        2292 :         return (*this);
      48             :     }
      49             : 
      50       14315 :     void write(const char* pch, size_t nSize)
      51             :     {
      52       14315 :         stream->write(pch, nSize);
      53       14315 :     }
      54             : 
      55       14919 :     void read(char* pch, size_t nSize)
      56             :     {
      57       14919 :         stream->read(pch, nSize);
      58       14919 :     }
      59             : 
      60        1629 :     int GetVersion() const { return nVersion; }
      61             :     int GetType() const { return nType; }
      62        1130 :     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      374022 :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
      81      187011 :     {
      82      187011 :         if(nPos > vchData.size())
      83           1 :             vchData.resize(nPos);
      84      374022 :     }
      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      180216 :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
      91             :     {
      92      180216 :         ::SerializeMany(*this, std::forward<Args>(args)...);
      93      180216 :     }
      94    11355849 :     void write(const char* pch, size_t nSize)
      95             :     {
      96    11355849 :         assert(nPos <= vchData.size());
      97    11355851 :         size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
      98    11355851 :         if (nOverwrite) {
      99          19 :             memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
     100          19 :         }
     101    11355850 :         if (nOverwrite < nSize) {
     102    11355832 :             vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
     103    11355832 :         }
     104    11355849 :         nPos += nSize;
     105    11355849 :     }
     106             :     template<typename T>
     107      602508 :     CVectorWriter& operator<<(const T& obj)
     108             :     {
     109             :         // Serialize to this stream
     110      602508 :         ::Serialize(*this, obj);
     111      602508 :         return (*this);
     112             :     }
     113       59896 :     int GetVersion() const
     114             :     {
     115       59896 :         return nVersion;
     116             :     }
     117       19555 :     int GetType() const
     118             :     {
     119       19555 :         return nType;
     120             :     }
     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        1158 :     VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
     147         579 :         : m_type(type), m_version(version), m_data(data), m_pos(pos)
     148         579 :     {
     149         579 :         if (m_pos > m_data.size()) {
     150           0 :             throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
     151             :         }
     152        1158 :     }
     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       48097 :     VectorReader& operator>>(T& obj)
     168             :     {
     169             :         // Unserialize from this stream
     170       48097 :         ::Unserialize(*this, obj);
     171       48097 :         return (*this);
     172             :     }
     173             : 
     174             :     int GetVersion() const { return m_version; }
     175             :     int GetType() const { return m_type; }
     176             : 
     177           5 :     size_t size() const { return m_data.size() - m_pos; }
     178         361 :     bool empty() const { return m_data.size() == m_pos; }
     179             : 
     180       48689 :     void read(char* dst, size_t n)
     181             :     {
     182       48689 :         if (n == 0) {
     183             :             return;
     184             :         }
     185             : 
     186             :         // Read from the beginning of the buffer
     187       48689 :         size_t pos_next = m_pos + n;
     188       48689 :         if (pos_next > m_data.size()) {
     189           2 :             throw std::ios_base::failure("VectorReader::read(): end of data");
     190             :         }
     191       48687 :         memcpy(dst, m_data.data() + m_pos, n);
     192       48687 :         m_pos = pos_next;
     193       48689 :     }
     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    16132953 : 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    14967644 :     explicit CDataStream(int nTypeIn, int nVersionIn)
     223     7483822 :     {
     224     7483822 :         Init(nTypeIn, nVersionIn);
     225    14967644 :     }
     226             : 
     227             :     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
     228             :     {
     229             :         Init(nTypeIn, nVersionIn);
     230             :     }
     231             : 
     232      441878 :     CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
     233      220939 :     {
     234      220939 :         Init(nTypeIn, nVersionIn);
     235      441878 :     }
     236             : 
     237             :     CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
     238             :     {
     239             :         Init(nTypeIn, nVersionIn);
     240             :     }
     241             : 
     242           2 :     CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
     243           1 :     {
     244           1 :         Init(nTypeIn, nVersionIn);
     245           2 :     }
     246             : 
     247       22892 :     CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
     248       11446 :     {
     249       11446 :         Init(nTypeIn, nVersionIn);
     250       22892 :     }
     251             : 
     252             :     template <typename... Args>
     253           2 :     CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
     254           1 :     {
     255           1 :         Init(nTypeIn, nVersionIn);
     256           1 :         ::SerializeMany(*this, std::forward<Args>(args)...);
     257           2 :     }
     258             : 
     259     7716228 :     void Init(int nTypeIn, int nVersionIn)
     260             :     {
     261     7716228 :         nReadPos = 0;
     262     7716228 :         nType = nTypeIn;
     263     7716228 :         nVersion = nVersionIn;
     264     7716228 :     }
     265             : 
     266             :     CDataStream& operator+=(const CDataStream& b)
     267             :     {
     268             :         vch.insert(vch.end(), b.begin(), b.end());
     269             :         return *this;
     270             :     }
     271             : 
     272             :     friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
     273             :     {
     274             :         CDataStream ret = a;
     275             :         ret += b;
     276             :         return (ret);
     277             :     }
     278             : 
     279         201 :     std::string str() const
     280             :     {
     281         201 :         return (std::string(begin(), end()));
     282             :     }
     283             : 
     284             : 
     285             :     //
     286             :     // Vector subset
     287             :     //
     288         201 :     const_iterator begin() const                     { return vch.begin() + nReadPos; }
     289       95738 :     iterator begin()                                 { return vch.begin() + nReadPos; }
     290         201 :     const_iterator end() const                       { return vch.end(); }
     291       47918 :     iterator end()                                   { return vch.end(); }
     292    34628542 :     size_type size() const                           { return vch.size() - nReadPos; }
     293       15679 :     bool empty() const                               { return vch.size() == nReadPos; }
     294      176593 :     void resize(size_type n, value_type c=0)         { vch.resize(n + nReadPos, c); }
     295     7124909 :     void reserve(size_type n)                        { vch.reserve(n + nReadPos); }
     296             :     const_reference operator[](size_type pos) const  { return vch[pos + nReadPos]; }
     297    18198261 :     reference operator[](size_type pos)              { return vch[pos + nReadPos]; }
     298      700759 :     void clear()                                     { vch.clear(); nReadPos = 0; }
     299           3 :     iterator insert(iterator it, const char x=char()) { return vch.insert(it, x); }
     300             :     void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
     301     6711350 :     value_type* data()                               { return vch.data() + nReadPos; }
     302           2 :     const value_type* data() const                   { return vch.data() + nReadPos; }
     303             : 
     304           2 :     void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
     305             :     {
     306           2 :         if (last == first) return;
     307           2 :         assert(last - first > 0);
     308           2 :         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
     309             :         {
     310             :             // 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             :         else
     315           2 :             vch.insert(it, first, last);
     316           2 :     }
     317             : 
     318             :     void insert(iterator it, const char* first, const char* last)
     319             :     {
     320             :         if (last == first) return;
     321             :         assert(last - first > 0);
     322             :         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
     323             :         {
     324             :             // special case for inserting at the front when there's room
     325             :             nReadPos -= (last - first);
     326             :             memcpy(&vch[nReadPos], &first[0], last - first);
     327             :         }
     328             :         else
     329             :             vch.insert(it, first, last);
     330             :     }
     331             : 
     332           3 :     iterator erase(iterator it)
     333             :     {
     334           3 :         if (it == vch.begin() + nReadPos)
     335             :         {
     336             :             // special case for erasing from the front
     337           1 :             if (++nReadPos >= vch.size())
     338             :             {
     339             :                 // 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             :             }
     343           1 :             return vch.begin() + nReadPos;
     344             :         }
     345             :         else
     346           2 :             return vch.erase(it);
     347           3 :     }
     348             : 
     349             :     iterator erase(iterator first, iterator last)
     350             :     {
     351             :         if (first == vch.begin() + nReadPos)
     352             :         {
     353             :             // special case for erasing from the front
     354             :             if (last == vch.end())
     355             :             {
     356             :                 nReadPos = 0;
     357             :                 return vch.erase(vch.begin(), vch.end());
     358             :             }
     359             :             else
     360             :             {
     361             :                 nReadPos = (last - vch.begin());
     362             :                 return last;
     363             :             }
     364             :         }
     365             :         else
     366             :             return vch.erase(first, last);
     367             :     }
     368             : 
     369             :     inline void Compact()
     370             :     {
     371             :         vch.erase(vch.begin(), vch.begin() + nReadPos);
     372             :         nReadPos = 0;
     373             :     }
     374             : 
     375          22 :     bool Rewind(size_type n)
     376             :     {
     377             :         // Rewind by n characters if the buffer hasn't been compacted yet
     378          22 :         if (n > nReadPos)
     379           0 :             return false;
     380          22 :         nReadPos -= n;
     381          22 :         return true;
     382          22 :     }
     383             : 
     384             : 
     385             :     //
     386             :     // Stream subset
     387             :     //
     388        2185 :     bool eof() const             { return size() == 0; }
     389             :     CDataStream* rdbuf()         { return this; }
     390         825 :     int in_avail() const         { return size(); }
     391             : 
     392      112236 :     void SetType(int n)          { nType = n; }
     393      181193 :     int GetType() const          { return nType; }
     394       82766 :     void SetVersion(int n)       { nVersion = n; }
     395      444808 :     int GetVersion() const       { return nVersion; }
     396             : 
     397     9189625 :     void read(char* pch, size_t nSize)
     398             :     {
     399     9189625 :         if (nSize == 0) return;
     400             : 
     401             :         // Read from the beginning of the buffer
     402     9188331 :         unsigned int nReadPosNext = nReadPos + nSize;
     403     9188331 :         if (nReadPosNext > vch.size()) {
     404         627 :             throw std::ios_base::failure("CDataStream::read(): end of data");
     405             :         }
     406     9187704 :         memcpy(pch, &vch[nReadPos], nSize);
     407     9187704 :         if (nReadPosNext == vch.size())
     408             :         {
     409      521761 :             nReadPos = 0;
     410      521761 :             vch.clear();
     411      521761 :             return;
     412             :         }
     413     8665954 :         nReadPos = nReadPosNext;
     414    17855582 :     }
     415             : 
     416           1 :     void ignore(int nSize)
     417             :     {
     418             :         // Ignore from the beginning of the buffer
     419           1 :         if (nSize < 0) {
     420           1 :             throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
     421             :         }
     422           0 :         unsigned int nReadPosNext = nReadPos + nSize;
     423           0 :         if (nReadPosNext >= vch.size())
     424             :         {
     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             :         }
     431           0 :         nReadPos = nReadPosNext;
     432           1 :     }
     433             : 
     434    42753015 :     void write(const char* pch, size_t nSize)
     435             :     {
     436             :         // Write to the end of the buffer
     437    42753015 :         vch.insert(vch.end(), pch, pch + nSize);
     438    42753015 :     }
     439             : 
     440             :     template<typename Stream>
     441           0 :     void Serialize(Stream& s) const
     442             :     {
     443             :         // 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    10710554 :     CDataStream& operator<<(const T& obj)
     450             :     {
     451             :         // Serialize to this stream
     452    10710554 :         ::Serialize(*this, obj);
     453    10710554 :         return (*this);
     454             :     }
     455             : 
     456             :     template<typename T>
     457     2058448 :     CDataStream& operator>>(T&& obj)
     458             :     {
     459             :         // Unserialize from this stream
     460     2058448 :         ::Unserialize(*this, obj);
     461     2058448 :         return (*this);
     462             :     }
     463             : 
     464           1 :     void GetAndClear(CSerializeData &d) {
     465           1 :         d.insert(d.end(), begin(), end());
     466           1 :         clear();
     467           1 :     }
     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      352145 :     void Xor(const std::vector<unsigned char>& key)
     475             :     {
     476      352145 :         if (key.size() == 0) {
     477             :             return;
     478             :         }
     479             : 
     480    17809790 :         for (size_type i = 0, j = 0; i != size(); i++) {
     481    17457645 :             vch[i] ^= key[j++];
     482             : 
     483             :             // This potentially acts on very many bytes of data, so it's
     484             :             // important that we calculate `j`, i.e. the `key` index in this
     485             :             // way instead of doing a %, which would effectively be a division
     486             :             // for each byte Xor'd -- much slower than need be.
     487    17457645 :             if (j == key.size())
     488     2031798 :                 j = 0;
     489             :         }
     490      352145 :     }
     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         577 :     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         577 :     int m_offset{8};
     507             : 
     508             : public:
     509        1154 :     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       56501 :     uint64_t Read(int nbits) {
     515       56501 :         if (nbits < 0 || nbits > 64) {
     516           0 :             throw std::out_of_range("nbits must be between 0 and 64");
     517             :         }
     518             : 
     519             :         uint64_t data = 0;
     520      154007 :         while (nbits > 0) {
     521       97507 :             if (m_offset == 8) {
     522       48097 :                 m_istream >> m_buffer;
     523       48097 :                 m_offset = 0;
     524       48097 :             }
     525             : 
     526       97506 :             int bits = std::min(8 - m_offset, nbits);
     527       97506 :             data <<= bits;
     528       97506 :             data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
     529       97506 :             m_offset += bits;
     530       97506 :             nbits -= bits;
     531             :         }
     532       56500 :         return data;
     533           0 :     }
     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        4460 :     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        4460 :     int m_offset{0};
     550             : 
     551             : public:
     552        8920 :     explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
     553             : 
     554        8920 :     ~BitStreamWriter()
     555        4460 :     {
     556        4460 :         Flush();
     557        8920 :     }
     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      294894 :     void Write(uint64_t data, int nbits) {
     563      294894 :         if (nbits < 0 || nbits > 64) {
     564           0 :             throw std::out_of_range("nbits must be between 0 and 64");
     565             :         }
     566             : 
     567      886879 :         while (nbits > 0) {
     568      591985 :             int bits = std::min(8 - m_offset, nbits);
     569      591985 :             m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
     570      591985 :             m_offset += bits;
     571      591985 :             nbits -= bits;
     572             : 
     573      591985 :             if (m_offset == 8) {
     574      332845 :                 Flush();
     575      332845 :             }
     576             :         }
     577      294894 :     }
     578             : 
     579             :     /** Flush any unwritten bits to the output stream, padding with 0's to the
     580             :      * next byte boundary.
     581             :      */
     582      341765 :     void Flush() {
     583      341765 :         if (m_offset == 0) {
     584             :             return;
     585             :         }
     586             : 
     587      337303 :         m_ostream << m_buffer;
     588      337303 :         m_buffer = 0;
     589      337303 :         m_offset = 0;
     590      341765 :     }
     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             :     const int nVersion;
     606             : 
     607             :     FILE* file;
     608             : 
     609             : public:
     610      428781 :     CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
     611      214391 :     {
     612      214390 :         file = filenew;
     613      428781 :     }
     614             : 
     615      428782 :     ~CAutoFile()
     616      214391 :     {
     617      214391 :         fclose();
     618      428782 :     }
     619             : 
     620             :     // Disallow copies
     621             :     CAutoFile(const CAutoFile&) = delete;
     622             :     CAutoFile& operator=(const CAutoFile&) = delete;
     623             : 
     624      216114 :     void fclose()
     625             :     {
     626      216114 :         if (file) {
     627      212968 :             ::fclose(file);
     628      212968 :             file = nullptr;
     629      212968 :         }
     630      216114 :     }
     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             :     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       90842 :     FILE* Get() const           { return file; }
     643             : 
     644             :     /** Return true if the wrapped FILE* is nullptr, false otherwise.
     645             :      */
     646      213893 :     bool IsNull() const         { return (file == nullptr); }
     647             : 
     648             :     //
     649             :     // Stream subset
     650             :     //
     651       36553 :     int GetType() const          { return nType; }
     652      331743 :     int GetVersion() const       { return nVersion; }
     653             : 
     654    11895225 :     void read(char* pch, size_t nSize)
     655             :     {
     656    11895225 :         if (!file)
     657           3 :             throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
     658    11895226 :         if (fread(pch, 1, nSize, file) != nSize)
     659           3 :             throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
     660    11895236 :     }
     661             : 
     662             :     void ignore(size_t nSize)
     663             :     {
     664             :         if (!file)
     665             :             throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
     666             :         unsigned char data[4096];
     667             :         while (nSize > 0) {
     668             :             size_t nNow = std::min<size_t>(nSize, sizeof(data));
     669             :             if (fread(data, 1, nNow, file) != nNow)
     670             :                 throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
     671             :             nSize -= nNow;
     672             :         }
     673             :     }
     674             : 
     675    19958463 :     void write(const char* pch, size_t nSize)
     676             :     {
     677    19958463 :         if (!file)
     678           1 :             throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
     679    19958463 :         if (fwrite(pch, 1, nSize, file) != nSize)
     680           1 :             throw std::ios_base::failure("CAutoFile::write: write failed");
     681    19958463 :     }
     682             : 
     683             :     template<typename T>
     684     1918031 :     CAutoFile& operator<<(const T& obj)
     685             :     {
     686             :         // Serialize to this stream
     687     1918031 :         if (!file)
     688           0 :             throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
     689     1918031 :         ::Serialize(*this, obj);
     690     1918031 :         return (*this);
     691           0 :     }
     692             : 
     693             :     template<typename T>
     694      934790 :     CAutoFile& operator>>(T&& obj)
     695             :     {
     696             :         // Unserialize from this stream
     697      934790 :         if (!file)
     698           0 :             throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
     699      934790 :         ::Unserialize(*this, obj);
     700      934790 :         return (*this);
     701           0 :     }
     702             : };
     703             : 
     704             : /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
     705             :  *  deserialize from. It guarantees the ability to rewind a given number of bytes.
     706             :  *
     707             :  *  Will automatically close the file when it goes out of scope if not null.
     708             :  *  If you need to close the file early, use file.fclose() instead of fclose(file).
     709             :  */
     710             : class CBufferedFile
     711             : {
     712             : private:
     713             :     const int nType;
     714             :     const int nVersion;
     715             : 
     716             :     FILE *src;            //!< source file
     717             :     uint64_t nSrcPos;     //!< how many bytes have been read from source
     718             :     uint64_t nReadPos;    //!< how many bytes have been read from this
     719             :     uint64_t nReadLimit;  //!< up to which position we're allowed to read
     720             :     uint64_t nRewind;     //!< how many bytes we guarantee to rewind
     721             :     std::vector<char> vchBuf; //!< the buffer
     722             : 
     723             : protected:
     724             :     //! read data from the source to fill the buffer
     725         371 :     bool Fill() {
     726         371 :         unsigned int pos = nSrcPos % vchBuf.size();
     727         371 :         unsigned int readNow = vchBuf.size() - pos;
     728         371 :         unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
     729         371 :         if (nAvail < readNow)
     730         318 :             readNow = nAvail;
     731         371 :         if (readNow == 0)
     732           0 :             return false;
     733         371 :         size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
     734         371 :         if (nBytes == 0) {
     735           9 :             throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
     736             :         }
     737         362 :         nSrcPos += nBytes;
     738             :         return true;
     739         371 :     }
     740             : 
     741             : public:
     742         122 :     CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
     743          61 :         nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0)
     744          61 :     {
     745          61 :         if (nRewindIn >= nBufSize)
     746           1 :             throw std::ios_base::failure("Rewind limit must be less than buffer size");
     747          60 :         src = fileIn;
     748         122 :     }
     749             : 
     750         120 :     ~CBufferedFile()
     751          60 :     {
     752          60 :         fclose();
     753         120 :     }
     754             : 
     755             :     // Disallow copies
     756             :     CBufferedFile(const CBufferedFile&) = delete;
     757             :     CBufferedFile& operator=(const CBufferedFile&) = delete;
     758             : 
     759        1550 :     int GetVersion() const { return nVersion; }
     760           1 :     int GetType() const { return nType; }
     761             : 
     762          61 :     void fclose()
     763             :     {
     764          61 :         if (src) {
     765          60 :             ::fclose(src);
     766          60 :             src = nullptr;
     767          60 :         }
     768          61 :     }
     769             : 
     770             :     //! check whether we're at the end of the source file
     771        5121 :     bool eof() const {
     772        5121 :         return nReadPos == nSrcPos && feof(src);
     773             :     }
     774             : 
     775             :     //! read a number of bytes
     776       46749 :     void read(char *pch, size_t nSize) {
     777       46749 :         if (nSize + nReadPos > nReadLimit)
     778           1 :             throw std::ios_base::failure("Read attempted past buffer limit");
     779       93623 :         while (nSize > 0) {
     780       46876 :             if (nReadPos == nSrcPos)
     781         208 :                 Fill();
     782       46875 :             unsigned int pos = nReadPos % vchBuf.size();
     783             :             size_t nNow = nSize;
     784       46875 :             if (nNow + pos > vchBuf.size())
     785          37 :                 nNow = vchBuf.size() - pos;
     786       46875 :             if (nNow + nReadPos > nSrcPos)
     787          98 :                 nNow = nSrcPos - nReadPos;
     788       46875 :             memcpy(pch, &vchBuf[pos], nNow);
     789       46875 :             nReadPos += nNow;
     790       46875 :             pch += nNow;
     791       46875 :             nSize -= nNow;
     792             :         }
     793       46748 :     }
     794             : 
     795             :     //! return the current reading position
     796        9441 :     uint64_t GetPos() const {
     797        9441 :         return nReadPos;
     798             :     }
     799             : 
     800             :     //! rewind to a given reading position
     801        2144 :     bool SetPos(uint64_t nPos) {
     802        2144 :         size_t bufsize = vchBuf.size();
     803        2144 :         if (nPos + bufsize < nSrcPos) {
     804             :             // rewinding too far, rewind as far as possible
     805          51 :             nReadPos = nSrcPos - bufsize;
     806          51 :             return false;
     807             :         }
     808        2093 :         if (nPos > nSrcPos) {
     809             :             // can't go this far forward, go as far as possible
     810          18 :             nReadPos = nSrcPos;
     811          18 :             return false;
     812             :         }
     813        2075 :         nReadPos = nPos;
     814        2075 :         return true;
     815        2144 :     }
     816             : 
     817             :     //! prevent reading beyond a certain position
     818             :     //! no argument removes the limit
     819        5854 :     bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
     820        5854 :         if (nPos < nReadPos)
     821           0 :             return false;
     822        5854 :         nReadLimit = nPos;
     823        5854 :         return true;
     824        5854 :     }
     825             : 
     826             :     template<typename T>
     827       18044 :     CBufferedFile& operator>>(T&& obj) {
     828             :         // Unserialize from this stream
     829       18044 :         ::Unserialize(*this, obj);
     830       18044 :         return (*this);
     831             :     }
     832             : 
     833             :     //! search for a given byte in the stream, and remain positioned on it
     834        2192 :     void FindByte(char ch) {
     835   133848844 :         while (true) {
     836   133848844 :             if (nReadPos == nSrcPos)
     837         163 :                 Fill();
     838   133848836 :             if (vchBuf[nReadPos % vchBuf.size()] == ch)
     839             :                 break;
     840   133846652 :             nReadPos++;
     841             :         }
     842        2184 :     }
     843             : };
     844             : 
     845             : #endif // BITCOIN_STREAMS_H

Generated by: LCOV version 1.15