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
>
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 /** Double ended buffer combining vector and stream-like interfaces.
74 * >> and << read and write unformatted data using the above serialization templates.
75 * Fills with data in linear time; some stringstream implementations take N^2 time.
80 typedef CSerializeData vector_type
;
82 unsigned int nReadPos
;
88 typedef vector_type::allocator_type allocator_type
;
89 typedef vector_type::size_type size_type
;
90 typedef vector_type::difference_type difference_type
;
91 typedef vector_type::reference reference
;
92 typedef vector_type::const_reference const_reference
;
93 typedef vector_type::value_type value_type
;
94 typedef vector_type::iterator iterator
;
95 typedef vector_type::const_iterator const_iterator
;
96 typedef vector_type::reverse_iterator reverse_iterator
;
98 explicit CDataStream(int nTypeIn
, int nVersionIn
)
100 Init(nTypeIn
, nVersionIn
);
103 CDataStream(const_iterator pbegin
, const_iterator pend
, int nTypeIn
, int nVersionIn
) : vch(pbegin
, pend
)
105 Init(nTypeIn
, nVersionIn
);
108 #if !defined(_MSC_VER) || _MSC_VER >= 1300
109 CDataStream(const char* pbegin
, const char* pend
, int nTypeIn
, int nVersionIn
) : vch(pbegin
, pend
)
111 Init(nTypeIn
, nVersionIn
);
115 CDataStream(const vector_type
& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
117 Init(nTypeIn
, nVersionIn
);
120 CDataStream(const std::vector
<char>& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
122 Init(nTypeIn
, nVersionIn
);
125 CDataStream(const std::vector
<unsigned char>& vchIn
, int nTypeIn
, int nVersionIn
) : vch(vchIn
.begin(), vchIn
.end())
127 Init(nTypeIn
, nVersionIn
);
130 template <typename
... Args
>
131 CDataStream(int nTypeIn
, int nVersionIn
, Args
&&... args
)
133 Init(nTypeIn
, nVersionIn
);
134 ::SerializeMany(*this, std::forward
<Args
>(args
)...);
137 void Init(int nTypeIn
, int nVersionIn
)
141 nVersion
= nVersionIn
;
144 CDataStream
& operator+=(const CDataStream
& b
)
146 vch
.insert(vch
.end(), b
.begin(), b
.end());
150 friend CDataStream
operator+(const CDataStream
& a
, const CDataStream
& b
)
157 std::string
str() const
159 return (std::string(begin(), end()));
166 const_iterator
begin() const { return vch
.begin() + nReadPos
; }
167 iterator
begin() { return vch
.begin() + nReadPos
; }
168 const_iterator
end() const { return vch
.end(); }
169 iterator
end() { return vch
.end(); }
170 size_type
size() const { return vch
.size() - nReadPos
; }
171 bool empty() const { return vch
.size() == nReadPos
; }
172 void resize(size_type n
, value_type c
=0) { vch
.resize(n
+ nReadPos
, c
); }
173 void reserve(size_type n
) { vch
.reserve(n
+ nReadPos
); }
174 const_reference
operator[](size_type pos
) const { return vch
[pos
+ nReadPos
]; }
175 reference
operator[](size_type pos
) { return vch
[pos
+ nReadPos
]; }
176 void clear() { vch
.clear(); nReadPos
= 0; }
177 iterator
insert(iterator it
, const char& x
=char()) { return vch
.insert(it
, x
); }
178 void insert(iterator it
, size_type n
, const char& x
) { vch
.insert(it
, n
, x
); }
180 void insert(iterator it
, std::vector
<char>::const_iterator first
, std::vector
<char>::const_iterator last
)
182 assert(last
- first
>= 0);
183 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
185 // special case for inserting at the front when there's room
186 nReadPos
-= (last
- first
);
187 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
190 vch
.insert(it
, first
, last
);
193 #if !defined(_MSC_VER) || _MSC_VER >= 1300
194 void insert(iterator it
, const char* first
, const char* last
)
196 assert(last
- first
>= 0);
197 if (it
== vch
.begin() + nReadPos
&& (unsigned int)(last
- first
) <= nReadPos
)
199 // special case for inserting at the front when there's room
200 nReadPos
-= (last
- first
);
201 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
204 vch
.insert(it
, first
, last
);
208 iterator
erase(iterator it
)
210 if (it
== vch
.begin() + nReadPos
)
212 // special case for erasing from the front
213 if (++nReadPos
>= vch
.size())
215 // whenever we reach the end, we take the opportunity to clear the buffer
217 return vch
.erase(vch
.begin(), vch
.end());
219 return vch
.begin() + nReadPos
;
222 return vch
.erase(it
);
225 iterator
erase(iterator first
, iterator last
)
227 if (first
== vch
.begin() + nReadPos
)
229 // special case for erasing from the front
230 if (last
== vch
.end())
233 return vch
.erase(vch
.begin(), vch
.end());
237 nReadPos
= (last
- vch
.begin());
242 return vch
.erase(first
, last
);
245 inline void Compact()
247 vch
.erase(vch
.begin(), vch
.begin() + nReadPos
);
251 bool Rewind(size_type n
)
253 // Rewind by n characters if the buffer hasn't been compacted yet
264 bool eof() const { return size() == 0; }
265 CDataStream
* rdbuf() { return this; }
266 int in_avail() { return size(); }
268 void SetType(int n
) { nType
= n
; }
269 int GetType() const { return nType
; }
270 void SetVersion(int n
) { nVersion
= n
; }
271 int GetVersion() const { return nVersion
; }
273 void read(char* pch
, size_t nSize
)
275 // Read from the beginning of the buffer
276 unsigned int nReadPosNext
= nReadPos
+ nSize
;
277 if (nReadPosNext
>= vch
.size())
279 if (nReadPosNext
> vch
.size())
281 throw std::ios_base::failure("CDataStream::read(): end of data");
283 memcpy(pch
, &vch
[nReadPos
], nSize
);
288 memcpy(pch
, &vch
[nReadPos
], nSize
);
289 nReadPos
= nReadPosNext
;
292 void ignore(int nSize
)
294 // Ignore from the beginning of the buffer
296 throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
298 unsigned int nReadPosNext
= nReadPos
+ nSize
;
299 if (nReadPosNext
>= vch
.size())
301 if (nReadPosNext
> vch
.size())
302 throw std::ios_base::failure("CDataStream::ignore(): end of data");
307 nReadPos
= nReadPosNext
;
310 void write(const char* pch
, size_t nSize
)
312 // Write to the end of the buffer
313 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
316 template<typename Stream
>
317 void Serialize(Stream
& s
) const
319 // Special case: stream << stream concatenates like stream += stream
321 s
.write((char*)&vch
[0], vch
.size() * sizeof(vch
[0]));
325 CDataStream
& operator<<(const T
& obj
)
327 // Serialize to this stream
328 ::Serialize(*this, obj
);
333 CDataStream
& operator>>(T
& obj
)
335 // Unserialize from this stream
336 ::Unserialize(*this, obj
);
340 void GetAndClear(CSerializeData
&data
) {
341 data
.insert(data
.end(), begin(), end());
346 * XOR the contents of this stream with a certain key.
348 * @param[in] key The key used to XOR the data in this stream.
350 void Xor(const std::vector
<unsigned char>& key
)
352 if (key
.size() == 0) {
356 for (size_type i
= 0, j
= 0; i
!= size(); i
++) {
359 // This potentially acts on very many bytes of data, so it's
360 // important that we calculate `j`, i.e. the `key` index in this
361 // way instead of doing a %, which would effectively be a division
362 // for each byte Xor'd -- much slower than need be.
378 /** Non-refcounted RAII wrapper for FILE*
380 * Will automatically close the file when it goes out of scope if not null.
381 * If you're returning the file pointer, return file.release().
382 * If you need to close the file early, use file.fclose() instead of fclose(file).
388 CAutoFile(const CAutoFile
&);
389 CAutoFile
& operator=(const CAutoFile
&);
397 CAutoFile(FILE* filenew
, int nTypeIn
, int nVersionIn
) : nType(nTypeIn
), nVersion(nVersionIn
)
415 /** Get wrapped FILE* with transfer of ownership.
416 * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
417 * of this function to clean up the returned FILE*.
419 FILE* release() { FILE* ret
= file
; file
= NULL
; return ret
; }
421 /** Get wrapped FILE* without transfer of ownership.
422 * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
423 * CAutoFile outlives use of the passed pointer.
425 FILE* Get() const { return file
; }
427 /** Return true if the wrapped FILE* is NULL, false otherwise.
429 bool IsNull() const { return (file
== NULL
); }
434 int GetType() const { return nType
; }
435 int GetVersion() const { return nVersion
; }
437 void read(char* pch
, size_t nSize
)
440 throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
441 if (fread(pch
, 1, nSize
, file
) != nSize
)
442 throw std::ios_base::failure(feof(file
) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
445 void 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");
458 void write(const char* pch
, size_t nSize
)
461 throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
462 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
463 throw std::ios_base::failure("CAutoFile::write: write failed");
467 CAutoFile
& operator<<(const T
& obj
)
469 // Serialize to this stream
471 throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
472 ::Serialize(*this, obj
);
477 CAutoFile
& operator>>(T
& obj
)
479 // Unserialize from this stream
481 throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
482 ::Unserialize(*this, obj
);
487 /** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
488 * deserialize from. It guarantees the ability to rewind a given number of bytes.
490 * Will automatically close the file when it goes out of scope if not null.
491 * If you need to close the file early, use file.fclose() instead of fclose(file).
497 CBufferedFile(const CBufferedFile
&);
498 CBufferedFile
& operator=(const CBufferedFile
&);
503 FILE *src
; // source file
504 uint64_t nSrcPos
; // how many bytes have been read from source
505 uint64_t nReadPos
; // how many bytes have been read from this
506 uint64_t nReadLimit
; // up to which position we're allowed to read
507 uint64_t nRewind
; // how many bytes we guarantee to rewind
508 std::vector
<char> vchBuf
; // the buffer
511 // read data from the source to fill the buffer
513 unsigned int pos
= nSrcPos
% vchBuf
.size();
514 unsigned int readNow
= vchBuf
.size() - pos
;
515 unsigned int nAvail
= vchBuf
.size() - (nSrcPos
- nReadPos
) - nRewind
;
516 if (nAvail
< readNow
)
520 size_t read
= fread((void*)&vchBuf
[pos
], 1, readNow
, src
);
522 throw std::ios_base::failure(feof(src
) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
530 CBufferedFile(FILE *fileIn
, uint64_t nBufSize
, uint64_t nRewindIn
, int nTypeIn
, int nVersionIn
) :
531 nType(nTypeIn
), nVersion(nVersionIn
), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn
), vchBuf(nBufSize
, 0)
541 int GetVersion() const { return nVersion
; }
542 int GetType() const { return nType
; }
552 // check whether we're at the end of the source file
554 return nReadPos
== nSrcPos
&& feof(src
);
557 // read a number of bytes
558 void read(char *pch
, size_t nSize
) {
559 if (nSize
+ nReadPos
> nReadLimit
)
560 throw std::ios_base::failure("Read attempted past buffer limit");
561 if (nSize
+ nRewind
> vchBuf
.size())
562 throw std::ios_base::failure("Read larger than buffer size");
564 if (nReadPos
== nSrcPos
)
566 unsigned int pos
= nReadPos
% vchBuf
.size();
568 if (nNow
+ pos
> vchBuf
.size())
569 nNow
= vchBuf
.size() - pos
;
570 if (nNow
+ nReadPos
> nSrcPos
)
571 nNow
= nSrcPos
- nReadPos
;
572 memcpy(pch
, &vchBuf
[pos
], nNow
);
579 // return the current reading position
584 // rewind to a given reading position
585 bool SetPos(uint64_t nPos
) {
587 if (nReadPos
+ nRewind
< nSrcPos
) {
588 nReadPos
= nSrcPos
- nRewind
;
590 } else if (nReadPos
> nSrcPos
) {
598 bool Seek(uint64_t nPos
) {
599 long nLongPos
= nPos
;
600 if (nPos
!= (uint64_t)nLongPos
)
602 if (fseek(src
, nLongPos
, SEEK_SET
))
604 nLongPos
= ftell(src
);
610 // prevent reading beyond a certain position
611 // no argument removes the limit
612 bool SetLimit(uint64_t nPos
= (uint64_t)(-1)) {
620 CBufferedFile
& operator>>(T
& obj
) {
621 // Unserialize from this stream
622 ::Unserialize(*this, obj
);
626 // search for a given byte in the stream, and remain positioned on it
627 void FindByte(char ch
) {
629 if (nReadPos
== nSrcPos
)
631 if (vchBuf
[nReadPos
% vchBuf
.size()] == ch
)
638 #endif // BITCOIN_STREAMS_H