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