Changeset View
Changeset View
Standalone View
Standalone View
src/streams.h
Show First 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | public: | ||||
* @param[in] nPosIn Starting position. Vector index where writes should | * @param[in] nPosIn Starting position. Vector index where writes should | ||||
* start. The vector will initially grow as necessary to max(nPosIn, | * start. The vector will initially grow as necessary to max(nPosIn, | ||||
* vec.size()). So to append, use vec.size(). | * vec.size()). So to append, use vec.size(). | ||||
*/ | */ | ||||
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<uint8_t> &vchDataIn, | CVectorWriter(int nTypeIn, int nVersionIn, std::vector<uint8_t> &vchDataIn, | ||||
size_t nPosIn) | size_t nPosIn) | ||||
: nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), | : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), | ||||
nPos(nPosIn) { | nPos(nPosIn) { | ||||
if (nPos > vchData.size()) vchData.resize(nPos); | if (nPos > vchData.size()) { | ||||
vchData.resize(nPos); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
* (other params same as above) | * (other params same as above) | ||||
* @param[in] args A list of items to serialize starting at nPosIn. | * @param[in] args A list of items to serialize starting at nPosIn. | ||||
*/ | */ | ||||
template <typename... Args> | template <typename... Args> | ||||
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<uint8_t> &vchDataIn, | CVectorWriter(int nTypeIn, int nVersionIn, std::vector<uint8_t> &vchDataIn, | ||||
size_t nPosIn, Args &&... args) | size_t nPosIn, Args &&... args) | ||||
Show All 18 Lines | template <typename T> CVectorWriter &operator<<(const T &obj) { | ||||
// Serialize to this stream | // Serialize to this stream | ||||
::Serialize(*this, obj); | ::Serialize(*this, obj); | ||||
return (*this); | return (*this); | ||||
} | } | ||||
int GetVersion() const { return nVersion; } | int GetVersion() const { return nVersion; } | ||||
int GetType() const { return nType; } | int GetType() const { return nType; } | ||||
void seek(size_t nSize) { | void seek(size_t nSize) { | ||||
nPos += nSize; | nPos += nSize; | ||||
if (nPos > vchData.size()) vchData.resize(nPos); | if (nPos > vchData.size()) { | ||||
vchData.resize(nPos); | |||||
} | |||||
} | } | ||||
private: | private: | ||||
const int nType; | const int nType; | ||||
const int nVersion; | const int nVersion; | ||||
std::vector<uint8_t> &vchData; | std::vector<uint8_t> &vchData; | ||||
size_t nPos; | size_t nPos; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | public: | ||||
inline void Compact() { | inline void Compact() { | ||||
vch.erase(vch.begin(), vch.begin() + nReadPos); | vch.erase(vch.begin(), vch.begin() + nReadPos); | ||||
nReadPos = 0; | nReadPos = 0; | ||||
} | } | ||||
bool Rewind(size_type n) { | bool Rewind(size_type n) { | ||||
// Rewind by n characters if the buffer hasn't been compacted yet | // Rewind by n characters if the buffer hasn't been compacted yet | ||||
if (n > nReadPos) return false; | if (n > nReadPos) { | ||||
return false; | |||||
} | |||||
nReadPos -= n; | nReadPos -= n; | ||||
return true; | return true; | ||||
} | } | ||||
// | // | ||||
// Stream subset | // Stream subset | ||||
// | // | ||||
bool eof() const { return size() == 0; } | bool eof() const { return size() == 0; } | ||||
Show All 27 Lines | public: | ||||
void ignore(int nSize) { | void ignore(int nSize) { | ||||
// Ignore from the beginning of the buffer | // Ignore from the beginning of the buffer | ||||
if (nSize < 0) { | if (nSize < 0) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CDataStream::ignore(): nSize negative"); | "CDataStream::ignore(): nSize negative"); | ||||
} | } | ||||
unsigned int nReadPosNext = nReadPos + nSize; | unsigned int nReadPosNext = nReadPos + nSize; | ||||
if (nReadPosNext >= vch.size()) { | if (nReadPosNext >= vch.size()) { | ||||
if (nReadPosNext > vch.size()) | if (nReadPosNext > vch.size()) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CDataStream::ignore(): end of data"); | "CDataStream::ignore(): end of data"); | ||||
} | |||||
nReadPos = 0; | nReadPos = 0; | ||||
vch.clear(); | vch.clear(); | ||||
return; | return; | ||||
} | } | ||||
nReadPos = nReadPosNext; | nReadPos = nReadPosNext; | ||||
} | } | ||||
void write(const char *pch, size_t nSize) { | void write(const char *pch, size_t nSize) { | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | public: | ||||
// | // | ||||
// Stream subset | // Stream subset | ||||
// | // | ||||
int GetType() const { return nType; } | int GetType() const { return nType; } | ||||
int GetVersion() const { return nVersion; } | int GetVersion() const { return nVersion; } | ||||
void read(char *pch, size_t nSize) { | void read(char *pch, size_t nSize) { | ||||
if (!file) | if (!file) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CAutoFile::read: file handle is nullptr"); | "CAutoFile::read: file handle is nullptr"); | ||||
if (fread(pch, 1, nSize, file) != nSize) | } | ||||
if (fread(pch, 1, nSize, file) != nSize) { | |||||
throw std::ios_base::failure(feof(file) | throw std::ios_base::failure(feof(file) | ||||
? "CAutoFile::read: end of file" | ? "CAutoFile::read: end of file" | ||||
: "CAutoFile::read: fread failed"); | : "CAutoFile::read: fread failed"); | ||||
} | } | ||||
} | |||||
void ignore(size_t nSize) { | void ignore(size_t nSize) { | ||||
if (!file) | if (!file) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CAutoFile::ignore: file handle is nullptr"); | "CAutoFile::ignore: file handle is nullptr"); | ||||
} | |||||
uint8_t data[4096]; | uint8_t data[4096]; | ||||
while (nSize > 0) { | while (nSize > 0) { | ||||
size_t nNow = std::min<size_t>(nSize, sizeof(data)); | size_t nNow = std::min<size_t>(nSize, sizeof(data)); | ||||
if (fread(data, 1, nNow, file) != nNow) | if (fread(data, 1, nNow, file) != nNow) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
feof(file) ? "CAutoFile::ignore: end of file" | feof(file) ? "CAutoFile::ignore: end of file" | ||||
: "CAutoFile::read: fread failed"); | : "CAutoFile::read: fread failed"); | ||||
} | |||||
nSize -= nNow; | nSize -= nNow; | ||||
} | } | ||||
} | } | ||||
void write(const char *pch, size_t nSize) { | void write(const char *pch, size_t nSize) { | ||||
if (!file) | if (!file) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CAutoFile::write: file handle is nullptr"); | "CAutoFile::write: file handle is nullptr"); | ||||
if (fwrite(pch, 1, nSize, file) != nSize) | } | ||||
if (fwrite(pch, 1, nSize, file) != nSize) { | |||||
throw std::ios_base::failure("CAutoFile::write: write failed"); | throw std::ios_base::failure("CAutoFile::write: write failed"); | ||||
} | } | ||||
} | |||||
template <typename T> CAutoFile &operator<<(const T &obj) { | template <typename T> CAutoFile &operator<<(const T &obj) { | ||||
// Serialize to this stream | // Serialize to this stream | ||||
if (!file) | if (!file) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CAutoFile::operator<<: file handle is nullptr"); | "CAutoFile::operator<<: file handle is nullptr"); | ||||
} | |||||
::Serialize(*this, obj); | ::Serialize(*this, obj); | ||||
return (*this); | return (*this); | ||||
} | } | ||||
template <typename T> CAutoFile &operator>>(T &&obj) { | template <typename T> CAutoFile &operator>>(T &&obj) { | ||||
// Unserialize from this stream | // Unserialize from this stream | ||||
if (!file) | if (!file) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"CAutoFile::operator>>: file handle is nullptr"); | "CAutoFile::operator>>: file handle is nullptr"); | ||||
} | |||||
::Unserialize(*this, obj); | ::Unserialize(*this, obj); | ||||
return (*this); | return (*this); | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
* Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to | * Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to | ||||
* deserialize from. It guarantees the ability to rewind a given number of | * deserialize from. It guarantees the ability to rewind a given number of | ||||
Show All 21 Lines | private: | ||||
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) readNow = nAvail; | if (nAvail < readNow) { | ||||
if (readNow == 0) return false; | readNow = nAvail; | ||||
} | |||||
if (readNow == 0) { | |||||
return false; | |||||
} | |||||
size_t nBytes = fread((void *)&vchBuf[pos], 1, readNow, src); | size_t nBytes = fread((void *)&vchBuf[pos], 1, readNow, src); | ||||
if (nBytes == 0) { | if (nBytes == 0) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
feof(src) ? "CBufferedFile::Fill: end of file" | feof(src) ? "CBufferedFile::Fill: end of file" | ||||
: "CBufferedFile::Fill: fread failed"); | : "CBufferedFile::Fill: fread failed"); | ||||
} else { | } else { | ||||
nSrcPos += nBytes; | nSrcPos += nBytes; | ||||
return true; | return true; | ||||
Show All 24 Lines | void fclose() { | ||||
} | } | ||||
} | } | ||||
// 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) { | ||||
if (nReadPos == nSrcPos) Fill(); | if (nReadPos == nSrcPos) { | ||||
Fill(); | |||||
} | |||||
unsigned int pos = nReadPos % vchBuf.size(); | unsigned int pos = nReadPos % vchBuf.size(); | ||||
size_t nNow = nSize; | size_t nNow = nSize; | ||||
if (nNow + pos > vchBuf.size()) nNow = vchBuf.size() - pos; | if (nNow + pos > vchBuf.size()) { | ||||
if (nNow + nReadPos > nSrcPos) nNow = nSrcPos - nReadPos; | nNow = vchBuf.size() - pos; | ||||
} | |||||
if (nNow + nReadPos > nSrcPos) { | |||||
nNow = nSrcPos - nReadPos; | |||||
} | |||||
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 | ||||
Show All 10 Lines | bool SetPos(uint64_t nPos) { | ||||
return false; | return false; | ||||
} else { | } else { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
bool Seek(uint64_t nPos) { | bool Seek(uint64_t nPos) { | ||||
long nLongPos = nPos; | long nLongPos = nPos; | ||||
if (nPos != (uint64_t)nLongPos) return false; | if (nPos != (uint64_t)nLongPos) { | ||||
if (fseek(src, nLongPos, SEEK_SET)) return false; | return false; | ||||
} | |||||
if (fseek(src, nLongPos, SEEK_SET)) { | |||||
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 = (uint64_t)(-1)) { | bool SetLimit(uint64_t nPos = (uint64_t)(-1)) { | ||||
if (nPos < nReadPos) return false; | if (nPos < nReadPos) { | ||||
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) Fill(); | if (nReadPos == nSrcPos) { | ||||
if (vchBuf[nReadPos % vchBuf.size()] == ch) break; | Fill(); | ||||
} | |||||
if (vchBuf[nReadPos % vchBuf.size()] == ch) { | |||||
break; | |||||
} | |||||
nReadPos++; | nReadPos++; | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
#endif // BITCOIN_STREAMS_H | #endif // BITCOIN_STREAMS_H |