Changeset View
Changeset View
Standalone View
Standalone View
src/streams.h
Show First 20 Lines • Show All 461 Lines • ▼ Show 20 Lines | void Xor(const std::vector<uint8_t> &key) { | ||||
// important that we calculate `j`, i.e. the `key` index in this way | // important that we calculate `j`, i.e. the `key` index in this way | ||||
// instead of doing a %, which would effectively be a division for | // instead of doing a %, which would effectively be a division for | ||||
// each byte Xor'd -- much slower than need be. | // each byte Xor'd -- much slower than need be. | ||||
if (j == key.size()) j = 0; | if (j == key.size()) j = 0; | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
template <typename IStream> class BitStreamReader { | |||||
private: | |||||
IStream &m_istream; | |||||
/// Buffered byte read in from the input stream. A new byte is read into the | |||||
/// buffer when m_offset reaches 8. | |||||
uint8_t m_buffer{0}; | |||||
/// Number of high order bits in m_buffer already returned by previous | |||||
/// Read() calls. The next bit to be returned is at this offset from the | |||||
/// most significant bit position. | |||||
int m_offset{8}; | |||||
public: | |||||
explicit BitStreamReader(IStream &istream) : m_istream(istream) {} | |||||
/** | |||||
* Read the specified number of bits from the stream. The data is returned | |||||
* in the nbits least significant bits of a 64-bit uint. | |||||
*/ | |||||
uint64_t Read(int nbits) { | |||||
if (nbits < 0 || nbits > 64) { | |||||
throw std::out_of_range("nbits must be between 0 and 64"); | |||||
} | |||||
uint64_t data = 0; | |||||
while (nbits > 0) { | |||||
if (m_offset == 8) { | |||||
m_istream >> m_buffer; | |||||
m_offset = 0; | |||||
} | |||||
int bits = std::min(8 - m_offset, nbits); | |||||
data <<= bits; | |||||
data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits); | |||||
m_offset += bits; | |||||
nbits -= bits; | |||||
} | |||||
return data; | |||||
} | |||||
}; | |||||
template <typename OStream> class BitStreamWriter { | |||||
private: | |||||
OStream &m_ostream; | |||||
/// Buffered byte waiting to be written to the output stream. The byte is | |||||
/// written buffer when m_offset reaches 8 or Flush() is called. | |||||
uint8_t m_buffer{0}; | |||||
/// Number of high order bits in m_buffer already written by previous | |||||
/// Write() calls and not yet flushed to the stream. The next bit to be | |||||
/// written to is at this offset from the most significant bit position. | |||||
int m_offset{0}; | |||||
public: | |||||
explicit BitStreamWriter(OStream &ostream) : m_ostream(ostream) {} | |||||
~BitStreamWriter() { Flush(); } | |||||
/** | |||||
* Write the nbits least significant bits of a 64-bit int to the output | |||||
* stream. Data is buffered until it completes an octet. | |||||
*/ | |||||
void Write(uint64_t data, int nbits) { | |||||
if (nbits < 0 || nbits > 64) { | |||||
throw std::out_of_range("nbits must be between 0 and 64"); | |||||
} | |||||
while (nbits > 0) { | |||||
int bits = std::min(8 - m_offset, nbits); | |||||
m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset); | |||||
m_offset += bits; | |||||
nbits -= bits; | |||||
if (m_offset == 8) { | |||||
Flush(); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Flush any unwritten bits to the output stream, padding with 0's to the | |||||
* next byte boundary. | |||||
*/ | |||||
void Flush() { | |||||
if (m_offset == 0) { | |||||
return; | |||||
} | |||||
m_ostream << m_buffer; | |||||
m_buffer = 0; | |||||
m_offset = 0; | |||||
} | |||||
}; | |||||
/** | /** | ||||
* Non-refcounted RAII wrapper for FILE* | * Non-refcounted RAII wrapper for FILE* | ||||
* | * | ||||
* 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're returning the file pointer, return file.release(). If you need to | * you're returning the file pointer, return file.release(). If you need to | ||||
* close the file early, use file.fclose() instead of fclose(file). | * close the file early, use file.fclose() instead of fclose(file). | ||||
*/ | */ | ||||
class CAutoFile { | class CAutoFile { | ||||
▲ Show 20 Lines • Show All 247 Lines • Show Last 20 Lines |