1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 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.
6 #ifndef BITCOIN_STREAMS_H
7 #define BITCOIN_STREAMS_H
9 #include "support/allocators/zeroafterfree.h"
10 #include "serialize.h"
25 template<typename Stream
>
33 OverrideStream(Stream
* stream_
, int nType_
, int nVersion_
) : stream(stream_
), nType(nType_
), nVersion(nVersion_
) {}
36 OverrideStream
<Stream
>& operator<<(const T
& obj
)
38 // Serialize to this stream
39 ::Serialize(*this->stream
, obj
, nType
, nVersion
);
44 OverrideStream
<Stream
>& operator>>(T
& obj
)
46 // Unserialize from this stream
47 ::Unserialize(*this->stream
, obj
, nType
, nVersion
);
53 OverrideStream
<S
> WithOrVersion(S
* s
, int nVersionFlag
)
55 return OverrideStream
<S
>(s
, s
->GetType(), s
->GetVersion() | nVersionFlag
);
58 /** Double ended buffer combining vector and stream-like interfaces.
60 * >> and << read and write unformatted data using the above serialization templates.
61 * Fills with data in linear time; some stringstream implementations take N^2 time.
66 typedef CSerializeData vector_type
;
68 unsigned int nReadPos
;
73 typedef vector_type::allocator_type allocator_type
;
74 typedef vector_type::size_type size_type
;
75 typedef vector_type::difference_type difference_type
;
76 typedef vector_type::reference reference
;
77 typedef vector_type::const_reference const_reference
;
78 typedef vector_type::value_type value_type
;
79 typedef vector_type::iterator iterator
;
80 typedef vector_type::const_iterator const_iterator
;
81 typedef vector_type::reverse_iterator reverse_iterator
;
83 explicit CDataStream(int nTypeIn
, int nVersionIn
)
85 Init(nTypeIn
, nVersionIn
);
88 CDataStream(const_iterator pbegin
, const_iterator pend
, int nTypeIn
, int nVersionIn
) : vch(pbegin
, pend
)
90 Init(nTypeIn
, nVersionIn
);
93 #if !defined(_MSC_VER) || _MSC_VER >= 1300
94 CDataStream(const char* pbegin
, const char* pend
, int nTypeIn
, int nVersionIn
) : vch(pbegin
, pend
)
96 Init(nTypeIn
, nVersionIn
);
100 CDataStream(const vector_type
& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
102 Init(nTypeIn
, nVersionIn
);
105 CDataStream(const std::vector
<char>& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
107 Init(nTypeIn
, nVersionIn
);
110 CDataStream(const std::vector
<unsigned char>& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
112 Init(nTypeIn
, nVersionIn
);
115 template <typename
... Args
>
116 CDataStream(int nTypeIn
, int nVersionIn
, Args
&&... args
)
118 Init(nTypeIn
, nVersionIn
);
119 ::SerializeMany(*this, nType
, nVersion
, std::forward
<Args
>(args
)...);
122 void Init(int nTypeIn
, int nVersionIn
)
126 nVersion
= nVersionIn
;
129 CDataStream
& operator+=(const CDataStream
& b
)
131 vch
.insert(vch
.end(), b
.begin(), b
.end());
135 friend CDataStream
operator+(const CDataStream
& a
, const CDataStream
& b
)
142 std::string
str() const
144 return (std::string(begin(), end()));
151 const_iterator
begin() const { return vch
.begin() + nReadPos
; }
152 iterator
begin() { return vch
.begin() + nReadPos
; }
153 const_iterator
end() const { return vch
.end(); }
154 iterator
end() { return vch
.end(); }
155 size_type
size() const { return vch
.size() - nReadPos
; }
156 bool empty() const { return vch
.size() == nReadPos
; }
157 void resize(size_type n
, value_type c
=0) { vch
.resize(n
+ nReadPos
, c
); }
158 void reserve(size_type n
) { vch
.reserve(n
+ nReadPos
); }
159 const_reference
operator[](size_type pos
) const { return vch
[pos
+ nReadPos
]; }
160 reference
operator[](size_type pos
) { return vch
[pos
+ nReadPos
]; }
161 void clear() { vch
.clear(); nReadPos
= 0; }
162 iterator
insert(iterator it
, const char& x
=char()) { return vch
.insert(it
, x
); }
163 void insert(iterator it
, size_type n
, const char& x
) { vch
.insert(it
, n
, x
); }
165 void insert(iterator it
, std::vector
<char>::const_iterator first
, std::vector
<char>::const_iterator last
)
167 assert(last
- first
>= 0);
168 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
170 // special case for inserting at the front when there's room
171 nReadPos
-= (last
- first
);
172 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
175 vch
.insert(it
, first
, last
);
178 #if !defined(_MSC_VER) || _MSC_VER >= 1300
179 void insert(iterator it
, const char* first
, const char* last
)
181 assert(last
- first
>= 0);
182 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
184 // special case for inserting at the front when there's room
185 nReadPos
-= (last
- first
);
186 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
189 vch
.insert(it
, first
, last
);
193 iterator
erase(iterator it
)
195 if (it
== vch
.begin() + nReadPos
)
197 // special case for erasing from the front
198 if (++nReadPos
>= vch
.size())
200 // whenever we reach the end, we take the opportunity to clear the buffer
202 return vch
.erase(vch
.begin(), vch
.end());
204 return vch
.begin() + nReadPos
;
207 return vch
.erase(it
);
210 iterator
erase(iterator first
, iterator last
)
212 if (first
== vch
.begin() + nReadPos
)
214 // special case for erasing from the front
215 if (last
== vch
.end())
218 return vch
.erase(vch
.begin(), vch
.end());
222 nReadPos
= (last
- vch
.begin());
227 return vch
.erase(first
, last
);
230 inline void Compact()
232 vch
.erase(vch
.begin(), vch
.begin() + nReadPos
);
236 bool Rewind(size_type n
)
238 // Rewind by n characters if the buffer hasn't been compacted yet
249 bool eof() const { return size() == 0; }
250 CDataStream
* rdbuf() { return this; }
251 int in_avail() { return size(); }
253 void SetType(int n
) { nType
= n
; }
254 int GetType() { return nType
; }
255 void SetVersion(int n
) { nVersion
= n
; }
256 int GetVersion() { return nVersion
; }
258 CDataStream
& read(char* pch
, size_t nSize
)
260 // Read from the beginning of the buffer
261 unsigned int nReadPosNext
= nReadPos
+ nSize
;
262 if (nReadPosNext
>= vch
.size())
264 if (nReadPosNext
> vch
.size())
266 throw std::ios_base::failure("CDataStream::read(): end of data");
268 memcpy(pch
, &vch
[nReadPos
], nSize
);
273 memcpy(pch
, &vch
[nReadPos
], nSize
);
274 nReadPos
= nReadPosNext
;
278 CDataStream
& ignore(int nSize
)
280 // Ignore from the beginning of the buffer
282 throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
284 unsigned int nReadPosNext
= nReadPos
+ nSize
;
285 if (nReadPosNext
>= vch
.size())
287 if (nReadPosNext
> vch
.size())
288 throw std::ios_base::failure("CDataStream::ignore(): end of data");
293 nReadPos
= nReadPosNext
;
297 CDataStream
& write(const char* pch
, size_t nSize
)
299 // Write to the end of the buffer
300 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
304 template<typename Stream
>
305 void Serialize(Stream
& s
, int nType
, int nVersion
) const
307 // Special case: stream << stream concatenates like stream += stream
309 s
.write((char*)&vch
[0], vch
.size() * sizeof(vch
[0]));
313 unsigned int GetSerializeSize(const T
& obj
)
315 // Tells the size of the object if serialized to this stream
316 return ::GetSerializeSize(obj
, nType
, nVersion
);
320 CDataStream
& operator<<(const T
& obj
)
322 // Serialize to this stream
323 ::Serialize(*this, obj
, nType
, nVersion
);
328 CDataStream
& operator>>(T
& obj
)
330 // Unserialize from this stream
331 ::Unserialize(*this, obj
, nType
, nVersion
);
335 void GetAndClear(CSerializeData
&data
) {
336 data
.insert(data
.end(), begin(), end());
341 * XOR the contents of this stream with a certain key.
343 * @param[in] key The key used to XOR the data in this stream.
345 void Xor(const std::vector
<unsigned char>& key
)
347 if (key
.size() == 0) {
351 for (size_type i
= 0, j
= 0; i
!= size(); i
++) {
354 // This potentially acts on very many bytes of data, so it's
355 // important that we calculate `j`, i.e. the `key` index in this
356 // way instead of doing a %, which would effectively be a division
357 // for each byte Xor'd -- much slower than need be.
373 /** Non-refcounted RAII wrapper for FILE*
375 * Will automatically close the file when it goes out of scope if not null.
376 * If you're returning the file pointer, return file.release().
377 * If you need to close the file early, use file.fclose() instead of fclose(file).
383 CAutoFile(const CAutoFile
&);
384 CAutoFile
& operator=(const CAutoFile
&);
392 CAutoFile(FILE* filenew
, int nTypeIn
, int nVersionIn
)
396 nVersion
= nVersionIn
;
412 /** Get wrapped FILE* with transfer of ownership.
413 * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
414 * of this function to clean up the returned FILE*.
416 FILE* release() { FILE* ret
= file
; file
= NULL
; return ret
; }
418 /** Get wrapped FILE* without transfer of ownership.
419 * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
420 * CAutoFile outlives use of the passed pointer.
422 FILE* Get() const { return file
; }
424 /** Return true if the wrapped FILE* is NULL, false otherwise.
426 bool IsNull() const { return (file
== NULL
); }
431 void SetType(int n
) { nType
= n
; }
432 int GetType() { return nType
; }
433 void SetVersion(int n
) { nVersion
= n
; }
434 int GetVersion() { return nVersion
; }
436 CAutoFile
& read(char* pch
, size_t nSize
)
439 throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
440 if (fread(pch
, 1, nSize
, file
) != nSize
)
441 throw std::ios_base::failure(feof(file
) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
445 CAutoFile
& ignore(size_t nSize
)
448 throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL");
449 unsigned char data
[4096];
451 size_t nNow
= std::min
<size_t>(nSize
, sizeof(data
));
452 if (fread(data
, 1, nNow
, file
) != nNow
)
453 throw std::ios_base::failure(feof(file
) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
459 CAutoFile
& write(const char* pch
, size_t nSize
)
462 throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
463 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
464 throw std::ios_base::failure("CAutoFile::write: write failed");
469 unsigned int GetSerializeSize(const T
& obj
)
471 // Tells the size of the object if serialized to this stream
472 return ::GetSerializeSize(obj
, nType
, nVersion
);
476 CAutoFile
& operator<<(const T
& obj
)
478 // Serialize to this stream
480 throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
481 ::Serialize(*this, obj
, nType
, nVersion
);
486 CAutoFile
& operator>>(T
& obj
)
488 // Unserialize from this stream
490 throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
491 ::Unserialize(*this, obj
, nType
, nVersion
);
496 /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
497 * deserialize from. It guarantees the ability to rewind a given number of bytes.
499 * Will automatically close the file when it goes out of scope if not null.
500 * If you need to close the file early, use file.fclose() instead of fclose(file).
506 CBufferedFile(const CBufferedFile
&);
507 CBufferedFile
& operator=(const CBufferedFile
&);
512 FILE *src
; // source file
513 uint64_t nSrcPos
; // how many bytes have been read from source
514 uint64_t nReadPos
; // how many bytes have been read from this
515 uint64_t nReadLimit
; // up to which position we're allowed to read
516 uint64_t nRewind
; // how many bytes we guarantee to rewind
517 std::vector
<char> vchBuf
; // the buffer
520 // read data from the source to fill the buffer
522 unsigned int pos
= nSrcPos
% vchBuf
.size();
523 unsigned int readNow
= vchBuf
.size() - pos
;
524 unsigned int nAvail
= vchBuf
.size() - (nSrcPos
- nReadPos
) - nRewind
;
525 if (nAvail
< readNow
)
529 size_t read
= fread((void*)&vchBuf
[pos
], 1, readNow
, src
);
531 throw std::ios_base::failure(feof(src
) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
539 CBufferedFile(FILE *fileIn
, uint64_t nBufSize
, uint64_t nRewindIn
, int nTypeIn
, int nVersionIn
) :
540 nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn
), vchBuf(nBufSize
, 0)
544 nVersion
= nVersionIn
;
560 // check whether we're at the end of the source file
562 return nReadPos
== nSrcPos
&& feof(src
);
565 // read a number of bytes
566 CBufferedFile
& read(char *pch
, size_t nSize
) {
567 if (nSize
+ nReadPos
> nReadLimit
)
568 throw std::ios_base::failure("Read attempted past buffer limit");
569 if (nSize
+ nRewind
> vchBuf
.size())
570 throw std::ios_base::failure("Read larger than buffer size");
572 if (nReadPos
== nSrcPos
)
574 unsigned int pos
= nReadPos
% vchBuf
.size();
576 if (nNow
+ pos
> vchBuf
.size())
577 nNow
= vchBuf
.size() - pos
;
578 if (nNow
+ nReadPos
> nSrcPos
)
579 nNow
= nSrcPos
- nReadPos
;
580 memcpy(pch
, &vchBuf
[pos
], nNow
);
588 // return the current reading position
593 // rewind to a given reading position
594 bool SetPos(uint64_t nPos
) {
596 if (nReadPos
+ nRewind
< nSrcPos
) {
597 nReadPos
= nSrcPos
- nRewind
;
599 } else if (nReadPos
> nSrcPos
) {
607 bool Seek(uint64_t nPos
) {
608 long nLongPos
= nPos
;
609 if (nPos
!= (uint64_t)nLongPos
)
611 if (fseek(src
, nLongPos
, SEEK_SET
))
613 nLongPos
= ftell(src
);
619 // prevent reading beyond a certain position
620 // no argument removes the limit
621 bool SetLimit(uint64_t nPos
= (uint64_t)(-1)) {
629 CBufferedFile
& operator>>(T
& obj
) {
630 // Unserialize from this stream
631 ::Unserialize(*this, obj
, nType
, nVersion
);
635 // search for a given byte in the stream, and remain positioned on it
636 void FindByte(char ch
) {
638 if (nReadPos
== nSrcPos
)
640 if (vchBuf
[nReadPos
% vchBuf
.size()] == ch
)
647 #endif // BITCOIN_STREAMS_H