mirror of https://github.com/infosecn1nja/C3.git
ByteConverter specialization can write to provided buffer
parent
83478fa403
commit
73a9aba7db
|
@ -13,14 +13,12 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize arithmetic type to ByteVector.
|
||||
/// @param obj. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(T obj)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(T obj, ByteVector& bv)
|
||||
{
|
||||
auto ret = ByteVector{};
|
||||
ret.resize(sizeof(T));
|
||||
*reinterpret_cast<T*>(ret.data()) = obj;
|
||||
|
||||
return ret;
|
||||
auto oldSize = bv.size();
|
||||
bv.resize(oldSize + Size());
|
||||
*reinterpret_cast<T*>(bv.data() + oldSize) = obj;
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
@ -39,8 +37,8 @@ namespace FSecure
|
|||
throw std::out_of_range{ OBF(": Cannot read size from ByteView ") };
|
||||
|
||||
T ret;
|
||||
memcpy(&ret, bv.data(), sizeof(T));
|
||||
bv.remove_prefix(sizeof(T));
|
||||
memcpy(&ret, bv.data(), Size());
|
||||
bv.remove_prefix(Size());
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
@ -51,10 +49,10 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize enum type to ByteVector.
|
||||
/// @param enumInstance. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(T enumInstance)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(T enumInstance, ByteVector& bv)
|
||||
{
|
||||
return ByteVector::Create(static_cast<std::underlying_type_t<T>>(enumInstance));
|
||||
bv.Store(static_cast<std::underlying_type_t<T>>(enumInstance));
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
@ -79,20 +77,16 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize iterable type to ByteVector.
|
||||
/// @param obj. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(T const& obj)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(T const& obj, ByteVector& bv)
|
||||
{
|
||||
auto ret = ByteVector{};
|
||||
ret.reserve(ByteVector::Size(obj));
|
||||
if (auto numberOfElements = Utils::Container::Size<T>::Calculate(obj); numberOfElements <= std::numeric_limits<uint32_t>::max())
|
||||
ret.Write(static_cast<uint32_t>(numberOfElements));
|
||||
bv.Write(static_cast<uint32_t>(numberOfElements));
|
||||
else
|
||||
throw std::out_of_range{ OBF(": Cannot write size to ByteVector ") };
|
||||
|
||||
for (auto&& e : obj)
|
||||
ret.Write(e);
|
||||
|
||||
return ret;
|
||||
bv.Write(e);
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
@ -101,7 +95,7 @@ namespace FSecure
|
|||
{
|
||||
using Element = Utils::Container::StoredValue<T>;
|
||||
auto ret = sizeof(uint32_t);
|
||||
if constexpr (ByteSizeFunctionType<Element>::value == ByteSizeFunctionType<Element>::compileTime)
|
||||
if constexpr (ConverterDeduction<Element>::FunctionSize::value == ConverterDeduction<Element>::FunctionSize::compileTime)
|
||||
ret += ByteConverter<Element>::Size() * obj.size(); // avoid extra calls when size of stored type is known at compile time
|
||||
else
|
||||
for (auto const& e : obj)
|
||||
|
@ -143,10 +137,10 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize path type to ByteVector.
|
||||
/// @param pathInstance. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(std::filesystem::path const& pathInstance)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(std::filesystem::path const& pathInstance, ByteVector& bv)
|
||||
{
|
||||
return ByteVector::Create(pathInstance.wstring());
|
||||
bv.Store(pathInstance.wstring());
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
@ -207,13 +201,10 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize tuple type to ByteVector.
|
||||
/// @param tupleInstance. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(T const& tupleInstance)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(T const& tupleInstance, ByteVector& bv)
|
||||
{
|
||||
ByteVector ret;
|
||||
ret.reserve(Size(tupleInstance));
|
||||
TupleHandler<T>::Write(ret, tupleInstance);
|
||||
return ret;
|
||||
TupleHandler<T>::Write(bv, tupleInstance);
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
|
|
@ -18,34 +18,41 @@ namespace FSecure
|
|||
template <typename T, typename = void>
|
||||
struct ByteConverter {};
|
||||
|
||||
/// Check if FSecure namespace has function to get size of type T when it is stored to ByteVector.
|
||||
/// This class performs test that looks for implementation of Size function in ByteConverter<T>.
|
||||
/// Depending on test result 'value' is set to one of:
|
||||
/// absent - No implementation is available for Size function. Size can only be determined after serialization.
|
||||
/// compileTime - Size is determined by type, not object instance. Size() is constexpr function.
|
||||
/// runTime - Size depends on object instance. Size(T const&) can be used before serialization
|
||||
/// Class detecting specifics of ByteConverter specialization for given type.
|
||||
template <typename T>
|
||||
class ByteSizeFunctionType
|
||||
struct ConverterDeduction
|
||||
{
|
||||
template <typename C> static uint32_t test(decltype(FSecure::ByteConverter<C>::Size(std::declval<C>())));
|
||||
template <typename C> static uint16_t test(decltype(FSecure::ByteConverter<C>::Size()));
|
||||
template <typename C> static uint8_t test(...);
|
||||
class FunctionSize
|
||||
{
|
||||
template <typename C> static uint32_t test(decltype(ByteConverter<C>::Size(std::declval<C>())));
|
||||
template <typename C> static uint16_t test(decltype(ByteConverter<C>::Size()));
|
||||
template <typename C> static uint8_t test(...);
|
||||
|
||||
public:
|
||||
enum { absent = 0, compileTime = (sizeof(uint16_t) - sizeof(uint8_t)), runTime = (sizeof(uint32_t) - sizeof(uint8_t)) };
|
||||
enum { value = (sizeof(test<T>(0)) - sizeof(uint8_t)) };
|
||||
public:
|
||||
enum { absent = 1, compileTime = 2, runTime = 4 };
|
||||
enum { value = sizeof(test<T>(0)) };
|
||||
};
|
||||
|
||||
class FunctionTo
|
||||
{
|
||||
template <typename C> static uint32_t test(decltype(ByteConverter<C>::To(std::declval<C>(), std::declval<ByteVector&>()))*);
|
||||
template <typename C> static uint16_t test(decltype(ByteConverter<C>::To(std::declval<C>()))*);
|
||||
template <typename C> static uint8_t test(...);
|
||||
|
||||
public:
|
||||
enum { absent = 1, createsContainer = 2, expandsContainer = 4 };
|
||||
enum { value = sizeof(test<T>(0)) };
|
||||
};
|
||||
|
||||
static_assert(!((FunctionTo::value == FunctionTo::expandsContainer) && (FunctionSize::value == FunctionSize::absent)),
|
||||
"ByteConverter::Size must be defined, if function ByteConverter::To expands already allocated container.");
|
||||
};
|
||||
|
||||
/// Informs if for all provided types ByteConverter is declared.
|
||||
/// Checks if ByteConverter is defined for all types.
|
||||
template <typename ...Ts>
|
||||
class IsConverterDeclared
|
||||
struct WriteCondition
|
||||
{
|
||||
/// Type returned by ByteConverter::To if function was declared.
|
||||
template <typename T>
|
||||
using DecltypeTo = decltype(ByteConverter<T>::To(std::declval<T>()));
|
||||
public:
|
||||
|
||||
constexpr static bool value = Utils::IsSame<ByteVector, DecltypeTo<Ts>...>::value;
|
||||
static constexpr bool value = ((ConverterDeduction<Ts>::FunctionTo::value != ConverterDeduction<Ts>::FunctionTo::absent) && ...);
|
||||
};
|
||||
|
||||
/// An owning container.
|
||||
|
@ -161,7 +168,7 @@ namespace FSecure
|
|||
/// @param arg. Object to be stored.
|
||||
/// @param args. Optional other objects to be stored.
|
||||
/// @return itself to allow chaining.
|
||||
template <typename T, typename ...Ts, typename std::enable_if_t<IsConverterDeclared<T, Ts...>::value, int> = 0>
|
||||
template <typename T, typename ...Ts, typename std::enable_if_t<WriteCondition<T, Ts...>::value, int> = 0>
|
||||
ByteVector& Write(T const& arg, Ts const& ...args)
|
||||
{
|
||||
reserve(size() + Size<T, Ts...>(arg, args...));
|
||||
|
@ -197,7 +204,7 @@ namespace FSecure
|
|||
/// @param arg. Object to be stored.
|
||||
/// @param args. Optional other objects to be stored.
|
||||
/// @see ByteVector::Write for more informations.
|
||||
template <typename T, typename ...Ts>
|
||||
template <typename T, typename ...Ts, typename std::enable_if_t<WriteCondition<T, Ts...>::value, int> = 0>
|
||||
static ByteVector Create(T const& arg, Ts const& ...args)
|
||||
{
|
||||
return ByteVector{}.Write(arg, args...);
|
||||
|
@ -212,25 +219,33 @@ namespace FSecure
|
|||
{
|
||||
if constexpr (sizeof...(Ts) != 0)
|
||||
return Size(arg) + Size(args...);
|
||||
else if constexpr (ByteSizeFunctionType<T>::value == ByteSizeFunctionType<T>::compileTime)
|
||||
return FSecure::ByteConverter<T>::Size();
|
||||
else if constexpr (ByteSizeFunctionType<T>::value == ByteSizeFunctionType<T>::runTime)
|
||||
return FSecure::ByteConverter<T>::Size(arg);
|
||||
else if constexpr (ByteSizeFunctionType<T>::value == ByteSizeFunctionType<T>::absent)
|
||||
return FSecure::ByteConverter<T>::To(arg).size();
|
||||
else if constexpr (ConverterDeduction<T>::FunctionSize::value == ConverterDeduction<T>::FunctionSize::compileTime)
|
||||
return ByteConverter<T>::Size();
|
||||
else if constexpr (ConverterDeduction<T>::FunctionSize::value == ConverterDeduction<T>::FunctionSize::runTime)
|
||||
return ByteConverter<T>::Size(arg);
|
||||
else if constexpr (ConverterDeduction<T>::FunctionSize::value == ConverterDeduction<T>::FunctionSize::absent)
|
||||
return ByteConverter<T>::To(arg).size();
|
||||
}
|
||||
|
||||
private:
|
||||
/// Store custom type.
|
||||
/// @param args. Objects to be stored.
|
||||
/// @param arg. Object to be stored. There must exsist FSecure::ByteConverter<T>::To method avalible to store custom type.
|
||||
/// @param args. Rest of objects that will be handled with recursion.
|
||||
/// @return itself to allow chaining.
|
||||
template<typename ...Ts, typename std::enable_if_t<IsConverterDeclared<Ts...>::value, int> = 0>
|
||||
ByteVector & Store(Ts const& ...args)
|
||||
template<typename T, typename ...Ts, typename std::enable_if_t<WriteCondition<T, Ts...>::value, int> = 0>
|
||||
ByteVector& Store(T const& arg, Ts const& ...args)
|
||||
{
|
||||
auto oldSize = size();
|
||||
try
|
||||
{
|
||||
Concat(FSecure::ByteConverter<Ts>::To(args)...);
|
||||
if constexpr (ConverterDeduction<T>::FunctionTo::value == ConverterDeduction<T>::FunctionTo::createsContainer)
|
||||
Concat(ByteConverter<T>::To(arg));
|
||||
else
|
||||
ByteConverter<T>::To(arg, *this);
|
||||
|
||||
if constexpr (sizeof...(Ts) != 0)
|
||||
Store(args...);
|
||||
|
||||
return *this;
|
||||
}
|
||||
catch (...)
|
||||
|
@ -238,8 +253,11 @@ namespace FSecure
|
|||
resize(oldSize);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Declaration of friendship.
|
||||
template <typename , typename>
|
||||
friend struct ByteConverter;
|
||||
};
|
||||
|
||||
namespace Literals
|
||||
|
@ -247,7 +265,7 @@ namespace FSecure
|
|||
/// Create ByteVector with syntax ""_bvec
|
||||
inline ByteVector operator "" _b(const char* data, size_t size)
|
||||
{
|
||||
FSecure::ByteVector ret;
|
||||
ByteVector ret;
|
||||
ret.resize(size);
|
||||
std::memcpy(ret.data(), data, size);
|
||||
return ret;
|
||||
|
@ -256,7 +274,7 @@ namespace FSecure
|
|||
/// Create ByteVector with syntax L""_bvec
|
||||
inline ByteVector operator "" _b(const wchar_t* data, size_t size)
|
||||
{
|
||||
FSecure::ByteVector ret;
|
||||
ByteVector ret;
|
||||
ret.resize(size * sizeof(wchar_t));
|
||||
std::memcpy(ret.data(), data, size * sizeof(wchar_t));
|
||||
return ret;
|
||||
|
@ -266,7 +284,7 @@ namespace FSecure
|
|||
/// Checks if the contents of lhs and rhs are equal.
|
||||
/// @param lhs. Left hand side of operator.
|
||||
/// @param rhs. Right hand side of operator.
|
||||
inline bool operator==(FSecure::ByteVector const& lhs, FSecure::ByteVector const& rhs)
|
||||
inline bool operator==(ByteVector const& lhs, ByteVector const& rhs)
|
||||
{
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
|
@ -277,7 +295,7 @@ namespace FSecure
|
|||
/// Checks if the contents of lhs and rhs are equal.
|
||||
/// @param lhs. Left hand side of operator.
|
||||
/// @param rhs. Right hand side of operator.
|
||||
inline bool operator!=(FSecure::ByteVector const& lhs, FSecure::ByteVector const& rhs)
|
||||
inline bool operator!=(ByteVector const& lhs, ByteVector const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
|
|
@ -45,13 +45,10 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize HostInfo type to ByteVector.
|
||||
/// @param obj. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(OSVERSIONINFOEXA const& obj)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(OSVERSIONINFOEXA const& obj, ByteVector& bv)
|
||||
{
|
||||
auto ret = ByteVector{};
|
||||
ret.reserve(Size());
|
||||
ret.Write(obj.dwOSVersionInfoSize, obj.dwMajorVersion, obj.dwMinorVersion, obj.dwBuildNumber, obj.dwPlatformId, obj.wServicePackMajor, obj.wServicePackMinor, obj.wProductType);
|
||||
return ret;
|
||||
bv.Store(obj.dwOSVersionInfoSize, obj.dwMajorVersion, obj.dwMinorVersion, obj.dwBuildNumber, obj.dwPlatformId, obj.wServicePackMajor, obj.wServicePackMinor, obj.wProductType);
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
@ -80,13 +77,10 @@ namespace FSecure
|
|||
{
|
||||
/// Serialize HostInfo type to ByteVector.
|
||||
/// @param obj. Object to be serialized.
|
||||
/// @return ByteVector. Serialized data.
|
||||
static ByteVector To(HostInfo const& obj)
|
||||
/// @param bv. ByteVector to be expanded.
|
||||
static void To(HostInfo const& obj, ByteVector& bv)
|
||||
{
|
||||
auto ret = ByteVector{};
|
||||
ret.reserve(ByteVector::Size(obj));
|
||||
ret.Write(obj.m_ComputerName, obj.m_UserName, obj.m_Domain, obj.m_OsVersionInfo, obj.m_ProcessId, obj.m_IsElevated);
|
||||
return ret;
|
||||
bv.Store(obj.m_ComputerName, obj.m_UserName, obj.m_Domain, obj.m_OsVersionInfo, obj.m_ProcessId, obj.m_IsElevated);
|
||||
}
|
||||
|
||||
/// Get size required after serialization.
|
||||
|
|
|
@ -112,12 +112,12 @@ namespace FSecure
|
|||
template <typename T>
|
||||
struct ByteConverter <C3::Identifier<T>>
|
||||
{
|
||||
static ByteVector To(C3::Identifier<T> const& obj)
|
||||
static void To(C3::Identifier<T> const& obj, ByteVector& bv)
|
||||
{
|
||||
return ByteVector::Create(obj.ToUnderlyingType());
|
||||
bv.Store(obj.ToUnderlyingType());
|
||||
}
|
||||
|
||||
static size_t Size()
|
||||
constexpr static size_t Size()
|
||||
{
|
||||
return sizeof(typename C3::Identifier<T>::UnderlyingIntegerType);
|
||||
}
|
||||
|
|
|
@ -80,12 +80,12 @@ namespace FSecure
|
|||
template <>
|
||||
struct ByteConverter <C3::RouteId>
|
||||
{
|
||||
static ByteVector To(C3::RouteId const& obj)
|
||||
static void To(C3::RouteId const& obj, ByteVector& bv)
|
||||
{
|
||||
return ByteVector::Create(obj.GetAgentId(), obj.GetInterfaceId());
|
||||
bv.Store(obj.GetAgentId(), obj.GetInterfaceId());
|
||||
}
|
||||
|
||||
static size_t Size(C3::RouteId const& obj)
|
||||
constexpr static size_t Size()
|
||||
{
|
||||
return C3::RouteId::BinarySize;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue