#ifndef BYTEARRAY_H
#define BYTEARRAY_H
#include <iomanip>
#include <ostream>
#include <stdint.h>
#include <type_traits>
#include <vector>
namespace util {
inline uint16_t
readU16BE(
const uint8_t *data,
size_t index) {
return (static_cast<uint16_t>(data[index]) << 8) |
static_cast<uint16_t>(data[index + 1]);
}
inline uint32_t
readU32BE(
const uint8_t *data,
size_t index) {
return (static_cast<uint32_t>(data[index]) << 24) |
(static_cast<uint32_t>(data[index + 1]) << 16) |
(static_cast<uint32_t>(data[index + 2]) << 8) |
static_cast<uint32_t>(data[index + 3]);
}
}
struct ByteArray : std::vector<uint8_t> {
explicit ByteArray(
const uint8_t *data,
size_t size) : std::vector<uint8_t>(data, data + size) {}
ByteArray(
const std::initializer_list<uint8_t> &init_list) : std::vector<uint8_t>(init_list) {}
if (index + 1 >= this->size()) {
throw std::out_of_range("Index out of range for writeU16BE");
}
(*this)[index] = static_cast<uint8_t>((value >> 8) & 0xFF);
(*this)[index + 1] = static_cast<uint8_t>(value & 0xFF);
}
emplace_back(static_cast<uint8_t>((value >> 8) & 0xFF));
emplace_back(static_cast<uint8_t>(value & 0xFF));
}
if (index + 3 >= this->size()) {
throw std::out_of_range("Index out of range for writeU32BE");
}
(*this)[index] = static_cast<uint8_t>((value >> 24) & 0xFF);
(*this)[index + 1] = static_cast<uint8_t>((value >> 16) & 0xFF);
(*this)[index + 2] = static_cast<uint8_t>((value >> 8) & 0xFF);
(*this)[index + 3] = static_cast<uint8_t>(value & 0xFF);
}
emplace_back(static_cast<uint8_t>((value >> 24) & 0xFF));
emplace_back(static_cast<uint8_t>((value >> 16) & 0xFF));
emplace_back(static_cast<uint8_t>((value >> 8) & 0xFF));
emplace_back(static_cast<uint8_t>(value & 0xFF));
}
template<typename E>
static_assert(std::is_enum_v<E>, "writeEnum requires an enum type");
using UnderlyingType = std::underlying_type_t<E>;
auto integral_value = static_cast<UnderlyingType>(value);
if constexpr (sizeof(UnderlyingType) == 1) {
emplace_back(static_cast<uint8_t>(integral_value));
} else if constexpr (sizeof(UnderlyingType) == 2) {
writeU16BE(
static_cast<uint16_t
>(integral_value));
} else if constexpr (sizeof(UnderlyingType) == 4) {
writeU32BE(
static_cast<uint32_t
>(integral_value));
} else {
static_assert(sizeof(UnderlyingType) <= 4, "Enum underlying type too large (max 32-bit supported)");
}
}
template<typename E>
static_assert(std::is_enum_v<E>, "writeEnumAt requires an enum type");
using UnderlyingType = std::underlying_type_t<E>;
auto integral_value = static_cast<UnderlyingType>(value);
if constexpr (sizeof(UnderlyingType) == 1) {
if (index >= this->size()) {
throw std::out_of_range("Index out of range for writeEnumAt");
}
(*this)[index] = static_cast<uint8_t>(integral_value);
} else if constexpr (sizeof(UnderlyingType) == 2) {
writeU16At(index,
static_cast<uint16_t
>(integral_value));
} else if constexpr (sizeof(UnderlyingType) == 4) {
writeU32At(index,
static_cast<uint32_t
>(integral_value));
} else {
static_assert(sizeof(UnderlyingType) <= 4, "Enum underlying type too large (max 32-bit supported)");
}
}
if (index + 1 >= this->size()) {
throw std::out_of_range("Index out of range for readU16BE");
}
}
if (index + 3 >= this->size()) {
throw std::out_of_range("Index out of range for readU32BE");
}
}
template<typename E>
static_assert(std::is_enum_v<E>, "readEnum requires an enum type");
using UnderlyingType = std::underlying_type_t<E>;
if constexpr (sizeof(UnderlyingType) == 1) {
if (index >= this->size()) {
throw std::out_of_range("Index out of range for readEnum");
}
return static_cast<E>((*this)[index]);
} else if constexpr (sizeof(UnderlyingType) == 2) {
} else if constexpr (sizeof(UnderlyingType) == 4) {
} else {
static_assert(sizeof(UnderlyingType) <= 4, "Enum underlying type too large (max 32-bit supported)");
}
}
};
inline std::ostream &
operator<<(std::ostream &os,
const ByteArray &arr) {
std::ios_base::fmtflags flags(os.flags());
for (size_t i = 0; i < arr.size(); ++i) {
if (i > 0) {
os << '.';
}
os << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
<< static_cast<unsigned int>(arr[i]);
}
os.flags(flags);
return os;
}
}
#endif
uint32_t readU32BE(const uint8_t *data, size_t index)
Reads a 32-bit unsigned integer in big-endian format from a byte array.
uint16_t readU16BE(const uint8_t *data, size_t index)
Reads a 16-bit unsigned integer in big-endian format from a byte array.
std::pair< const uint8_t *, size_t > ByteArrayRef
Reference to raw array of bytes.
std::ostream & operator<<(std::ostream &os, const ByteArray &arr)
Stream operator for ByteArray.
ByteArray()=default
Default constructor - creates an empty ByteArray.
E readEnum(size_t index) const
uint16_t readU16BE(size_t index) const
Reads a 16-bit unsigned integer in big-endian format from a specific index.
void writeEnumAt(size_t index, E value)
Writes an enum class value at a specific index as its underlying integral type.
void writeU16At(size_t index, uint16_t value)
Writes a 16-bit unsigned integer in big-endian format at a specific index.
void writeU32BE(uint32_t value)
Appends a 32-bit unsigned integer in big-endian format to the end.
void writeU32At(size_t index, uint32_t value)
Writes a 32-bit unsigned integer in big-endian format at a specific index.
uint32_t readU32BE(size_t index) const
Reads a 32-bit unsigned integer in big-endian format from a specific index.
void writeU16BE(uint16_t value)
Appends a 16-bit unsigned integer in big-endian format to the end.