]> Git Repo - VerusCoin.git/blame - src/streams.h
Merge branch 'dev' of https://github.com/miketout/komodo into dev
[VerusCoin.git] / src / streams.h
CommitLineData
fa736190 1// Copyright (c) 2009-2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2013 The Bitcoin Core developers
78253fcb 3// Distributed under the MIT software license, see the accompanying
bc909a7a 4// file COPYING or https://www.opensource.org/licenses/mit-license.php .
fa736190
CF
5
6#ifndef BITCOIN_STREAMS_H
7#define BITCOIN_STREAMS_H
8
d7d187e8 9#include "support/allocators/zeroafterfree.h"
fa736190
CF
10#include "serialize.h"
11
12#include <algorithm>
13#include <assert.h>
14#include <ios>
15#include <limits>
16#include <map>
17#include <set>
18#include <stdint.h>
1630219d 19#include <stdio.h>
fa736190
CF
20#include <string>
21#include <string.h>
22#include <utility>
23#include <vector>
24
b7e75b17
JG
25template<typename Stream>
26class OverrideStream
27{
28 Stream* stream;
29
30 const int nType;
31 const int nVersion;
32
33public:
34 OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
35
36 template<typename T>
37 OverrideStream<Stream>& operator<<(const T& obj)
38 {
39 // Serialize to this stream
40 ::Serialize(*this, obj);
41 return (*this);
42 }
43
44 template<typename T>
45 OverrideStream<Stream>& operator>>(T&& obj)
46 {
47 // Unserialize from this stream
48 ::Unserialize(*this, obj);
49 return (*this);
50 }
51
52 void write(const char* pch, size_t nSize)
53 {
54 stream->write(pch, nSize);
55 }
56
57 void read(char* pch, size_t nSize)
58 {
59 stream->read(pch, nSize);
60 }
61
62 int GetVersion() const { return nVersion; }
63 int GetType() const { return nType; }
64};
65
66template<typename S>
67OverrideStream<S> WithVersion(S* s, int nVersion)
68{
69 return OverrideStream<S>(s, s->GetType(), nVersion);
70}
71
fa736190
CF
72/** Double ended buffer combining vector and stream-like interfaces.
73 *
74 * >> and << read and write unformatted data using the above serialization templates.
75 * Fills with data in linear time; some stringstream implementations take N^2 time.
76 */
6bffc46a
JG
77template<typename SerializeType>
78class CBaseDataStream
fa736190
CF
79{
80protected:
6bffc46a 81 typedef SerializeType vector_type;
fa736190
CF
82 vector_type vch;
83 unsigned int nReadPos;
7f4acac4 84
fa736190
CF
85 int nType;
86 int nVersion;
7f4acac4 87public:
fa736190 88
6bffc46a
JG
89 typedef typename vector_type::allocator_type allocator_type;
90 typedef typename vector_type::size_type size_type;
91 typedef typename vector_type::difference_type difference_type;
92 typedef typename vector_type::reference reference;
93 typedef typename vector_type::const_reference const_reference;
94 typedef typename vector_type::value_type value_type;
95 typedef typename vector_type::iterator iterator;
96 typedef typename vector_type::const_iterator const_iterator;
97 typedef typename vector_type::reverse_iterator reverse_iterator;
98
99 explicit CBaseDataStream(int nTypeIn, int nVersionIn)
fa736190
CF
100 {
101 Init(nTypeIn, nVersionIn);
102 }
103
6bffc46a 104 CBaseDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
fa736190
CF
105 {
106 Init(nTypeIn, nVersionIn);
107 }
108
109#if !defined(_MSC_VER) || _MSC_VER >= 1300
6bffc46a 110 CBaseDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
fa736190
CF
111 {
112 Init(nTypeIn, nVersionIn);
113 }
114#endif
115
6bffc46a 116 CBaseDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
fa736190
CF
117 {
118 Init(nTypeIn, nVersionIn);
119 }
120
6bffc46a 121 CBaseDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
fa736190
CF
122 {
123 Init(nTypeIn, nVersionIn);
124 }
125
6bffc46a 126 CBaseDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
fa736190
CF
127 {
128 Init(nTypeIn, nVersionIn);
129 }
130
d1c9ef86
CF
131 template <typename... Args>
132 CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args)
133 {
134 Init(nTypeIn, nVersionIn);
242f1421 135 ::SerializeMany(*this, std::forward<Args>(args)...);
d1c9ef86
CF
136 }
137
fa736190
CF
138 void Init(int nTypeIn, int nVersionIn)
139 {
140 nReadPos = 0;
141 nType = nTypeIn;
142 nVersion = nVersionIn;
143 }
144
6bffc46a 145 CBaseDataStream& operator+=(const CBaseDataStream& b)
fa736190
CF
146 {
147 vch.insert(vch.end(), b.begin(), b.end());
148 return *this;
149 }
150
6bffc46a 151 friend CBaseDataStream operator+(const CBaseDataStream& a, const CBaseDataStream& b)
fa736190 152 {
6bffc46a 153 CBaseDataStream ret = a;
fa736190
CF
154 ret += b;
155 return (ret);
156 }
157
158 std::string str() const
159 {
160 return (std::string(begin(), end()));
161 }
162
163
164 //
165 // Vector subset
166 //
167 const_iterator begin() const { return vch.begin() + nReadPos; }
168 iterator begin() { return vch.begin() + nReadPos; }
169 const_iterator end() const { return vch.end(); }
170 iterator end() { return vch.end(); }
171 size_type size() const { return vch.size() - nReadPos; }
172 bool empty() const { return vch.size() == nReadPos; }
173 void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
174 void reserve(size_type n) { vch.reserve(n + nReadPos); }
175 const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
176 reference operator[](size_type pos) { return vch[pos + nReadPos]; }
177 void clear() { vch.clear(); nReadPos = 0; }
178 iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
179 void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
180
181 void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
182 {
1878f3a7
PW
183 if (last == first) return;
184 assert(last - first > 0);
fa736190
CF
185 if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
186 {
187 // special case for inserting at the front when there's room
188 nReadPos -= (last - first);
189 memcpy(&vch[nReadPos], &first[0], last - first);
190 }
191 else
192 vch.insert(it, first, last);
193 }
194
195#if !defined(_MSC_VER) || _MSC_VER >= 1300
196 void insert(iterator it, const char* first, const char* last)
197 {
1878f3a7
PW
198 if (last == first) return;
199 assert(last - first > 0);
fa736190
CF
200 if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
201 {
202 // special case for inserting at the front when there's room
203 nReadPos -= (last - first);
204 memcpy(&vch[nReadPos], &first[0], last - first);
205 }
206 else
207 vch.insert(it, first, last);
208 }
209#endif
210
211 iterator erase(iterator it)
212 {
213 if (it == vch.begin() + nReadPos)
214 {
215 // special case for erasing from the front
216 if (++nReadPos >= vch.size())
217 {
218 // whenever we reach the end, we take the opportunity to clear the buffer
219 nReadPos = 0;
220 return vch.erase(vch.begin(), vch.end());
221 }
222 return vch.begin() + nReadPos;
223 }
224 else
225 return vch.erase(it);
226 }
227
228 iterator erase(iterator first, iterator last)
229 {
230 if (first == vch.begin() + nReadPos)
231 {
232 // special case for erasing from the front
233 if (last == vch.end())
234 {
235 nReadPos = 0;
236 return vch.erase(vch.begin(), vch.end());
237 }
238 else
239 {
240 nReadPos = (last - vch.begin());
241 return last;
242 }
243 }
244 else
245 return vch.erase(first, last);
246 }
247
248 inline void Compact()
249 {
250 vch.erase(vch.begin(), vch.begin() + nReadPos);
251 nReadPos = 0;
252 }
253
254 bool Rewind(size_type n)
255 {
256 // Rewind by n characters if the buffer hasn't been compacted yet
257 if (n > nReadPos)
258 return false;
259 nReadPos -= n;
260 return true;
261 }
262
263
264 //
265 // Stream subset
266 //
267 bool eof() const { return size() == 0; }
6bffc46a 268 CBaseDataStream* rdbuf() { return this; }
fa736190
CF
269 int in_avail() { return size(); }
270
271 void SetType(int n) { nType = n; }
7f4acac4 272 int GetType() const { return nType; }
fa736190 273 void SetVersion(int n) { nVersion = n; }
7f4acac4 274 int GetVersion() const { return nVersion; }
fa736190 275
1315591c 276 void read(char* pch, size_t nSize)
fa736190 277 {
1878f3a7
PW
278 if (nSize == 0) return;
279
54a872f0
S
280 if (pch == nullptr) {
281 throw std::ios_base::failure("CBaseDataStream::read(): cannot read from null pointer");
282 }
283
fa736190
CF
284 // Read from the beginning of the buffer
285 unsigned int nReadPosNext = nReadPos + nSize;
286 if (nReadPosNext >= vch.size())
287 {
288 if (nReadPosNext > vch.size())
289 {
6bffc46a 290 throw std::ios_base::failure("CBaseDataStream::read(): end of data");
fa736190
CF
291 }
292 memcpy(pch, &vch[nReadPos], nSize);
293 nReadPos = 0;
294 vch.clear();
1315591c 295 return;
fa736190
CF
296 }
297 memcpy(pch, &vch[nReadPos], nSize);
298 nReadPos = nReadPosNext;
fa736190
CF
299 }
300
1315591c 301 void ignore(int nSize)
fa736190
CF
302 {
303 // Ignore from the beginning of the buffer
e9d221e7
PS
304 if (nSize < 0) {
305 throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
306 }
fa736190
CF
307 unsigned int nReadPosNext = nReadPos + nSize;
308 if (nReadPosNext >= vch.size())
309 {
310 if (nReadPosNext > vch.size())
6bffc46a 311 throw std::ios_base::failure("CBaseDataStream::ignore(): end of data");
fa736190
CF
312 nReadPos = 0;
313 vch.clear();
1315591c 314 return;
fa736190
CF
315 }
316 nReadPos = nReadPosNext;
fa736190
CF
317 }
318
1315591c 319 void write(const char* pch, size_t nSize)
fa736190
CF
320 {
321 // Write to the end of the buffer
322 vch.insert(vch.end(), pch, pch + nSize);
fa736190
CF
323 }
324
325 template<typename Stream>
242f1421 326 void Serialize(Stream& s) const
fa736190
CF
327 {
328 // Special case: stream << stream concatenates like stream += stream
329 if (!vch.empty())
330 s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
331 }
332
fa736190 333 template<typename T>
6bffc46a 334 CBaseDataStream& operator<<(const T& obj)
fa736190
CF
335 {
336 // Serialize to this stream
242f1421 337 ::Serialize(*this, obj);
fa736190
CF
338 return (*this);
339 }
340
341 template<typename T>
6bffc46a 342 CBaseDataStream& operator>>(T& obj)
fa736190
CF
343 {
344 // Unserialize from this stream
242f1421 345 ::Unserialize(*this, obj);
fa736190
CF
346 return (*this);
347 }
348
f0e90192
PJ
349 void GetAndClear(CSerializeData &d) {
350 d.insert(d.end(), begin(), end());
fa736190
CF
351 clear();
352 }
353};
354
6bffc46a
JG
355class CDataStream : public CBaseDataStream<CSerializeData>
356{
357public:
358 explicit CDataStream(int nTypeIn, int nVersionIn) : CBaseDataStream(nTypeIn, nVersionIn) { }
359
360 CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) :
361 CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
362
363#if !defined(_MSC_VER) || _MSC_VER >= 1300
364 CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) :
365 CBaseDataStream(pbegin, pend, nTypeIn, nVersionIn) { }
366#endif
367
368 CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) :
369 CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
370
371 CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) :
372 CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
373
374 CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) :
375 CBaseDataStream(vchIn, nTypeIn, nVersionIn) { }
376
d1c9ef86
CF
377 template <typename... Args>
378 CDataStream(int nTypeIn, int nVersionIn, Args&&... args) :
379 CBaseDataStream(nTypeIn, nVersionIn, args...) { }
380
6bffc46a
JG
381};
382
fa736190
CF
383
384
385
386
387
388
389
390
391
392/** Non-refcounted RAII wrapper for FILE*
393 *
394 * Will automatically close the file when it goes out of scope if not null.
395 * If you're returning the file pointer, return file.release().
396 * If you need to close the file early, use file.fclose() instead of fclose(file).
397 */
398class CAutoFile
399{
400private:
401 // Disallow copies
402 CAutoFile(const CAutoFile&);
403 CAutoFile& operator=(const CAutoFile&);
404
7f4acac4
PW
405 const int nType;
406 const int nVersion;
407
fa736190
CF
408 FILE* file;
409
410public:
7f4acac4 411 CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
fa736190
CF
412 {
413 file = filenew;
fa736190
CF
414 }
415
416 ~CAutoFile()
417 {
418 fclose();
419 }
420
421 void fclose()
422 {
423 if (file) {
424 ::fclose(file);
425 file = NULL;
426 }
427 }
428
429 /** Get wrapped FILE* with transfer of ownership.
430 * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
431 * of this function to clean up the returned FILE*.
432 */
433 FILE* release() { FILE* ret = file; file = NULL; return ret; }
434
435 /** Get wrapped FILE* without transfer of ownership.
436 * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
437 * CAutoFile outlives use of the passed pointer.
438 */
439 FILE* Get() const { return file; }
440
441 /** Return true if the wrapped FILE* is NULL, false otherwise.
442 */
443 bool IsNull() const { return (file == NULL); }
444
445 //
446 // Stream subset
447 //
7f4acac4
PW
448 int GetType() const { return nType; }
449 int GetVersion() const { return nVersion; }
fa736190 450
1315591c 451 void read(char* pch, size_t nSize)
fa736190
CF
452 {
453 if (!file)
5262fde0 454 throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
fa736190 455 if (fread(pch, 1, nSize, file) != nSize)
5262fde0 456 throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
fa736190
CF
457 }
458
1315591c 459 void ignore(size_t nSize)
f588c5ed
PW
460 {
461 if (!file)
462 throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL");
463 unsigned char data[4096];
464 while (nSize > 0) {
465 size_t nNow = std::min<size_t>(nSize, sizeof(data));
466 if (fread(data, 1, nNow, file) != nNow)
467 throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
468 nSize -= nNow;
469 }
f588c5ed
PW
470 }
471
1315591c 472 void write(const char* pch, size_t nSize)
fa736190
CF
473 {
474 if (!file)
5262fde0 475 throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
fa736190 476 if (fwrite(pch, 1, nSize, file) != nSize)
5262fde0 477 throw std::ios_base::failure("CAutoFile::write: write failed");
fa736190 478 }
fa736190
CF
479
480 template<typename T>
481 CAutoFile& operator<<(const T& obj)
482 {
483 // Serialize to this stream
484 if (!file)
5262fde0 485 throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
242f1421 486 ::Serialize(*this, obj);
fa736190
CF
487 return (*this);
488 }
489
490 template<typename T>
491 CAutoFile& operator>>(T& obj)
492 {
493 // Unserialize from this stream
494 if (!file)
5262fde0 495 throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
242f1421 496 ::Unserialize(*this, obj);
fa736190
CF
497 return (*this);
498 }
499};
500
501/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
502 * deserialize from. It guarantees the ability to rewind a given number of bytes.
503 *
504 * Will automatically close the file when it goes out of scope if not null.
505 * If you need to close the file early, use file.fclose() instead of fclose(file).
506 */
507class CBufferedFile
508{
509private:
510 // Disallow copies
511 CBufferedFile(const CBufferedFile&);
512 CBufferedFile& operator=(const CBufferedFile&);
513
7f4acac4
PW
514 const int nType;
515 const int nVersion;
fa736190
CF
516
517 FILE *src; // source file
518 uint64_t nSrcPos; // how many bytes have been read from source
519 uint64_t nReadPos; // how many bytes have been read from this
520 uint64_t nReadLimit; // up to which position we're allowed to read
521 uint64_t nRewind; // how many bytes we guarantee to rewind
522 std::vector<char> vchBuf; // the buffer
523
524protected:
525 // read data from the source to fill the buffer
526 bool Fill() {
527 unsigned int pos = nSrcPos % vchBuf.size();
528 unsigned int readNow = vchBuf.size() - pos;
529 unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
530 if (nAvail < readNow)
531 readNow = nAvail;
532 if (readNow == 0)
533 return false;
534 size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
535 if (read == 0) {
5262fde0 536 throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
fa736190
CF
537 } else {
538 nSrcPos += read;
539 return true;
540 }
541 }
542
543public:
544 CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
7f4acac4 545 nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
fa736190
CF
546 {
547 src = fileIn;
fa736190
CF
548 }
549
550 ~CBufferedFile()
551 {
552 fclose();
553 }
554
242f1421
PW
555 int GetVersion() const { return nVersion; }
556 int GetType() const { return nType; }
557
fa736190
CF
558 void fclose()
559 {
560 if (src) {
561 ::fclose(src);
562 src = NULL;
563 }
564 }
565
566 // check whether we're at the end of the source file
567 bool eof() const {
568 return nReadPos == nSrcPos && feof(src);
569 }
570
571 // read a number of bytes
1315591c 572 void read(char *pch, size_t nSize) {
54a872f0
S
573 if (nSize == 0) return;
574
575 if (pch == nullptr) {
576 throw std::ios_base::failure("CBufferedFile::read(): cannot read from null pointer");
577 }
578
fa736190
CF
579 if (nSize + nReadPos > nReadLimit)
580 throw std::ios_base::failure("Read attempted past buffer limit");
581 if (nSize + nRewind > vchBuf.size())
582 throw std::ios_base::failure("Read larger than buffer size");
583 while (nSize > 0) {
584 if (nReadPos == nSrcPos)
585 Fill();
586 unsigned int pos = nReadPos % vchBuf.size();
587 size_t nNow = nSize;
588 if (nNow + pos > vchBuf.size())
589 nNow = vchBuf.size() - pos;
590 if (nNow + nReadPos > nSrcPos)
591 nNow = nSrcPos - nReadPos;
592 memcpy(pch, &vchBuf[pos], nNow);
593 nReadPos += nNow;
594 pch += nNow;
595 nSize -= nNow;
596 }
fa736190
CF
597 }
598
599 // return the current reading position
600 uint64_t GetPos() {
601 return nReadPos;
602 }
603
604 // rewind to a given reading position
605 bool SetPos(uint64_t nPos) {
606 nReadPos = nPos;
607 if (nReadPos + nRewind < nSrcPos) {
608 nReadPos = nSrcPos - nRewind;
609 return false;
610 } else if (nReadPos > nSrcPos) {
611 nReadPos = nSrcPos;
612 return false;
613 } else {
614 return true;
615 }
616 }
617
618 bool Seek(uint64_t nPos) {
619 long nLongPos = nPos;
620 if (nPos != (uint64_t)nLongPos)
621 return false;
622 if (fseek(src, nLongPos, SEEK_SET))
623 return false;
624 nLongPos = ftell(src);
625 nSrcPos = nLongPos;
626 nReadPos = nLongPos;
627 return true;
628 }
629
630 // prevent reading beyond a certain position
631 // no argument removes the limit
632 bool SetLimit(uint64_t nPos = (uint64_t)(-1)) {
633 if (nPos < nReadPos)
634 return false;
635 nReadLimit = nPos;
636 return true;
637 }
638
639 template<typename T>
640 CBufferedFile& operator>>(T& obj) {
641 // Unserialize from this stream
242f1421 642 ::Unserialize(*this, obj);
fa736190
CF
643 return (*this);
644 }
645
646 // search for a given byte in the stream, and remain positioned on it
647 void FindByte(char ch) {
648 while (true) {
649 if (nReadPos == nSrcPos)
650 Fill();
651 if (vchBuf[nReadPos % vchBuf.size()] == ch)
652 break;
653 nReadPos++;
654 }
655 }
656};
657
658#endif // BITCOIN_STREAMS_H
This page took 0.233115 seconds and 4 git commands to generate.