LCOV - code coverage report
Current view: top level - src - streams.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 310 335 92.5 %
Date: 2026-06-25 07:23:43 Functions: 725 810 89.5 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 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             : #include <util/overflow.h>
      13             : 
      14             : #include <algorithm>
      15             : #include <assert.h>
      16             : #include <cstdio>
      17             : #include <ios>
      18             : #include <limits>
      19             : #include <optional>
      20             : #include <stdint.h>
      21             : #include <string.h>
      22             : #include <string>
      23             : #include <utility>
      24             : #include <vector>
      25             : 
      26             : template<typename Stream>
      27             : class OverrideStream
      28             : {
      29             :     Stream* stream;
      30             : 
      31             :     const int nType;
      32             :     const int nVersion;
      33             : 
      34             : public:
      35      428790 :     OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
      36             : 
      37             :     template<typename T>
      38     6731791 :     OverrideStream<Stream>& operator<<(const T& obj)
      39             :     {
      40             :         // Serialize to this stream
      41     6731791 :         ::Serialize(*this, obj);
      42     6731791 :         return (*this);
      43             :     }
      44             : 
      45             :     template<typename T>
      46     1907713 :     OverrideStream<Stream>& operator>>(T&& obj)
      47             :     {
      48             :         // Unserialize from this stream
      49     1907713 :         ::Unserialize(*this, obj);
      50     1907713 :         return (*this);
      51             :     }
      52             : 
      53     7783592 :     void write(Span<const std::byte> src)
      54             :     {
      55     7783592 :         stream->write(src);
      56     7783592 :     }
      57             : 
      58     2254265 :     void read(Span<std::byte> dst)
      59             :     {
      60     2254265 :         stream->read(dst);
      61     2254265 :     }
      62             : 
      63      677327 :     int GetVersion() const { return nVersion; }
      64      511802 :     int GetType() const { return nType; }
      65             :     size_t size() const { return stream->size(); }
      66           2 :     void ignore(size_t size) { return stream->ignore(size); }
      67             : };
      68             : 
      69             : /* Minimal stream for overwriting and/or appending to an existing byte vector
      70             :  *
      71             :  * The referenced vector will grow as necessary
      72             :  */
      73             : class CVectorWriter
      74             : {
      75             :  public:
      76             : 
      77             : /*
      78             :  * @param[in]  nTypeIn Serialization Type
      79             :  * @param[in]  nVersionIn Serialization Version (including any flags)
      80             :  * @param[in]  vchDataIn  Referenced byte vector to overwrite/append
      81             :  * @param[in]  nPosIn Starting position. Vector index where writes should start. The vector will initially
      82             :  *                    grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().
      83             : */
      84    15849606 :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
      85     7924818 :     {
      86     7924788 :         if(nPos > vchData.size())
      87           1 :             vchData.resize(nPos);
      88    15849606 :     }
      89             : /*
      90             :  * (other params same as above)
      91             :  * @param[in]  args  A list of items to serialize starting at nPosIn.
      92             : */
      93             :     template <typename... Args>
      94     1505948 :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
      95             :     {
      96     1505948 :         ::SerializeMany(*this, std::forward<Args>(args)...);
      97     1505948 :     }
      98    50555171 :     void write(Span<const std::byte> src)
      99             :     {
     100    50555171 :         assert(nPos <= vchData.size());
     101    50555171 :         size_t nOverwrite = std::min(src.size(), vchData.size() - nPos);
     102    50555171 :         if (nOverwrite) {
     103    37436486 :             memcpy(vchData.data() + nPos, src.data(), nOverwrite);
     104    37436486 :         }
     105    50555171 :         if (nOverwrite < src.size()) {
     106    13119640 :             vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.end()));
     107    13119640 :         }
     108    50555171 :         nPos += src.size();
     109    50555171 :     }
     110             :     template<typename T>
     111     8614089 :     CVectorWriter& operator<<(const T& obj)
     112             :     {
     113             :         // Serialize to this stream
     114     8614089 :         ::Serialize(*this, obj);
     115     8614089 :         return (*this);
     116             :     }
     117       97238 :     int GetVersion() const
     118             :     {
     119       97238 :         return nVersion;
     120             :     }
     121      160708 :     int GetType() const
     122             :     {
     123      160708 :         return nType;
     124             :     }
     125             :     size_t size() const
     126             :     {
     127             :         return vchData.size() - nPos;
     128             :     }
     129             : private:
     130             :     const int nType;
     131             :     const int nVersion;
     132             :     std::vector<unsigned char>& vchData;
     133             :     size_t nPos;
     134             : };
     135             : 
     136             : /** Minimal stream for reading from an existing byte array by Span.
     137             :  */
     138             : class SpanReader
     139             : {
     140             : private:
     141             :     const int m_type;
     142             :     const int m_version;
     143             :     Span<const unsigned char> m_data;
     144             : 
     145             : public:
     146             : 
     147             :     /**
     148             :      * @param[in]  type Serialization Type
     149             :      * @param[in]  version Serialization Version (including any flags)
     150             :      * @param[in]  data Referenced byte vector to overwrite/append
     151             :      */
     152       10686 :     SpanReader(int type, int version, Span<const unsigned char> data)
     153       10686 :         : m_type(type), m_version(version), m_data(data) {}
     154             : 
     155             :     template<typename T>
     156       15963 :     SpanReader& operator>>(T&& obj)
     157             :     {
     158             :         // Unserialize from this stream
     159       15963 :         ::Unserialize(*this, obj);
     160       15963 :         return (*this);
     161             :     }
     162             : 
     163             :     int GetVersion() const { return m_version; }
     164             :     int GetType() const { return m_type; }
     165             : 
     166           5 :     size_t size() const { return m_data.size(); }
     167           7 :     bool empty() const { return m_data.empty(); }
     168             : 
     169       21337 :     void read(Span<std::byte> dst)
     170             :     {
     171       21337 :         if (dst.size() == 0) {
     172           0 :             return;
     173             :         }
     174             : 
     175             :         // Read from the beginning of the buffer
     176       21337 :         if (dst.size() > m_data.size()) {
     177           2 :             throw std::ios_base::failure("SpanReader::read(): end of data");
     178             :         }
     179       21335 :         memcpy(dst.data(), m_data.data(), dst.size());
     180       21335 :         m_data = m_data.subspan(dst.size());
     181       21335 :     }
     182             : };
     183             : 
     184             : /** Double ended buffer combining vector and stream-like interfaces.
     185             :  *
     186             :  * >> and << read and write unformatted data using the above serialization templates.
     187             :  * Fills with data in linear time; some stringstream implementations take N^2 time.
     188             :  */
     189             : class DataStream
     190             : {
     191             : protected:
     192             :     using vector_type = SerializeData;
     193             :     vector_type vch;
     194    50510467 :     vector_type::size_type m_read_pos{0};
     195             : 
     196             : public:
     197             :     typedef vector_type::allocator_type   allocator_type;
     198             :     typedef vector_type::size_type        size_type;
     199             :     typedef vector_type::difference_type  difference_type;
     200             :     typedef vector_type::reference        reference;
     201             :     typedef vector_type::const_reference  const_reference;
     202             :     typedef vector_type::value_type       value_type;
     203             :     typedef vector_type::iterator         iterator;
     204             :     typedef vector_type::const_iterator   const_iterator;
     205             :     typedef vector_type::reverse_iterator reverse_iterator;
     206             : 
     207    92876075 :     explicit DataStream() {}
     208             :     explicit DataStream(Span<const uint8_t> sp) : DataStream{AsBytes(sp)} {}
     209     8144860 :     explicit DataStream(Span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {}
     210             : 
     211         567 :     std::string str() const
     212             :     {
     213         567 :         return std::string{UCharCast(data()), UCharCast(data() + size())};
     214             :     }
     215             : 
     216             : 
     217             :     //
     218             :     // Vector subset
     219             :     //
     220             :     const_iterator begin() const                     { return vch.begin() + m_read_pos; }
     221      684306 :     iterator begin()                                 { return vch.begin() + m_read_pos; }
     222             :     const_iterator end() const                       { return vch.end(); }
     223      342849 :     iterator end()                                   { return vch.end(); }
     224   290451002 :     size_type size() const                           { return vch.size() - m_read_pos; }
     225     1709348 :     bool empty() const                               { return vch.size() == m_read_pos; }
     226     1620896 :     void resize(size_type n, value_type c = value_type{}) { vch.resize(n + m_read_pos, c); }
     227    26561218 :     void reserve(size_type n)                        { vch.reserve(n + m_read_pos); }
     228             :     const_reference operator[](size_type pos) const  { return vch[pos + m_read_pos]; }
     229    18349258 :     reference operator[](size_type pos)              { return vch[pos + m_read_pos]; }
     230     6211792 :     void clear()                                     { vch.clear(); m_read_pos = 0; }
     231     3684195 :     value_type* data()                               { return vch.data() + m_read_pos; }
     232   173434794 :     const value_type* data() const                   { return vch.data() + m_read_pos; }
     233             : 
     234             :     inline void Compact()
     235             :     {
     236             :         vch.erase(vch.begin(), vch.begin() + m_read_pos);
     237             :         m_read_pos = 0;
     238             :     }
     239             : 
     240       26200 :     bool Rewind(std::optional<size_type> n = std::nullopt)
     241             :     {
     242             :         // Total rewind if no size is passed
     243       26200 :         if (!n) {
     244           0 :             m_read_pos = 0;
     245           0 :             return true;
     246             :         }
     247             :         // Rewind by n characters if the buffer hasn't been compacted yet
     248       26200 :         if (*n > m_read_pos)
     249           0 :             return false;
     250       26200 :         m_read_pos -= *n;
     251       26200 :         return true;
     252       26200 :     }
     253             : 
     254             : 
     255             :     //
     256             :     // Stream subset
     257             :     //
     258       15519 :     bool eof() const             { return size() == 0; }
     259       21884 :     int in_avail() const         { return size(); }
     260             : 
     261    57131764 :     void read(Span<value_type> dst)
     262             :     {
     263    57131764 :         if (dst.size() == 0) return;
     264             : 
     265             :         // Read from the beginning of the buffer
     266    57130894 :         auto next_read_pos{CheckedAdd(m_read_pos, dst.size())};
     267    57130894 :         if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
     268       28737 :             throw std::ios_base::failure("DataStream::read(): end of data");
     269             :         }
     270    57102157 :         memcpy(dst.data(), &vch[m_read_pos], dst.size());
     271    57102157 :         if (next_read_pos.value() == vch.size()) {
     272     6007693 :             m_read_pos = 0;
     273     6007693 :             vch.clear();
     274     6007693 :             return;
     275             :         }
     276    51094464 :         m_read_pos = next_read_pos.value();
     277    57103027 :     }
     278             : 
     279       18023 :     void ignore(size_t num_ignore)
     280             :     {
     281             :         // Ignore from the beginning of the buffer
     282       18023 :         auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)};
     283       18023 :         if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
     284           1 :             throw std::ios_base::failure("DataStream::ignore(): end of data");
     285             :         }
     286       18022 :         if (next_read_pos.value() == vch.size()) {
     287           3 :             m_read_pos = 0;
     288           3 :             vch.clear();
     289           3 :             return;
     290             :         }
     291       18019 :         m_read_pos = next_read_pos.value();
     292       18022 :     }
     293             : 
     294   130242066 :     void write(Span<const value_type> src)
     295             :     {
     296             :         // Write to the end of the buffer
     297   130242066 :         vch.insert(vch.end(), src.begin(), src.end());
     298   130242066 :     }
     299             : 
     300             :     template<typename Stream>
     301       29525 :     void Serialize(Stream& s) const
     302             :     {
     303             :         // Special case: stream << stream concatenates like stream += stream
     304       29525 :         if (!vch.empty())
     305       29469 :             s.write(MakeByteSpan(vch));
     306       29525 :     }
     307             : 
     308             :     template<typename T>
     309           2 :     DataStream& operator<<(const T& obj)
     310             :     {
     311             :         // Serialize to this stream
     312           2 :         ::Serialize(*this, obj);
     313           2 :         return (*this);
     314             :     }
     315             : 
     316             :     template<typename T>
     317           2 :     DataStream& operator>>(T&& obj)
     318             :     {
     319             :         // Unserialize from this stream
     320           2 :         ::Unserialize(*this, obj);
     321           2 :         return (*this);
     322             :     }
     323             : 
     324             :     /**
     325             :      * XOR the contents of this stream with a certain key.
     326             :      *
     327             :      * @param[in] key    The key used to XOR the data in this stream.
     328             :      */
     329     3363632 :     void Xor(const std::vector<unsigned char>& key)
     330             :     {
     331     3363632 :         if (key.size() == 0) {
     332           0 :             return;
     333             :         }
     334             : 
     335   176080340 :         for (size_type i = 0, j = 0; i != size(); i++) {
     336   172716708 :             vch[i] ^= std::byte{key[j++]};
     337             : 
     338             :             // This potentially acts on very many bytes of data, so it's
     339             :             // important that we calculate `j`, i.e. the `key` index in this
     340             :             // way instead of doing a %, which would effectively be a division
     341             :             // for each byte Xor'd -- much slower than need be.
     342   172716708 :             if (j == key.size())
     343    20224675 :                 j = 0;
     344   172716708 :         }
     345     3363632 :     }
     346             : };
     347             : 
     348             : class CDataStream : public DataStream
     349             : {
     350             : private:
     351             :     int nType;
     352             :     int nVersion;
     353             : 
     354             : public:
     355    92876075 :     explicit CDataStream(int nTypeIn, int nVersionIn)
     356    46438035 :         : nType{nTypeIn},
     357    92876075 :           nVersion{nVersionIn} {}
     358             : 
     359     1657969 :     explicit CDataStream(Span<const uint8_t> sp, int type, int version) : CDataStream{AsBytes(sp), type, version} {}
     360     8144860 :     explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)
     361     4072430 :         : DataStream{sp},
     362     4072430 :           nType{nTypeIn},
     363     8144860 :           nVersion{nVersionIn} {}
     364             : 
     365             : 
     366      266118 :     void SetType(int n)          { nType = n; }
     367      745599 :     int GetType() const          { return nType; }
     368      786287 :     void SetVersion(int n)       { nVersion = n; }
     369      792777 :     int GetVersion() const       { return nVersion; }
     370             : 
     371             :     template <typename T>
     372    42183670 :     CDataStream& operator<<(const T& obj)
     373             :     {
     374    42183670 :         ::Serialize(*this, obj);
     375    42183670 :         return *this;
     376             :     }
     377             : 
     378             :     template <typename T>
     379    13328204 :     CDataStream& operator>>(T&& obj)
     380             :     {
     381    13328204 :         ::Unserialize(*this, obj);
     382    13328204 :         return *this;
     383             :     }
     384             : };
     385             : 
     386             : template <typename IStream>
     387             : class BitStreamReader
     388             : {
     389             : private:
     390             :     IStream& m_istream;
     391             : 
     392             :     /// Buffered byte read in from the input stream. A new byte is read into the
     393             :     /// buffer when m_offset reaches 8.
     394        1055 :     uint8_t m_buffer{0};
     395             : 
     396             :     /// Number of high order bits in m_buffer already returned by previous
     397             :     /// Read() calls. The next bit to be returned is at this offset from the
     398             :     /// most significant bit position.
     399        1055 :     int m_offset{8};
     400             : 
     401             : public:
     402        3165 :     explicit BitStreamReader(IStream& istream) : m_istream(istream) {}
     403             : 
     404             :     /** Read the specified number of bits from the stream. The data is returned
     405             :      * in the nbits least significant bits of a 64-bit uint.
     406             :      */
     407       24923 :     uint64_t Read(int nbits) {
     408       24923 :         if (nbits < 0 || nbits > 64) {
     409           0 :             throw std::out_of_range("nbits must be between 0 and 64");
     410             :         }
     411             : 
     412       24923 :         uint64_t data = 0;
     413       62394 :         while (nbits > 0) {
     414       37471 :             if (m_offset == 8) {
     415       15946 :                 m_istream >> m_buffer;
     416       15946 :                 m_offset = 0;
     417       15946 :             }
     418             : 
     419       37471 :             int bits = std::min(8 - m_offset, nbits);
     420       37471 :             data <<= bits;
     421       37471 :             data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
     422       37471 :             m_offset += bits;
     423       37471 :             nbits -= bits;
     424             :         }
     425       24923 :         return data;
     426           0 :     }
     427             : };
     428             : 
     429             : template <typename OStream>
     430             : class BitStreamWriter
     431             : {
     432             : private:
     433             :     OStream& m_ostream;
     434             : 
     435             :     /// Buffered byte waiting to be written to the output stream. The byte is
     436             :     /// written buffer when m_offset reaches 8 or Flush() is called.
     437      146656 :     uint8_t m_buffer{0};
     438             : 
     439             :     /// Number of high order bits in m_buffer already written by previous
     440             :     /// Write() calls and not yet flushed to the stream. The next bit to be
     441             :     /// written to is at this offset from the most significant bit position.
     442      146656 :     int m_offset{0};
     443             : 
     444             : public:
     445      439968 :     explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
     446             : 
     447      293312 :     ~BitStreamWriter()
     448      146656 :     {
     449      146656 :         Flush();
     450      293312 :     }
     451             : 
     452             :     /** Write the nbits least significant bits of a 64-bit int to the output
     453             :      * stream. Data is buffered until it completes an octet.
     454             :      */
     455      812803 :     void Write(uint64_t data, int nbits) {
     456      812803 :         if (nbits < 0 || nbits > 64) {
     457           0 :             throw std::out_of_range("nbits must be between 0 and 64");
     458             :         }
     459             : 
     460     2358001 :         while (nbits > 0) {
     461     1545198 :             int bits = std::min(8 - m_offset, nbits);
     462     1545198 :             m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
     463     1545198 :             m_offset += bits;
     464     1545198 :             nbits -= bits;
     465             : 
     466     1545198 :             if (m_offset == 8) {
     467      776632 :                 Flush();
     468      776632 :             }
     469             :         }
     470      812803 :     }
     471             : 
     472             :     /** Flush any unwritten bits to the output stream, padding with 0's to the
     473             :      * next byte boundary.
     474             :      */
     475     1069944 :     void Flush() {
     476     1069944 :         if (m_offset == 0) {
     477      154178 :             return;
     478             :         }
     479             : 
     480      915766 :         m_ostream << m_buffer;
     481      915766 :         m_buffer = 0;
     482      915766 :         m_offset = 0;
     483     1069944 :     }
     484             : };
     485             : 
     486             : 
     487             : /** Non-refcounted RAII wrapper for FILE*
     488             :  *
     489             :  * Will automatically close the file when it goes out of scope if not null.
     490             :  * If you're returning the file pointer, return file.release().
     491             :  * If you need to close the file early, use file.fclose() instead of fclose(file).
     492             :  */
     493             : class AutoFile
     494             : {
     495             : protected:
     496             :     FILE* file;
     497             : 
     498             : public:
     499     1856407 :     explicit AutoFile(FILE* filenew) : file{filenew} {}
     500             : 
     501     1856407 :     ~AutoFile()
     502      228592 :     {
     503     1627815 :         fclose();
     504     1856407 :     }
     505             : 
     506             :     // Disallow copies
     507             :     AutoFile(const AutoFile&) = delete;
     508             :     AutoFile& operator=(const AutoFile&) = delete;
     509             : 
     510     1664215 :     void fclose()
     511             :     {
     512     1664215 :         if (file) {
     513     1612580 :             ::fclose(file);
     514     1612580 :             file = nullptr;
     515     1612580 :         }
     516     1664215 :     }
     517             : 
     518             :     /** Get wrapped FILE* with transfer of ownership.
     519             :      * @note This will invalidate the AutoFile object, and makes it the responsibility of the caller
     520             :      * of this function to clean up the returned FILE*.
     521             :      */
     522             :     FILE* release()             { FILE* ret = file; file = nullptr; return ret; }
     523             : 
     524             :     /** Get wrapped FILE* without transfer of ownership.
     525             :      * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
     526             :      * AutoFile outlives use of the passed pointer.
     527             :      */
     528      526683 :     FILE* Get() const           { return file; }
     529             : 
     530             :     /** Return true if the wrapped FILE* is nullptr, false otherwise.
     531             :      */
     532     1624976 :     bool IsNull() const         { return (file == nullptr); }
     533             : 
     534             :     //
     535             :     // Stream subset
     536             :     //
     537    71651792 :     void read(Span<std::byte> dst)
     538             :     {
     539    71651792 :         if (!file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr");
     540    71651792 :         if (fread(dst.data(), 1, dst.size(), file) != dst.size()) {
     541           9 :             throw std::ios_base::failure(feof(file) ? "AutoFile::read: end of file" : "AutoFile::read: fread failed");
     542             :         }
     543    71651783 :     }
     544             : 
     545           0 :     void ignore(size_t nSize)
     546             :     {
     547           0 :         if (!file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr");
     548             :         unsigned char data[4096];
     549           0 :         while (nSize > 0) {
     550           0 :             size_t nNow = std::min<size_t>(nSize, sizeof(data));
     551           0 :             if (fread(data, 1, nNow, file) != nNow)
     552           0 :                 throw std::ios_base::failure(feof(file) ? "AutoFile::ignore: end of file" : "AutoFile::read: fread failed");
     553           0 :             nSize -= nNow;
     554             :         }
     555           0 :     }
     556             : 
     557   110839691 :     void write(Span<const std::byte> src)
     558             :     {
     559   110839691 :         if (!file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
     560   110839691 :         if (fwrite(src.data(), 1, src.size(), file) != src.size()) {
     561           1 :             throw std::ios_base::failure("AutoFile::write: write failed");
     562             :         }
     563   110839690 :     }
     564             : 
     565             :     template <typename T>
     566    90973511 :     AutoFile& operator<<(const T& obj)
     567             :     {
     568    90973511 :         if (!file) throw std::ios_base::failure("AutoFile::operator<<: file handle is nullptr");
     569    90973511 :         ::Serialize(*this, obj);
     570    90973511 :         return *this;
     571           0 :     }
     572             : 
     573             :     template <typename T>
     574    43166596 :     AutoFile& operator>>(T&& obj)
     575             :     {
     576    43166596 :         if (!file) throw std::ios_base::failure("AutoFile::operator>>: file handle is nullptr");
     577    43166596 :         ::Unserialize(*this, obj);
     578    43166596 :         return *this;
     579           0 :     }
     580             : };
     581             : 
     582             : class CAutoFile : public AutoFile
     583             : {
     584             : private:
     585             :     const int nType;
     586             :     const int nVersion;
     587             : 
     588             : public:
     589     2798454 :     CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : AutoFile{filenew}, nType(nTypeIn), nVersion(nVersionIn) {}
     590      197652 :     int GetType() const          { return nType; }
     591      682922 :     int GetVersion() const       { return nVersion; }
     592             : 
     593             :     template<typename T>
     594     4373771 :     CAutoFile& operator<<(const T& obj)
     595             :     {
     596             :         // Serialize to this stream
     597     4373771 :         if (!file)
     598           0 :             throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
     599     4373771 :         ::Serialize(*this, obj);
     600     4373771 :         return (*this);
     601           0 :     }
     602             : 
     603             :     template<typename T>
     604      903343 :     CAutoFile& operator>>(T&& obj)
     605             :     {
     606             :         // Unserialize from this stream
     607      903343 :         if (!file)
     608           0 :             throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
     609      903343 :         ::Unserialize(*this, obj);
     610      903343 :         return (*this);
     611           0 :     }
     612             : };
     613             : 
     614             : /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
     615             :  *  deserialize from. It guarantees the ability to rewind a given number of bytes.
     616             :  *
     617             :  *  Will automatically close the file when it goes out of scope if not null.
     618             :  *  If you need to close the file early, use file.fclose() instead of fclose(file).
     619             :  */
     620             : class CBufferedFile
     621             : {
     622             : private:
     623             :     const int nType;
     624             :     const int nVersion;
     625             : 
     626             :     FILE *src;            //!< source file
     627         120 :     uint64_t nSrcPos{0};  //!< how many bytes have been read from source
     628         120 :     uint64_t m_read_pos{0}; //!< how many bytes have been read from this
     629             :     uint64_t nReadLimit;  //!< up to which position we're allowed to read
     630             :     uint64_t nRewind;     //!< how many bytes we guarantee to rewind
     631             :     std::vector<std::byte> vchBuf; //!< the buffer
     632             : 
     633             :     //! read data from the source to fill the buffer
     634         467 :     bool Fill() {
     635         467 :         unsigned int pos = nSrcPos % vchBuf.size();
     636         467 :         unsigned int readNow = vchBuf.size() - pos;
     637         467 :         unsigned int nAvail = vchBuf.size() - (nSrcPos - m_read_pos) - nRewind;
     638         467 :         if (nAvail < readNow)
     639         354 :             readNow = nAvail;
     640         467 :         if (readNow == 0)
     641           0 :             return false;
     642         467 :         size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
     643         467 :         if (nBytes == 0) {
     644          66 :             throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
     645             :         }
     646         401 :         nSrcPos += nBytes;
     647         401 :         return true;
     648         401 :     }
     649             : 
     650             :     //! Advance the stream's read pointer (m_read_pos) by up to 'length' bytes,
     651             :     //! filling the buffer from the file so that at least one byte is available.
     652             :     //! Return a pointer to the available buffer data and the number of bytes
     653             :     //! (which may be less than the requested length) that may be accessed
     654             :     //! beginning at that pointer.
     655      402278 :     std::pair<std::byte*, size_t> AdvanceStream(size_t length)
     656             :     {
     657      402278 :         assert(m_read_pos <= nSrcPos);
     658      402278 :         if (m_read_pos + length > nReadLimit) {
     659           2 :             throw std::ios_base::failure("Attempt to position past buffer limit");
     660             :         }
     661             :         // If there are no bytes available, read from the file.
     662      402276 :         if (m_read_pos == nSrcPos && length > 0) Fill();
     663             : 
     664      402276 :         size_t buffer_offset{static_cast<size_t>(m_read_pos % vchBuf.size())};
     665      402276 :         size_t buffer_available{static_cast<size_t>(vchBuf.size() - buffer_offset)};
     666      402276 :         size_t bytes_until_source_pos{static_cast<size_t>(nSrcPos - m_read_pos)};
     667      402276 :         size_t advance{std::min({length, buffer_available, bytes_until_source_pos})};
     668      402276 :         m_read_pos += advance;
     669      402276 :         return std::make_pair(&vchBuf[buffer_offset], advance);
     670           0 :     }
     671             : 
     672             : public:
     673         240 :     CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn)
     674         240 :         : nType(nTypeIn), nVersion(nVersionIn), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
     675         120 :     {
     676         120 :         if (nRewindIn >= nBufSize)
     677           1 :             throw std::ios_base::failure("Rewind limit must be less than buffer size");
     678         119 :         src = fileIn;
     679         240 :     }
     680             : 
     681         238 :     ~CBufferedFile()
     682         119 :     {
     683         119 :         fclose();
     684         238 :     }
     685             : 
     686             :     // Disallow copies
     687             :     CBufferedFile(const CBufferedFile&) = delete;
     688             :     CBufferedFile& operator=(const CBufferedFile&) = delete;
     689             : 
     690           1 :     int GetVersion() const { return nVersion; }
     691           1 :     int GetType() const { return nType; }
     692             : 
     693         121 :     void fclose()
     694             :     {
     695         121 :         if (src) {
     696         119 :             ::fclose(src);
     697         119 :             src = nullptr;
     698         119 :         }
     699         121 :     }
     700             : 
     701             :     //! check whether we're at the end of the source file
     702       14066 :     bool eof() const {
     703       14066 :         return m_read_pos == nSrcPos && feof(src);
     704             :     }
     705             : 
     706             :     //! read a number of bytes
     707      391395 :     void read(Span<std::byte> dst)
     708             :     {
     709      782883 :         while (dst.size() > 0) {
     710     1565952 :             auto [buffer_pointer, length]{AdvanceStream(dst.size())};
     711     1174464 :             memcpy(dst.data(), buffer_pointer, length);
     712      391488 :             dst = dst.subspan(length);
     713             :         }
     714      391395 :     }
     715             : 
     716             :     //! Move the read position ahead in the stream to the given position.
     717             :     //! Use SetPos() to back up in the stream, not SkipTo().
     718       10896 :     void SkipTo(const uint64_t file_pos)
     719             :     {
     720       10896 :         assert(file_pos >= m_read_pos);
     721       21686 :         while (m_read_pos < file_pos) AdvanceStream(file_pos - m_read_pos);
     722       10896 :     }
     723             : 
     724             :     //! return the current reading position
     725       35844 :     uint64_t GetPos() const {
     726       35844 :         return m_read_pos;
     727             :     }
     728             : 
     729             :     //! rewind to a given reading position
     730       21235 :     bool SetPos(uint64_t nPos) {
     731       21235 :         size_t bufsize = vchBuf.size();
     732       21235 :         if (nPos + bufsize < nSrcPos) {
     733             :             // rewinding too far, rewind as far as possible
     734          52 :             m_read_pos = nSrcPos - bufsize;
     735          52 :             return false;
     736             :         }
     737       21183 :         if (nPos > nSrcPos) {
     738             :             // can't go this far forward, go as far as possible
     739          15 :             m_read_pos = nSrcPos;
     740          15 :             return false;
     741             :         }
     742       21168 :         m_read_pos = nPos;
     743       21168 :         return true;
     744       21235 :     }
     745             : 
     746             :     //! prevent reading beyond a certain position
     747             :     //! no argument removes the limit
     748       23724 :     bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
     749       23724 :         if (nPos < m_read_pos)
     750           0 :             return false;
     751       23724 :         nReadLimit = nPos;
     752       23724 :         return true;
     753       23724 :     }
     754             : 
     755             :     template<typename T>
     756       43630 :     CBufferedFile& operator>>(T&& obj) {
     757             :         // Unserialize from this stream
     758       43630 :         ::Unserialize(*this, obj);
     759       43630 :         return (*this);
     760             :     }
     761             : 
     762             :     //! search for a given byte in the stream, and remain positioned on it
     763       10904 :     void FindByte(uint8_t ch)
     764             :     {
     765     2552785 :         while (true) {
     766     2552785 :             if (m_read_pos == nSrcPos)
     767         252 :                 Fill();
     768     2552785 :             if (vchBuf[m_read_pos % vchBuf.size()] == std::byte{ch}) {
     769       10904 :                 break;
     770             :             }
     771     2541881 :             m_read_pos++;
     772             :         }
     773       10904 :     }
     774             : };
     775             : 
     776             : #endif // BITCOIN_STREAMS_H

Generated by: LCOV version 1.16