LCOV - code coverage report
Current view: top level - src - streams.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 318 410 77.6 %
Date: 2021-06-29 14:35:33 Functions: 437 471 92.8 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 163 260 62.7 %

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

Generated by: LCOV version 1.14