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