Files
SimControl/include/CommService/Convert.hpp
Henry Winkel cc67e4840f Squashed 'libs/CommService/' content from commit 7ccc0fc
git-subtree-dir: libs/CommService
git-subtree-split: 7ccc0fce88bbc5969df060058cf0fb57abe3bcf9
2022-09-15 09:53:53 +02:00

241 lines
7.8 KiB
C++

#ifndef NETWORKBUFFCONVERT
#define NETWORKBUFFCONVERT
#include <cstring>
#include <stdexcept>
#include <vector>
#include <string>
namespace CommService {
class Convert{
public:
/*
* @brief template function to byte swap int/uint datatypes - used for endianess conversion
*
* @param v - pointer to a variable of some int/uint datatype - in place byte swapped
*/
template <typename T>
static void swapBytes(T *v) {
for (unsigned int i = 0; i < sizeof(T)/2; ++i)
{
std::swap(((char *)v)[i], ((char *)v)[sizeof(T)-1-i]);
}
}
/**
* @brief function to convert a std::vector<unsigned char> to an simple datatype
*
* this is the partner function to fromSimpleToByteArray.
* it extracts the simple datatype like int, double, etc. from the vector and
* returns it
*
* @param v - the vector to convert to a simple datatype
* @return simple datatype
* @throw std::invalid_argument: "the bytevector is too small to fit the datatype"
*/
template<typename T>
static T fromByteArrayToSimple(std::vector<unsigned char> &bytes)
{
T convVariable;
if(bytes.size() < sizeof(T))
{
throw(std::invalid_argument(std::string(__FILE__) + ":" + std::string(__PRETTY_FUNCTION__) + ":" + std::to_string(__LINE__) + ": the bytevector is too small to fit the datatype"));
}
std::memcpy(reinterpret_cast<unsigned char*>(&convVariable),bytes.data(),sizeof(T));
#ifndef IS_BIG_ENDIAN
swapBytes(&convVariable);
#endif
return std::move(convVariable);
}
/**
* @brief template for converting of simple datatypes to a byte_array, including endianness conversion to big endian
*
* @param variable - the variable to convert to a byte vector, needs to be int/uint datatype
*
* @return the std::vector<unsigned char>
*/
template<typename T>
static std::vector<unsigned char> fromSimpleToByteArray(T &variable)
{
std::vector<unsigned char> bytes;
bytes.clear();
bytes.resize(sizeof(T));
#ifndef IS_BIG_ENDIAN
T convVariable = variable;
swapBytes(&convVariable);
std::memcpy(bytes.data(),reinterpret_cast<const unsigned char*>(&convVariable),sizeof(T));
#else
std::memcpy(bytes.data(),reinterpret_cast<const unsigned char*>(&variable),sizeof(T));
#endif
return bytes;
}
/**
* @brief function to convert a container of a simple datatype to a std::vector<unsigned char>
*
* this is the partner function to fromByteArrayToSimpleContainer.
* the number of container elements is prepended to the std::vector and the simple datatype
* elements follow.
*
* @param data - the container of a simple datatype
*
* @return the std::vector<unsigned char>;
*/
template<class T>
static std::vector<unsigned char> fromSimpleContainerToByteArray(T &data)
{
std::vector<unsigned char> bytes;
std::vector<unsigned char> convert;
uint32_t size=data.size();
bytes=fromSimpleToByteArray(size);
for(auto it = data.begin(); it!=data.end(); ++it)
{
convert=fromSimpleToByteArray(*it);
bytes.insert(std::end(bytes), std::begin(convert), std::end(convert));
}
return bytes;
}
/**
* @brief function to convert a std::vector<unsigned char> to a container of simple datatype elements
*
* this is the partner function to fromSimpleContainerToByteArray. It takes the
* first 4 byte of the vector as an uint32_t element count and parses the all the elements
* from the vector.
*
* @param v - the vector to convert to a container of simple datatype elements
*
* @return the container
*/
template<class T, typename S>
static T fromByteArrayToSimpleContainer(std::vector<unsigned char> &v)
{
T data;
uint32_t size = fromByteArrayToSimple<S>(v);
v.erase(v.begin(), v.begin()+sizeof(size));
for(uint32_t i=0; i<size; i++)
{
S convert = fromByteArrayToSimple<S>(v);
v.erase(v.begin(), v.begin()+sizeof(convert));
data.push_back(convert);
}
return std::move(data);
}
/**
* @brief function to convert a std::string to an std::vector<unsigned char>
*
* for converting the string, first the length of the string is converted as
* an uint32_t into the std::vector to be able to correctly parse the string
* in a larger vector.
*
* @param variable - the std::string to convert
*
* @return the std::vector<unsigned char>
*/
static std::vector<unsigned char> fromStringToByteArray(const std::string &variable)
{
std::vector<unsigned char> bytes;
uint32_t size=variable.length();
bytes=fromSimpleToByteArray(size);
bytes.insert(std::end(bytes),std::begin(variable), std::end(variable));
return bytes;
}
/**
* @brief function to convert a std::vector<unsigned char> to an std::string
*
* this is the partner function to fromStringToByteArray. It takes the
* first 4 byte of the vector as an uint32_t string length identifier and
* uses the following length chars as the string
*
* @param v - the vector to convert to a string
* @return the string read from the vector
* @throw std::invalid_argument: "vector too short for <X> chars"
*/
static std::string fromByteArrayToString(std::vector<unsigned char> &v)
{
uint32_t length=fromByteArrayToSimple<uint32_t>(v);
if (v.size()-sizeof(uint32_t) < length)
{
throw(std::invalid_argument(std::string(__FILE__) + ":" + std::string(__PRETTY_FUNCTION__) + ":" + std::to_string(__LINE__) + ": vector too short for " + std::to_string(length) + " chars"));
}
std::string str(v.begin()+sizeof(uint32_t), v.begin()+sizeof(uint32_t)+length) ;
return str;
}
/**
* @brief function to convert a container of strings to a std::vector<unsigned char>
*
* @param data - the container of std::string
*
* @return the std::vector<unsigned char>
*/
template<class T>
static std::vector<unsigned char> fromStringContainerToByteArray(T &data)
{
std::vector<unsigned char> bytes;
std::vector<unsigned char> convert;
uint32_t size=data.size();
bytes=fromSimpleToByteArray(size);
for(auto it = data.begin(); it!=data.end(); ++it)
{
convert=fromStringToByteArray(*it);
bytes.insert(std::end(bytes), std::begin(convert), std::end(convert));
}
return bytes;
}
/**
* @brief function to convert a std::vector<unsigned char> to a container of strings
*
* @param data - the container of std::string
*
* @return the std::vector<unsigned char>
*/
template<class T>
static T fromByteArrayToStringContainer(std::vector<unsigned char> &v)
{
T data;
uint32_t size = fromByteArrayToSimple<uint32_t>(v);
v.erase(v.begin(), v.begin()+sizeof(size));
for(uint32_t i=0; i<size; i++)
{
std::string convert = fromByteArrayToString(v);
data.push_back(convert);
}
return std::move(data);
}
};
};
#endif