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 3 : 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 8 : {
# 37 8 : // Serialize to this stream
# 38 8 : ::Serialize(*this, obj);
# 39 8 : return (*this);
# 40 8 : }
# 41 :
# 42 : template<typename T>
# 43 : OverrideStream<Stream>& operator>>(T&& obj)
# 44 4 : {
# 45 4 : // Unserialize from this stream
# 46 4 : ::Unserialize(*this, obj);
# 47 4 : return (*this);
# 48 4 : }
# 49 :
# 50 : void write(const char* pch, size_t nSize)
# 51 35 : {
# 52 35 : stream->write(pch, nSize);
# 53 35 : }
# 54 :
# 55 : void read(char* pch, size_t nSize)
# 56 19 : {
# 57 19 : stream->read(pch, nSize);
# 58 19 : }
# 59 :
# 60 5 : int GetVersion() const { return nVersion; }
# 61 : int GetType() const { return nType; }
# 62 2 : 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 : CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
# 81 577 : {
# 82 577 : if(nPos > vchData.size())
# 83 2 : vchData.resize(nPos);
# 84 577 : }
# 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 : CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
# 91 94 : {
# 92 94 : ::SerializeMany(*this, std::forward<Args>(args)...);
# 93 94 : }
# 94 : void write(const char* pch, size_t nSize)
# 95 2854 : {
# 96 2854 : assert(nPos <= vchData.size());
# 97 2854 : size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
# 98 2854 : if (nOverwrite) {
# 99 38 : memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
# 100 38 : }
# 101 2854 : if (nOverwrite < nSize) {
# 102 2818 : vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
# 103 2818 : }
# 104 2854 : nPos += nSize;
# 105 2854 : }
# 106 : template<typename T>
# 107 : CVectorWriter& operator<<(const T& obj)
# 108 1921 : {
# 109 1921 : // Serialize to this stream
# 110 1921 : ::Serialize(*this, obj);
# 111 1921 : return (*this);
# 112 1921 : }
# 113 : int GetVersion() const
# 114 88 : {
# 115 88 : return nVersion;
# 116 88 : }
# 117 : int GetType() const
# 118 88 : {
# 119 88 : return nType;
# 120 88 : }
# 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 : VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
# 147 : : m_type(type), m_version(version), m_data(data), m_pos(pos)
# 148 1091 : {
# 149 1091 : if (m_pos > m_data.size()) {
# 150 0 : throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())");
# 151 0 : }
# 152 1091 : }
# 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 : VectorReader& operator>>(T& obj)
# 168 29135 : {
# 169 29135 : // Unserialize from this stream
# 170 29135 : ::Unserialize(*this, obj);
# 171 29135 : return (*this);
# 172 29135 : }
# 173 :
# 174 0 : int GetVersion() const { return m_version; }
# 175 0 : int GetType() const { return m_type; }
# 176 :
# 177 10 : size_t size() const { return m_data.size() - m_pos; }
# 178 678 : bool empty() const { return m_data.size() == m_pos; }
# 179 :
# 180 : void read(char* dst, size_t n)
# 181 30226 : {
# 182 30226 : if (n == 0) {
# 183 0 : return;
# 184 0 : }
# 185 30226 :
# 186 30226 : // Read from the beginning of the buffer
# 187 30226 : size_t pos_next = m_pos + n;
# 188 30226 : if (pos_next > m_data.size()) {
# 189 4 : throw std::ios_base::failure("VectorReader::read(): end of data");
# 190 4 : }
# 191 30222 : memcpy(dst, m_data.data() + m_pos, n);
# 192 30222 : m_pos = pos_next;
# 193 30222 : }
# 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 : 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 : explicit CDataStream(int nTypeIn, int nVersionIn)
# 223 11359357 : {
# 224 11359357 : Init(nTypeIn, nVersionIn);
# 225 11359357 : }
# 226 :
# 227 : CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
# 228 0 : {
# 229 0 : Init(nTypeIn, nVersionIn);
# 230 0 : }
# 231 :
# 232 : CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
# 233 153278 : {
# 234 153278 : Init(nTypeIn, nVersionIn);
# 235 153278 : }
# 236 :
# 237 : CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
# 238 0 : {
# 239 0 : Init(nTypeIn, nVersionIn);
# 240 0 : }
# 241 :
# 242 : CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
# 243 2 : {
# 244 2 : Init(nTypeIn, nVersionIn);
# 245 2 : }
# 246 :
# 247 : CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
# 248 1508 : {
# 249 1508 : Init(nTypeIn, nVersionIn);
# 250 1508 : }
# 251 :
# 252 : template <typename... Args>
# 253 : CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
# 254 2 : {
# 255 2 : Init(nTypeIn, nVersionIn);
# 256 2 : ::SerializeMany(*this, std::forward<Args>(args)...);
# 257 2 : }
# 258 :
# 259 : void Init(int nTypeIn, int nVersionIn)
# 260 11514147 : {
# 261 11514147 : nReadPos = 0;
# 262 11514147 : nType = nTypeIn;
# 263 11514147 : nVersion = nVersionIn;
# 264 11514147 : }
# 265 :
# 266 : CDataStream& operator+=(const CDataStream& b)
# 267 0 : {
# 268 0 : vch.insert(vch.end(), b.begin(), b.end());
# 269 0 : return *this;
# 270 0 : }
# 271 :
# 272 : friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
# 273 0 : {
# 274 0 : CDataStream ret = a;
# 275 0 : ret += b;
# 276 0 : return (ret);
# 277 0 : }
# 278 :
# 279 : std::string str() const
# 280 22 : {
# 281 22 : return (std::string(begin(), end()));
# 282 22 : }
# 283 :
# 284 :
# 285 : //
# 286 : // Vector subset
# 287 : //
# 288 58 : const_iterator begin() const { return vch.begin() + nReadPos; }
# 289 285 : iterator begin() { return vch.begin() + nReadPos; }
# 290 58 : const_iterator end() const { return vch.end(); }
# 291 251 : iterator end() { return vch.end(); }
# 292 33929078 : size_type size() const { return vch.size() - nReadPos; }
# 293 12 : bool empty() const { return vch.size() == nReadPos; }
# 294 34 : void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
# 295 10418138 : void reserve(size_type n) { vch.reserve(n + nReadPos); }
# 296 0 : const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
# 297 28105878 : reference operator[](size_type pos) { return vch[pos + nReadPos]; }
# 298 138918 : void clear() { vch.clear(); nReadPos = 0; }
# 299 6 : iterator insert(iterator it, const char x=char()) { return vch.insert(it, x); }
# 300 0 : void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
# 301 10418138 : value_type* data() { return vch.data() + nReadPos; }
# 302 0 : const value_type* data() const { return vch.data() + nReadPos; }
# 303 :
# 304 : void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
# 305 4 : {
# 306 4 : if (last == first) return;
# 307 4 : assert(last - first > 0);
# 308 4 : if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
# 309 0 : {
# 310 0 : // 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 4 : else
# 315 4 : vch.insert(it, first, last);
# 316 4 : }
# 317 :
# 318 : void insert(iterator it, const char* first, const char* last)
# 319 0 : {
# 320 0 : if (last == first) return;
# 321 0 : assert(last - first > 0);
# 322 0 : if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
# 323 0 : {
# 324 0 : // special case for inserting at the front when there's room
# 325 0 : nReadPos -= (last - first);
# 326 0 : memcpy(&vch[nReadPos], &first[0], last - first);
# 327 0 : }
# 328 0 : else
# 329 0 : vch.insert(it, first, last);
# 330 0 : }
# 331 :
# 332 : iterator erase(iterator it)
# 333 6 : {
# 334 6 : if (it == vch.begin() + nReadPos)
# 335 2 : {
# 336 2 : // special case for erasing from the front
# 337 2 : if (++nReadPos >= vch.size())
# 338 0 : {
# 339 0 : // 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 0 : }
# 343 2 : return vch.begin() + nReadPos;
# 344 2 : }
# 345 4 : else
# 346 4 : return vch.erase(it);
# 347 6 : }
# 348 :
# 349 : iterator erase(iterator first, iterator last)
# 350 0 : {
# 351 0 : if (first == vch.begin() + nReadPos)
# 352 0 : {
# 353 0 : // special case for erasing from the front
# 354 0 : if (last == vch.end())
# 355 0 : {
# 356 0 : nReadPos = 0;
# 357 0 : return vch.erase(vch.begin(), vch.end());
# 358 0 : }
# 359 0 : else
# 360 0 : {
# 361 0 : nReadPos = (last - vch.begin());
# 362 0 : return last;
# 363 0 : }
# 364 0 : }
# 365 0 : else
# 366 0 : return vch.erase(first, last);
# 367 0 : }
# 368 :
# 369 : inline void Compact()
# 370 0 : {
# 371 0 : vch.erase(vch.begin(), vch.begin() + nReadPos);
# 372 0 : nReadPos = 0;
# 373 0 : }
# 374 :
# 375 : bool Rewind(size_type n)
# 376 0 : {
# 377 0 : // Rewind by n characters if the buffer hasn't been compacted yet
# 378 0 : if (n > nReadPos)
# 379 0 : return false;
# 380 0 : nReadPos -= n;
# 381 0 : return true;
# 382 0 : }
# 383 :
# 384 :
# 385 : //
# 386 : // Stream subset
# 387 : //
# 388 8 : bool eof() const { return size() == 0; }
# 389 0 : CDataStream* rdbuf() { return this; }
# 390 0 : int in_avail() const { return size(); }
# 391 :
# 392 24070 : void SetType(int n) { nType = n; }
# 393 9319 : int GetType() const { return nType; }
# 394 50 : void SetVersion(int n) { nVersion = n; }
# 395 14051 : int GetVersion() const { return nVersion; }
# 396 :
# 397 : void read(char* pch, size_t nSize)
# 398 2176597 : {
# 399 2176597 : if (nSize == 0) return;
# 400 2174061 :
# 401 2174061 : // Read from the beginning of the buffer
# 402 2174061 : unsigned int nReadPosNext = nReadPos + nSize;
# 403 2174061 : if (nReadPosNext > vch.size()) {
# 404 314 : throw std::ios_base::failure("CDataStream::read(): end of data");
# 405 314 : }
# 406 2173747 : memcpy(pch, &vch[nReadPos], nSize);
# 407 2173747 : if (nReadPosNext == vch.size())
# 408 179348 : {
# 409 179348 : nReadPos = 0;
# 410 179348 : vch.clear();
# 411 179348 : return;
# 412 179348 : }
# 413 1994399 : nReadPos = nReadPosNext;
# 414 1994399 : }
# 415 :
# 416 : void ignore(int nSize)
# 417 2 : {
# 418 2 : // Ignore from the beginning of the buffer
# 419 2 : if (nSize < 0) {
# 420 2 : throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
# 421 2 : }
# 422 0 : unsigned int nReadPosNext = nReadPos + nSize;
# 423 0 : if (nReadPosNext >= vch.size())
# 424 0 : {
# 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 0 : }
# 431 0 : nReadPos = nReadPosNext;
# 432 0 : }
# 433 :
# 434 : void write(const char* pch, size_t nSize)
# 435 58252285 : {
# 436 58252285 : // Write to the end of the buffer
# 437 58252285 : vch.insert(vch.end(), pch, pch + nSize);
# 438 58252285 : }
# 439 :
# 440 : template<typename Stream>
# 441 : void Serialize(Stream& s) const
# 442 0 : {
# 443 0 : // 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 : CDataStream& operator<<(const T& obj)
# 450 11855949 : {
# 451 11855949 : // Serialize to this stream
# 452 11855949 : ::Serialize(*this, obj);
# 453 11855949 : return (*this);
# 454 11855949 : }
# 455 :
# 456 : template<typename T>
# 457 : CDataStream& operator>>(T&& obj)
# 458 924392 : {
# 459 924392 : // Unserialize from this stream
# 460 924392 : ::Unserialize(*this, obj);
# 461 924392 : return (*this);
# 462 924392 : }
# 463 :
# 464 2 : void GetAndClear(CSerializeData &d) {
# 465 2 : d.insert(d.end(), begin(), end());
# 466 2 : clear();
# 467 2 : }
# 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 : void Xor(const std::vector<unsigned char>& key)
# 475 194026 : {
# 476 194026 : if (key.size() == 0) {
# 477 0 : return;
# 478 0 : }
# 479 194026 :
# 480 7719332 : for (size_type i = 0, j = 0; i != size(); i++) {
# 481 7525306 : vch[i] ^= key[j++];
# 482 7525306 :
# 483 7525306 : // This potentially acts on very many bytes of data, so it's
# 484 7525306 : // important that we calculate `j`, i.e. the `key` index in this
# 485 7525306 : // way instead of doing a %, which would effectively be a division
# 486 7525306 : // for each byte Xor'd -- much slower than need be.
# 487 7525306 : if (j == key.size())
# 488 856008 : j = 0;
# 489 7525306 : }
# 490 194026 : }
# 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 : 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 : int m_offset{8};
# 507 :
# 508 : public:
# 509 1088 : 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 48302 : uint64_t Read(int nbits) {
# 515 48302 : if (nbits < 0 || nbits > 64) {
# 516 0 : throw std::out_of_range("nbits must be between 0 and 64");
# 517 0 : }
# 518 48302 :
# 519 48302 : uint64_t data = 0;
# 520 119834 : while (nbits > 0) {
# 521 71532 : if (m_offset == 8) {
# 522 29136 : m_istream >> m_buffer;
# 523 29136 : m_offset = 0;
# 524 29136 : }
# 525 71532 :
# 526 71532 : int bits = std::min(8 - m_offset, nbits);
# 527 71532 : data <<= bits;
# 528 71532 : data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
# 529 71532 : m_offset += bits;
# 530 71532 : nbits -= bits;
# 531 71532 : }
# 532 48302 : return data;
# 533 48302 : }
# 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 : 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 : int m_offset{0};
# 550 :
# 551 : public:
# 552 472 : explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
# 553 :
# 554 : ~BitStreamWriter()
# 555 472 : {
# 556 472 : Flush();
# 557 472 : }
# 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 1786 : void Write(uint64_t data, int nbits) {
# 563 1786 : if (nbits < 0 || nbits > 64) {
# 564 0 : throw std::out_of_range("nbits must be between 0 and 64");
# 565 0 : }
# 566 1786 :
# 567 4914 : while (nbits > 0) {
# 568 3128 : int bits = std::min(8 - m_offset, nbits);
# 569 3128 : m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
# 570 3128 : m_offset += bits;
# 571 3128 : nbits -= bits;
# 572 3128 :
# 573 3128 : if (m_offset == 8) {
# 574 1418 : Flush();
# 575 1418 : }
# 576 3128 : }
# 577 1786 : }
# 578 :
# 579 : /** Flush any unwritten bits to the output stream, padding with 0's to the
# 580 : * next byte boundary.
# 581 : */
# 582 2362 : void Flush() {
# 583 2362 : if (m_offset == 0) {
# 584 474 : return;
# 585 474 : }
# 586 1888 :
# 587 1888 : m_ostream << m_buffer;
# 588 1888 : m_buffer = 0;
# 589 1888 : m_offset = 0;
# 590 1888 : }
# 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 : int nVersion;
# 606 :
# 607 : FILE* file;
# 608 :
# 609 : public:
# 610 : CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
# 611 13477 : {
# 612 13477 : file = filenew;
# 613 13477 : }
# 614 :
# 615 : ~CAutoFile()
# 616 13477 : {
# 617 13477 : fclose();
# 618 13477 : }
# 619 :
# 620 : // Disallow copies
# 621 : CAutoFile(const CAutoFile&) = delete;
# 622 : CAutoFile& operator=(const CAutoFile&) = delete;
# 623 :
# 624 : void fclose()
# 625 13666 : {
# 626 13666 : if (file) {
# 627 13224 : ::fclose(file);
# 628 13224 : file = nullptr;
# 629 13224 : }
# 630 13666 : }
# 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 0 : 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 9661 : FILE* Get() const { return file; }
# 643 :
# 644 : /** Return true if the wrapped FILE* is nullptr, false otherwise.
# 645 : */
# 646 13465 : bool IsNull() const { return (file == nullptr); }
# 647 :
# 648 : //
# 649 : // Stream subset
# 650 : //
# 651 880 : int GetType() const { return nType; }
# 652 16914 : int GetVersion() const { return nVersion; }
# 653 0 : void SetVersion(int n) { nVersion = n; }
# 654 :
# 655 : void read(char* pch, size_t nSize)
# 656 54034 : {
# 657 54034 : if (!file)
# 658 0 : throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
# 659 54034 : if (fread(pch, 1, nSize, file) != nSize)
# 660 2 : throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
# 661 54034 : }
# 662 :
# 663 : void ignore(size_t nSize)
# 664 0 : {
# 665 0 : if (!file)
# 666 0 : throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
# 667 0 : unsigned char data[4096];
# 668 0 : while (nSize > 0) {
# 669 0 : size_t nNow = std::min<size_t>(nSize, sizeof(data));
# 670 0 : if (fread(data, 1, nNow, file) != nNow)
# 671 0 : throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
# 672 0 : nSize -= nNow;
# 673 0 : }
# 674 0 : }
# 675 :
# 676 : void write(const char* pch, size_t nSize)
# 677 138988 : {
# 678 138988 : if (!file)
# 679 0 : throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
# 680 138988 : if (fwrite(pch, 1, nSize, file) != nSize)
# 681 2 : throw std::ios_base::failure("CAutoFile::write: write failed");
# 682 138988 : }
# 683 :
# 684 : template<typename T>
# 685 : CAutoFile& operator<<(const T& obj)
# 686 54946 : {
# 687 54946 : // Serialize to this stream
# 688 54946 : if (!file)
# 689 0 : throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
# 690 54946 : ::Serialize(*this, obj);
# 691 54946 : return (*this);
# 692 54946 : }
# 693 :
# 694 : template<typename T>
# 695 : CAutoFile& operator>>(T&& obj)
# 696 15028 : {
# 697 15028 : // Unserialize from this stream
# 698 15028 : if (!file)
# 699 0 : throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
# 700 15028 : ::Unserialize(*this, obj);
# 701 15028 : return (*this);
# 702 15028 : }
# 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
# 726 612 : bool Fill() {
# 727 612 : unsigned int pos = nSrcPos % vchBuf.size();
# 728 612 : unsigned int readNow = vchBuf.size() - pos;
# 729 612 : unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
# 730 612 : if (nAvail < readNow)
# 731 538 : readNow = nAvail;
# 732 612 : if (readNow == 0)
# 733 0 : return false;
# 734 612 : size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
# 735 612 : if (nBytes == 0) {
# 736 2 : throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
# 737 2 : }
# 738 610 : nSrcPos += nBytes;
# 739 610 : return true;
# 740 610 : }
# 741 :
# 742 : public:
# 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 104 : {
# 746 104 : if (nRewindIn >= nBufSize)
# 747 2 : throw std::ios_base::failure("Rewind limit must be less than buffer size");
# 748 102 : src = fileIn;
# 749 102 : }
# 750 :
# 751 : ~CBufferedFile()
# 752 102 : {
# 753 102 : fclose();
# 754 102 : }
# 755 :
# 756 : // Disallow copies
# 757 : CBufferedFile(const CBufferedFile&) = delete;
# 758 : CBufferedFile& operator=(const CBufferedFile&) = delete;
# 759 :
# 760 2 : int GetVersion() const { return nVersion; }
# 761 2 : int GetType() const { return nType; }
# 762 :
# 763 : void fclose()
# 764 104 : {
# 765 104 : if (src) {
# 766 102 : ::fclose(src);
# 767 102 : src = nullptr;
# 768 102 : }
# 769 104 : }
# 770 :
# 771 : //! check whether we're at the end of the source file
# 772 7348 : bool eof() const {
# 773 7348 : return nReadPos == nSrcPos && feof(src);
# 774 7348 : }
# 775 :
# 776 : //! read a number of bytes
# 777 5972 : void read(char *pch, size_t nSize) {
# 778 5972 : if (nSize + nReadPos > nReadLimit)
# 779 2 : throw std::ios_base::failure("Read attempted past buffer limit");
# 780 12196 : while (nSize > 0) {
# 781 6226 : if (nReadPos == nSrcPos)
# 782 416 : Fill();
# 783 6226 : unsigned int pos = nReadPos % vchBuf.size();
# 784 6226 : size_t nNow = nSize;
# 785 6226 : if (nNow + pos > vchBuf.size())
# 786 74 : nNow = vchBuf.size() - pos;
# 787 6226 : if (nNow + nReadPos > nSrcPos)
# 788 196 : nNow = nSrcPos - nReadPos;
# 789 6226 : memcpy(pch, &vchBuf[pos], nNow);
# 790 6226 : nReadPos += nNow;
# 791 6226 : pch += nNow;
# 792 6226 : nSize -= nNow;
# 793 6226 : }
# 794 5970 : }
# 795 :
# 796 : //! return the current reading position
# 797 10236 : uint64_t GetPos() const {
# 798 10236 : return nReadPos;
# 799 10236 : }
# 800 :
# 801 : //! rewind to a given reading position
# 802 1396 : bool SetPos(uint64_t nPos) {
# 803 1396 : size_t bufsize = vchBuf.size();
# 804 1396 : if (nPos + bufsize < nSrcPos) {
# 805 102 : // rewinding too far, rewind as far as possible
# 806 102 : nReadPos = nSrcPos - bufsize;
# 807 102 : return false;
# 808 102 : }
# 809 1294 : if (nPos > nSrcPos) {
# 810 36 : // can't go this far forward, go as far as possible
# 811 36 : nReadPos = nSrcPos;
# 812 36 : return false;
# 813 36 : }
# 814 1258 : nReadPos = nPos;
# 815 1258 : return true;
# 816 1258 : }
# 817 :
# 818 0 : bool Seek(uint64_t nPos) {
# 819 0 : long nLongPos = nPos;
# 820 0 : if (nPos != (uint64_t)nLongPos)
# 821 0 : return false;
# 822 0 : if (fseek(src, nLongPos, SEEK_SET))
# 823 0 : return false;
# 824 0 : nLongPos = ftell(src);
# 825 0 : nSrcPos = nLongPos;
# 826 0 : nReadPos = nLongPos;
# 827 0 : return true;
# 828 0 : }
# 829 :
# 830 : //! prevent reading beyond a certain position
# 831 : //! no argument removes the limit
# 832 5940 : bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
# 833 5940 : if (nPos < nReadPos)
# 834 0 : return false;
# 835 5940 : nReadLimit = nPos;
# 836 5940 : return true;
# 837 5940 : }
# 838 :
# 839 : template<typename T>
# 840 5972 : CBufferedFile& operator>>(T&& obj) {
# 841 5972 : // Unserialize from this stream
# 842 5972 : ::Unserialize(*this, obj);
# 843 5972 : return (*this);
# 844 5972 : }
# 845 :
# 846 : //! search for a given byte in the stream, and remain positioned on it
# 847 1492 : void FindByte(char ch) {
# 848 6642 : while (true) {
# 849 6642 : if (nReadPos == nSrcPos)
# 850 196 : Fill();
# 851 6642 : if (vchBuf[nReadPos % vchBuf.size()] == ch)
# 852 1492 : break;
# 853 5150 : nReadPos++;
# 854 5150 : }
# 855 1492 : }
# 856 : };
# 857 :
# 858 : #endif // BITCOIN_STREAMS_H
|