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