Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2014 The Bitcoin developers
3 : // Copyright (c) 2017-2021 The PIVX Core developers
4 : // Distributed under the MIT/X11 software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : #ifndef PIVX_STREAMS_H
8 : #define PIVX_STREAMS_H
9 :
10 : #include "serialize.h"
11 : #include "support/allocators/zeroafterfree.h"
12 :
13 : #include <algorithm>
14 : #include <assert.h>
15 : #include <ios>
16 : #include <limits>
17 : #include <map>
18 : #include <set>
19 : #include <stdint.h>
20 : #include <stdio.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 27718 : OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
36 :
37 : template<typename T>
38 59265 : OverrideStream<Stream>& operator<<(const T& obj)
39 : {
40 : // Serialize to this stream
41 1362593 : ::Serialize(*this, obj);
42 35951 : return (*this);
43 : }
44 :
45 : template<typename T>
46 100827 : OverrideStream<Stream>& operator>>(T&& obj)
47 : {
48 : // Unserialize from this stream
49 100838 : ::Unserialize(*this, obj);
50 : return (*this);
51 : }
52 :
53 12660 : void write(const char* pch, size_t nSize)
54 : {
55 1536360 : stream->write(pch, nSize);
56 35951 : }
57 :
58 115815 : void read(char* pch, size_t nSize)
59 : {
60 115523 : stream->read(pch, nSize);
61 0 : }
62 :
63 84399 : int GetVersion() const { return nVersion; }
64 42872 : int GetType() const { return nType; }
65 : size_t size() const { return stream->size(); }
66 1 : void ignore(size_t size) { return stream->ignore(size); }
67 : };
68 :
69 : /** Double ended buffer combining vector and stream-like interfaces.
70 : *
71 : * >> and << read and write unformatted data using the above serialization templates.
72 : * Fills with data in linear time; some stringstream implementations take N^2 time.
73 : */
74 : template<typename SerializeType>
75 40927045 : class CBaseDataStream
76 : {
77 : protected:
78 : typedef SerializeType vector_type;
79 : vector_type vch;
80 : unsigned int nReadPos;
81 : int nType;
82 : int nVersion;
83 :
84 : public:
85 : typedef typename vector_type::allocator_type allocator_type;
86 : typedef typename vector_type::size_type size_type;
87 : typedef typename vector_type::difference_type difference_type;
88 : typedef typename vector_type::reference reference;
89 : typedef typename vector_type::const_reference const_reference;
90 : typedef typename vector_type::value_type value_type;
91 : typedef typename vector_type::iterator iterator;
92 : typedef typename vector_type::const_iterator const_iterator;
93 : typedef typename vector_type::reverse_iterator reverse_iterator;
94 :
95 6592541 : explicit CBaseDataStream(int nTypeIn, int nVersionIn)
96 6592541 : {
97 6592541 : Init(nTypeIn, nVersionIn);
98 : }
99 :
100 : CBaseDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
101 : {
102 : Init(nTypeIn, nVersionIn);
103 : }
104 :
105 27129430 : CBaseDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
106 : {
107 13564767 : Init(nTypeIn, nVersionIn);
108 : }
109 :
110 15931 : CBaseDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
111 : {
112 15931 : Init(nTypeIn, nVersionIn);
113 15931 : }
114 :
115 : CBaseDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
116 : {
117 : Init(nTypeIn, nVersionIn);
118 : }
119 :
120 238663 : CBaseDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
121 : {
122 238663 : Init(nTypeIn, nVersionIn);
123 238663 : }
124 :
125 : template <typename... Args>
126 1 : CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args)
127 1 : {
128 1 : Init(nTypeIn, nVersionIn);
129 1 : ::SerializeMany(*this, std::forward<Args>(args)...);
130 1 : }
131 :
132 20411891 : void Init(int nTypeIn, int nVersionIn)
133 : {
134 20411891 : nReadPos = 0;
135 20411882 : nType = nTypeIn;
136 4724105 : nVersion = nVersionIn;
137 : }
138 :
139 : CBaseDataStream& operator+=(const CBaseDataStream& b)
140 : {
141 : vch.insert(vch.end(), b.begin(), b.end());
142 : return *this;
143 : }
144 :
145 : friend CBaseDataStream operator+(const CBaseDataStream& a, const CBaseDataStream& b)
146 : {
147 : CBaseDataStream ret = a;
148 : ret += b;
149 : return (ret);
150 : }
151 :
152 19 : std::string str() const
153 : {
154 38 : return (std::string(begin(), end()));
155 : }
156 :
157 :
158 : //
159 : // Vector subset
160 : //
161 19 : const_iterator begin() const { return vch.begin() + nReadPos; }
162 751450 : iterator begin() { return vch.begin() + nReadPos; }
163 19 : const_iterator end() const { return vch.end(); }
164 750603 : iterator end() { return vch.end(); }
165 20820920 : size_type size() const { return vch.size() - nReadPos; }
166 227998 : bool empty() const { return vch.size() == nReadPos; }
167 754091 : void resize(size_type n, value_type c = 0) { vch.resize(n + nReadPos, c); }
168 5370670 : void reserve(size_type n) { vch.reserve(n + nReadPos); }
169 : const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
170 13242264 : reference operator[](size_type pos) { return vch[pos + nReadPos]; }
171 2519343 : void clear()
172 : {
173 2519342 : vch.clear();
174 2519342 : nReadPos = 0;
175 : }
176 3 : iterator insert(iterator it, const char x = char()) { return vch.insert(it, x); }
177 : void insert(iterator it, size_type n, const char x) { vch.insert(it, n, x); }
178 2241212 : value_type* data() { return vch.data() + nReadPos; }
179 3840674 : const value_type* data() const { return vch.data() + nReadPos; }
180 :
181 : void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
182 : {
183 : if (last == first) return;
184 : assert(last - first > 0);
185 : if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) {
186 : // special case for inserting at the front when there's room
187 : nReadPos -= (last - first);
188 : memcpy(&vch[nReadPos], &first[0], last - first);
189 : } else
190 : vch.insert(it, first, last);
191 : }
192 :
193 : void insert(iterator it, const char* first, const char* last)
194 : {
195 : if (last == first) return;
196 : assert(last - first > 0);
197 : if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) {
198 : // special case for inserting at the front when there's room
199 : nReadPos -= (last - first);
200 : memcpy(&vch[nReadPos], &first[0], last - first);
201 : } else
202 : vch.insert(it, first, last);
203 : }
204 :
205 3 : iterator erase(iterator it)
206 : {
207 3 : if (it == vch.begin() + nReadPos) {
208 : // special case for erasing from the front
209 1 : if (++nReadPos >= vch.size()) {
210 : // whenever we reach the end, we take the opportunity to clear the buffer
211 0 : nReadPos = 0;
212 0 : return vch.erase(vch.begin(), vch.end());
213 : }
214 1 : return vch.begin() + nReadPos;
215 : } else
216 2 : return vch.erase(it);
217 : }
218 :
219 : iterator erase(iterator first, iterator last)
220 : {
221 : if (first == vch.begin() + nReadPos) {
222 : // special case for erasing from the front
223 : if (last == vch.end()) {
224 : nReadPos = 0;
225 : return vch.erase(vch.begin(), vch.end());
226 : } else {
227 : nReadPos = (last - vch.begin());
228 : return last;
229 : }
230 : } else
231 : return vch.erase(first, last);
232 : }
233 :
234 : inline void Compact()
235 : {
236 : vch.erase(vch.begin(), vch.begin() + nReadPos);
237 : nReadPos = 0;
238 : }
239 :
240 0 : bool Rewind(size_type n)
241 : {
242 : // Rewind by n characters if the buffer hasn't been compacted yet
243 0 : if (n > nReadPos)
244 : return false;
245 0 : nReadPos -= n;
246 : return true;
247 : }
248 :
249 :
250 : //
251 : // Stream subset
252 : //
253 121 : bool eof() const { return size() == 0; }
254 : CBaseDataStream* rdbuf() { return this; }
255 1550 : int in_avail() { return size(); }
256 :
257 64768 : void SetType(int n) { nType = n; }
258 108179 : int GetType() const { return nType; }
259 378832 : void SetVersion(int n) { nVersion = n; }
260 106472 : int GetVersion() const { return nVersion; }
261 :
262 100218861 : void read(char* pch, size_t nSize)
263 : {
264 100218861 : if (nSize == 0) return;
265 :
266 : // Read from the beginning of the buffer
267 100218308 : unsigned int nReadPosNext = nReadPos + nSize;
268 100218308 : if (nReadPosNext > vch.size()) {
269 1509 : throw std::ios_base::failure("CDataStream::read(): end of data");
270 : }
271 100216799 : memcpy(pch, &vch[nReadPos], nSize);
272 100216799 : if (nReadPosNext == vch.size()) {
273 14607475 : nReadPos = 0;
274 14607475 : vch.clear();
275 14607475 : return;
276 : }
277 85609329 : nReadPos = nReadPosNext;
278 : }
279 :
280 0 : CBaseDataStream& movePos(size_t nSize){
281 0 : nReadPos = nReadPos + nSize;
282 : return (*this);
283 : }
284 :
285 5 : void ignore(int nSize)
286 : {
287 : // Ignore from the beginning of the buffer
288 5 : if (nSize < 0) {
289 1 : throw std::ios_base::failure("CBaseDataStream::ignore(): nSize negative");
290 : }
291 4 : unsigned int nReadPosNext = nReadPos + nSize;
292 4 : if (nReadPosNext >= vch.size()) {
293 2 : if (nReadPosNext > vch.size())
294 0 : throw std::ios_base::failure("CBaseDataStream::ignore() : end of data");
295 2 : nReadPos = 0;
296 2 : vch.clear();
297 2 : return;
298 : }
299 2 : nReadPos = nReadPosNext;
300 : }
301 :
302 4693248 : void write(const char* pch, size_t nSize)
303 : {
304 : // Write to the end of the buffer
305 54265917 : vch.insert(vch.end(), pch, pch + nSize);
306 5438677 : }
307 :
308 : template <typename Stream>
309 34321 : void Serialize(Stream& s) const
310 : {
311 : // Special case: stream << stream concatenates like stream += stream
312 34321 : if (!vch.empty())
313 34321 : s.write((char*)vch.data(), vch.size() * sizeof(value_type));
314 19490 : }
315 :
316 : template <typename T>
317 7915226 : CBaseDataStream& operator<<(const T& obj)
318 : {
319 : // Serialize to this stream
320 8714850 : ::Serialize(*this, obj);
321 12792 : return (*this);
322 : }
323 :
324 : template <typename T>
325 36210037 : CBaseDataStream& operator>>(T&& obj)
326 : {
327 : // Unserialize from this stream
328 37242999 : ::Unserialize(*this, obj);
329 27775 : return (*this);
330 : }
331 :
332 1 : void GetAndClear(CSerializeData& data)
333 : {
334 1 : data.insert(data.end(), begin(), end());
335 1 : clear();
336 1 : }
337 : };
338 :
339 : /* Minimal stream for overwriting and/or appending to an existing byte vector
340 : *
341 : * The referenced vector will grow as necessary
342 : */
343 : class CVectorWriter
344 : {
345 : public:
346 :
347 : /*
348 : * @param[in] nTypeIn Serialization Type
349 : * @param[in] nVersionIn Serialization Version (including any flags)
350 : * @param[in] vchDataIn Referenced byte vector to overwrite/append
351 : * @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
352 : * grow as necessary to max(index, vec.size()). So to append, use vec.size().
353 : */
354 659182 : CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
355 : {
356 362627 : if(nPos > vchData.size())
357 1 : vchData.resize(nPos);
358 : }
359 : /*
360 : * (other params same as above)
361 : * @param[in] args A list of items to serialize starting at nPos.
362 : */
363 : template <typename... Args>
364 654291 : CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
365 : {
366 654290 : ::SerializeMany(*this, std::forward<Args>(args)...);
367 654290 : }
368 5561975 : void write(const char* pch, size_t nSize)
369 : {
370 5561975 : assert(nPos <= vchData.size());
371 5561975 : size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
372 5561975 : if (nOverwrite) {
373 19 : memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
374 : }
375 5561975 : if (nOverwrite < nSize) {
376 5561957 : vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
377 : }
378 5561975 : nPos += nSize;
379 5561975 : }
380 : template<typename T>
381 107291 : CVectorWriter& operator<<(const T& obj)
382 : {
383 : // Serialize to this stream
384 112290 : ::Serialize(*this, obj);
385 5120 : return (*this);
386 : }
387 4089 : int GetVersion() const
388 : {
389 4089 : return nVersion;
390 : }
391 12591 : int GetType() const
392 : {
393 6923 : return nType;
394 : }
395 : void seek(size_t nSize)
396 : {
397 : nPos += nSize;
398 : if(nPos > vchData.size())
399 : vchData.resize(nPos);
400 : }
401 : private:
402 : const int nType;
403 : const int nVersion;
404 : std::vector<unsigned char>& vchData;
405 : size_t nPos;
406 : };
407 :
408 19611819 : class CDataStream : public CBaseDataStream<CSerializeData>
409 : {
410 : public:
411 6213281 : explicit CDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
412 :
413 : CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
414 : CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
415 :
416 : #if !defined(_MSC_VER) || _MSC_VER >= 1300
417 13564767 : CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) :
418 13564767 : CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
419 : #endif
420 :
421 15820 : CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
422 15820 : CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
423 :
424 : CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) :
425 : CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
426 :
427 238663 : CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) :
428 238663 : CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
429 :
430 : template <typename... Args>
431 1 : CDataStream(int nTypeIn, int nVersionIn, Args&&... args) :
432 1 : CBaseDataStream(nTypeIn, nVersionIn, args...) { }
433 :
434 : };
435 :
436 :
437 :
438 :
439 :
440 :
441 :
442 :
443 :
444 :
445 : /** Non-refcounted RAII wrapper for FILE*
446 : *
447 : * Will automatically close the file when it goes out of scope if not null.
448 : * If you're returning the file pointer, return file.release().
449 : * If you need to close the file early, use file.fclose() instead of fclose(file).
450 : */
451 : class CAutoFile
452 : {
453 : private:
454 : const int nType;
455 : const int nVersion;
456 :
457 : FILE* file;
458 :
459 : public:
460 378670 : CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
461 : {
462 378511 : file = filenew;
463 : }
464 :
465 378670 : ~CAutoFile()
466 3542 : {
467 378670 : fclose();
468 0 : }
469 :
470 : // Disallow copies
471 : CAutoFile(const CAutoFile&) = delete;
472 : CAutoFile& operator=(const CAutoFile&) = delete;
473 :
474 382242 : void fclose()
475 : {
476 382083 : if (file) {
477 4023 : ::fclose(file);
478 376217 : file = nullptr;
479 : }
480 : }
481 :
482 : /** Get wrapped FILE* with transfer of ownership.
483 : * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
484 : * of this function to clean up the returned FILE*.
485 : */
486 : FILE* release()
487 : {
488 : FILE* ret = file;
489 : file = nullptr;
490 : return ret;
491 : }
492 :
493 : /** Get wrapped FILE* without transfer of ownership.
494 : * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
495 : * CAutoFile outlives use of the passed pointer.
496 : */
497 287537 : FILE* Get() const { return file; }
498 :
499 : /** Return true if the wrapped FILE* is nullptr, false otherwise.
500 : */
501 378317 : bool IsNull() const { return (file == nullptr); }
502 :
503 : //
504 : // Stream subset
505 : //
506 3212 : int GetType() const { return nType; }
507 85602 : int GetVersion() const { return nVersion; }
508 :
509 22972838 : void read(char* pch, size_t nSize)
510 : {
511 22972838 : if (!file)
512 0 : throw std::ios_base::failure("CAutoFile::read : file handle is nullptr");
513 45945816 : if (fread(pch, 1, nSize, file) != nSize)
514 2 : throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
515 22972837 : }
516 :
517 : void ignore(size_t nSize)
518 : {
519 : if (!file)
520 : throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
521 : unsigned char data[4096];
522 : while (nSize > 0) {
523 : size_t nNow = std::min<size_t>(nSize, sizeof(data));
524 : if (fread(data, 1, nNow, file) != nNow)
525 : throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
526 : nSize -= nNow;
527 : }
528 : }
529 :
530 :
531 15276407 : void write(const char* pch, size_t nSize)
532 : {
533 15276407 : if (!file)
534 0 : throw std::ios_base::failure("CAutoFile::write : file handle is nullptr");
535 15276407 : if (fwrite(pch, 1, nSize, file) != nSize)
536 1 : throw std::ios_base::failure("CAutoFile::write : write failed");
537 15276406 : }
538 :
539 : template <typename T>
540 2806920 : CAutoFile& operator<<(const T& obj)
541 : {
542 : // Serialize to this stream
543 2806920 : if (!file)
544 0 : throw std::ios_base::failure("CAutoFile::operator<< : file handle is nullptr");
545 2806919 : ::Serialize(*this, obj);
546 2806918 : return (*this);
547 : }
548 :
549 : template<typename T>
550 4164542 : CAutoFile& operator>>(T&& obj)
551 : {
552 : // Unserialize from this stream
553 4164542 : if (!file)
554 0 : throw std::ios_base::failure("CAutoFile::operator>> : file handle is nullptr");
555 4164541 : ::Unserialize(*this, obj);
556 4164541 : return (*this);
557 : }
558 : };
559 :
560 : /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
561 : * deserialize from. It guarantees the ability to rewind a given number of bytes.
562 : *
563 : * Will automatically close the file when it goes out of scope if not null.
564 : * If you need to close the file early, use file.fclose() instead of fclose(file).
565 : */
566 : class CBufferedFile
567 : {
568 : private:
569 : const int nType;
570 : const int nVersion;
571 :
572 : FILE* src; // source file
573 : uint64_t nSrcPos; // how many bytes have been read from source
574 : uint64_t nReadPos; // how many bytes have been read from this
575 : uint64_t nReadLimit; // up to which position we're allowed to read
576 : uint64_t nRewind; // how many bytes we guarantee to rewind
577 : std::vector<char> vchBuf; // the buffer
578 :
579 : protected:
580 : // read data from the source to fill the buffer
581 376 : bool Fill()
582 : {
583 376 : unsigned int pos = nSrcPos % vchBuf.size();
584 376 : unsigned int readNow = vchBuf.size() - pos;
585 376 : unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
586 376 : if (nAvail < readNow)
587 319 : readNow = nAvail;
588 376 : if (readNow == 0)
589 : return false;
590 376 : size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
591 376 : if (nBytes == 0) {
592 6 : throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
593 : }
594 370 : nSrcPos += nBytes;
595 370 : return true;
596 : }
597 :
598 : public:
599 57 : CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
600 58 : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
601 : {
602 57 : if (nRewindIn >= nBufSize)
603 1 : throw std::ios_base::failure("Rewind limit must be less than buffer size");
604 56 : src = fileIn;
605 56 : }
606 :
607 56 : ~CBufferedFile()
608 112 : {
609 56 : fclose();
610 56 : }
611 :
612 : int GetVersion() const { return nVersion; }
613 : int GetType() const { return nType; }
614 :
615 : // Disallow copies
616 : CBufferedFile(const CBufferedFile&) = delete;
617 : CBufferedFile& operator=(const CBufferedFile&) = delete;
618 :
619 57 : void fclose()
620 : {
621 57 : if (src) {
622 56 : ::fclose(src);
623 56 : src = nullptr;
624 : }
625 : }
626 :
627 : // check whether we're at the end of the source file
628 4023 : bool eof() const
629 : {
630 4023 : return nReadPos == nSrcPos && feof(src);
631 : }
632 :
633 : // read a number of bytes
634 10824 : void read(char* pch, size_t nSize)
635 : {
636 10824 : if (nSize + nReadPos > nReadLimit)
637 1 : throw std::ios_base::failure("Read attempted past buffer limit");
638 21773 : while (nSize > 0) {
639 10951 : if (nReadPos == nSrcPos)
640 208 : Fill();
641 10950 : unsigned int pos = nReadPos % vchBuf.size();
642 10950 : size_t nNow = nSize;
643 10950 : if (nNow + pos > vchBuf.size())
644 37 : nNow = vchBuf.size() - pos;
645 10950 : if (nNow + nReadPos > nSrcPos)
646 98 : nNow = nSrcPos - nReadPos;
647 10950 : memcpy(pch, &vchBuf[pos], nNow);
648 10950 : nReadPos += nNow;
649 10950 : pch += nNow;
650 10950 : nSize -= nNow;
651 : }
652 10822 : }
653 :
654 : // return the current reading position
655 6155 : uint64_t GetPos()
656 : {
657 6155 : return nReadPos;
658 : }
659 :
660 : //! rewind to a given reading position
661 1391 : bool SetPos(uint64_t nPos) {
662 1391 : size_t bufsize = vchBuf.size();
663 1391 : if (nPos + bufsize < nSrcPos) {
664 : // rewinding too far, rewind as far as possible
665 51 : nReadPos = nSrcPos - bufsize;
666 51 : return false;
667 : }
668 1338 : if (nPos > nSrcPos) {
669 : // can't go this far forward, go as far as possible
670 18 : nReadPos = nSrcPos;
671 18 : return false;
672 : }
673 1322 : nReadPos = nPos;
674 1322 : return true;
675 : }
676 :
677 : //! prevent reading beyond a certain position
678 : //! no argument removes the limit
679 3663 : bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
680 3313 : if (nPos < nReadPos)
681 : return false;
682 3663 : nReadLimit = nPos;
683 3663 : return true;
684 : }
685 :
686 : template<typename T>
687 4742 : CBufferedFile& operator>>(T&& obj) {
688 : // Unserialize from this stream
689 10691 : ::Unserialize(*this, obj);
690 0 : return (*this);
691 : }
692 :
693 : // search for a given byte in the stream, and remain positioned on it
694 1095 : void FindByte(char ch)
695 : {
696 167646896 : while (true) {
697 83824021 : if (nReadPos == nSrcPos)
698 168 : Fill();
699 83824021 : if (vchBuf[nReadPos % vchBuf.size()] == ch)
700 : break;
701 83822975 : nReadPos++;
702 : }
703 1090 : }
704 : };
705 :
706 : #endif // PIVX_STREAMS_H
|