ByteConverter specialization can write to provided buffer

dependabot/npm_and_yarn/Src/WebController/UI/websocket-extensions-0.1.4
Pawel Kurowski 2020-03-18 13:37:29 +01:00
parent 83478fa403
commit 73a9aba7db
5 changed files with 89 additions and 86 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -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.

View File

@ -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);
}

View File

@ -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;
}