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