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())
350 if (nReadPosNext
> vch
.size())
352 throw std::ios_base::failure("CDataStream::read(): end of data");
354 memcpy(pch
, &vch
[nReadPos
], nSize
);
359 memcpy(pch
, &vch
[nReadPos
], nSize
);
360 nReadPos
= nReadPosNext
;
363 void ignore(int nSize
)
365 // Ignore from the beginning of the buffer
367 throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
369 unsigned int nReadPosNext
= nReadPos
+ nSize
;
370 if (nReadPosNext
>= vch
.size())
372 if (nReadPosNext
> vch
.size())
373 throw std::ios_base::failure("CDataStream::ignore(): end of data");
378 nReadPos
= nReadPosNext
;
381 void write(const char* pch
, size_t nSize
)
383 // Write to the end of the buffer
384 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
387 template<typename Stream
>
388 void Serialize(Stream
& s
) const
390 // Special case: stream << stream concatenates like stream += stream
392 s
.write((char*)vch
.data(), vch
.size() * sizeof(value_type
));
396 CDataStream
& operator<<(const T
& obj
)
398 // Serialize to this stream
399 ::Serialize(*this, obj
);
404 CDataStream
& operator>>(T
& obj
)
406 // Unserialize from this stream
407 ::Unserialize(*this, obj
);
411 void GetAndClear(CSerializeData
&d
) {
412 d
.insert(d
.end(), begin(), end());
417 * XOR the contents of this stream with a certain key.
419 * @param[in] key The key used to XOR the data in this stream.
421 void Xor(const std::vector
<unsigned char>& key
)
423 if (key
.size() == 0) {
427 for (size_type i
= 0, j
= 0; i
!= size(); i
++) {
430 // This potentially acts on very many bytes of data, so it's
431 // important that we calculate `j`, i.e. the `key` index in this
432 // way instead of doing a %, which would effectively be a division
433 // for each byte Xor'd -- much slower than need be.
449 /** Non-refcounted RAII wrapper for FILE*
451 * Will automatically close the file when it goes out of scope if not null.
452 * If you're returning the file pointer, return file.release().
453 * If you need to close the file early, use file.fclose() instead of fclose(file).
464 CAutoFile(FILE* filenew
, int nTypeIn
, int nVersionIn
) : nType(nTypeIn
), nVersion(nVersionIn
)
475 CAutoFile(const CAutoFile
&) = delete;
476 CAutoFile
& operator=(const CAutoFile
&) = delete;
486 /** Get wrapped FILE* with transfer of ownership.
487 * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
488 * of this function to clean up the returned FILE*.
490 FILE* release() { FILE* ret
= file
; file
= nullptr; return ret
; }
492 /** Get wrapped FILE* without transfer of ownership.
493 * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
494 * CAutoFile outlives use of the passed pointer.
496 FILE* Get() const { return file
; }
498 /** Return true if the wrapped FILE* is nullptr, false otherwise.
500 bool IsNull() const { return (file
== nullptr); }
505 int GetType() const { return nType
; }
506 int GetVersion() const { return nVersion
; }
508 void read(char* pch
, size_t nSize
)
511 throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
512 if (fread(pch
, 1, nSize
, file
) != nSize
)
513 throw std::ios_base::failure(feof(file
) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
516 void ignore(size_t nSize
)
519 throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
520 unsigned char data
[4096];
522 size_t nNow
= std::min
<size_t>(nSize
, sizeof(data
));
523 if (fread(data
, 1, nNow
, file
) != nNow
)
524 throw std::ios_base::failure(feof(file
) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
529 void write(const char* pch
, size_t nSize
)
532 throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
533 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
534 throw std::ios_base::failure("CAutoFile::write: write failed");
538 CAutoFile
& operator<<(const T
& obj
)
540 // Serialize to this stream
542 throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
543 ::Serialize(*this, obj
);
548 CAutoFile
& operator>>(T
& obj
)
550 // Unserialize from this stream
552 throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
553 ::Unserialize(*this, obj
);
558 /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
559 * deserialize from. It guarantees the ability to rewind a given number of bytes.
561 * Will automatically close the file when it goes out of scope if not null.
562 * If you need to close the file early, use file.fclose() instead of fclose(file).
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 nBytes
= 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)
609 CBufferedFile(const CBufferedFile
&) = delete;
610 CBufferedFile
& operator=(const CBufferedFile
&) = delete;
612 int GetVersion() const { return nVersion
; }
613 int GetType() const { return nType
; }
623 // check whether we're at the end of the source file
625 return nReadPos
== nSrcPos
&& feof(src
);
628 // read a number of bytes
629 void read(char *pch
, size_t nSize
) {
630 if (nSize
+ nReadPos
> nReadLimit
)
631 throw std::ios_base::failure("Read attempted past buffer limit");
632 if (nSize
+ nRewind
> vchBuf
.size())
633 throw std::ios_base::failure("Read larger than buffer size");
635 if (nReadPos
== nSrcPos
)
637 unsigned int pos
= nReadPos
% vchBuf
.size();
639 if (nNow
+ pos
> vchBuf
.size())
640 nNow
= vchBuf
.size() - pos
;
641 if (nNow
+ nReadPos
> nSrcPos
)
642 nNow
= nSrcPos
- nReadPos
;
643 memcpy(pch
, &vchBuf
[pos
], nNow
);
650 // return the current reading position
651 uint64_t GetPos() const {
655 // rewind to a given reading position
656 bool SetPos(uint64_t nPos
) {
658 if (nReadPos
+ nRewind
< nSrcPos
) {
659 nReadPos
= nSrcPos
- nRewind
;
661 } else if (nReadPos
> nSrcPos
) {
669 bool Seek(uint64_t nPos
) {
670 long nLongPos
= nPos
;
671 if (nPos
!= (uint64_t)nLongPos
)
673 if (fseek(src
, nLongPos
, SEEK_SET
))
675 nLongPos
= ftell(src
);
681 // prevent reading beyond a certain position
682 // no argument removes the limit
683 bool SetLimit(uint64_t nPos
= (uint64_t)(-1)) {
691 CBufferedFile
& operator>>(T
& obj
) {
692 // Unserialize from this stream
693 ::Unserialize(*this, obj
);
697 // search for a given byte in the stream, and remain positioned on it
698 void FindByte(char ch
) {
700 if (nReadPos
== nSrcPos
)
702 if (vchBuf
[nReadPos
% vchBuf
.size()] == ch
)
709 #endif // BITCOIN_STREAMS_H