Changeset View
Changeset View
Standalone View
Standalone View
src/streams.h
Show First 20 Lines • Show All 700 Lines • ▼ Show 20 Lines | |||||
* Will automatically close the file when it goes out of scope if not null. If | * Will automatically close the file when it goes out of scope if not null. If | ||||
* you need to close the file early, use file.fclose() instead of fclose(file). | * you need to close the file early, use file.fclose() instead of fclose(file). | ||||
*/ | */ | ||||
class CBufferedFile { | class CBufferedFile { | ||||
private: | private: | ||||
const int nType; | const int nType; | ||||
const int nVersion; | const int nVersion; | ||||
// source file | //! source file | ||||
FILE *src; | FILE *src; | ||||
// how many bytes have been read from source | //! how many bytes have been read from source | ||||
uint64_t nSrcPos; | uint64_t nSrcPos; | ||||
// how many bytes have been read from this | //! how many bytes have been read from this | ||||
uint64_t nReadPos; | uint64_t nReadPos; | ||||
// up to which position we're allowed to read | //! up to which position we're allowed to read | ||||
uint64_t nReadLimit; | uint64_t nReadLimit; | ||||
// how many bytes we guarantee to rewind | //! how many bytes we guarantee to rewind | ||||
uint64_t nRewind; | uint64_t nRewind; | ||||
// the buffer | //! the buffer | ||||
std::vector<char> vchBuf; | std::vector<char> vchBuf; | ||||
protected: | protected: | ||||
// read data from the source to fill the buffer | //! read data from the source to fill the buffer | ||||
bool Fill() { | bool Fill() { | ||||
unsigned int pos = nSrcPos % vchBuf.size(); | unsigned int pos = nSrcPos % vchBuf.size(); | ||||
unsigned int readNow = vchBuf.size() - pos; | unsigned int readNow = vchBuf.size() - pos; | ||||
unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind; | unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind; | ||||
if (nAvail < readNow) { | if (nAvail < readNow) { | ||||
readNow = nAvail; | readNow = nAvail; | ||||
} | } | ||||
if (readNow == 0) { | if (readNow == 0) { | ||||
Show All 30 Lines | public: | ||||
void fclose() { | void fclose() { | ||||
if (src) { | if (src) { | ||||
::fclose(src); | ::fclose(src); | ||||
src = nullptr; | src = nullptr; | ||||
} | } | ||||
} | } | ||||
// check whether we're at the end of the source file | //! check whether we're at the end of the source file | ||||
bool eof() const { return nReadPos == nSrcPos && feof(src); } | bool eof() const { return nReadPos == nSrcPos && feof(src); } | ||||
// read a number of bytes | //! read a number of bytes | ||||
void read(char *pch, size_t nSize) { | void read(char *pch, size_t nSize) { | ||||
if (nSize + nReadPos > nReadLimit) { | if (nSize + nReadPos > nReadLimit) { | ||||
throw std::ios_base::failure("Read attempted past buffer limit"); | throw std::ios_base::failure("Read attempted past buffer limit"); | ||||
} | } | ||||
if (nSize + nRewind > vchBuf.size()) { | if (nSize + nRewind > vchBuf.size()) { | ||||
throw std::ios_base::failure("Read larger than buffer size"); | throw std::ios_base::failure("Read larger than buffer size"); | ||||
} | } | ||||
while (nSize > 0) { | while (nSize > 0) { | ||||
Show All 10 Lines | void read(char *pch, size_t nSize) { | ||||
} | } | ||||
memcpy(pch, &vchBuf[pos], nNow); | memcpy(pch, &vchBuf[pos], nNow); | ||||
nReadPos += nNow; | nReadPos += nNow; | ||||
pch += nNow; | pch += nNow; | ||||
nSize -= nNow; | nSize -= nNow; | ||||
} | } | ||||
} | } | ||||
// return the current reading position | //! return the current reading position | ||||
uint64_t GetPos() const { return nReadPos; } | uint64_t GetPos() const { return nReadPos; } | ||||
// rewind to a given reading position | //! rewind to a given reading position | ||||
bool SetPos(uint64_t nPos) { | bool SetPos(uint64_t nPos) { | ||||
nReadPos = nPos; | nReadPos = nPos; | ||||
if (nReadPos + nRewind < nSrcPos) { | if (nReadPos + nRewind < nSrcPos) { | ||||
nReadPos = nSrcPos - nRewind; | nReadPos = nSrcPos - nRewind; | ||||
return false; | return false; | ||||
} else if (nReadPos > nSrcPos) { | } else if (nReadPos > nSrcPos) { | ||||
nReadPos = nSrcPos; | nReadPos = nSrcPos; | ||||
return false; | return false; | ||||
Show All 11 Lines | bool Seek(uint64_t nPos) { | ||||
return false; | return false; | ||||
} | } | ||||
nLongPos = ftell(src); | nLongPos = ftell(src); | ||||
nSrcPos = nLongPos; | nSrcPos = nLongPos; | ||||
nReadPos = nLongPos; | nReadPos = nLongPos; | ||||
return true; | return true; | ||||
} | } | ||||
// Prevent reading beyond a certain position. No argument removes the limit. | //! Prevent reading beyond a certain position. No argument removes the | ||||
//! limit. | |||||
bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) { | bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) { | ||||
if (nPos < nReadPos) { | if (nPos < nReadPos) { | ||||
return false; | return false; | ||||
} | } | ||||
nReadLimit = nPos; | nReadLimit = nPos; | ||||
return true; | return true; | ||||
} | } | ||||
template <typename T> CBufferedFile &operator>>(T &&obj) { | template <typename T> CBufferedFile &operator>>(T &&obj) { | ||||
// Unserialize from this stream | // Unserialize from this stream | ||||
::Unserialize(*this, obj); | ::Unserialize(*this, obj); | ||||
return (*this); | return (*this); | ||||
} | } | ||||
// search for a given byte in the stream, and remain positioned on it | //! search for a given byte in the stream, and remain positioned on it | ||||
void FindByte(char ch) { | void FindByte(char ch) { | ||||
while (true) { | while (true) { | ||||
if (nReadPos == nSrcPos) { | if (nReadPos == nSrcPos) { | ||||
Fill(); | Fill(); | ||||
} | } | ||||
if (vchBuf[nReadPos % vchBuf.size()] == ch) { | if (vchBuf[nReadPos % vchBuf.size()] == ch) { | ||||
break; | break; | ||||
} | } | ||||
nReadPos++; | nReadPos++; | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
#endif // BITCOIN_STREAMS_H | #endif // BITCOIN_STREAMS_H |