1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 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
>
34 OverrideStream(Stream
* stream_
, int nType_
, int nVersion_
) : stream(stream_
), nType(nType_
), nVersion(nVersion_
) {}
37 OverrideStream
<Stream
>& operator<<(const T
& obj
)
39 // Serialize to this stream
40 ::Serialize(*this, obj
);
45 OverrideStream
<Stream
>& operator>>(T
& obj
)
47 // Unserialize from this stream
48 ::Unserialize(*this, obj
);
52 void write(const char* pch
, size_t nSize
)
54 stream
->write(pch
, nSize
);
57 void read(char* pch
, size_t nSize
)
59 stream
->read(pch
, nSize
);
62 int GetVersion() const { return nVersion
; }
63 int GetType() const { return nType
; }
67 OverrideStream
<S
> WithOrVersion(S
* s
, int nVersionFlag
)
69 return OverrideStream
<S
>(s
, s
->GetType(), s
->GetVersion() | nVersionFlag
);
72 /* Minimal stream for overwriting and/or appending to an existing byte vector
74 * The referenced vector will grow as necessary
81 * @param[in] nTypeIn Serialization Type
82 * @param[in] nVersionIn Serialization Version (including any flags)
83 * @param[in] vchDataIn Referenced byte vector to overwrite/append
84 * @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
85 * grow as necessary to max(index, vec.size()). So to append, use vec.size().
87 CVectorWriter(int nTypeIn
, int nVersionIn
, std::vector
<unsigned char>& vchDataIn
, size_t nPosIn
) : nType(nTypeIn
), nVersion(nVersionIn
), vchData(vchDataIn
), nPos(nPosIn
)
89 if(nPos
> vchData
.size())
93 * (other params same as above)
94 * @param[in] args A list of items to serialize starting at nPos.
96 template <typename
... Args
>
97 CVectorWriter(int nTypeIn
, int nVersionIn
, std::vector
<unsigned char>& vchDataIn
, size_t nPosIn
, Args
&&... args
) : CVectorWriter(nTypeIn
, nVersionIn
, vchDataIn
, nPosIn
)
99 ::SerializeMany(*this, std::forward
<Args
>(args
)...);
101 void write(const char* pch
, size_t nSize
)
103 assert(nPos
<= vchData
.size());
104 size_t nOverwrite
= std::min(nSize
, vchData
.size() - nPos
);
106 memcpy(vchData
.data() + nPos
, reinterpret_cast<const unsigned char*>(pch
), nOverwrite
);
108 if (nOverwrite
< nSize
) {
109 vchData
.insert(vchData
.end(), reinterpret_cast<const unsigned char*>(pch
) + nOverwrite
, reinterpret_cast<const unsigned char*>(pch
) + nSize
);
114 CVectorWriter
& operator<<(const T
& obj
)
116 // Serialize to this stream
117 ::Serialize(*this, obj
);
120 int GetVersion() const
128 void seek(size_t nSize
)
131 if(nPos
> vchData
.size())
132 vchData
.resize(nPos
);
137 std::vector
<unsigned char>& vchData
;
141 /** Double ended buffer combining vector and stream-like interfaces.
143 * >> and << read and write unformatted data using the above serialization templates.
144 * Fills with data in linear time; some stringstream implementations take N^2 time.
149 typedef CSerializeData vector_type
;
151 unsigned int nReadPos
;
157 typedef vector_type::allocator_type allocator_type
;
158 typedef vector_type::size_type size_type
;
159 typedef vector_type::difference_type difference_type
;
160 typedef vector_type::reference reference
;
161 typedef vector_type::const_reference const_reference
;
162 typedef vector_type::value_type value_type
;
163 typedef vector_type::iterator iterator
;
164 typedef vector_type::const_iterator const_iterator
;
165 typedef vector_type::reverse_iterator reverse_iterator
;
167 explicit CDataStream(int nTypeIn
, int nVersionIn
)
169 Init(nTypeIn
, nVersionIn
);
172 CDataStream(const_iterator pbegin
, const_iterator pend
, int nTypeIn
, int nVersionIn
) : vch(pbegin
, pend
)
174 Init(nTypeIn
, nVersionIn
);
177 CDataStream(const char* pbegin
, const char* pend
, int nTypeIn
, int nVersionIn
) : vch(pbegin
, pend
)
179 Init(nTypeIn
, nVersionIn
);
182 CDataStream(const vector_type
& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
184 Init(nTypeIn
, nVersionIn
);
187 CDataStream(const std::vector
<char>& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
189 Init(nTypeIn
, nVersionIn
);
192 CDataStream(const std::vector
<unsigned char>& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
194 Init(nTypeIn
, nVersionIn
);
197 template <typename
... Args
>
198 CDataStream(int nTypeIn
, int nVersionIn
, Args
&&... args
)
200 Init(nTypeIn
, nVersionIn
);
201 ::SerializeMany(*this, std::forward
<Args
>(args
)...);
204 void Init(int nTypeIn
, int nVersionIn
)
208 nVersion
= nVersionIn
;
211 CDataStream
& operator+=(const CDataStream
& b
)
213 vch
.insert(vch
.end(), b
.begin(), b
.end());
217 friend CDataStream
operator+(const CDataStream
& a
, const CDataStream
& b
)
224 std::string
str() const
226 return (std::string(begin(), end()));
233 const_iterator
begin() const { return vch
.begin() + nReadPos
; }
234 iterator
begin() { return vch
.begin() + nReadPos
; }
235 const_iterator
end() const { return vch
.end(); }
236 iterator
end() { return vch
.end(); }
237 size_type
size() const { return vch
.size() - nReadPos
; }
238 bool empty() const { return vch
.size() == nReadPos
; }
239 void resize(size_type n
, value_type c
=0) { vch
.resize(n
+ nReadPos
, c
); }
240 void reserve(size_type n
) { vch
.reserve(n
+ nReadPos
); }
241 const_reference
operator[](size_type pos
) const { return vch
[pos
+ nReadPos
]; }
242 reference
operator[](size_type pos
) { return vch
[pos
+ nReadPos
]; }
243 void clear() { vch
.clear(); nReadPos
= 0; }
244 iterator
insert(iterator it
, const char& x
=char()) { return vch
.insert(it
, x
); }
245 void insert(iterator it
, size_type n
, const char& x
) { vch
.insert(it
, n
, x
); }
246 value_type
* data() { return vch
.data() + nReadPos
; }
247 const value_type
* data() const { return vch
.data() + nReadPos
; }
249 void insert(iterator it
, std::vector
<char>::const_iterator first
, std::vector
<char>::const_iterator last
)
251 assert(last
- first
>= 0);
252 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
254 // special case for inserting at the front when there's room
255 nReadPos
-= (last
- first
);
256 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
259 vch
.insert(it
, first
, last
);
262 void insert(iterator it
, const char* first
, const char* last
)
264 assert(last
- first
>= 0);
265 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
267 // special case for inserting at the front when there's room
268 nReadPos
-= (last
- first
);
269 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
272 vch
.insert(it
, first
, last
);
275 iterator
erase(iterator it
)
277 if (it
== vch
.begin() + nReadPos
)
279 // special case for erasing from the front
280 if (++nReadPos
>= vch
.size())
282 // whenever we reach the end, we take the opportunity to clear the buffer
284 return vch
.erase(vch
.begin(), vch
.end());
286 return vch
.begin() + nReadPos
;
289 return vch
.erase(it
);
292 iterator
erase(iterator first
, iterator last
)
294 if (first
== vch
.begin() + nReadPos
)
296 // special case for erasing from the front
297 if (last
== vch
.end())
300 return vch
.erase(vch
.begin(), vch
.end());
304 nReadPos
= (last
- vch
.begin());
309 return vch
.erase(first
, last
);
312 inline void Compact()
314 vch
.erase(vch
.begin(), vch
.begin() + nReadPos
);
318 bool Rewind(size_type n
)
320 // Rewind by n characters if the buffer hasn't been compacted yet
331 bool eof() const { return size() == 0; }
332 CDataStream
* rdbuf() { return this; }
333 int in_avail() { return size(); }
335 void SetType(int n
) { nType
= n
; }
336 int GetType() const { return nType
; }
337 void SetVersion(int n
) { nVersion
= n
; }
338 int GetVersion() const { return nVersion
; }
340 void read(char* pch
, size_t nSize
)
342 // Read from the beginning of the buffer
343 unsigned int nReadPosNext
= nReadPos
+ nSize
;
344 if (nReadPosNext
>= vch
.size())
346 if (nReadPosNext
> vch
.size())
348 throw std::ios_base::failure("CDataStream::read(): end of data");
350 memcpy(pch
, &vch
[nReadPos
], nSize
);
355 memcpy(pch
, &vch
[nReadPos
], nSize
);
356 nReadPos
= nReadPosNext
;
359 void ignore(int nSize
)
361 // Ignore from the beginning of the buffer
363 throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
365 unsigned int nReadPosNext
= nReadPos
+ nSize
;
366 if (nReadPosNext
>= vch
.size())
368 if (nReadPosNext
> vch
.size())
369 throw std::ios_base::failure("CDataStream::ignore(): end of data");
374 nReadPos
= nReadPosNext
;
377 void write(const char* pch
, size_t nSize
)
379 // Write to the end of the buffer
380 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
383 template<typename Stream
>
384 void Serialize(Stream
& s
) const
386 // Special case: stream << stream concatenates like stream += stream
388 s
.write((char*)&vch
[0], vch
.size() * sizeof(vch
[0]));
392 CDataStream
& operator<<(const T
& obj
)
394 // Serialize to this stream
395 ::Serialize(*this, obj
);
400 CDataStream
& operator>>(T
& obj
)
402 // Unserialize from this stream
403 ::Unserialize(*this, obj
);
407 void GetAndClear(CSerializeData
&data
) {
408 data
.insert(data
.end(), begin(), end());
413 * XOR the contents of this stream with a certain key.
415 * @param[in] key The key used to XOR the data in this stream.
417 void Xor(const std::vector
<unsigned char>& key
)
419 if (key
.size() == 0) {
423 for (size_type i
= 0, j
= 0; i
!= size(); i
++) {
426 // This potentially acts on very many bytes of data, so it's
427 // important that we calculate `j`, i.e. the `key` index in this
428 // way instead of doing a %, which would effectively be a division
429 // for each byte Xor'd -- much slower than need be.
445 /** Non-refcounted RAII wrapper for FILE*
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).
455 CAutoFile(const CAutoFile
&);
456 CAutoFile
& operator=(const CAutoFile
&);
464 CAutoFile(FILE* filenew
, int nTypeIn
, int nVersionIn
) : nType(nTypeIn
), nVersion(nVersionIn
)
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*.
486 FILE* release() { FILE* ret
= file
; file
= NULL
; return ret
; }
488 /** Get wrapped FILE* without transfer of ownership.
489 * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
490 * CAutoFile outlives use of the passed pointer.
492 FILE* Get() const { return file
; }
494 /** Return true if the wrapped FILE* is NULL, false otherwise.
496 bool IsNull() const { return (file
== NULL
); }
501 int GetType() const { return nType
; }
502 int GetVersion() const { return nVersion
; }
504 void read(char* pch
, size_t nSize
)
507 throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
508 if (fread(pch
, 1, nSize
, file
) != nSize
)
509 throw std::ios_base::failure(feof(file
) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
512 void ignore(size_t nSize
)
515 throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL");
516 unsigned char data
[4096];
518 size_t nNow
= std::min
<size_t>(nSize
, sizeof(data
));
519 if (fread(data
, 1, nNow
, file
) != nNow
)
520 throw std::ios_base::failure(feof(file
) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
525 void write(const char* pch
, size_t nSize
)
528 throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
529 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
530 throw std::ios_base::failure("CAutoFile::write: write failed");
534 CAutoFile
& operator<<(const T
& obj
)
536 // Serialize to this stream
538 throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
539 ::Serialize(*this, obj
);
544 CAutoFile
& operator>>(T
& obj
)
546 // Unserialize from this stream
548 throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
549 ::Unserialize(*this, obj
);
554 /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
555 * deserialize from. It guarantees the ability to rewind a given number of bytes.
557 * Will automatically close the file when it goes out of scope if not null.
558 * If you need to close the file early, use file.fclose() instead of fclose(file).
564 CBufferedFile(const CBufferedFile
&);
565 CBufferedFile
& operator=(const CBufferedFile
&);
570 FILE *src
; // source file
571 uint64_t nSrcPos
; // how many bytes have been read from source
572 uint64_t nReadPos
; // how many bytes have been read from this
573 uint64_t nReadLimit
; // up to which position we're allowed to read
574 uint64_t nRewind
; // how many bytes we guarantee to rewind
575 std::vector
<char> vchBuf
; // the buffer
578 // read data from the source to fill the buffer
580 unsigned int pos
= nSrcPos
% vchBuf
.size();
581 unsigned int readNow
= vchBuf
.size() - pos
;
582 unsigned int nAvail
= vchBuf
.size() - (nSrcPos
- nReadPos
) - nRewind
;
583 if (nAvail
< readNow
)
587 size_t read
= fread((void*)&vchBuf
[pos
], 1, readNow
, src
);
589 throw std::ios_base::failure(feof(src
) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
597 CBufferedFile(FILE *fileIn
, uint64_t nBufSize
, uint64_t nRewindIn
, int nTypeIn
, int nVersionIn
) :
598 nType(nTypeIn
), nVersion(nVersionIn
), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn
), vchBuf(nBufSize
, 0)
608 int GetVersion() const { return nVersion
; }
609 int GetType() const { return nType
; }
619 // check whether we're at the end of the source file
621 return nReadPos
== nSrcPos
&& feof(src
);
624 // read a number of bytes
625 void read(char *pch
, size_t nSize
) {
626 if (nSize
+ nReadPos
> nReadLimit
)
627 throw std::ios_base::failure("Read attempted past buffer limit");
628 if (nSize
+ nRewind
> vchBuf
.size())
629 throw std::ios_base::failure("Read larger than buffer size");
631 if (nReadPos
== nSrcPos
)
633 unsigned int pos
= nReadPos
% vchBuf
.size();
635 if (nNow
+ pos
> vchBuf
.size())
636 nNow
= vchBuf
.size() - pos
;
637 if (nNow
+ nReadPos
> nSrcPos
)
638 nNow
= nSrcPos
- nReadPos
;
639 memcpy(pch
, &vchBuf
[pos
], nNow
);
646 // return the current reading position
651 // rewind to a given reading position
652 bool SetPos(uint64_t nPos
) {
654 if (nReadPos
+ nRewind
< nSrcPos
) {
655 nReadPos
= nSrcPos
- nRewind
;
657 } else if (nReadPos
> nSrcPos
) {
665 bool Seek(uint64_t nPos
) {
666 long nLongPos
= nPos
;
667 if (nPos
!= (uint64_t)nLongPos
)
669 if (fseek(src
, nLongPos
, SEEK_SET
))
671 nLongPos
= ftell(src
);
677 // prevent reading beyond a certain position
678 // no argument removes the limit
679 bool SetLimit(uint64_t nPos
= (uint64_t)(-1)) {
687 CBufferedFile
& operator>>(T
& obj
) {
688 // Unserialize from this stream
689 ::Unserialize(*this, obj
);
693 // search for a given byte in the stream, and remain positioned on it
694 void FindByte(char ch
) {
696 if (nReadPos
== nSrcPos
)
698 if (vchBuf
[nReadPos
% vchBuf
.size()] == ch
)
705 #endif // BITCOIN_STREAMS_H