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 144 : OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
36 :
37 : template<typename T>
38 7352 : OverrideStream<Stream>& operator<<(const T& obj)
39 : {
40 : // Serialize to this stream
41 7352 : ::Serialize(*this, obj);
42 7352 : return (*this);
43 : }
44 :
45 : template<typename T>
46 7417 : OverrideStream<Stream>& operator>>(T&& obj)
47 : {
48 : // Unserialize from this stream
49 7417 : ::Unserialize(*this, obj);
50 7417 : return (*this);
51 : }
52 :
53 7491 : void write(Span<const std::byte> src)
54 : {
55 7491 : stream->write(src);
56 7491 : }
57 :
58 7530 : void read(Span<std::byte> dst)
59 : {
60 7530 : stream->read(dst);
61 7530 : }
62 :
63 132 : int GetVersion() const { return nVersion; }
64 118 : 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 2040812 : CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
85 1020406 : {
86 1020406 : if(nPos > vchData.size())
87 1 : vchData.resize(nPos);
88 2040812 : }
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 50 : CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
95 : {
96 50 : ::SerializeMany(*this, std::forward<Args>(args)...);
97 50 : }
98 6122220 : void write(Span<const std::byte> src)
99 : {
100 6122220 : assert(nPos <= vchData.size());
101 6122220 : size_t nOverwrite = std::min(src.size(), vchData.size() - nPos);
102 6122220 : if (nOverwrite) {
103 6120668 : memcpy(vchData.data() + nPos, src.data(), nOverwrite);
104 6120668 : }
105 6122220 : if (nOverwrite < src.size()) {
106 1589 : vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.end()));
107 1589 : }
108 6122220 : nPos += src.size();
109 6122220 : }
110 : template<typename T>
111 1021130 : CVectorWriter& operator<<(const T& obj)
112 : {
113 : // Serialize to this stream
114 1021130 : ::Serialize(*this, obj);
115 1021130 : return (*this);
116 : }
117 49 : int GetVersion() const
118 : {
119 49 : return nVersion;
120 : }
121 7 : int GetType() const
122 : {
123 7 : 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 1128 : SpanReader(int type, int version, Span<const unsigned char> data)
153 1128 : : m_type(type), m_version(version), m_data(data) {}
154 :
155 : template<typename T>
156 13423 : SpanReader& operator>>(T&& obj)
157 : {
158 : // Unserialize from this stream
159 13423 : ::Unserialize(*this, obj);
160 13423 : 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 13990 : void read(Span<std::byte> dst)
170 : {
171 13990 : if (dst.size() == 0) {
172 0 : return;
173 : }
174 :
175 : // Read from the beginning of the buffer
176 13990 : if (dst.size() > m_data.size()) {
177 2 : throw std::ios_base::failure("SpanReader::read(): end of data");
178 : }
179 13988 : memcpy(dst.data(), m_data.data(), dst.size());
180 13988 : m_data = m_data.subspan(dst.size());
181 13988 : }
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 27383128 : 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 54164047 : explicit DataStream() {}
208 : explicit DataStream(Span<const uint8_t> sp) : DataStream{AsBytes(sp)} {}
209 602210 : explicit DataStream(Span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {}
210 :
211 39 : std::string str() const
212 : {
213 39 : 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 22 : iterator begin() { return vch.begin() + m_read_pos; }
222 : const_iterator end() const { return vch.end(); }
223 11 : iterator end() { return vch.end(); }
224 33014990 : size_type size() const { return vch.size() - m_read_pos; }
225 233309 : bool empty() const { return vch.size() == m_read_pos; }
226 312 : void resize(size_type n, value_type c = value_type{}) { vch.resize(n + m_read_pos, c); }
227 13676949 : 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 16704904 : reference operator[](size_type pos) { return vch[pos + m_read_pos]; }
230 143221 : void clear() { vch.clear(); m_read_pos = 0; }
231 273197 : value_type* data() { return vch.data() + m_read_pos; }
232 25169392 : 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 0 : bool Rewind(std::optional<size_type> n = std::nullopt)
241 : {
242 : // Total rewind if no size is passed
243 0 : 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 0 : if (*n > m_read_pos)
249 0 : return false;
250 0 : m_read_pos -= *n;
251 0 : return true;
252 0 : }
253 :
254 :
255 : //
256 : // Stream subset
257 : //
258 15495 : bool eof() const { return size() == 0; }
259 0 : int in_avail() const { return size(); }
260 :
261 4310787 : void read(Span<value_type> dst)
262 : {
263 4310787 : if (dst.size() == 0) return;
264 :
265 : // Read from the beginning of the buffer
266 4309917 : auto next_read_pos{CheckedAdd(m_read_pos, dst.size())};
267 4309917 : if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
268 33 : throw std::ios_base::failure("DataStream::read(): end of data");
269 : }
270 4309884 : memcpy(dst.data(), &vch[m_read_pos], dst.size());
271 4309884 : if (next_read_pos.value() == vch.size()) {
272 307999 : m_read_pos = 0;
273 307999 : vch.clear();
274 307999 : return;
275 : }
276 4001885 : m_read_pos = next_read_pos.value();
277 4310754 : }
278 :
279 9 : void ignore(size_t num_ignore)
280 : {
281 : // Ignore from the beginning of the buffer
282 9 : auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)};
283 9 : 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 8 : if (next_read_pos.value() == vch.size()) {
287 3 : m_read_pos = 0;
288 3 : vch.clear();
289 3 : return;
290 : }
291 5 : m_read_pos = next_read_pos.value();
292 8 : }
293 :
294 69060563 : void write(Span<const value_type> src)
295 : {
296 : // Write to the end of the buffer
297 69060563 : vch.insert(vch.end(), src.begin(), src.end());
298 69060563 : }
299 :
300 : template<typename Stream>
301 0 : void Serialize(Stream& s) const
302 : {
303 : // Special case: stream << stream concatenates like stream += stream
304 0 : if (!vch.empty())
305 0 : s.write(MakeByteSpan(vch));
306 0 : }
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 124582 : void Xor(const std::vector<unsigned char>& key)
330 : {
331 124582 : if (key.size() == 0) {
332 0 : return;
333 : }
334 :
335 4019754 : for (size_type i = 0, j = 0; i != size(); i++) {
336 3895172 : 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 3895172 : if (j == key.size())
343 424223 : j = 0;
344 3895172 : }
345 124582 : }
346 : };
347 :
348 : class CDataStream : public DataStream
349 : {
350 : private:
351 : int nType;
352 : int nVersion;
353 :
354 : public:
355 54164044 : explicit CDataStream(int nTypeIn, int nVersionIn)
356 27082022 : : nType{nTypeIn},
357 54164044 : nVersion{nVersionIn} {}
358 :
359 234011 : explicit CDataStream(Span<const uint8_t> sp, int type, int version) : CDataStream{AsBytes(sp), type, version} {}
360 602210 : explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)
361 301105 : : DataStream{sp},
362 301105 : nType{nTypeIn},
363 602210 : nVersion{nVersionIn} {}
364 :
365 :
366 184 : void SetType(int n) { nType = n; }
367 17364 : int GetType() const { return nType; }
368 5 : void SetVersion(int n) { nVersion = n; }
369 17386 : int GetVersion() const { return nVersion; }
370 :
371 : template <typename T>
372 17599964 : CDataStream& operator<<(const T& obj)
373 : {
374 17599964 : ::Serialize(*this, obj);
375 17599964 : return *this;
376 : }
377 :
378 : template <typename T>
379 1121830 : CDataStream& operator>>(T&& obj)
380 : {
381 1121830 : ::Unserialize(*this, obj);
382 1121830 : 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 227 : 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 227 : int m_offset{8};
400 :
401 : public:
402 681 : 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 22867 : uint64_t Read(int nbits) {
408 22867 : if (nbits < 0 || nbits > 64) {
409 0 : throw std::out_of_range("nbits must be between 0 and 64");
410 : }
411 :
412 22867 : uint64_t data = 0;
413 56594 : while (nbits > 0) {
414 33727 : if (m_offset == 8) {
415 13422 : m_istream >> m_buffer;
416 13422 : m_offset = 0;
417 13422 : }
418 :
419 33727 : int bits = std::min(8 - m_offset, nbits);
420 33727 : data <<= bits;
421 33727 : data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
422 33727 : m_offset += bits;
423 33727 : nbits -= bits;
424 : }
425 22867 : 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 236 : 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 236 : int m_offset{0};
443 :
444 : public:
445 708 : explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
446 :
447 472 : ~BitStreamWriter()
448 236 : {
449 236 : Flush();
450 472 : }
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 896 : void Write(uint64_t data, int nbits) {
456 896 : if (nbits < 0 || nbits > 64) {
457 0 : throw std::out_of_range("nbits must be between 0 and 64");
458 : }
459 :
460 2492 : while (nbits > 0) {
461 1596 : int bits = std::min(8 - m_offset, nbits);
462 1596 : m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
463 1596 : m_offset += bits;
464 1596 : nbits -= bits;
465 :
466 1596 : if (m_offset == 8) {
467 741 : Flush();
468 741 : }
469 : }
470 896 : }
471 :
472 : /** Flush any unwritten bits to the output stream, padding with 0's to the
473 : * next byte boundary.
474 : */
475 1213 : void Flush() {
476 1213 : if (m_offset == 0) {
477 237 : return;
478 : }
479 :
480 976 : m_ostream << m_buffer;
481 976 : m_buffer = 0;
482 976 : m_offset = 0;
483 1213 : }
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 96765 : explicit AutoFile(FILE* filenew) : file{filenew} {}
500 :
501 96765 : ~AutoFile()
502 955 : {
503 95810 : fclose();
504 96765 : }
505 :
506 : // Disallow copies
507 : AutoFile(const AutoFile&) = delete;
508 : AutoFile& operator=(const AutoFile&) = delete;
509 :
510 95819 : void fclose()
511 : {
512 95819 : if (file) {
513 95522 : ::fclose(file);
514 95522 : file = nullptr;
515 95522 : }
516 95819 : }
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 49492 : FILE* Get() const { return file; }
529 :
530 : /** Return true if the wrapped FILE* is nullptr, false otherwise.
531 : */
532 95779 : bool IsNull() const { return (file == nullptr); }
533 :
534 : //
535 : // Stream subset
536 : //
537 1399825 : void read(Span<std::byte> dst)
538 : {
539 1399825 : if (!file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr");
540 1399825 : if (fread(dst.data(), 1, dst.size(), file) != dst.size()) {
541 5 : throw std::ios_base::failure(feof(file) ? "AutoFile::read: end of file" : "AutoFile::read: fread failed");
542 : }
543 1399820 : }
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 789343 : void write(Span<const std::byte> src)
558 : {
559 789343 : if (!file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
560 789343 : if (fwrite(src.data(), 1, src.size(), file) != src.size()) {
561 1 : throw std::ios_base::failure("AutoFile::write: write failed");
562 : }
563 789342 : }
564 :
565 : template <typename T>
566 4582 : AutoFile& operator<<(const T& obj)
567 : {
568 4582 : if (!file) throw std::ios_base::failure("AutoFile::operator<<: file handle is nullptr");
569 4582 : ::Serialize(*this, obj);
570 4582 : return *this;
571 0 : }
572 :
573 : template <typename T>
574 4009 : AutoFile& operator>>(T&& obj)
575 : {
576 4009 : if (!file) throw std::ios_base::failure("AutoFile::operator>>: file handle is nullptr");
577 4009 : ::Unserialize(*this, obj);
578 4009 : 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 189710 : CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : AutoFile{filenew}, nType(nTypeIn), nVersion(nVersionIn) {}
590 815 : int GetType() const { return nType; }
591 50010 : int GetVersion() const { return nVersion; }
592 :
593 : template<typename T>
594 352939 : CAutoFile& operator<<(const T& obj)
595 : {
596 : // Serialize to this stream
597 352939 : if (!file)
598 0 : throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
599 352939 : ::Serialize(*this, obj);
600 352939 : return (*this);
601 0 : }
602 :
603 : template<typename T>
604 45554 : CAutoFile& operator>>(T&& obj)
605 : {
606 : // Unserialize from this stream
607 45554 : if (!file)
608 0 : throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
609 45554 : ::Unserialize(*this, obj);
610 45554 : 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 53 : uint64_t nSrcPos{0}; //!< how many bytes have been read from source
628 53 : 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 335 : bool Fill() {
635 335 : unsigned int pos = nSrcPos % vchBuf.size();
636 335 : unsigned int readNow = vchBuf.size() - pos;
637 335 : unsigned int nAvail = vchBuf.size() - (nSrcPos - m_read_pos) - nRewind;
638 335 : if (nAvail < readNow)
639 222 : readNow = nAvail;
640 335 : if (readNow == 0)
641 0 : return false;
642 335 : size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
643 335 : if (nBytes == 0) {
644 1 : throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
645 : }
646 334 : nSrcPos += nBytes;
647 334 : return true;
648 334 : }
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 3075 : std::pair<std::byte*, size_t> AdvanceStream(size_t length)
656 : {
657 3075 : assert(m_read_pos <= nSrcPos);
658 3075 : 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 3073 : if (m_read_pos == nSrcPos && length > 0) Fill();
663 :
664 3073 : size_t buffer_offset{static_cast<size_t>(m_read_pos % vchBuf.size())};
665 3073 : size_t buffer_available{static_cast<size_t>(vchBuf.size() - buffer_offset)};
666 3073 : size_t bytes_until_source_pos{static_cast<size_t>(nSrcPos - m_read_pos)};
667 3073 : size_t advance{std::min({length, buffer_available, bytes_until_source_pos})};
668 3073 : m_read_pos += advance;
669 3073 : return std::make_pair(&vchBuf[buffer_offset], advance);
670 0 : }
671 :
672 : public:
673 106 : CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn)
674 106 : : nType(nTypeIn), nVersion(nVersionIn), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
675 53 : {
676 53 : if (nRewindIn >= nBufSize)
677 1 : throw std::ios_base::failure("Rewind limit must be less than buffer size");
678 52 : src = fileIn;
679 106 : }
680 :
681 104 : ~CBufferedFile()
682 52 : {
683 52 : fclose();
684 104 : }
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 54 : void fclose()
694 : {
695 54 : if (src) {
696 52 : ::fclose(src);
697 52 : src = nullptr;
698 52 : }
699 54 : }
700 :
701 : //! check whether we're at the end of the source file
702 3702 : bool eof() const {
703 3702 : return m_read_pos == nSrcPos && feof(src);
704 : }
705 :
706 : //! read a number of bytes
707 2489 : void read(Span<std::byte> dst)
708 : {
709 5071 : while (dst.size() > 0) {
710 10328 : auto [buffer_pointer, length]{AdvanceStream(dst.size())};
711 7746 : memcpy(dst.data(), buffer_pointer, length);
712 2582 : dst = dst.subspan(length);
713 : }
714 2489 : }
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 599 : void SkipTo(const uint64_t file_pos)
719 : {
720 599 : assert(file_pos >= m_read_pos);
721 1092 : while (m_read_pos < file_pos) AdvanceStream(file_pos - m_read_pos);
722 599 : }
723 :
724 : //! return the current reading position
725 4933 : uint64_t GetPos() const {
726 4933 : return m_read_pos;
727 : }
728 :
729 : //! rewind to a given reading position
730 623 : bool SetPos(uint64_t nPos) {
731 623 : size_t bufsize = vchBuf.size();
732 623 : 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 571 : 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 556 : m_read_pos = nPos;
743 556 : return true;
744 623 : }
745 :
746 : //! prevent reading beyond a certain position
747 : //! no argument removes the limit
748 3065 : bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
749 3065 : if (nPos < m_read_pos)
750 0 : return false;
751 3065 : nReadLimit = nPos;
752 3065 : return true;
753 3065 : }
754 :
755 : template<typename T>
756 2489 : CBufferedFile& operator>>(T&& obj) {
757 : // Unserialize from this stream
758 2489 : ::Unserialize(*this, obj);
759 2489 : return (*this);
760 : }
761 :
762 : //! search for a given byte in the stream, and remain positioned on it
763 607 : void FindByte(uint8_t ch)
764 : {
765 2573 : while (true) {
766 2573 : if (m_read_pos == nSrcPos)
767 120 : Fill();
768 2573 : if (vchBuf[m_read_pos % vchBuf.size()] == std::byte{ch}) {
769 607 : break;
770 : }
771 1966 : m_read_pos++;
772 : }
773 607 : }
774 : };
775 :
776 : #endif // BITCOIN_STREAMS_H
|