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