1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
#include "./binaryreader.h"
#include "../conversion/conversionexception.h"
#include <cstring>
#include <sstream>
using namespace std;
namespace CppUtilities {
/*!
* \class BinaryReader
* \brief Reads primitive data types from a std::istream.
* \remarks Supports both, little endian and big endian.
* \sa For automatic serialization of structs, see https://github.com/Martchus/reflective-rapidjson.
*/
/*!
* \brief Assigns the stream the reader will read from when calling one of the read-methods.
*
* You can assign a null pointer when ensuring that none of the read-methods is called
* until a stream is assigned.
*
* \param stream Specifies the stream to be assigned.
* \param giveOwnership Specifies whether the reader should take ownership.
*
* \sa setStream()
*/
void BinaryReader::setStream(istream *stream, bool giveOwnership)
{
if (m_ownership) {
delete m_stream;
}
if (stream) {
m_stream = stream;
m_ownership = giveOwnership;
} else {
m_stream = nullptr;
m_ownership = false;
}
}
/*!
* \brief Returns the size of the assigned stream.
* \remarks
* - The size is determined by seeking to the end of the stream and returning this offset.
* - The method will seek back to the previous offset before returning.
*/
istream::pos_type BinaryReader::readStreamsize()
{
istream::pos_type cp = m_stream->tellg();
m_stream->seekg(0, ios_base::end);
const auto streamsize = m_stream->tellg();
m_stream->seekg(cp);
return streamsize;
}
/*!
* \brief Returns the number of remaining bytes in the stream from the current offset.
* \remarks
* - This is achieved by seeking to the end of the stream.
* - The method will seek back to the previous offset before returning.
*/
istream::pos_type BinaryReader::readRemainingBytes()
{
istream::pos_type cp = m_stream->tellg();
m_stream->seekg(0, ios_base::end);
const auto streamsize = m_stream->tellg();
m_stream->seekg(cp);
return streamsize - cp;
}
void BinaryReader::bufferVariableLengthInteger()
{
static constexpr int maxPrefixLength = 8;
int prefixLength = 1;
const auto beg = static_cast<std::uint8_t>(m_stream->peek());
std::uint8_t mask = 0x80;
while (prefixLength <= maxPrefixLength && (beg & mask) == 0) {
++prefixLength;
mask >>= 1;
}
if (prefixLength > maxPrefixLength) {
throw ConversionException("Length denotation of variable length unsigned integer exceeds maximum.");
}
memset(m_buffer, 0, maxPrefixLength);
m_stream->read(m_buffer + (maxPrefixLength - prefixLength), prefixLength);
*(m_buffer + (maxPrefixLength - prefixLength)) ^= static_cast<char>(mask);
}
/*!
* \brief Reads a string from the current stream of the given \a length from the stream and advances the current position of the stream by \a length byte.
*/
string BinaryReader::readString(size_t length)
{
string res;
res.resize(length);
m_stream->read(&res[0], static_cast<streamsize>(length));
return res;
}
/*!
* \brief Reads a terminated string from the current stream.
*
* Advances the current position of the stream by the string length plus one byte.
*
* \param termination The byte to be recognized as termination value.
*/
std::string BinaryReader::readTerminatedString(std::uint8_t termination)
{
stringstream ss(ios_base::in | ios_base::out | ios_base::binary);
ss.exceptions(ios_base::badbit | ios_base::failbit);
m_stream->get(*ss.rdbuf(), static_cast<char>(termination)); // delim byte is not extracted from the stream
m_stream->seekg(1, ios_base::cur); // "extract" delim byte manually
return ss.str();
}
/*!
* \brief Reads a terminated string from the current stream.
*
* Advances the current position of the stream by the string length plus one byte
* but maximal by \a maxBytesToRead.
*
* \param maxBytesToRead The maximal number of bytes to read.
* \param termination The value to be recognized as termination.
*/
string BinaryReader::readTerminatedString(std::size_t maxBytesToRead, std::uint8_t termination)
{
string res;
res.reserve(maxBytesToRead);
while (res.size() < maxBytesToRead) {
const auto c = static_cast<char>(m_stream->get());
if (static_cast<std::uint8_t>(c) == termination) {
return res;
}
res += c;
}
return res;
}
/*!
* \brief Reads \a length bytes from the stream and computes the CRC-32 for that block of data.
*
* \remarks Cyclic redundancy check (CRC) is an error-detecting code commonly used in
* digital networks and storage devices to detect accidental changes to raw data.
* \remarks Ogg compatible version
* \sa <a href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">Cyclic redundancy check - Wikipedia</a>
*/
std::uint32_t BinaryReader::readCrc32(size_t length)
{
std::uint32_t crc = 0x00;
for (std::uint32_t i = 0; i < length; ++i) {
crc = (crc << 8) ^ crc32Table[((crc >> 24) & 0xff) ^ static_cast<std::uint8_t>(m_stream->get())];
}
return crc;
}
/*!
* \brief Reads \a length bytes from the buffer and computes the CRC-32 for that block of data.
*
* \remarks Cyclic redundancy check (CRC) is an error-detecting code commonly used in
* digital networks and storage devices to detect accidental changes to raw data.
* \remarks Ogg compatible version
* \sa <a href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">Cyclic redundancy check - Wikipedia</a>
*/
std::uint32_t BinaryReader::computeCrc32(const char *buffer, size_t length)
{
std::uint32_t crc = 0x00;
for (const char *i = buffer, *end = buffer + length; i != end; ++i) {
crc = (crc << 8) ^ crc32Table[((crc >> 24) & 0xff) ^ static_cast<std::uint8_t>(*i)];
}
return crc;
}
/*!
* \brief CRC-32 table.
* \remarks Internally used by readCrc32() method.
* \sa readCrc32()
*/
const std::uint32_t BinaryReader::crc32Table[] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 };
} // namespace CppUtilities
|