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(nPosIn, 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 nPosIn.
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 if (last
== first
) return;
252 assert(last
- first
> 0);
253 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
255 // special case for inserting at the front when there's room
256 nReadPos
-= (last
- first
);
257 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
260 vch
.insert(it
, first
, last
);
263 void insert(iterator it
, const char* first
, const char* last
)
265 if (last
== first
) return;
266 assert(last
- first
> 0);
267 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
269 // special case for inserting at the front when there's room
270 nReadPos
-= (last
- first
);
271 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
274 vch
.insert(it
, first
, last
);
277 iterator
erase(iterator it
)
279 if (it
== vch
.begin() + nReadPos
)
281 // special case for erasing from the front
282 if (++nReadPos
>= vch
.size())
284 // whenever we reach the end, we take the opportunity to clear the buffer
286 return vch
.erase(vch
.begin(), vch
.end());
288 return vch
.begin() + nReadPos
;
291 return vch
.erase(it
);
294 iterator
erase(iterator first
, iterator last
)
296 if (first
== vch
.begin() + nReadPos
)
298 // special case for erasing from the front
299 if (last
== vch
.end())
302 return vch
.erase(vch
.begin(), vch
.end());
306 nReadPos
= (last
- vch
.begin());
311 return vch
.erase(first
, last
);
314 inline void Compact()
316 vch
.erase(vch
.begin(), vch
.begin() + nReadPos
);
320 bool Rewind(size_type n
)
322 // Rewind by n characters if the buffer hasn't been compacted yet
333 bool eof() const { return size() == 0; }
334 CDataStream
* rdbuf() { return this; }
335 int in_avail() const { return size(); }
337 void SetType(int n
) { nType
= n
; }
338 int GetType() const { return nType
; }
339 void SetVersion(int n
) { nVersion
= n
; }
340 int GetVersion() const { return nVersion
; }
342 void read(char* pch
, size_t nSize
)
344 if (nSize
== 0) return;
346 // Read from the beginning of the buffer
347 unsigned int nReadPosNext
= nReadPos
+ nSize
;
348 if (nReadPosNext
> vch
.size()) {
349 throw std::ios_base::failure("CDataStream::read(): end of data");
351 memcpy(pch
, &vch
[nReadPos
], nSize
);
352 if (nReadPosNext
== vch
.size())
358 nReadPos
= nReadPosNext
;
361 void ignore(int nSize
)
363 // Ignore from the beginning of the buffer
365 throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
367 unsigned int nReadPosNext
= nReadPos
+ nSize
;
368 if (nReadPosNext
>= vch
.size())
370 if (nReadPosNext
> vch
.size())
371 throw std::ios_base::failure("CDataStream::ignore(): end of data");
376 nReadPos
= nReadPosNext
;
379 void write(const char* pch
, size_t nSize
)
381 // Write to the end of the buffer
382 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
385 template<typename Stream
>
386 void Serialize(Stream
& s
) const
388 // Special case: stream << stream concatenates like stream += stream
390 s
.write((char*)vch
.data(), vch
.size() * sizeof(value_type
));
394 CDataStream
& operator<<(const T
& obj
)
396 // Serialize to this stream
397 ::Serialize(*this, obj
);
402 CDataStream
& operator>>(T
& obj
)
404 // Unserialize from this stream
405 ::Unserialize(*this, obj
);
409 void GetAndClear(CSerializeData
&d
) {
410 d
.insert(d
.end(), begin(), end());
415 * XOR the contents of this stream with a certain key.
417 * @param[in] key The key used to XOR the data in this stream.
419 void Xor(const std::vector
<unsigned char>& key
)
421 if (key
.size() == 0) {
425 for (size_type i
= 0, j
= 0; i
!= size(); i
++) {
428 // This potentially acts on very many bytes of data, so it's
429 // important that we calculate `j`, i.e. the `key` index in this
430 // way instead of doing a %, which would effectively be a division
431 // for each byte Xor'd -- much slower than need be.
447 /** Non-refcounted RAII wrapper for FILE*
449 * Will automatically close the file when it goes out of scope if not null.
450 * If you're returning the file pointer, return file.release().
451 * If you need to close the file early, use file.fclose() instead of fclose(file).
462 CAutoFile(FILE* filenew
, int nTypeIn
, int nVersionIn
) : nType(nTypeIn
), nVersion(nVersionIn
)
473 CAutoFile(const CAutoFile
&) = delete;
474 CAutoFile
& operator=(const CAutoFile
&) = delete;
484 /** Get wrapped FILE* with transfer of ownership.
485 * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
486 * of this function to clean up the returned FILE*.
488 FILE* release() { FILE* ret
= file
; file
= nullptr; return ret
; }
490 /** Get wrapped FILE* without transfer of ownership.
491 * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
492 * CAutoFile outlives use of the passed pointer.
494 FILE* Get() const { return file
; }
496 /** Return true if the wrapped FILE* is nullptr, false otherwise.
498 bool IsNull() const { return (file
== nullptr); }
503 int GetType() const { return nType
; }
504 int GetVersion() const { return nVersion
; }
506 void read(char* pch
, size_t nSize
)
509 throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
510 if (fread(pch
, 1, nSize
, file
) != nSize
)
511 throw std::ios_base::failure(feof(file
) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
514 void ignore(size_t nSize
)
517 throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
518 unsigned char data
[4096];
520 size_t nNow
= std::min
<size_t>(nSize
, sizeof(data
));
521 if (fread(data
, 1, nNow
, file
) != nNow
)
522 throw std::ios_base::failure(feof(file
) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
527 void write(const char* pch
, size_t nSize
)
530 throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
531 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
532 throw std::ios_base::failure("CAutoFile::write: write failed");
536 CAutoFile
& operator<<(const T
& obj
)
538 // Serialize to this stream
540 throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
541 ::Serialize(*this, obj
);
546 CAutoFile
& operator>>(T
& obj
)
548 // Unserialize from this stream
550 throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
551 ::Unserialize(*this, obj
);
556 /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
557 * deserialize from. It guarantees the ability to rewind a given number of bytes.
559 * Will automatically close the file when it goes out of scope if not null.
560 * If you need to close the file early, use file.fclose() instead of fclose(file).
568 FILE *src
; // source file
569 uint64_t nSrcPos
; // how many bytes have been read from source
570 uint64_t nReadPos
; // how many bytes have been read from this
571 uint64_t nReadLimit
; // up to which position we're allowed to read
572 uint64_t nRewind
; // how many bytes we guarantee to rewind
573 std::vector
<char> vchBuf
; // the buffer
576 // read data from the source to fill the buffer
578 unsigned int pos
= nSrcPos
% vchBuf
.size();
579 unsigned int readNow
= vchBuf
.size() - pos
;
580 unsigned int nAvail
= vchBuf
.size() - (nSrcPos
- nReadPos
) - nRewind
;
581 if (nAvail
< readNow
)
585 size_t nBytes
= fread((void*)&vchBuf
[pos
], 1, readNow
, src
);
587 throw std::ios_base::failure(feof(src
) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
595 CBufferedFile(FILE *fileIn
, uint64_t nBufSize
, uint64_t nRewindIn
, int nTypeIn
, int nVersionIn
) :
596 nType(nTypeIn
), nVersion(nVersionIn
), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn
), vchBuf(nBufSize
, 0)
607 CBufferedFile(const CBufferedFile
&) = delete;
608 CBufferedFile
& operator=(const CBufferedFile
&) = delete;
610 int GetVersion() const { return nVersion
; }
611 int GetType() const { return nType
; }
621 // check whether we're at the end of the source file
623 return nReadPos
== nSrcPos
&& feof(src
);
626 // read a number of bytes
627 void read(char *pch
, size_t nSize
) {
628 if (nSize
+ nReadPos
> nReadLimit
)
629 throw std::ios_base::failure("Read attempted past buffer limit");
630 if (nSize
+ nRewind
> vchBuf
.size())
631 throw std::ios_base::failure("Read larger than buffer size");
633 if (nReadPos
== nSrcPos
)
635 unsigned int pos
= nReadPos
% vchBuf
.size();
637 if (nNow
+ pos
> vchBuf
.size())
638 nNow
= vchBuf
.size() - pos
;
639 if (nNow
+ nReadPos
> nSrcPos
)
640 nNow
= nSrcPos
- nReadPos
;
641 memcpy(pch
, &vchBuf
[pos
], nNow
);
648 // return the current reading position
649 uint64_t GetPos() const {
653 // rewind to a given reading position
654 bool SetPos(uint64_t nPos
) {
656 if (nReadPos
+ nRewind
< nSrcPos
) {
657 nReadPos
= nSrcPos
- nRewind
;
659 } else if (nReadPos
> nSrcPos
) {
667 bool Seek(uint64_t nPos
) {
668 long nLongPos
= nPos
;
669 if (nPos
!= (uint64_t)nLongPos
)
671 if (fseek(src
, nLongPos
, SEEK_SET
))
673 nLongPos
= ftell(src
);
679 // prevent reading beyond a certain position
680 // no argument removes the limit
681 bool SetLimit(uint64_t nPos
= (uint64_t)(-1)) {
689 CBufferedFile
& operator>>(T
& obj
) {
690 // Unserialize from this stream
691 ::Unserialize(*this, obj
);
695 // search for a given byte in the stream, and remain positioned on it
696 void FindByte(char ch
) {
698 if (nReadPos
== nSrcPos
)
700 if (vchBuf
[nReadPos
% vchBuf
.size()] == ch
)
707 #endif // BITCOIN_STREAMS_H