Newer
Older
#include <string>
#include <cstring>
#include <algorithm>
using Structure = std::vector<std::tuple<uint, std::string, uint>>;
uint byteSize;
std::vector<uint> fieldSizes;
std::unordered_map<uint, uint> indexToOffsetsMap;
std::unordered_map<std::string, uint> fieldNameToIndexMap;
std::unordered_map<uint, std::string> indexToFieldNameMap;
std::function<Structure(std::string)> sourceReadingFunc;
std::for_each(paramsTuple.begin(), paramsTuple.end(),
this->fieldSizes.push_back(std::get<2>(tup));
});
}
void updateFieldNameAndIndexMap(const Structure ¶msTuple) {
std::for_each(paramsTuple.begin(), paramsTuple.end(),
this->fieldNameToIndexMap[std::get<1>(tup)] = std::get<0>(
tup);
this->indexToFieldNameMap[std::get<0>(tup)] = std::get<1>(
tup);
});
}
this->structure = sourceReadingFunc(source);
updateFieldSizes(structure);
updateFieldOffsets(structure);
updateFieldNameAndIndexMap(structure);
uint bitSize = std::accumulate(fieldSizes.begin(), fieldSizes.end(), 0);
this->byteSize = bitSize % 8 == 0 ? bitSize / 8 : bitSize / 8 + 1;
}
public:
virtual ~BasePacketStructure() = default;
BasePacketStructure(std::string source,
std::function<Structure(std::string)> sourceReadingFunc) :
source(source), sourceReadingFunc(sourceReadingFunc) {
}
;
BasePacketStructure(const BasePacketStructure &other) {
this->source = other.source;
this->byteSize = other.byteSize;
this->fieldSizes = other.fieldSizes;
this->indexToOffsetsMap = other.indexToOffsetsMap;
this->fieldNameToIndexMap = other.fieldNameToIndexMap;
this->indexToFieldNameMap = other.indexToFieldNameMap;
this->sourceReadingFunc = other.sourceReadingFunc;
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "No field at " << index
<< ", max is " << numberOfFields() << ", returning nullopt."
<< std::endl;
if (index <= this->numberOfFields()) {
return this->fieldSizes[index];
} else {
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "No field at " << index
<< ", max is " << numberOfFields() << ", returning nullopt."
<< std::endl;
std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(),
[](unsigned char c) {
return std::tolower(c);
});
try {
return this->fieldNameToIndexMap.at(fieldName);
} catch (const std::out_of_range &oor) {
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "No field of name " << fieldName
<< ", returning nullopt." << std::endl;
return std::nullopt;
}
}
try {
return this->indexToFieldNameMap.at(index);
} catch (const std::out_of_range &oor) {
time_t now = time(nullptr);
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "No field at " << index
<< ", max is " << numberOfFields() << ", returning nullopt."
<< std::endl;
std::unordered_map<std::string, uint> getFieldNameToIndexMap() const {
std::unordered_map<uint, uint> getIndexToOffsetsMap() const{
return this->indexToOffsetsMap;
}
std::unordered_map<uint, std::string> getIndexToFieldNameMap() const {
return this->indexToFieldNameMap;
}
using iterator_category = std::random_access_iterator_tag;
using value_type = ValueType;
using difference_type = std::ptrdiff_t;
using pointer = ValueType*;
using reference = ValueType&;
bit_iterator(const uint8_t *data, int offset,
BasePacketStructure *structure,
m_data(data), m_offset(offset), m_structure(structure), m_func(func) {
}
bit_iterator(const bit_iterator &other) :
m_data(other.m_data), m_offset(other.m_offset), m_structure(
other.m_structure), m_func(other.m_func) {
}
bit_iterator& operator++() {
++m_offset;
return *this;
}
bit_iterator operator++(int) {
bit_iterator temp(*this);
++m_offset;
return temp;
}
bit_iterator& operator--() {
--m_offset;
return *this;
}
bit_iterator operator--(int) {
bit_iterator temp(*this);
--m_offset;
return temp;
}
bit_iterator operator+(int n) const {
return bit_iterator(m_data, m_offset + n, m_structure, m_func);
return bit_iterator(m_data, m_offset - n, m_structure, m_func);
}
int operator-(const bit_iterator &other) const {
return m_offset - other.m_offset;
}
bool operator==(const bit_iterator &other) const {
return m_data == other.m_data && m_offset == other.m_offset;
}
bool operator!=(const bit_iterator &other) const {
return !(*this == other);
}
ValueType operator*() const {
auto offset = m_structure->bitOffsetOf(m_offset); // offset from the beginning of the byte
auto num_bits = m_structure->bitSizeOf(m_offset);
return m_func(m_data, offset.value(), num_bits.value());
}
private:
const uint8_t *m_data;
int m_offset;
};
template<typename ValueType>
class BasePacketTempl {
BasePacketStructure *packetStructure;
uint8_t *memoryPointer;
// This C++ function reads a binary value from a memory location pointed to by binaryPointer.
// The binary value is represented by num_bits number of bits starting from the offset-th bit in the memory.
// The function returns the value of the binary as a ValueType.
static ValueType _readValueFromMemoryAt_(const uint8_t *binaryPointer,
// Calculate the bit offset from the byte offset:
// Calculate the byte offset from the bit offset:
// Calculate the byte and bit index of the current bit:
uint byte_index = byte_offset + (bit_offset + i) / 8;
uint bit_index = (bit_offset + i) % 8;
// Create a bit mask to isolate the desired bit:
// Set the corresponding bit in the return value if the retrieved bit is 1:
value |= (byte & bit_mask) ? ( bit << (num_bits - i - 1)) : 0;
size_t minBitsRequired(size_t value) const {
BasePacketTempl(BasePacketStructure &structure) {
this->packetStructure = new BasePacketStructure(structure);
this->memoryPointer = new uint8_t[structure.getByteSize()];
this->packetStructure = new BasePacketStructure(other.getPacketStructure());
this->memoryPointer = new uint8_t[other.packetStructure->getByteSize()];
std::memcpy(this->memoryPointer, other.memoryPointer,
other.packetStructure->getByteSize());
void updatePacketStructure(BasePacketStructure &structure) {
std::memcpy(buff, memoryPointer, std::min(newSize, oldSize));
delete this->memoryPointer;
this->memoryPointer = new uint8_t[newSize];
std::memcpy(memoryPointer, buff, newSize);
std::optional<ValueType> readValueFromMemoryAt(uint index) const {
auto offset = packetStructure->bitOffsetOf(index); // offset from the beginning of the byte
auto num_bits = packetStructure->bitSizeOf(index); //remaining bits to read
if (offset.has_value() && num_bits.has_value())
return _readValueFromMemoryAt_(memoryPointer, offset.value(),
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "Error: No field at " << index
uint8_t const* getPointerToMemory() const {
return memoryPointer;
int copyToMemory(const uint8_t *from, uint size) {
uint max_writable = this->packetStructure->getByteSize();
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "Error: you are trying to copy "
<< size << " byte where the max size is: " << max_writable
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "\tI copy only until "
<< max_writable << " byte" << std::endl;
int copyToMemory(const uint8_t *from, uint size, uint offset) {
uint max_writable = this->packetStructure->getByteSize();
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t"
<< "Error: you are trying to copy starting from " << offset
<< " byte where the max size is: " << max_writable
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "Error: you are trying to copy "
<< size + offset << " byte where the max size is: "
<< max_writable << std::endl;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "\tI copy only until "
<< max_writable << " byte" << std::endl;
std::optional<ValueType> operator[](uint index) const {
std::optional<ValueType> operator[](std::string fieldName) const {
std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(),
[](unsigned char c) {
return std::tolower(c);
});
return bit_iterator<ValueType>(memoryPointer, 0, packetStructure,
&_readValueFromMemoryAt_);
return bit_iterator<ValueType>(memoryPointer,
packetStructure->numberOfFields(), packetStructure,
&_readValueFromMemoryAt_);
std::optional<uint> writeValueIntoMemoryAtIndex(uint index, ValueType value) {
auto offset = this->packetStructure->bitOffsetOf(index);
auto numbits = this->packetStructure->bitSizeOf(index);
size_t min_req = minBitsRequired(value);
if (!offset.has_value() || !numbits.has_value())
return std::nullopt;
if (numbits < min_req) {
time_t now = time(nullptr) ;
std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S")
<< "]\t[Base Packet]\t" << "Error: you are trying to write "
<< value << " which requires at least " << min_req
<< " bits in a field of size " << numbits << std::endl;
return std::nullopt;
}
// Calculate the bit offset from the byte offset:
uint byteoffset = offset.value() / 8;
uint numbits_written = 0;
for (size_t i = 0; i < numbits; i++) {
// Calculate the byte and bit index of the current bit:
uint byte_index = byteoffset + (bitoffset + i) / 8;
uint bit_index = (bitoffset + i) % 8;
// Create a bit mask to isolate the desired bit:
uint8_t bit_mask = 1 << (7 - bit_index);
// Set the corresponding bit in the binary array if the value is 1:
if ((value >> (numbits.value() - i - 1)) & 1) {
}
BasePacketStructure& getPacketStructure() const {
virtual bool isRecognizedHeader(std::vector<uint8_t> buff) const = 0;
virtual uint getHeaderSize() const = 0;
virtual uint getPayloadSize() const = 0;
virtual uint getTailSize() const = 0;
class BasePacket: public BasePacketTempl<valueType> {
}
virtual ~BasePacket() = default;
};