#include <iostream>
#include <vector>
enum Endian
{
LITTLE,
BIG,
};
// template the function so we don't have to write it more than once
template <typename RT> // RT = read type
RT read_type(const std::vector<uint8_t>& buf, size_t idx, Endian end = LITTLE)
// takes a const ref to the buffer, this prevents us (to some degree)
// from modifying it in the function
// size_t is just an unsigned int64
{
RT* conv_buf = (RT*)&buf[0]; // interpret the ptr to the first element of the buff as
// a ptr to the type we want to read as
// because the memory is contiguous, we can index this ptr
if (end == LITTLE)
{
return conv_buf[idx]; // it's already little endian, so just index and return
}
else
{
const auto type_size = sizeof(RT); // byte size of the read type
RT val = conv_buf[idx]; // copy the value of the section we're looking at
uint8_t* interm_buf = (uint8_t*)&val; // reinterpret the copied value's ptr as a byte
// again, it's contiguous in memory, so we can index it safely
for (int iii = 0; iii < (type_size / 2); iii++)
{
// for until halfway through the copied value (we're looking at its bytes)
// swap the opposite bytes
auto& a = interm_buf[iii];
auto& b = interm_buf[type_size - iii - 1];
std::swap(a, b);
}
return val; // return the value, because we were modifying the copy directly.
}
}
int main() {
std::vector<uint8_t> buf = { 0xfc, 0xc5, 0x3f, 0x2a, 0x4c, 0x53, 0x7d, 0xef };
printf("%.4lx\n", read_type<uint16_t>(buf, 3, BIG));
printf("%.8lx\n", read_type<uint32_t>(buf, 1, BIG));
printf("%.16lx\n", read_type<uint64_t>(buf, 0, BIG));
return 0;
}