LCOV - code coverage report
Current view: top level - src - streams.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 234 249 94.0 %
Date: 2025-02-23 09:33:43 Functions: 99 109 90.8 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2017-2021 The PIVX Core developers
       4             : // Distributed under the MIT/X11 software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #ifndef PIVX_STREAMS_H
       8             : #define PIVX_STREAMS_H
       9             : 
      10             : #include "serialize.h"
      11             : #include "support/allocators/zeroafterfree.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <assert.h>
      15             : #include <ios>
      16             : #include <limits>
      17             : #include <map>
      18             : #include <set>
      19             : #include <stdint.h>
      20             : #include <stdio.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       27718 :     OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
      36             : 
      37             :     template<typename T>
      38       59265 :     OverrideStream<Stream>& operator<<(const T& obj)
      39             :     {
      40             :         // Serialize to this stream
      41     1362593 :         ::Serialize(*this, obj);
      42       35951 :         return (*this);
      43             :     }
      44             : 
      45             :     template<typename T>
      46      100827 :     OverrideStream<Stream>& operator>>(T&& obj)
      47             :     {
      48             :         // Unserialize from this stream
      49      100838 :         ::Unserialize(*this, obj);
      50             :         return (*this);
      51             :     }
      52             : 
      53       12660 :     void write(const char* pch, size_t nSize)
      54             :     {
      55     1536360 :         stream->write(pch, nSize);
      56       35951 :     }
      57             : 
      58      115815 :     void read(char* pch, size_t nSize)
      59             :     {
      60      115523 :         stream->read(pch, nSize);
      61           0 :     }
      62             : 
      63       84399 :     int GetVersion() const { return nVersion; }
      64       42872 :     int GetType() const { return nType; }
      65             :     size_t size() const { return stream->size(); }
      66           1 :     void ignore(size_t size) { return stream->ignore(size); }
      67             : };
      68             : 
      69             : /** Double ended buffer combining vector and stream-like interfaces.
      70             :  *
      71             :  * >> and << read and write unformatted data using the above serialization templates.
      72             :  * Fills with data in linear time; some stringstream implementations take N^2 time.
      73             :  */
      74             : template<typename SerializeType>
      75    40927045 : class CBaseDataStream
      76             : {
      77             : protected:
      78             :     typedef SerializeType vector_type;
      79             :     vector_type vch;
      80             :     unsigned int nReadPos;
      81             :     int nType;
      82             :     int nVersion;
      83             : 
      84             : public:
      85             :     typedef typename vector_type::allocator_type   allocator_type;
      86             :     typedef typename vector_type::size_type        size_type;
      87             :     typedef typename vector_type::difference_type  difference_type;
      88             :     typedef typename vector_type::reference        reference;
      89             :     typedef typename vector_type::const_reference  const_reference;
      90             :     typedef typename vector_type::value_type       value_type;
      91             :     typedef typename vector_type::iterator         iterator;
      92             :     typedef typename vector_type::const_iterator   const_iterator;
      93             :     typedef typename vector_type::reverse_iterator reverse_iterator;
      94             : 
      95     6592541 :     explicit CBaseDataStream(int nTypeIn, int nVersionIn)
      96     6592541 :     {
      97     6592541 :         Init(nTypeIn, nVersionIn);
      98             :     }
      99             : 
     100             :     CBaseDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
     101             :     {
     102             :         Init(nTypeIn, nVersionIn);
     103             :     }
     104             : 
     105    27129430 :     CBaseDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
     106             :     {
     107    13564767 :         Init(nTypeIn, nVersionIn);
     108             :     }
     109             : 
     110       15931 :     CBaseDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
     111             :     {
     112       15931 :         Init(nTypeIn, nVersionIn);
     113       15931 :     }
     114             : 
     115             :     CBaseDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
     116             :     {
     117             :         Init(nTypeIn, nVersionIn);
     118             :     }
     119             : 
     120      238663 :     CBaseDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
     121             :     {
     122      238663 :         Init(nTypeIn, nVersionIn);
     123      238663 :     }
     124             : 
     125             :     template <typename... Args>
     126           1 :     CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args)
     127           1 :     {
     128           1 :         Init(nTypeIn, nVersionIn);
     129           1 :         ::SerializeMany(*this, std::forward<Args>(args)...);
     130           1 :     }
     131             : 
     132    20411891 :     void Init(int nTypeIn, int nVersionIn)
     133             :     {
     134    20411891 :         nReadPos = 0;
     135    20411882 :         nType = nTypeIn;
     136     4724105 :         nVersion = nVersionIn;
     137             :     }
     138             : 
     139             :     CBaseDataStream& operator+=(const CBaseDataStream& b)
     140             :     {
     141             :         vch.insert(vch.end(), b.begin(), b.end());
     142             :         return *this;
     143             :     }
     144             : 
     145             :     friend CBaseDataStream operator+(const CBaseDataStream& a, const CBaseDataStream& b)
     146             :     {
     147             :         CBaseDataStream ret = a;
     148             :         ret += b;
     149             :         return (ret);
     150             :     }
     151             : 
     152          19 :     std::string str() const
     153             :     {
     154          38 :         return (std::string(begin(), end()));
     155             :     }
     156             : 
     157             : 
     158             :     //
     159             :     // Vector subset
     160             :     //
     161          19 :     const_iterator begin() const { return vch.begin() + nReadPos; }
     162      751450 :     iterator begin() { return vch.begin() + nReadPos; }
     163          19 :     const_iterator end() const { return vch.end(); }
     164      750603 :     iterator end() { return vch.end(); }
     165    20820920 :     size_type size() const { return vch.size() - nReadPos; }
     166      227998 :     bool empty() const { return vch.size() == nReadPos; }
     167      754091 :     void resize(size_type n, value_type c = 0) { vch.resize(n + nReadPos, c); }
     168     5370670 :     void reserve(size_type n) { vch.reserve(n + nReadPos); }
     169             :     const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
     170    13242264 :     reference operator[](size_type pos) { return vch[pos + nReadPos]; }
     171     2519343 :     void clear()
     172             :     {
     173     2519342 :         vch.clear();
     174     2519342 :         nReadPos = 0;
     175             :     }
     176           3 :     iterator insert(iterator it, const char x = char()) { return vch.insert(it, x); }
     177             :     void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
     178     2241212 :     value_type* data()                               { return vch.data() + nReadPos; }
     179     3840674 :     const value_type* data() const                   { return vch.data() + nReadPos; }
     180             : 
     181             :     void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
     182             :     {
     183             :         if (last == first) return;
     184             :         assert(last - first > 0);
     185             :         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) {
     186             :             // special case for inserting at the front when there's room
     187             :             nReadPos -= (last - first);
     188             :             memcpy(&vch[nReadPos], &first[0], last - first);
     189             :         } else
     190             :             vch.insert(it, first, last);
     191             :     }
     192             : 
     193             :     void insert(iterator it, const char* first, const char* last)
     194             :     {
     195             :         if (last == first) return;
     196             :         assert(last - first > 0);
     197             :         if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) {
     198             :             // special case for inserting at the front when there's room
     199             :             nReadPos -= (last - first);
     200             :             memcpy(&vch[nReadPos], &first[0], last - first);
     201             :         } else
     202             :             vch.insert(it, first, last);
     203             :     }
     204             : 
     205           3 :     iterator erase(iterator it)
     206             :     {
     207           3 :         if (it == vch.begin() + nReadPos) {
     208             :             // special case for erasing from the front
     209           1 :             if (++nReadPos >= vch.size()) {
     210             :                 // whenever we reach the end, we take the opportunity to clear the buffer
     211           0 :                 nReadPos = 0;
     212           0 :                 return vch.erase(vch.begin(), vch.end());
     213             :             }
     214           1 :             return vch.begin() + nReadPos;
     215             :         } else
     216           2 :             return vch.erase(it);
     217             :     }
     218             : 
     219             :     iterator erase(iterator first, iterator last)
     220             :     {
     221             :         if (first == vch.begin() + nReadPos) {
     222             :             // special case for erasing from the front
     223             :             if (last == vch.end()) {
     224             :                 nReadPos = 0;
     225             :                 return vch.erase(vch.begin(), vch.end());
     226             :             } else {
     227             :                 nReadPos = (last - vch.begin());
     228             :                 return last;
     229             :             }
     230             :         } else
     231             :             return vch.erase(first, last);
     232             :     }
     233             : 
     234             :     inline void Compact()
     235             :     {
     236             :         vch.erase(vch.begin(), vch.begin() + nReadPos);
     237             :         nReadPos = 0;
     238             :     }
     239             : 
     240           0 :     bool Rewind(size_type n)
     241             :     {
     242             :         // Rewind by n characters if the buffer hasn't been compacted yet
     243           0 :         if (n > nReadPos)
     244             :             return false;
     245           0 :         nReadPos -= n;
     246             :         return true;
     247             :     }
     248             : 
     249             : 
     250             :     //
     251             :     // Stream subset
     252             :     //
     253         121 :     bool eof() const { return size() == 0; }
     254             :     CBaseDataStream* rdbuf() { return this; }
     255        1550 :     int in_avail() { return size(); }
     256             : 
     257       64768 :     void SetType(int n)     { nType = n; }
     258      108179 :     int GetType() const     { return nType; }
     259      378832 :     void SetVersion(int n)  { nVersion = n; }
     260      106472 :     int GetVersion() const  { return nVersion; }
     261             : 
     262   100218861 :     void read(char* pch, size_t nSize)
     263             :     {
     264   100218861 :         if (nSize == 0) return;
     265             : 
     266             :         // Read from the beginning of the buffer
     267   100218308 :         unsigned int nReadPosNext = nReadPos + nSize;
     268   100218308 :         if (nReadPosNext > vch.size()) {
     269        1509 :             throw std::ios_base::failure("CDataStream::read(): end of data");
     270             :         }
     271   100216799 :         memcpy(pch, &vch[nReadPos], nSize);
     272   100216799 :         if (nReadPosNext == vch.size()) {
     273    14607475 :             nReadPos = 0;
     274    14607475 :             vch.clear();
     275    14607475 :             return;
     276             :         }
     277    85609329 :         nReadPos = nReadPosNext;
     278             :     }
     279             : 
     280           0 :     CBaseDataStream& movePos(size_t nSize){
     281           0 :         nReadPos = nReadPos + nSize;
     282             :         return (*this);
     283             :     }
     284             : 
     285           5 :     void ignore(int nSize)
     286             :     {
     287             :         // Ignore from the beginning of the buffer
     288           5 :         if (nSize < 0) {
     289           1 :             throw std::ios_base::failure("CBaseDataStream::ignore(): nSize negative");
     290             :         }
     291           4 :         unsigned int nReadPosNext = nReadPos + nSize;
     292           4 :         if (nReadPosNext >= vch.size()) {
     293           2 :             if (nReadPosNext > vch.size())
     294           0 :                 throw std::ios_base::failure("CBaseDataStream::ignore() : end of data");
     295           2 :             nReadPos = 0;
     296           2 :             vch.clear();
     297           2 :             return;
     298             :         }
     299           2 :         nReadPos = nReadPosNext;
     300             :     }
     301             : 
     302     4693248 :     void write(const char* pch, size_t nSize)
     303             :     {
     304             :         // Write to the end of the buffer
     305    54265917 :         vch.insert(vch.end(), pch, pch + nSize);
     306     5438677 :     }
     307             : 
     308             :     template <typename Stream>
     309       34321 :     void Serialize(Stream& s) const
     310             :     {
     311             :         // Special case: stream << stream concatenates like stream += stream
     312       34321 :         if (!vch.empty())
     313       34321 :             s.write((char*)vch.data(), vch.size() * sizeof(value_type));
     314       19490 :     }
     315             : 
     316             :     template <typename T>
     317     7915226 :     CBaseDataStream& operator<<(const T& obj)
     318             :     {
     319             :         // Serialize to this stream
     320     8714850 :         ::Serialize(*this, obj);
     321       12792 :         return (*this);
     322             :     }
     323             : 
     324             :     template <typename T>
     325    36210037 :     CBaseDataStream& operator>>(T&& obj)
     326             :     {
     327             :         // Unserialize from this stream
     328    37242999 :         ::Unserialize(*this, obj);
     329       27775 :         return (*this);
     330             :     }
     331             : 
     332           1 :     void GetAndClear(CSerializeData& data)
     333             :     {
     334           1 :         data.insert(data.end(), begin(), end());
     335           1 :         clear();
     336           1 :     }
     337             : };
     338             : 
     339             : /* Minimal stream for overwriting and/or appending to an existing byte vector
     340             :  *
     341             :  * The referenced vector will grow as necessary
     342             :  */
     343             : class CVectorWriter
     344             : {
     345             :  public:
     346             : 
     347             : /*
     348             :  * @param[in]  nTypeIn Serialization Type
     349             :  * @param[in]  nVersionIn Serialization Version (including any flags)
     350             :  * @param[in]  vchDataIn  Referenced byte vector to overwrite/append
     351             :  * @param[in]  nPosIn Starting position. Vector index where writes should start. The vector will initially
     352             :  *                    grow as necessary to  max(index, vec.size()). So to append, use vec.size().
     353             : */
     354      659182 :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
     355             :     {
     356      362627 :         if(nPos > vchData.size())
     357           1 :             vchData.resize(nPos);
     358             :     }
     359             : /*
     360             :  * (other params same as above)
     361             :  * @param[in]  args  A list of items to serialize starting at nPos.
     362             : */
     363             :     template <typename... Args>
     364      654291 :     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
     365             :     {
     366      654290 :         ::SerializeMany(*this, std::forward<Args>(args)...);
     367      654290 :     }
     368     5561975 :     void write(const char* pch, size_t nSize)
     369             :     {
     370     5561975 :         assert(nPos <= vchData.size());
     371     5561975 :         size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
     372     5561975 :         if (nOverwrite) {
     373          19 :             memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
     374             :         }
     375     5561975 :         if (nOverwrite < nSize) {
     376     5561957 :             vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
     377             :         }
     378     5561975 :         nPos += nSize;
     379     5561975 :     }
     380             :     template<typename T>
     381      107291 :     CVectorWriter& operator<<(const T& obj)
     382             :     {
     383             :         // Serialize to this stream
     384      112290 :         ::Serialize(*this, obj);
     385        5120 :         return (*this);
     386             :     }
     387        4089 :     int GetVersion() const
     388             :     {
     389        4089 :         return nVersion;
     390             :     }
     391       12591 :     int GetType() const
     392             :     {
     393        6923 :         return nType;
     394             :     }
     395             :     void seek(size_t nSize)
     396             :     {
     397             :         nPos += nSize;
     398             :         if(nPos > vchData.size())
     399             :             vchData.resize(nPos);
     400             :     }
     401             : private:
     402             :     const int nType;
     403             :     const int nVersion;
     404             :     std::vector<unsigned char>& vchData;
     405             :     size_t nPos;
     406             : };
     407             : 
     408    19611819 : class CDataStream : public CBaseDataStream<CSerializeData>
     409             : {
     410             : public:
     411     6213281 :     explicit CDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
     412             : 
     413             :     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
     414             :             CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
     415             : 
     416             : #if !defined(_MSC_VER) || _MSC_VER >= 1300
     417    13564767 :     CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) :
     418    13564767 :             CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
     419             : #endif
     420             : 
     421       15820 :     CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
     422       15820 :             CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
     423             : 
     424             :     CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) :
     425             :             CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
     426             : 
     427      238663 :     CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) :
     428      238663 :             CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
     429             : 
     430             :     template <typename... Args>
     431           1 :     CDataStream(int nTypeIn, int nVersionIn, Args&&... args) :
     432           1 :             CBaseDataStream(nTypeIn, nVersionIn, args...) { }
     433             : 
     434             : };
     435             : 
     436             : 
     437             : 
     438             : 
     439             : 
     440             : 
     441             : 
     442             : 
     443             : 
     444             : 
     445             : /** Non-refcounted RAII wrapper for FILE*
     446             :  *
     447             :  * Will automatically close the file when it goes out of scope if not null.
     448             :  * If you're returning the file pointer, return file.release().
     449             :  * If you need to close the file early, use file.fclose() instead of fclose(file).
     450             :  */
     451             : class CAutoFile
     452             : {
     453             : private:
     454             :     const int nType;
     455             :     const int nVersion;
     456             : 
     457             :     FILE* file;
     458             : 
     459             : public:
     460      378670 :     CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
     461             :     {
     462      378511 :         file = filenew;
     463             :     }
     464             : 
     465      378670 :     ~CAutoFile()
     466        3542 :     {
     467      378670 :         fclose();
     468           0 :     }
     469             : 
     470             :     // Disallow copies
     471             :     CAutoFile(const CAutoFile&) = delete;
     472             :     CAutoFile& operator=(const CAutoFile&) = delete;
     473             : 
     474      382242 :     void fclose()
     475             :     {
     476      382083 :         if (file) {
     477        4023 :             ::fclose(file);
     478      376217 :             file = nullptr;
     479             :         }
     480             :     }
     481             : 
     482             :     /** Get wrapped FILE* with transfer of ownership.
     483             :      * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
     484             :      * of this function to clean up the returned FILE*.
     485             :      */
     486             :     FILE* release()
     487             :     {
     488             :         FILE* ret = file;
     489             :         file = nullptr;
     490             :         return ret;
     491             :     }
     492             : 
     493             :     /** Get wrapped FILE* without transfer of ownership.
     494             :      * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
     495             :      * CAutoFile outlives use of the passed pointer.
     496             :      */
     497      287537 :     FILE* Get() const { return file; }
     498             : 
     499             :     /** Return true if the wrapped FILE* is nullptr, false otherwise.
     500             :      */
     501      378317 :     bool IsNull() const { return (file == nullptr); }
     502             : 
     503             :     //
     504             :     // Stream subset
     505             :     //
     506        3212 :     int GetType() const          { return nType; }
     507       85602 :     int GetVersion() const       { return nVersion; }
     508             : 
     509    22972838 :     void read(char* pch, size_t nSize)
     510             :     {
     511    22972838 :         if (!file)
     512           0 :             throw std::ios_base::failure("CAutoFile::read : file handle is nullptr");
     513    45945816 :         if (fread(pch, 1, nSize, file) != nSize)
     514           2 :             throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
     515    22972837 :     }
     516             : 
     517             :     void ignore(size_t nSize)
     518             :     {
     519             :         if (!file)
     520             :             throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
     521             :         unsigned char data[4096];
     522             :         while (nSize > 0) {
     523             :             size_t nNow = std::min<size_t>(nSize, sizeof(data));
     524             :             if (fread(data, 1, nNow, file) != nNow)
     525             :                 throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
     526             :             nSize -= nNow;
     527             :         }
     528             :     }
     529             : 
     530             : 
     531    15276407 :     void write(const char* pch, size_t nSize)
     532             :     {
     533    15276407 :         if (!file)
     534           0 :             throw std::ios_base::failure("CAutoFile::write : file handle is nullptr");
     535    15276407 :         if (fwrite(pch, 1, nSize, file) != nSize)
     536           1 :             throw std::ios_base::failure("CAutoFile::write : write failed");
     537    15276406 :     }
     538             : 
     539             :     template <typename T>
     540     2806920 :     CAutoFile& operator<<(const T& obj)
     541             :     {
     542             :         // Serialize to this stream
     543     2806920 :         if (!file)
     544           0 :             throw std::ios_base::failure("CAutoFile::operator<< : file handle is nullptr");
     545     2806919 :         ::Serialize(*this, obj);
     546     2806918 :         return (*this);
     547             :     }
     548             : 
     549             :     template<typename T>
     550     4164542 :     CAutoFile& operator>>(T&& obj)
     551             :     {
     552             :         // Unserialize from this stream
     553     4164542 :         if (!file)
     554           0 :             throw std::ios_base::failure("CAutoFile::operator>> : file handle is nullptr");
     555     4164541 :         ::Unserialize(*this, obj);
     556     4164541 :         return (*this);
     557             :     }
     558             : };
     559             : 
     560             : /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
     561             :  *  deserialize from. It guarantees the ability to rewind a given number of bytes.
     562             :  *
     563             :  *  Will automatically close the file when it goes out of scope if not null.
     564             :  *  If you need to close the file early, use file.fclose() instead of fclose(file).
     565             :  */
     566             : class CBufferedFile
     567             : {
     568             : private:
     569             :     const int nType;
     570             :     const int nVersion;
     571             : 
     572             :     FILE* src;                // source file
     573             :     uint64_t nSrcPos;         // how many bytes have been read from source
     574             :     uint64_t nReadPos;        // how many bytes have been read from this
     575             :     uint64_t nReadLimit;      // up to which position we're allowed to read
     576             :     uint64_t nRewind;         // how many bytes we guarantee to rewind
     577             :     std::vector<char> vchBuf; // the buffer
     578             : 
     579             : protected:
     580             :     // read data from the source to fill the buffer
     581         376 :     bool Fill()
     582             :     {
     583         376 :         unsigned int pos = nSrcPos % vchBuf.size();
     584         376 :         unsigned int readNow = vchBuf.size() - pos;
     585         376 :         unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
     586         376 :         if (nAvail < readNow)
     587         319 :             readNow = nAvail;
     588         376 :         if (readNow == 0)
     589             :             return false;
     590         376 :         size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
     591         376 :         if (nBytes == 0) {
     592           6 :             throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
     593             :         }
     594         370 :         nSrcPos += nBytes;
     595         370 :         return true;
     596             :     }
     597             : 
     598             : public:
     599          57 :     CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
     600          58 :         nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
     601             :     {
     602          57 :         if (nRewindIn >= nBufSize)
     603           1 :             throw std::ios_base::failure("Rewind limit must be less than buffer size");
     604          56 :         src = fileIn;
     605          56 :     }
     606             : 
     607          56 :     ~CBufferedFile()
     608         112 :     {
     609          56 :         fclose();
     610          56 :     }
     611             : 
     612             :     int GetVersion() const { return nVersion; }
     613             :     int GetType() const { return nType; }
     614             : 
     615             :     // Disallow copies
     616             :     CBufferedFile(const CBufferedFile&) = delete;
     617             :     CBufferedFile& operator=(const CBufferedFile&) = delete;
     618             : 
     619          57 :     void fclose()
     620             :     {
     621          57 :         if (src) {
     622          56 :             ::fclose(src);
     623          56 :             src = nullptr;
     624             :         }
     625             :     }
     626             : 
     627             :     // check whether we're at the end of the source file
     628        4023 :     bool eof() const
     629             :     {
     630        4023 :         return nReadPos == nSrcPos && feof(src);
     631             :     }
     632             : 
     633             :     // read a number of bytes
     634       10824 :     void read(char* pch, size_t nSize)
     635             :     {
     636       10824 :         if (nSize + nReadPos > nReadLimit)
     637           1 :             throw std::ios_base::failure("Read attempted past buffer limit");
     638       21773 :         while (nSize > 0) {
     639       10951 :             if (nReadPos == nSrcPos)
     640         208 :                 Fill();
     641       10950 :             unsigned int pos = nReadPos % vchBuf.size();
     642       10950 :             size_t nNow = nSize;
     643       10950 :             if (nNow + pos > vchBuf.size())
     644          37 :                 nNow = vchBuf.size() - pos;
     645       10950 :             if (nNow + nReadPos > nSrcPos)
     646          98 :                 nNow = nSrcPos - nReadPos;
     647       10950 :             memcpy(pch, &vchBuf[pos], nNow);
     648       10950 :             nReadPos += nNow;
     649       10950 :             pch += nNow;
     650       10950 :             nSize -= nNow;
     651             :         }
     652       10822 :     }
     653             : 
     654             :     // return the current reading position
     655        6155 :     uint64_t GetPos()
     656             :     {
     657        6155 :         return nReadPos;
     658             :     }
     659             : 
     660             :     //! rewind to a given reading position
     661        1391 :     bool SetPos(uint64_t nPos) {
     662        1391 :         size_t bufsize = vchBuf.size();
     663        1391 :         if (nPos + bufsize < nSrcPos) {
     664             :             // rewinding too far, rewind as far as possible
     665          51 :             nReadPos = nSrcPos - bufsize;
     666          51 :             return false;
     667             :         }
     668        1338 :         if (nPos > nSrcPos) {
     669             :             // can't go this far forward, go as far as possible
     670          18 :             nReadPos = nSrcPos;
     671          18 :             return false;
     672             :         }
     673        1322 :         nReadPos = nPos;
     674        1322 :         return true;
     675             :     }
     676             : 
     677             :     //! prevent reading beyond a certain position
     678             :     //! no argument removes the limit
     679        3663 :     bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
     680        3313 :         if (nPos < nReadPos)
     681             :             return false;
     682        3663 :         nReadLimit = nPos;
     683        3663 :         return true;
     684             :     }
     685             : 
     686             :     template<typename T>
     687        4742 :     CBufferedFile& operator>>(T&& obj) {
     688             :         // Unserialize from this stream
     689       10691 :         ::Unserialize(*this, obj);
     690           0 :         return (*this);
     691             :     }
     692             : 
     693             :     // search for a given byte in the stream, and remain positioned on it
     694        1095 :     void FindByte(char ch)
     695             :     {
     696   167646896 :         while (true) {
     697    83824021 :             if (nReadPos == nSrcPos)
     698         168 :                 Fill();
     699    83824021 :             if (vchBuf[nReadPos % vchBuf.size()] == ch)
     700             :                 break;
     701    83822975 :             nReadPos++;
     702             :         }
     703        1090 :     }
     704             : };
     705             : 
     706             : #endif // PIVX_STREAMS_H

Generated by: LCOV version 1.14