mirror of https://github.com/infosecn1nja/C3.git
Use improved, header only ByteView/ByteVector
parent
08c3087aa7
commit
97a0a76dfa
|
@ -22,10 +22,7 @@
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Interfaces\Peripherals\Beacon.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Interfaces\Peripherals\Beacon.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\Interface.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\Interface.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\InterfaceFactory.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\InterfaceFactory.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteVector.cpp" />
|
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteView.cpp" />
|
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\Utils.cpp" />
|
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Crypto\Sodium.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Crypto\Sodium.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Slack\SlackApi.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Slack\SlackApi.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Sockets\AddrInfo.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Sockets\AddrInfo.cpp" />
|
||||||
|
@ -64,6 +61,7 @@
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\PrecompiledHeader.hpp" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\PrecompiledHeader.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\Sdk.hpp" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\Sdk.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteArray.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteArray.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteConverter.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteVector.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteVector.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteView.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteView.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.h" />
|
||||||
|
@ -72,8 +70,8 @@
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\PrecompiledHeader.hpp" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\PrecompiledHeader.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\SafeSmartPointerContainer.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\SafeSmartPointerContainer.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ScopeGuard.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ScopeGuard.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\SecureString.hpp" />
|
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Utils.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Utils.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\SecureString.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\XError.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\XError.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base32.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base32.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base64.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base64.h" />
|
||||||
|
|
|
@ -8,10 +8,7 @@
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Interfaces\Peripherals\Beacon.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Interfaces\Peripherals\Beacon.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\Interface.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\Interface.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\InterfaceFactory.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\InterfaceFactory.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteVector.cpp" />
|
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteView.cpp" />
|
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\CppTools\Utils.cpp" />
|
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Crypto\Sodium.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Crypto\Sodium.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Sockets\AddrInfo.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Sockets\AddrInfo.cpp" />
|
||||||
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Sockets\InitializeSockets.cpp" />
|
<ClCompile Include="$(MSBuildThisFileDirectory)MWR\Sockets\InitializeSockets.cpp" />
|
||||||
|
@ -42,15 +39,11 @@
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\InterfaceFactory.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\Internals\InterfaceFactory.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\PrecompiledHeader.hpp" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\PrecompiledHeader.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\Sdk.hpp" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\C3\Sdk.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteArray.h" />
|
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteVector.h" />
|
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteView.h" />
|
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Encryption.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Hash.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Hash.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Payload.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Payload.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\PrecompiledHeader.hpp" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\PrecompiledHeader.hpp" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ScopeGuard.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ScopeGuard.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Utils.h" />
|
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\XError.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\XError.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base32.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base32.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base64.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\Crypto\Base64.h" />
|
||||||
|
@ -88,5 +81,10 @@
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\WinTools\StructuredExceptionHandling.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\WinTools\StructuredExceptionHandling.h" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)C3_BUILD_VERSION_HASH_PART.hxx" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)C3_BUILD_VERSION_HASH_PART.hxx" />
|
||||||
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\WinTools\InjectionBuffer.h" />
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\WinTools\InjectionBuffer.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteArray.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteConverter.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteVector.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\ByteView.h" />
|
||||||
|
<ClInclude Include="$(MSBuildThisFileDirectory)MWR\CppTools\Utils.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,337 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ByteView.h"
|
||||||
|
|
||||||
|
/// Example code of specializing ByteConverter for custom type A.
|
||||||
|
//struct A
|
||||||
|
//{
|
||||||
|
// uint16_t m_a, m_b;
|
||||||
|
//
|
||||||
|
// A(uint16_t a, uint16_t b) : m_a(a), m_b(b) {}
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//namespace MWR
|
||||||
|
//{
|
||||||
|
// template <>
|
||||||
|
// struct ByteConverter<A>
|
||||||
|
// {
|
||||||
|
// static ByteVector To(A const& a)
|
||||||
|
// {
|
||||||
|
// return ByteVector::Create(a.m_a, a.m_b);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// static size_t Size(A const& a)
|
||||||
|
// {
|
||||||
|
// return 2 * sizeof(uint16_t);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// static A From(ByteView& bv)
|
||||||
|
// {
|
||||||
|
// auto [a, b] = bv.Read<uint16_t, uint16_t>();
|
||||||
|
// return A(a, b);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//}
|
||||||
|
|
||||||
|
// specializations for ByteConverter for common types.
|
||||||
|
namespace MWR
|
||||||
|
{
|
||||||
|
// ByteConverter specialization for enums.
|
||||||
|
template <typename T>
|
||||||
|
struct ByteConverter<T, std::enable_if_t<std::is_enum_v<T>>>
|
||||||
|
{
|
||||||
|
static ByteVector To(T obj)
|
||||||
|
{
|
||||||
|
return ByteVector::Create(static_cast<std::underlying_type_t<T>>(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static size_t Size()
|
||||||
|
{
|
||||||
|
return sizeof(std::underlying_type_t<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T From(ByteView& bv)
|
||||||
|
{
|
||||||
|
return static_cast<T>(bv.Read<std::underlying_type_t<T>>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for std::pair<>.
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct ByteConverter<std::pair<T1, T2>>
|
||||||
|
{
|
||||||
|
static ByteVector To(std::pair<T1, T2> const& obj)
|
||||||
|
{
|
||||||
|
return ByteVector::Create(obj.first, obj.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Size(std::pair<T1, T2> const& obj)
|
||||||
|
{
|
||||||
|
return ByteVector::Size(obj.first) + ByteVector::Size(obj.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<T1, T2> From(ByteView& bv)
|
||||||
|
{
|
||||||
|
auto [t1, t2] = bv.Read<T1, T2>();
|
||||||
|
return { std::move(t1), std::move(t2) };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for std::filesystem::path.
|
||||||
|
template <>
|
||||||
|
struct ByteConverter<std::filesystem::path>
|
||||||
|
{
|
||||||
|
static ByteVector To(std::filesystem::path const& obj)
|
||||||
|
{
|
||||||
|
return ByteVector::Create(obj.wstring());
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Size(std::filesystem::path const& obj)
|
||||||
|
{
|
||||||
|
return ByteVector::Size(obj.wstring());
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::filesystem::path From(ByteView& bv)
|
||||||
|
{
|
||||||
|
return { bv.Read<std::wstring>() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for std::byte.
|
||||||
|
template <>
|
||||||
|
struct ByteConverter<std::byte>
|
||||||
|
{
|
||||||
|
static ByteVector To(std::byte obj)
|
||||||
|
{
|
||||||
|
return ByteVector::Create(static_cast<unsigned char>(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static size_t Size()
|
||||||
|
{
|
||||||
|
return sizeof(unsigned char);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::byte From(ByteView& bv)
|
||||||
|
{
|
||||||
|
return static_cast<std::byte>(bv.Read<unsigned char>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Class allowing reading N bytes without coping data like in ByeView::Read<ByteArray<N>> or ByteView::Reed(size_t).
|
||||||
|
/// Using Bytes class in read will return ByteView with requested size using simple syntax:
|
||||||
|
/// someByteViewObject.Read<int, int, Bytes<7>, std::string>
|
||||||
|
template<size_t N>
|
||||||
|
class Bytes
|
||||||
|
{
|
||||||
|
/// This class should never be instantiated.
|
||||||
|
Bytes() = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for MWR::Bytes.
|
||||||
|
template <size_t N>
|
||||||
|
struct ByteConverter<MWR::Bytes<N>>
|
||||||
|
{
|
||||||
|
static ByteView From(ByteView& bv)
|
||||||
|
{
|
||||||
|
if (N > bv.size())
|
||||||
|
throw std::out_of_range{ OBF(": Cannot read data from ByteView") };
|
||||||
|
|
||||||
|
auto retVal = bv.SubString(0, N);
|
||||||
|
bv.remove_prefix(N);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for vector types.
|
||||||
|
template <typename T>
|
||||||
|
struct ByteConverter<std::vector<T>>
|
||||||
|
{
|
||||||
|
static ByteVector To(std::vector<T> const& obj)
|
||||||
|
{
|
||||||
|
ByteVector ret;
|
||||||
|
ret.reserve(ByteVector::Size(obj));
|
||||||
|
ret.Write(static_cast<uint32_t>(obj.size()));
|
||||||
|
for (auto const& e : obj)
|
||||||
|
ret.Concat(ByteVector::Create(e));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Size(std::vector<T> const& obj)
|
||||||
|
{
|
||||||
|
size_t size = sizeof(uint32_t); //four bytes for vector size.
|
||||||
|
for (auto const& e : obj)
|
||||||
|
size += ByteVector::Size(e);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<T> From(ByteView& bv)
|
||||||
|
{
|
||||||
|
std::vector<T> ret;
|
||||||
|
auto size = bv.Read<uint32_t>();
|
||||||
|
ret.reserve(size);
|
||||||
|
for (auto i = 0u; i < size; ++i)
|
||||||
|
ret.push_back(bv.Read<T>());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for map types.
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct ByteConverter<std::map<T1, T2>>
|
||||||
|
{
|
||||||
|
static ByteVector To(std::map<T1, T2> const& obj)
|
||||||
|
{
|
||||||
|
ByteVector ret;
|
||||||
|
ret.reserve(ByteVector::Size(obj));
|
||||||
|
ret.Write(static_cast<uint32_t>(obj.size()));
|
||||||
|
for (auto const& [key, val] : obj)
|
||||||
|
ret.Concat(ByteVector::Create(key, val));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Size(std::map<T1, T2> const& obj)
|
||||||
|
{
|
||||||
|
size_t size = sizeof(uint32_t); //four bytes for map size.
|
||||||
|
for (auto const& [key, val] : obj)
|
||||||
|
size += ByteVector::Size(key) + ByteVector::Size(val);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<T1, T2> From(ByteView& bv)
|
||||||
|
{
|
||||||
|
std::map<T1, T2> ret;
|
||||||
|
auto size = bv.Read<uint32_t>();
|
||||||
|
for (auto i = 0u; i < size; ++i)
|
||||||
|
{
|
||||||
|
auto [key, val] = bv.Read<T1, T2>();
|
||||||
|
ret.emplace(std::move(key), std::move(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for std:array.
|
||||||
|
template <typename T, size_t N>
|
||||||
|
struct ByteConverter<std::array<T, N>>
|
||||||
|
{
|
||||||
|
static ByteVector To(std::array<T, N> const& obj)
|
||||||
|
{
|
||||||
|
ByteVector ret;
|
||||||
|
ret.reserve(ByteVector::Size(obj));
|
||||||
|
for (auto const& e : obj)
|
||||||
|
ret.Write(e);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Size(std::array<T, N> const& obj)
|
||||||
|
{
|
||||||
|
auto ret = size_t{ 0 };
|
||||||
|
if constexpr (std::is_arithmetic_v<T>)
|
||||||
|
{
|
||||||
|
static_cast<void>(obj);
|
||||||
|
ret = sizeof(T) * N; // avoid extra calls when size of array is known.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto const& e : obj)
|
||||||
|
ret += ByteVector::Size(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::array<T, N> From(ByteView& bv)
|
||||||
|
{
|
||||||
|
// T might not be default constructible, array must be filled like aggregator,
|
||||||
|
// order of reading from ByteView would depend on calling convention.
|
||||||
|
std::vector<T> temp;
|
||||||
|
temp.reserve(N);
|
||||||
|
for (auto i = 0u; i < N; ++i)
|
||||||
|
temp.push_back(bv.Read<T>());
|
||||||
|
|
||||||
|
return MakeArray(std::move(temp), std::make_index_sequence<N>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<size_t...Is>
|
||||||
|
static std::array<T, N> MakeArray(std::vector<T>&& vec, std::index_sequence<Is...>)
|
||||||
|
{
|
||||||
|
return { std::move(vec[Is])... };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ByteConverter specialization for tuple.
|
||||||
|
template <typename T>
|
||||||
|
struct ByteConverter<T, std::enable_if_t<Utils::IsTuple<T>>>
|
||||||
|
{
|
||||||
|
static ByteVector To(T const& obj)
|
||||||
|
{
|
||||||
|
ByteVector ret;
|
||||||
|
ret.reserve(Size(obj));
|
||||||
|
TupleHandler<T>::Write(ret, obj);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Size(T const& obj)
|
||||||
|
{
|
||||||
|
return TupleHandler<T>::Size(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto From(ByteView& bv)
|
||||||
|
{
|
||||||
|
return TupleHandler<T>::Read(bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @tparam T. Tuple type to read/write.
|
||||||
|
/// @tparam N. How many elements of tuple to handle. Functions will use recursion, decrementing N with each call.
|
||||||
|
template <typename T, size_t N = std::tuple_size_v<T>>
|
||||||
|
struct TupleHandler
|
||||||
|
{
|
||||||
|
/// Function responsible for recursively packing data to ByteVector.
|
||||||
|
/// @param self. Reference to ByteVector object using VariadicWriter.
|
||||||
|
/// @param t. reference to tuple.
|
||||||
|
static void Write(ByteVector& self, T const& t)
|
||||||
|
{
|
||||||
|
if constexpr (N != 0)
|
||||||
|
{
|
||||||
|
self.Write(std::get<std::tuple_size_v<T> - N>(t));
|
||||||
|
TupleHandler<T, N - 1>::Write(self, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function responsible for recursively calculating buffer size needed for call with tuple argument.
|
||||||
|
/// @return size_t number of bytes needed.
|
||||||
|
static size_t Size(T const& t)
|
||||||
|
{
|
||||||
|
if constexpr (N != 0)
|
||||||
|
return ByteVector::Size(std::get<std::tuple_size_v<T> - N>(t)) + TupleHandler<T, N - 1>::Size(t);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function responsible for recursively packing data to tuple.
|
||||||
|
/// @param self. Reference to ByteView object using generate method.
|
||||||
|
static auto Read(ByteView& self)
|
||||||
|
{
|
||||||
|
if constexpr (N != 0)
|
||||||
|
{
|
||||||
|
auto current = std::make_tuple(self.Read<std::tuple_element_t<std::tuple_size_v<T> - N, T>>());
|
||||||
|
auto rest = TupleHandler<T, N - 1>::Read(self);
|
||||||
|
return std::tuple_cat(current, rest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::tuple<>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,82 +0,0 @@
|
||||||
#include "StdAfx.h"
|
|
||||||
#include "ByteVector.h"
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector::~ByteVector()
|
|
||||||
{
|
|
||||||
// Increase OpSec by clearing memory when ByteVector is not needed anymore.
|
|
||||||
SecureZeroMemory(data(), size());
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector::ByteVector(ByteVector const& other)
|
|
||||||
: Super(static_cast<Super const&>(other))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector::ByteVector(ByteVector&& other)
|
|
||||||
: Super(static_cast<Super&&>(other))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector::ByteVector(std::vector<uint8_t> other)
|
|
||||||
: Super(std::move(other))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector& MWR::ByteVector::operator=(ByteVector const& other)
|
|
||||||
{
|
|
||||||
auto tmp = Super{ static_cast<Super const&>(other) };
|
|
||||||
std::swap(static_cast<Super&>(*this), tmp);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector& MWR::ByteVector::operator=(ByteVector&& other)
|
|
||||||
{
|
|
||||||
std::swap(static_cast<Super&>(*this), static_cast<Super&>(other));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool MWR::operator==(ByteVector const& lhs, ByteVector const& rhs)
|
|
||||||
{
|
|
||||||
if (lhs.size() != rhs.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < lhs.size(); ++i)
|
|
||||||
if (lhs[i] != rhs[i])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool MWR::operator!=(ByteVector const& lhs, ByteVector const& rhs)
|
|
||||||
{
|
|
||||||
return !(lhs == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector MWR::Literals::operator "" _b(const char* data, size_t size)
|
|
||||||
{
|
|
||||||
MWR::ByteVector ret;
|
|
||||||
ret.resize(size);
|
|
||||||
std::memcpy(ret.data(), data, size);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector MWR::Literals::operator "" _b(const wchar_t* data, size_t size)
|
|
||||||
{
|
|
||||||
MWR::ByteVector ret;
|
|
||||||
ret.resize(size * sizeof(wchar_t));
|
|
||||||
std::memcpy(ret.data(), data, size * sizeof(wchar_t));
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ByteArray.h"
|
#include "ByteArray.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
namespace MWR
|
namespace MWR
|
||||||
{
|
{
|
||||||
|
@ -9,77 +10,21 @@ namespace MWR
|
||||||
class ByteVector;
|
class ByteVector;
|
||||||
|
|
||||||
/// Empty template of class that can convert data from and to byte form.
|
/// Empty template of class that can convert data from and to byte form.
|
||||||
/// @tparam T. Custom type that will work with byte containers using this converter type.
|
/// Look for example in ByteConventer.h
|
||||||
/// Specialize this class to add methods:
|
template <typename T, typename = void>
|
||||||
/// static ByteVector To(T const&);
|
|
||||||
/// Used to write data.
|
|
||||||
/// static T From(ByteView&);
|
|
||||||
/// Used to retrieve data.
|
|
||||||
/// Function must move ByteView& argument to position after the data that was retrieved.
|
|
||||||
/// static size_t Size(T const&);
|
|
||||||
/// Used to calculate size that type will need to be stored in ByteVector.
|
|
||||||
/// This function is not mandatory. If not provided function `To` will be called twice.
|
|
||||||
/// Once to calculate size for ByteVector allocation, and a second time to copy data.
|
|
||||||
template <typename T>
|
|
||||||
struct ByteConverter {};
|
struct ByteConverter {};
|
||||||
|
|
||||||
/// Example code of specializing ByteConverter for custom type A.
|
|
||||||
//struct A
|
|
||||||
//{
|
|
||||||
// uint16_t m_a, m_b;
|
|
||||||
|
|
||||||
// A(uint16_t a, uint16_t b) : m_a(a), m_b(b) {}
|
|
||||||
//};
|
|
||||||
|
|
||||||
//namespace MWR
|
|
||||||
//{
|
|
||||||
// template <>
|
|
||||||
// struct ByteConverter<A>
|
|
||||||
// {
|
|
||||||
// static ByteVector To(A const& a)
|
|
||||||
// {
|
|
||||||
// return ByteVector::Create(a.m_a, a.m_b);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static size_t Size(A const& a)
|
|
||||||
// {
|
|
||||||
// return 2 * sizeof(uint16_t);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static A From(ByteView& bv)
|
|
||||||
// {
|
|
||||||
// auto [a, b] = bv.Read<uint16_t, uint16_t>();
|
|
||||||
// return A(a, b);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// Idiom for detecting tuple types.
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool IsTuple = false;
|
|
||||||
template<typename ...T>
|
|
||||||
constexpr bool IsTuple<std::tuple<T...>> = true;
|
|
||||||
|
|
||||||
/// Alias finding Store method return type.
|
|
||||||
/// Should be used with MWR::Utils::CanApply, and not directly.
|
|
||||||
template<class T, class...Ts>
|
|
||||||
using StoreReturnType = decltype(std::declval<T>().Store(std::declval<bool>(), std::declval<Ts>()...));
|
|
||||||
|
|
||||||
/// Alias for testing if type can be stored in ByteVector.
|
|
||||||
/// Expresion CanStoreType<int, double, std::string>::value will be true.
|
|
||||||
/// Expresion CanStoreType<SomeCustomType>::value will be false.
|
|
||||||
template<class...Ts>
|
|
||||||
using CanStoreType = MWR::Utils::CanApply<StoreReturnType, ByteVector, Ts...>;
|
|
||||||
|
|
||||||
/// Check if MWR namespace has function to get size of type T when it is stored to ByteVector.
|
/// Check if MWR namespace has function to get size of type T when it is stored to ByteVector.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class GotByteSize
|
class ByteSizeFunctionType
|
||||||
{
|
{
|
||||||
template <typename C> static uint8_t test(decltype(MWR::ByteConverter<T>::Size(std::declval<T>())));
|
template <typename C> static uint32_t test(decltype(MWR::ByteConverter<T>::Size(std::declval<C>())));
|
||||||
template <typename C> static uint16_t test(...);
|
template <typename C> static uint16_t test(decltype(MWR::ByteConverter<T>::Size(std::void_t<C>)));
|
||||||
|
template <typename C> static uint8_t test(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { value = sizeof(test<T>(0)) == sizeof(uint8_t) };
|
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)) };
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An owning container.
|
/// An owning container.
|
||||||
|
@ -93,27 +38,52 @@ namespace MWR
|
||||||
using ValueType = Super::value_type;
|
using ValueType = Super::value_type;
|
||||||
|
|
||||||
/// Destructor zeroing memory.
|
/// Destructor zeroing memory.
|
||||||
~ByteVector();
|
~ByteVector()
|
||||||
|
{
|
||||||
|
// Increase OpSec by clearing memory when ByteVector is not needed anymore.
|
||||||
|
Utils::SecureMemzero(data(), size());
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy constructor.
|
/// Copy constructor.
|
||||||
/// @param other. Object to copy.
|
/// @param other. Object to copy.
|
||||||
ByteVector(ByteVector const& other);
|
ByteVector(ByteVector const& other)
|
||||||
|
: Super(static_cast<Super const&>(other))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Move constructor.
|
/// Move constructor.
|
||||||
/// @param other. Object to move.
|
/// @param other. Object to move.
|
||||||
ByteVector(ByteVector&& other);
|
ByteVector(ByteVector&& other)
|
||||||
|
: Super(static_cast<Super&&>(other))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy assignment operator.
|
/// Copy assignment operator.
|
||||||
/// @param other. Object to copy.
|
/// @param other. Object to copy.
|
||||||
ByteVector& operator=(ByteVector const& other);
|
ByteVector& operator=(ByteVector const& other)
|
||||||
|
{
|
||||||
|
auto tmp = Super{ static_cast<Super const&>(other) };
|
||||||
|
std::swap(static_cast<Super&>(*this), tmp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// Move assignment operator.
|
/// Move assignment operator.
|
||||||
/// @param other. Object to move.
|
/// @param other. Object to move.
|
||||||
ByteVector& operator=(ByteVector&& other);
|
ByteVector& operator=(ByteVector&& other)
|
||||||
|
{
|
||||||
|
std::swap(static_cast<Super&>(*this), static_cast<Super&>(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create from std::vector.
|
/// Create from std::vector.
|
||||||
/// @param other. Object to copy.
|
/// @param other. Object to copy.
|
||||||
ByteVector(std::vector<uint8_t> other);
|
ByteVector(std::vector<uint8_t> other)
|
||||||
|
: Super(std::move(other))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Enable methods.
|
// Enable methods.
|
||||||
using Super::vector;
|
using Super::vector;
|
||||||
|
@ -165,57 +135,57 @@ namespace MWR
|
||||||
/// Writes 4 Bytes header with size for types that have variable buffer length.
|
/// Writes 4 Bytes header with size for types that have variable buffer length.
|
||||||
/// @tparam T. Types to be stored.
|
/// @tparam T. Types to be stored.
|
||||||
/// @return itself to allow chaining.
|
/// @return itself to allow chaining.
|
||||||
template <typename ...T, typename std::enable_if_t<CanStoreType<T...>::value, int> = 0>
|
template <typename ...T>
|
||||||
ByteVector & Write(T const& ...args)
|
ByteVector & Write(T const& ...args)
|
||||||
{
|
{
|
||||||
reserve(size() + CalculateStoreSize<T...>(true, args...));
|
reserve(size() + Size<T...>(args...));
|
||||||
Store<T...>(true, args...);
|
Store<T...>(args...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write content of of provided objects.
|
/// Write content of of provided objects.
|
||||||
/// Suports arithmetic types, std::string, std::wstring, std::string_view, std::wstring_view, ByteVector and ByteArray, and std::tuple of those types.
|
/// Supports ByteView and ByteVector.
|
||||||
/// Does not write header with size for types that have variable buffer length. Recipient must know size in advance to read, therefore should use Read<ByteArray<someSize>>.
|
/// Does not write header with size.
|
||||||
/// @tparam T. Types to be stored.
|
|
||||||
/// @return itself to allow chaining.
|
/// @return itself to allow chaining.
|
||||||
template <typename ...T, typename std::enable_if_t<CanStoreType<T...>::value, int> = 0>
|
template <typename T, typename ...Ts, typename = std::enable_if_t<Utils::IsOneOf<T, ByteView, ByteVector>::value>>
|
||||||
ByteVector & Concat(T const& ...args)
|
ByteVector& Concat(T const& arg, Ts const& ...args)
|
||||||
{
|
{
|
||||||
reserve(size() + CalculateStoreSize<T...>(false, args...));
|
if constexpr (!sizeof...(Ts))
|
||||||
Store<T...>(false, args...);
|
{
|
||||||
|
auto oldSize = size();
|
||||||
|
resize(oldSize + arg.size());
|
||||||
|
memcpy(data() + oldSize, arg.data(), arg.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Concat(arg);
|
||||||
|
Concat(args...);
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// msvc can handle fold expression in debug mode, but fails with internal compiler error in release.
|
||||||
|
//template <typename ...T, typename = std::enable_if_t<((Utils::IsOneOf<T, ByteView, ByteVector>::value && ...))>>
|
||||||
|
//ByteVector& Concat(T const& ...arg)
|
||||||
|
//{
|
||||||
|
// auto oldSize = size();
|
||||||
|
// auto foldSize = (arg.size() + ...);
|
||||||
|
// resize(oldSize + foldSize);
|
||||||
|
// auto ptr = data() + oldSize;
|
||||||
|
// ((memcpy(ptr, arg.data(), arg.size()), (ptr += arg.size())), ...);
|
||||||
|
// return *this;
|
||||||
|
//}
|
||||||
|
|
||||||
/// Create new ByteVector with Variadic list of parameters.
|
/// Create new ByteVector with Variadic list of parameters.
|
||||||
/// This function cannot be constructor, becouse it would be ambigious with std::vector costructors.
|
/// This function cannot be constructor, becouse it would be ambigious with std::vector costructors.
|
||||||
/// @see ByteVector::Write and ByteVector::Concat for more informations.
|
/// @see ByteVector::Write and ByteVector::Concat for more informations.
|
||||||
template <bool preferWriteOverConcat = true, typename ...T, typename std::enable_if_t<CanStoreType<T...>::value, int> = 0>
|
template <typename ...T>
|
||||||
static ByteVector Create(T const& ...args)
|
static ByteVector Create(T const& ...args)
|
||||||
{
|
|
||||||
if constexpr (preferWriteOverConcat)
|
|
||||||
return CreateByWrite(args...);
|
|
||||||
else
|
|
||||||
return CreateByConcat(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create new ByteVector with Variadic list of parameters.
|
|
||||||
/// This function cannot be constructor, becouse it would be ambigious with std::vector costructors.
|
|
||||||
/// @see ByteVector::Write for more informations.
|
|
||||||
template <typename ...T, typename std::enable_if_t<CanStoreType<T...>::value, int> = 0>
|
|
||||||
static ByteVector CreateByWrite(T const& ...args)
|
|
||||||
{
|
{
|
||||||
return ByteVector{}.Write(args...);
|
return ByteVector{}.Write(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create new ByteVector with Variadic list of parameters.
|
|
||||||
/// This function cannot be constructor, becouse it would be ambigious with std::vector costructors.
|
|
||||||
/// @see ByteVector::Concat for more informations.
|
|
||||||
template <typename ...T, typename std::enable_if_t<CanStoreType<T...>::value, int> = 0>
|
|
||||||
static ByteVector CreateByConcat(T const& ...args)
|
|
||||||
{
|
|
||||||
return ByteVector{}.Concat(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Proxy function to ByteView::Read.
|
/// Proxy function to ByteView::Read.
|
||||||
/// This function is added for convenience, but it does not change the state of ByteVector in a way ByteView::Read moves to next stored element after each Read.
|
/// This function is added for convenience, but it does not change the state of ByteVector in a way ByteView::Read moves to next stored element after each Read.
|
||||||
template<typename ...T, typename = std::void_t<decltype(std::declval<ByteView>().Read<T...>())>>
|
template<typename ...T, typename = std::void_t<decltype(std::declval<ByteView>().Read<T...>())>>
|
||||||
|
@ -224,304 +194,142 @@ namespace MWR
|
||||||
return ByteView{ *this }.Read<T...>();
|
return ByteView{ *this }.Read<T...>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/// Calculate the size that the argument will take in memory
|
||||||
/// Store content of of provided object.
|
/// @param arg. argument to be stored.
|
||||||
/// @param storeSize. If true function will add four byte header with size for those types.
|
/// @param args. rest of types that will be handled with recursion.
|
||||||
/// @param arg. argument to be stored. Supported types are ByteVector, ByteView, std::string, std::string_view, std::wstring, std::wstring_view.
|
/// @return size_t number of bytes needed.
|
||||||
/// @return itself to allow chaining.
|
template<typename T, typename ...Ts>
|
||||||
template<typename T, typename std::enable_if_t<
|
static size_t Size(T const& arg, Ts const& ...args)
|
||||||
(
|
|
||||||
std::is_same_v<T, ByteVector>
|
|
||||||
|| std::is_same_v<T, ByteView>
|
|
||||||
|| std::is_same_v<T, std::string>
|
|
||||||
|| std::is_same_v<T, std::string_view>
|
|
||||||
|| std::is_same_v<T, std::wstring>
|
|
||||||
|| std::is_same_v<T, std::wstring_view>
|
|
||||||
), int> = 0>
|
|
||||||
ByteVector & Store(bool storeSize, T const& arg)
|
|
||||||
{
|
{
|
||||||
auto oldSize = size();
|
if constexpr (!sizeof...(Ts))
|
||||||
if (storeSize)
|
|
||||||
{
|
{
|
||||||
resize(oldSize + sizeof(uint32_t) + arg.size() * sizeof(T::value_type));
|
// There is only one type to calculate size for. Find implementation of Size for that type.
|
||||||
*reinterpret_cast<uint32_t*>(data() + oldSize) = static_cast<uint32_t>(arg.size());
|
if constexpr (ByteSizeFunctionType<T>::value == ByteSizeFunctionType<T>::compileTime)
|
||||||
std::memcpy(data() + oldSize + sizeof(uint32_t), arg.data(), arg.size() * sizeof(T::value_type));
|
return MWR::ByteConverter<T>::Size();
|
||||||
|
else if constexpr (ByteSizeFunctionType<T>::value == ByteSizeFunctionType<T>::runTime)
|
||||||
|
return MWR::ByteConverter<T>::Size(arg);
|
||||||
|
else if constexpr (ByteSizeFunctionType<T>::value == ByteSizeFunctionType<T>::absent)
|
||||||
|
return MWR::ByteConverter<T>::To(arg).size();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resize(oldSize + arg.size() * sizeof(T::value_type));
|
return Size(arg) + Size(args...);
|
||||||
std::memcpy(data() + oldSize, arg.data(), arg.size() * sizeof(T::value_type));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Store content of array. Size must be known at compile time and will not be saved in data.
|
|
||||||
/// @tparam T. Type to be stored. Supported types are ByteArray.
|
|
||||||
/// @return itself to allow chaining.
|
|
||||||
template<typename T, typename std::enable_if_t<IsByteArray<T>, int> = 0>
|
|
||||||
ByteVector & Store(bool unused, T const& arg)
|
|
||||||
{
|
|
||||||
auto oldSize = size();
|
|
||||||
resize(oldSize + arg.size());
|
|
||||||
std::memcpy(data() + oldSize, arg.data(), arg.size());
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Store arithmetic type.
|
|
||||||
/// tparam T. Type to be stored.
|
|
||||||
/// @return itself to allow chaining.
|
|
||||||
template<typename T, typename std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
|
|
||||||
ByteVector & Store(bool unused, T const& arg)
|
|
||||||
{
|
|
||||||
auto oldSize = size();
|
|
||||||
resize(oldSize + sizeof(T));
|
|
||||||
*reinterpret_cast<T*>(data() + oldSize) = arg;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
/// Store custom type.
|
/// Store custom type.
|
||||||
/// tparam T. Type to be stored. There must exsist MWR::ToBytes(T const&) method avalible to store custom type.
|
/// param arg. object to be stored. There must exsist MWR::ByteConverter<T>::To(T const&) method avalible to store custom type.
|
||||||
|
/// param args. rest of objects that will be handled with recursion.
|
||||||
/// @return itself to allow chaining.
|
/// @return itself to allow chaining.
|
||||||
template<typename T, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), MWR::ByteVector >, int> = 0>
|
template<typename T, typename ...Ts, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), MWR::ByteVector >, int> = 0>
|
||||||
ByteVector & Store(bool unused, T const& arg)
|
ByteVector & Store(T const& arg, Ts const& ...args)
|
||||||
|
{
|
||||||
|
if constexpr (!sizeof...(Ts))
|
||||||
{
|
{
|
||||||
Concat(MWR::ByteConverter<T>::To(arg));
|
Concat(MWR::ByteConverter<T>::To(arg));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Store(arg);
|
||||||
|
Store(args...);
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Store all arguments at the end of ByteVector.
|
/// ByteConverter specialization for ByteVector, ByteView, std::string, std::string_view, std::wstring, std::wstring_view.
|
||||||
/// @param storeSize if true four byte header will be added to types in T that does not have size defined at compile time.
|
/// This is a basic specialization and will not be moved to ByteConverter.h
|
||||||
/// @tparam T. Parameter pack to be written. Types are deduced from function call.
|
template <typename T>
|
||||||
/// @return itself to allow chaining.
|
struct ByteConverter<T, std::enable_if_t<Utils::IsOneOf<T, ByteVector, ByteView, std::string, std::string_view, std::wstring, std::wstring_view>::value>>
|
||||||
/// @remarks This function is called only for two or more arguments.
|
|
||||||
/// @remarks Each type in parameter pack must have corresponding Write method for one argument.
|
|
||||||
template <typename ...T, typename std::enable_if_t<(sizeof...(T) > 1), int> = 0>
|
|
||||||
ByteVector & Store(bool storeSize, T const& ...args)
|
|
||||||
{
|
{
|
||||||
VariadicStoreHelper<T...>::Store(*this, storeSize, args...);
|
static ByteVector To(T const& obj)
|
||||||
return *this;
|
{
|
||||||
|
auto ret = ByteVector{};
|
||||||
|
auto elementSize = static_cast<uint32_t>(obj.size());
|
||||||
|
ret.resize(Size(obj));
|
||||||
|
memcpy(ret.data(), &elementSize, sizeof(elementSize));
|
||||||
|
memcpy(ret.data() + sizeof(elementSize), obj.data(), elementSize * sizeof(T::value_type));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store tuple type.
|
static size_t Size(T const& obj)
|
||||||
/// @param storeSize if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// tparam T. Tuple type to be stored.
|
|
||||||
/// @return itself to allow chaining.
|
|
||||||
template<typename T, typename std::enable_if_t<IsTuple<T>, int> = 0>
|
|
||||||
ByteVector & Store(bool storeSize, T const& arg)
|
|
||||||
{
|
{
|
||||||
StoreHelper<T>::Store(*this, storeSize, arg);
|
return sizeof(uint32_t) + (obj.size() * sizeof(T::value_type));
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the size that the argument will take in memory
|
// Reading functions are part of ByteView implementation. To deserialize data include ByteView.h
|
||||||
/// @param storeSizeHeader. If true function will add four byte header with size for those types.
|
static T From(ByteView& bv);
|
||||||
/// @param arg. argument to be stored. Supported types are ByteVector, ByteView, std::string, std::string_view, std::wstring, std::wstring_view.
|
};
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template<typename T, typename std::enable_if_t<
|
/// ByteConverter specialization for arithmetic types.
|
||||||
(
|
/// This is a basic specialization and will not be moved to ByteConverter.h
|
||||||
std::is_same_v<T, ByteVector>
|
template <typename T>
|
||||||
|| std::is_same_v<T, ByteView>
|
struct ByteConverter<T, std::enable_if_t<std::is_arithmetic_v<T>>>
|
||||||
|| std::is_same_v<T, std::string>
|
|
||||||
|| std::is_same_v<T, std::string_view>
|
|
||||||
|| std::is_same_v<T, std::wstring>
|
|
||||||
|| std::is_same_v<T, std::wstring_view>
|
|
||||||
), int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool storeSizeHeader, T const& arg)
|
|
||||||
{
|
{
|
||||||
return storeSizeHeader ? arg.size() + sizeof(uint32_t) : arg.size();
|
static ByteVector To(T obj)
|
||||||
|
{
|
||||||
|
auto ret = ByteVector{};
|
||||||
|
ret.resize(sizeof(T));
|
||||||
|
*reinterpret_cast<T*>(ret.data()) = obj;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the size that the argument will take in memory
|
constexpr static size_t Size()
|
||||||
/// @param unused. Supports finding this function in template calls.
|
|
||||||
/// @param arg. argument to be stored. Supports ByteArray type.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template<typename T, typename std::enable_if_t<IsByteArray<T>, int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool unused, T const& arg)
|
|
||||||
{
|
|
||||||
return arg.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the size that the argument will take in memory
|
|
||||||
/// @param unused. Supports finding this function in template calls.
|
|
||||||
/// @param arg. argument to be stored. Supports arithmetic types.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template<typename T, typename std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool unused, T const& arg)
|
|
||||||
{
|
{
|
||||||
return sizeof(T);
|
return sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the size that the argument will take in memory
|
// Reading functions are part of ByteView implementation. To deserialize data include ByteView.h
|
||||||
/// tparam T. Type to be stored. There must exsist MWR::ByteConverter<T>::To(T const&) function and MWR::ByteConverter<T>::Size(T const&)
|
static T From(ByteView& bv);
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template<typename T, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), ByteVector> && GotByteSize<T>::value, int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool unused, T const& arg)
|
|
||||||
{
|
|
||||||
return MWR::ByteConverter<T>::Size(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the size that the argument will take in memory
|
|
||||||
/// tparam T. Type to be stored. There must exsist MWR::ByteConverter<T>::To(T const&) method avalible to store custom type.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template<typename T, typename std::enable_if_t<std::is_same_v<decltype(MWR::ByteConverter<T>::To(std::declval<T>())), ByteVector> && !GotByteSize<T>::value, int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool unused, T const& arg)
|
|
||||||
{
|
|
||||||
return MWR::ByteConverter<T>::To(arg).size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the size that the arguments will take in memory. This function is responsible for unwrapping variadic arguments calls.
|
|
||||||
/// @param storeSizeHeader. If true function writes 4 bytes header with size for types that have variable buffer length.
|
|
||||||
/// @param args. arguments to be stored.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template <typename ...T, typename std::enable_if_t<(sizeof...(T) > 1), int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool storeSizeHeader, T const& ...args)
|
|
||||||
{
|
|
||||||
return VariadicStoreHelper<T...>::CalculateStoreSize(storeSizeHeader, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the size that the arguments will take in memory. This function is responsible for unwrapping calls with tuple type.
|
|
||||||
/// @param storeSizeHeader. If true function writes 4 bytes header with size for types that have variable buffer length.
|
|
||||||
/// @param arg. arguments to be stored in form of tuple.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
template<typename T, typename std::enable_if_t<IsTuple<T>, int> = 0>
|
|
||||||
static size_t CalculateStoreSize(bool storeSizeHeader, T const& arg)
|
|
||||||
{
|
|
||||||
return StoreHelper<T>::CalculateStoreSize(storeSizeHeader, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// @tparam T. First type from parameter pack. Each recursive call will unfold one type.
|
|
||||||
/// @tparam Rest. Parameter pack storing rest of provided types.
|
|
||||||
template <typename T, typename ...Rest>
|
|
||||||
struct VariadicStoreHelper
|
|
||||||
{
|
|
||||||
/// Function responsible for recursively packing data to ByteVector.
|
|
||||||
/// @param storeSizeHeader if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// @param self. Reference to ByteVector object using VariadicWriter.
|
|
||||||
/// @note Template used here should remove function if one of types cannot be stored.
|
|
||||||
/// Compiler should mark error of compilation in code location where function was used with wrong parameters.
|
|
||||||
/// Becouse of MSVC SFINAE bug compiler can mark this function with std::enable_if_t<false... error.
|
|
||||||
/// If you see this error examine ByteVector::Write and ByteVector::Concat usages for potential invalid parameters.
|
|
||||||
template <typename std::enable_if_t<CanStoreType<T>::value, int> = 0>
|
|
||||||
static void Store(ByteVector& self, bool storeSizeHeader, T const& current, Rest const& ...rest)
|
|
||||||
{
|
|
||||||
self.Store(storeSizeHeader, current);
|
|
||||||
VariadicStoreHelper<Rest...>::Store(self, storeSizeHeader, rest...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function responsible for recursively calculating buffer size needed for call with variadic argument list.
|
|
||||||
/// @param storeSizeHeader if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
static size_t CalculateStoreSize(bool storeSizeHeader, T const& current, Rest const& ...rest)
|
|
||||||
{
|
|
||||||
return ByteVector::CalculateStoreSize(storeSizeHeader, current) + VariadicStoreHelper<Rest...>::CalculateStoreSize(storeSizeHeader, rest...);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// Closure specialization.
|
|
||||||
/// @tparam T. Type to be extracted stored in ByteVector.
|
|
||||||
/// @note Template used here should remove function if one of types cannot be stored.
|
|
||||||
/// Compiler should mark error of compilation in code location where function was used with wrong parameters.
|
|
||||||
/// Becouse of MSVC SFINAE bug compiler can mark this function with std::enable_if_t<false... error.
|
|
||||||
/// If you see this error examine ByteVector::Write and ByteVector::Concat usages for potential invalid parameters.
|
|
||||||
template <typename T>
|
|
||||||
struct VariadicStoreHelper<T>
|
|
||||||
{
|
|
||||||
/// Function responsible for recursively packing data to ByteVector.
|
|
||||||
/// @param storeSizeHeader if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// @param self. Reference to ByteVector object using VariadicWriter.
|
|
||||||
template <typename std::enable_if_t<CanStoreType<T>::value, int> = 0>
|
|
||||||
static void Store(ByteVector& self, bool storeSizeHeader, T const& current)
|
|
||||||
{
|
|
||||||
self.Store(storeSizeHeader, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function responsible for recursively calculating buffer size needed for call with variadic argument list.
|
|
||||||
/// @param storeSizeHeader if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
static size_t CalculateStoreSize(bool storeSizeHeader, T const& current)
|
|
||||||
{
|
|
||||||
return ByteVector::CalculateStoreSize(storeSizeHeader, current);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// @tparam T. Tuple type to write.
|
|
||||||
/// @tparam N. How many elements of tuple to write.
|
|
||||||
template <typename T, size_t N = std::tuple_size_v<T>>
|
|
||||||
struct StoreHelper
|
|
||||||
{
|
|
||||||
/// Function responsible for recursively packing data to ByteVector.
|
|
||||||
/// @param self. Reference to ByteVector object using VariadicWriter.
|
|
||||||
/// @param storeSizeHeader if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// @param t. reference to tuple.
|
|
||||||
/// @note Template used here should remove function if one of types cannot be stored.
|
|
||||||
/// Compiler should mark error of compilation in code location where function was used with wrong parameters.
|
|
||||||
/// Becouse of MSVC SFINAE bug compiler can mark this function with std::enable_if_t<false... error.
|
|
||||||
/// If you see this error examine ByteVector::Write and ByteVector::Concat usages for potential invalid parameters.
|
|
||||||
template <typename std::enable_if_t<CanStoreType<decltype(std::get<std::tuple_size_v<T> -N>(t))>::value, int> = 0>
|
|
||||||
static void Store(ByteVector& self, bool storeSizeHeader, T const& t)
|
|
||||||
{
|
|
||||||
self.Store(storeSizeHeader, std::get<std::tuple_size_v<T> - N>(t));
|
|
||||||
StoreHelper<T, N - 1>::Store(self, storeSizeHeader, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function responsible for recursively calculating buffer size needed for call with tuple argument.
|
|
||||||
/// @param storeSizeHeader if true four byte header will be added to types in T that does not have size defined at compile time.
|
|
||||||
/// @return size_t number of bytes needed.
|
|
||||||
static size_t CalculateStoreSize(bool storeSize, T const& t)
|
|
||||||
{
|
|
||||||
return ByteVector::CalculateStoreSize(storeSizeHeader, std::get<std::tuple_size_v<T> - N>(t)) + StoreHelper<T, N - 1>::CalculateStoreSize(storeSizeHeader, t);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// Closure specialization.
|
|
||||||
/// @tparam T. Tuple type to write.
|
|
||||||
template <typename T>
|
|
||||||
struct StoreHelper<T, 0>
|
|
||||||
{
|
|
||||||
/// Closing function, does nothing.
|
|
||||||
static void Store(ByteVector&, bool, T const&)
|
|
||||||
{
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Closing function, returns 0.
|
|
||||||
static size_t CalculateStoreSize(bool, T const&)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Checks if the contents of lhs and rhs are equal.
|
|
||||||
/// @param lhs. Left hand side of operator.
|
|
||||||
/// @param rhs. Right hand side of operator.
|
|
||||||
bool operator==(ByteVector const& lhs, ByteVector const& rhs);
|
|
||||||
|
|
||||||
/// Checks if the contents of lhs and rhs are equal.
|
|
||||||
/// @param lhs. Left hand side of operator.
|
|
||||||
/// @param rhs. Right hand side of operator.
|
|
||||||
bool operator!=(ByteVector const& lhs, ByteVector const& rhs);
|
|
||||||
|
|
||||||
namespace Literals
|
namespace Literals
|
||||||
{
|
{
|
||||||
/// Create ByteVector with syntax ""_bvec
|
/// Create ByteVector with syntax ""_bvec
|
||||||
ByteVector operator "" _b(const char* data, size_t size);
|
inline ByteVector operator "" _b(const char* data, size_t size)
|
||||||
|
{
|
||||||
|
MWR::ByteVector ret;
|
||||||
|
ret.resize(size);
|
||||||
|
std::memcpy(ret.data(), data, size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create ByteVector with syntax L""_bvec
|
/// Create ByteVector with syntax L""_bvec
|
||||||
ByteVector operator "" _b(const wchar_t* data, size_t size);
|
inline ByteVector operator "" _b(const wchar_t* data, size_t size)
|
||||||
|
{
|
||||||
|
MWR::ByteVector ret;
|
||||||
|
ret.resize(size * sizeof(wchar_t));
|
||||||
|
std::memcpy(ret.data(), data, size * sizeof(wchar_t));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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==(MWR::ByteVector const& lhs, MWR::ByteVector const& rhs)
|
||||||
|
{
|
||||||
|
if (lhs.size() != rhs.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lhs.size(); ++i)
|
||||||
|
if (lhs[i] != rhs[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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!=(MWR::ByteVector const& lhs, MWR::ByteVector const& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
#include "StdAfx.h"
|
|
||||||
#include "ByteView.h"
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
std::vector<std::string> MWR::SplitAndCopy(std::string_view stringToBeSplitted, std::string_view delimiter)
|
|
||||||
{
|
|
||||||
return Split<true>(stringToBeSplitted, delimiter);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::ByteView(ByteVector const& data, size_t offset)
|
|
||||||
: Super([&]() { return data.size() >= offset ? data.data() + offset : throw std::out_of_range{ OBF("Out of range. Data size: ") + std::to_string(data.size()) + OBF(" offset: ") + std::to_string(offset) }; }(), data.size() - offset)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::ByteView(ByteVector::const_iterator begin, ByteVector::const_iterator end)
|
|
||||||
: Super([&]() { return end >= begin ? begin._Ptr : throw std::out_of_range{ OBF("Out of range by: ") + std::to_string(begin - end) + OBF(" elements.") }; }(), static_cast<size_t>(end - begin))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::ByteView(std::basic_string_view<ByteVector::value_type> basicSring)
|
|
||||||
: Super(basicSring)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::ByteView(std::string_view data)
|
|
||||||
: Super{ reinterpret_cast<const ByteVector::value_type*>(data.data()), data.size() }
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::operator MWR::ByteView::Super() const noexcept
|
|
||||||
{
|
|
||||||
return Super{ data(), size() };
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::operator MWR::ByteVector() const
|
|
||||||
{
|
|
||||||
return { begin(), end() };
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::operator std::string() const
|
|
||||||
{
|
|
||||||
return { reinterpret_cast<const char*>(data()), size() };
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView::operator std::string_view() const
|
|
||||||
{
|
|
||||||
return { reinterpret_cast<const char*>(data()), size() };
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteVector MWR::ByteView::Read(size_t byteCount)
|
|
||||||
{
|
|
||||||
if (byteCount > size())
|
|
||||||
throw std::out_of_range{ OBF(": Size: ") + std::to_string(size()) + OBF(". Cannot read ") + std::to_string(byteCount) + OBF(" bytes.") };
|
|
||||||
|
|
||||||
auto retVal = ByteVector{ begin(), begin() + byteCount };
|
|
||||||
remove_prefix(byteCount);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView MWR::ByteView::SubString(const size_type offset, size_type count) const
|
|
||||||
{
|
|
||||||
return Super::substr(offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView MWR::Literals::operator "" _bv(const char* data, size_t size)
|
|
||||||
{
|
|
||||||
return { reinterpret_cast<const uint8_t*>(data), size };
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
MWR::ByteView MWR::Literals::operator "" _bv(const wchar_t* data, size_t size)
|
|
||||||
{
|
|
||||||
return { reinterpret_cast<const uint8_t*>(data), size * sizeof(wchar_t) };
|
|
||||||
}
|
|
|
@ -4,46 +4,6 @@
|
||||||
|
|
||||||
namespace MWR
|
namespace MWR
|
||||||
{
|
{
|
||||||
/// Function splitting string.
|
|
||||||
///
|
|
||||||
/// @tparam copy. Indicates should strings be copied.
|
|
||||||
/// @param stringToBeSplitted initial string to be tokenized.
|
|
||||||
/// @param delimiter to be searched in string.
|
|
||||||
/// @throws std::runtime_error if delimiter empty or greatter equal to stringToBeSplitted
|
|
||||||
/// @returns std::vector<std::string> or std::vector<std::string_view> depending on copy flag.
|
|
||||||
template<bool copy = false>
|
|
||||||
std::vector<std::conditional_t<copy, std::string, std::string_view>> Split(std::string_view stringToBeSplitted, std::string_view delimiter)
|
|
||||||
{
|
|
||||||
if (delimiter.empty() && delimiter.size() >= stringToBeSplitted.size())
|
|
||||||
throw std::runtime_error{ OBF("Delimiter size is incorrect") };
|
|
||||||
|
|
||||||
using ReturnType = decltype(Split<copy>(stringToBeSplitted, delimiter));
|
|
||||||
ReturnType splittedString;
|
|
||||||
// startIndex can overflow, endIndex is checked first, and lazy check on startIndex will avoid last empty token.
|
|
||||||
for (size_t startIndex = 0u, endIndex = 0u; endIndex < stringToBeSplitted.size() && startIndex < stringToBeSplitted.size(); startIndex = endIndex + delimiter.size())
|
|
||||||
{
|
|
||||||
endIndex = stringToBeSplitted.find(delimiter, startIndex);
|
|
||||||
|
|
||||||
// skip empty tokens when delimiter is repeated.
|
|
||||||
if (endIndex - startIndex)
|
|
||||||
splittedString.emplace_back(stringToBeSplitted.substr(startIndex, endIndex - startIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
return splittedString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Proxy to Split<true>
|
|
||||||
///
|
|
||||||
/// @param stringToBeSplitted initial string to be tokenized.
|
|
||||||
/// @param delimiter to be searched in string.
|
|
||||||
/// @throws std::runtime_error if delimiter empty or greatter equal to stringToBeSplitted
|
|
||||||
/// @returns std::vector<std::string> tokenized string.
|
|
||||||
std::vector<std::string> SplitAndCopy(std::string_view stringToBeSplitted, std::string_view delimiter);
|
|
||||||
|
|
||||||
/// Idiom for detecting ByteView::Get.
|
|
||||||
template <typename X>
|
|
||||||
constexpr bool IsGetter = false;
|
|
||||||
|
|
||||||
/// Non owning container.
|
/// Non owning container.
|
||||||
class ByteView : std::basic_string_view<ByteVector::value_type>
|
class ByteView : std::basic_string_view<ByteVector::value_type>
|
||||||
{
|
{
|
||||||
|
@ -59,19 +19,37 @@ namespace MWR
|
||||||
/// @param offset. Offset from first byte of data collection.
|
/// @param offset. Offset from first byte of data collection.
|
||||||
/// @return ByteView. View of data.
|
/// @return ByteView. View of data.
|
||||||
/// @throw std::out_of range. If offset is greater than data.size().
|
/// @throw std::out_of range. If offset is greater than data.size().
|
||||||
ByteView(ByteVector const& data, size_t offset = 0);
|
ByteView(ByteVector const& data, size_t offset = 0)
|
||||||
|
: Super([&]()
|
||||||
|
{
|
||||||
|
return data.size() >= offset ? data.data() + offset : throw std::out_of_range{ OBF("Out of range. Data size: ") + std::to_string(data.size()) + OBF(" offset: ") + std::to_string(offset) };
|
||||||
|
}(), data.size() - offset)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Create from ByteVector iterators.
|
/// Create from ByteVector iterators.
|
||||||
/// @param begin. Iterator to first element of data.
|
/// @param begin. Iterator to first element of data.
|
||||||
/// @param end. Iterator to past the last element of data.
|
/// @param end. Iterator to past the last element of data.
|
||||||
/// @return ByteView. View of data.
|
/// @return ByteView. View of data.
|
||||||
/// @throw std::out_of range. If begin is greater than end.
|
/// @throw std::out_of range. If begin is greater than end.
|
||||||
ByteView(ByteVector::const_iterator begin, ByteVector::const_iterator end);
|
ByteView(ByteVector::const_iterator begin, ByteVector::const_iterator end)
|
||||||
|
: Super([&]()
|
||||||
|
{
|
||||||
|
return end >= begin ? begin._Ptr : throw std::out_of_range{ OBF("Out of range by: ") + std::to_string(begin - end) + OBF(" elements.") };
|
||||||
|
}(), static_cast<size_t>(end - begin))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Create from std::basic_string_view<uint8_t>.
|
/// Create from std::basic_string_view<uint8_t>.
|
||||||
/// @param data. Data from which view will be constructed.
|
/// @param data. Data from which view will be constructed.
|
||||||
/// @return ByteView. View of data.
|
/// @return ByteView. View of data.
|
||||||
ByteView(std::basic_string_view<ByteVector::value_type> data);
|
ByteView(std::basic_string_view<ByteVector::value_type> data)
|
||||||
|
: Super(data)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Create from ByteArray.
|
/// Create from ByteArray.
|
||||||
/// @param data. Data from which view will be constructed.
|
/// @param data. Data from which view will be constructed.
|
||||||
|
@ -86,25 +64,43 @@ namespace MWR
|
||||||
/// Create from std::string_view.
|
/// Create from std::string_view.
|
||||||
/// @param data. Data from which view will be constructed.
|
/// @param data. Data from which view will be constructed.
|
||||||
/// @return ByteView. View of data.
|
/// @return ByteView. View of data.
|
||||||
ByteView(std::string_view data);
|
ByteView(std::string_view data)
|
||||||
|
: Super{ reinterpret_cast<const ByteVector::value_type*>(data.data()), data.size() }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow cast to Privately inherited Type.
|
/// Allow cast to Privately inherited Type.
|
||||||
operator Super() const noexcept;
|
operator Super() const noexcept
|
||||||
|
{
|
||||||
|
return Super{ data(), size() };
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow cast to ByteVector.
|
/// Allow cast to ByteVector.
|
||||||
operator ByteVector() const;
|
operator ByteVector() const
|
||||||
|
{
|
||||||
|
return { begin(), end() };
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow cast to std::string().
|
/// Allow cast to std::string().
|
||||||
operator std::string() const;
|
operator std::string() const
|
||||||
|
{
|
||||||
|
return { reinterpret_cast<const char*>(data()), size() };
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow cast to std::string_view.
|
/// Allow cast to std::string_view.
|
||||||
operator std::string_view() const;
|
operator std::string_view() const
|
||||||
|
{
|
||||||
|
return { reinterpret_cast<const char*>(data()), size() };
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a sub-string from this ByteView.
|
/// Create a sub-string from this ByteView.
|
||||||
/// @param offset. Position of the first byte.
|
/// @param offset. Position of the first byte.
|
||||||
/// @param count. Requested length
|
/// @param count. Requested length
|
||||||
/// @returns ByteView. View of the substring
|
/// @returns ByteView. View of the substring
|
||||||
ByteView SubString(const size_type offset = 0, size_type count = npos) const;
|
ByteView SubString(const size_type offset = 0, size_type count = npos) const
|
||||||
|
{
|
||||||
|
return Super::substr(offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
// Enable methods.
|
// Enable methods.
|
||||||
using std::basic_string_view<ByteVector::value_type>::basic_string_view;
|
using std::basic_string_view<ByteVector::value_type>::basic_string_view;
|
||||||
|
@ -143,260 +139,89 @@ namespace MWR
|
||||||
|
|
||||||
/// @returns ByteVector. Owning container with the read bytes.
|
/// @returns ByteVector. Owning container with the read bytes.
|
||||||
/// @param byteCount. How many bytes should be read.
|
/// @param byteCount. How many bytes should be read.
|
||||||
/// @remarks Read is not compatible with Read<ByteVector>.
|
|
||||||
/// Data stored in ByteVector with Write<ByteVector> should be accessed with Read<ByteVector>
|
|
||||||
/// @throws std::out_of_range. If byteCount > size().
|
/// @throws std::out_of_range. If byteCount > size().
|
||||||
ByteVector Read(size_t byteCount);
|
ByteVector Read(size_t byteCount)
|
||||||
|
|
||||||
/// Read bytes and remove them from ByteView.
|
|
||||||
/// @remarks Read is not compatible with Read<ByteVector>.
|
|
||||||
/// Data stored in ByteVector with Write<ByteVector> should be accessed with Read<ByteVector>
|
|
||||||
/// @returns T. Owning container with the read bytes.
|
|
||||||
/// @throws std::out_of_range. If ByteView is too short to hold size of object to return.
|
|
||||||
template<typename T = ByteVector>
|
|
||||||
std::enable_if_t<(std::is_same_v<T, ByteVector> || std::is_same_v<T, std::string> || std::is_same_v<T, std::wstring>), T> Read()
|
|
||||||
{
|
{
|
||||||
if (sizeof(uint32_t) > size())
|
if (byteCount > size())
|
||||||
throw std::out_of_range{ OBF(": Cannot read size from ByteView ") };
|
throw std::out_of_range{ OBF(": Size: ") + std::to_string(size()) + OBF(". Cannot read ") + std::to_string(byteCount) + OBF(" bytes.") };
|
||||||
|
|
||||||
auto elementCount = *reinterpret_cast<const uint32_t*>(data());
|
auto retVal = ByteVector{ begin(), begin() + byteCount };
|
||||||
auto byteCount = elementCount * sizeof(T::value_type);
|
|
||||||
remove_prefix(sizeof(uint32_t));
|
|
||||||
|
|
||||||
T retVal;
|
|
||||||
retVal.resize(elementCount);
|
|
||||||
std::memcpy(retVal.data(), data(), byteCount);
|
|
||||||
remove_prefix(byteCount);
|
remove_prefix(byteCount);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read bytes and remove them from ByteView.
|
|
||||||
/// This function will return non owning container. It is helpful to prevent coping large buffers, if user know that original container is still valid.
|
|
||||||
/// @returns T. Non owning container with the read bytes.
|
|
||||||
/// @throws std::out_of_range. If ByteView is too short to hold size of object to return.
|
|
||||||
template<typename T>
|
|
||||||
std::enable_if_t<(std::is_same_v<T, ByteView> || std::is_same_v<T, std::string_view> || std::is_same_v<T, std::wstring_view>), T> Read()
|
|
||||||
{
|
|
||||||
if (sizeof(uint32_t) > size())
|
|
||||||
throw std::out_of_range{ OBF(": Cannot read size from ByteView ") };
|
|
||||||
|
|
||||||
auto elementCount = *reinterpret_cast<const uint32_t*>(data());
|
|
||||||
auto byteCount = elementCount * sizeof(T::value_type);
|
|
||||||
remove_prefix(sizeof(uint32_t));
|
|
||||||
|
|
||||||
auto retVal = T{reinterpret_cast<T::value_type const*>(data()), elementCount};
|
|
||||||
remove_prefix(byteCount);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read bytes and remove them from ByteView.
|
|
||||||
/// @returns ByteArray. Owning container with the read bytes.
|
|
||||||
/// @throws std::out_of_range. If ByteView is too short to hold size of object to return.
|
|
||||||
template<typename T>
|
|
||||||
std::enable_if_t<IsByteArray<T>, T> Read()
|
|
||||||
{
|
|
||||||
if (std::tuple_size<typename T>::value > size())
|
|
||||||
throw std::out_of_range{ OBF(": Cannot read data from ByteView") };
|
|
||||||
|
|
||||||
T retVal;
|
|
||||||
std::memcpy(retVal.data(), data(), std::tuple_size<typename T>::value);
|
|
||||||
remove_prefix(std::tuple_size<typename T>::value);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read arithmetic type and remove it from ByteView.
|
|
||||||
/// @tparam T. Type to return;
|
|
||||||
/// @returns T. Owning container with the read bytes.
|
|
||||||
/// @throws std::out_of_range. If sizeof(T) > size().
|
|
||||||
template<typename T>
|
|
||||||
std::enable_if_t<std::is_arithmetic<T>::value, T> Read()
|
|
||||||
{
|
|
||||||
if (sizeof(T) > size())
|
|
||||||
throw std::out_of_range{ OBF(": Size: ") + std::to_string(size()) + OBF(". Cannot read ") + std::to_string(sizeof(T)) + OBF(" bytes.") };
|
|
||||||
|
|
||||||
auto retVal = *reinterpret_cast<const T*>(data());
|
|
||||||
remove_prefix(sizeof(T));
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read custom type and remove it from ByteView.
|
/// Read custom type and remove it from ByteView.
|
||||||
/// @tparam T. Type to return;
|
/// @param arg. Type to be read from ByteView
|
||||||
/// @returns T.
|
/// @param args. Rest of types that need to be handled with recursion.
|
||||||
template<typename T>
|
template<typename T, typename ...Ts, typename = decltype(MWR::ByteConverter<std::remove_const_t<T>>::From(std::declval<ByteView>()))>
|
||||||
std::enable_if_t < std::is_same_v<decltype(MWR::ByteConverter<T>::From(std::declval<ByteView>())), T > , T > Read()
|
auto Read()
|
||||||
{
|
{
|
||||||
return ByteConverter<T>::From(*this);
|
if constexpr (!sizeof...(Ts))
|
||||||
|
{
|
||||||
|
return ByteConverter<std::remove_const_t<T>>::From(*this);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/// Read tuple type.
|
|
||||||
/// @tparam T. Tuple type to return;
|
|
||||||
/// @returns T. Owning container with the read bytes.
|
|
||||||
template<typename T>
|
|
||||||
std::enable_if_t<IsTuple<T>, T> Read()
|
|
||||||
{
|
{
|
||||||
return TupleGenerator<T>::Generate(*this);
|
auto current = std::make_tuple(Read<T>());
|
||||||
|
if constexpr (sizeof...(Ts) > 1)
|
||||||
|
return std::tuple_cat(std::move(current), Read<Ts...>());
|
||||||
|
else
|
||||||
|
return std::tuple_cat(std::move(current), std::make_tuple(Read<Ts...>()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Class allowing reading N bytes without coping data like in ByeView::Read<ByteArray<N>> or ByteView::Reed(size_t).
|
|
||||||
template <size_t N>
|
|
||||||
class Get
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Define size marker.
|
|
||||||
static constexpr size_t size = N;
|
|
||||||
static constexpr size_t Size = size;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Private constructor.
|
|
||||||
/// This class should never be instantiated.
|
|
||||||
Get() = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Read bytes and remove them from ByteView.
|
/// ByteConverter::From specialization for arithmetic types.
|
||||||
/// @returns ByteView. Non owning container with the read bytes.
|
/// This is a basic specialization and will not be moved to ByteConverter.h
|
||||||
/// @throws std::out_of_range. If ByteView is too short to hold size of object to return.
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<IsGetter<T>, ByteView> Read()
|
T ByteConverter<T, std::enable_if_t<Utils::IsOneOf<T, ByteVector, ByteView, std::string, std::string_view, std::wstring, std::wstring_view>::value>>::From(ByteView& bv)
|
||||||
{
|
{
|
||||||
if (T::Size > size())
|
if (sizeof(uint32_t) > bv.size())
|
||||||
throw std::out_of_range{ OBF(": Cannot read data from ByteView") };
|
throw std::out_of_range{ OBF(": Cannot read size from ByteView ") };
|
||||||
|
|
||||||
auto retVal = SubString(0, T::Size);
|
auto elementCount = *reinterpret_cast<const uint32_t*>(bv.data());
|
||||||
remove_prefix(T::Size);
|
auto byteCount = elementCount * sizeof(T::value_type);
|
||||||
|
bv.remove_prefix(sizeof(uint32_t));
|
||||||
|
|
||||||
|
T retVal;
|
||||||
|
if constexpr (Utils::IsOneOf<T, ByteVector, std::string, std::wstring>::value)
|
||||||
|
{
|
||||||
|
retVal.resize(elementCount);
|
||||||
|
std::memcpy(retVal.data(), bv.data(), byteCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retVal = T{ reinterpret_cast<typename T::value_type const*>(bv.data()), elementCount };
|
||||||
|
}
|
||||||
|
|
||||||
|
bv.remove_prefix(byteCount);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read tuple and remove bytes from ByteView.
|
/// ByteConverter::from specialization for ByteVector, ByteView, std::string, std::string_view, std::wstring, std::wstring_view.
|
||||||
/// @tparam T. Parameter pack of types to be stored in tuple. Must consist more then one type. Each of types must be parsable by Reed template for one type.
|
/// This is a basic specialization and will not be moved to ByteConverter.h
|
||||||
/// @returns std::tuple. Tuple will store types provided in parameter pack.
|
|
||||||
/// @throws std::out_of_range. If ByteView is too short to possibly store all provided types.
|
|
||||||
template<typename ...T, typename std::enable_if_t<(sizeof...(T) > 1), int> = 0>
|
|
||||||
auto Read()
|
|
||||||
{
|
|
||||||
return VariadicTupleGenerator<T...>::Generate(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Template function allowing structured binding to new std::string or std::string_view variables from text stored in ByteView.
|
|
||||||
///
|
|
||||||
/// auto [a,b] = ToStringArray<2>();
|
|
||||||
/// @tparam expectedSize number of words that should be returned from function.
|
|
||||||
/// @tparam copy if true words will be copied to std::string variables.
|
|
||||||
/// @tparam modifyByteView if true parsed words will be removed from ByteView object.
|
|
||||||
/// @returns std::array<std::string, expectedSize> or std::array<std::string_view, expectedSize> array of strings. Size of array is known at compile time.
|
|
||||||
/// @throws std::runtime_error if bytes is empty or when bytes does not consist at least expectedSize numer of space separated strings.
|
|
||||||
template<size_t expectedSize, bool copy = true, bool modifyByteView = true>
|
|
||||||
std::array<std::conditional_t<copy, std::string, std::string_view>, expectedSize> ToStringArray()
|
|
||||||
{
|
|
||||||
auto splited = Split(*this, OBF(" "));
|
|
||||||
if (splited.size() < expectedSize)
|
|
||||||
throw std::runtime_error{ OBF("ByteVector does not consist expected number of strings") };
|
|
||||||
|
|
||||||
using ReturnType = decltype(ToStringArray<expectedSize, copy, modifyByteView>());
|
|
||||||
ReturnType retValue;
|
|
||||||
for (auto i = 0u; i < expectedSize; ++i)
|
|
||||||
retValue[i] = splited[i];
|
|
||||||
|
|
||||||
if constexpr (modifyByteView)
|
|
||||||
remove_prefix(splited[expectedSize - 1].data() - reinterpret_cast<const char*>(data()) + splited[expectedSize - 1].size());
|
|
||||||
|
|
||||||
return retValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// @tparam T. First type from parameter pack. Each recursive call will unfold one type.
|
|
||||||
/// @tparam Rest. Parameter pack storing rest of provided types.
|
|
||||||
template <typename T, typename ...Rest>
|
|
||||||
struct VariadicTupleGenerator
|
|
||||||
{
|
|
||||||
/// Function responsible for recursively packing data to tuple.
|
|
||||||
/// @param self. Reference to ByteView object using generate method.
|
|
||||||
static auto Generate(ByteView& self)
|
|
||||||
{
|
|
||||||
auto current = std::make_tuple(self.Read<T>());
|
|
||||||
auto rest = VariadicTupleGenerator<Rest...>::Generate(self);
|
|
||||||
return std::tuple_cat(std::move(current), std::move(rest));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// Closure specialization.
|
|
||||||
/// @tparam T. Type to be extracted from ByteView and stored in tuple.
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct VariadicTupleGenerator<T>
|
T ByteConverter<T, std::enable_if_t<std::is_arithmetic_v<T>>>::From(ByteView& bv)
|
||||||
{
|
{
|
||||||
/// Function responsible for recursively packing data to tuple.
|
T ret;
|
||||||
/// @param self. Reference to ByteView object using generate method.
|
memcpy(&ret, bv.data(), sizeof(T));
|
||||||
static auto Generate(ByteView& self)
|
bv.remove_prefix(sizeof(T));
|
||||||
{
|
return ret;
|
||||||
return std::make_tuple(self.Read<T>());
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// @tparam T. Tuple to be extracted.
|
|
||||||
/// @tparam N. How many elements out of tuple to use.
|
|
||||||
template <typename T, size_t N = std::tuple_size_v<T>>
|
|
||||||
struct TupleGenerator
|
|
||||||
{
|
|
||||||
/// Function responsible for recursively packing data to tuple.
|
|
||||||
/// @param self. Reference to ByteView object using generate method.
|
|
||||||
static auto Generate(ByteView& self)
|
|
||||||
{
|
|
||||||
auto current = std::make_tuple(self.Read<std::tuple_element_t<std::tuple_size_v<T> -N, T>>());
|
|
||||||
auto rest = TupleGenerator<T, N - 1>::Generate(self);
|
|
||||||
return std::tuple_cat(current, rest);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Delegate to class idiom.
|
|
||||||
/// Function templates cannot be partially specialized.
|
|
||||||
/// Closure specialization, return empty tuple.
|
|
||||||
/// @tparam T. Tuple to be extracted.
|
|
||||||
template <typename T>
|
|
||||||
struct TupleGenerator<T, 0>
|
|
||||||
{
|
|
||||||
/// Function responsible for recursively packing data to tuple.
|
|
||||||
/// @param self. Reference to ByteView object using generate method.
|
|
||||||
static auto Generate(ByteView& self)
|
|
||||||
{
|
|
||||||
return std::tuple<>{};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Specialization of idiom for detecting ByteView::Get.
|
|
||||||
template<size_t N>
|
|
||||||
constexpr bool IsGetter<ByteView::Get<N>> = true;
|
|
||||||
|
|
||||||
/// Alias for simpler use of ByteView::Get.
|
|
||||||
template<size_t N>
|
|
||||||
using Bytes = ByteView::Get<N>;
|
|
||||||
|
|
||||||
namespace Literals
|
namespace Literals
|
||||||
{
|
{
|
||||||
/// Create ByteView with syntax ""_bvec
|
/// Create ByteView with syntax ""_bvec
|
||||||
MWR::ByteView operator "" _bv(const char* data, size_t size);
|
inline MWR::ByteView operator "" _bv(const char* data, size_t size)
|
||||||
|
{
|
||||||
/// Create ByteView with syntax L""_bvec
|
return { reinterpret_cast<const uint8_t*>(data), size };
|
||||||
MWR::ByteView operator "" _bv(const wchar_t* data, size_t size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Template function allowing structured binding to new std::string or std::string_view variables from text command stored in ByteView.
|
/// Create ByteView with syntax L""_bvec
|
||||||
///
|
inline MWR::ByteView operator "" _bv(const wchar_t* data, size_t size)
|
||||||
/// auto [a,b] = ToStringArray<2>(someByteView);
|
|
||||||
/// @tparam expectedSize number of words that should be returned from function.
|
|
||||||
/// @tparam copy if true words will be copied to std::string variables.
|
|
||||||
/// @param bytes ByteView to parse. Strings should be separated with spaces.
|
|
||||||
/// @returns std::array<std::string, expectedSize> or std::array<std::string_view, expectedSize> array of strings. Size of array is known at compile time.
|
|
||||||
/// @throws std::runtime_error if bytes is empty or when bytes does not consist at least expectedSize numer of space separated strings.
|
|
||||||
template<size_t expectedSize, bool copy = true>
|
|
||||||
std::array<std::conditional_t<copy, std::string, std::string_view>, expectedSize> ToStringArray(ByteView bytes)
|
|
||||||
{
|
{
|
||||||
return bytes.ToStringArray<expectedSize, copy, false>();
|
return { reinterpret_cast<const uint8_t*>(data), size * sizeof(wchar_t) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,8 @@
|
||||||
|
|
||||||
#include "Common/ADVobfuscator/MetaString.h"
|
#include "Common/ADVobfuscator/MetaString.h"
|
||||||
|
|
||||||
#include "Utils.h" //< For common functions.
|
#include "ByteConverter.h" //< Bor ByteView, ByteVector and ByteConverter specializations for common types.
|
||||||
#include "ByteArray.h" //< For ByteArray.
|
|
||||||
#include "ByteVector.h" //< For ByteVector.
|
|
||||||
#include "ByteView.h" //< For ByteView.
|
|
||||||
|
|
||||||
|
|
||||||
// Literals.
|
// Literals.
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
#include "StdAfx.h"
|
|
||||||
#include "Utils.h"
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool MWR::Utils::IsProcess64bit()
|
|
||||||
{
|
|
||||||
#if defined(_WIN64)
|
|
||||||
return true;
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
std::string MWR::Utils::GenerateRandomString(size_t size)
|
|
||||||
{
|
|
||||||
static const std::string charset = OBF("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
|
||||||
static std::random_device rd;
|
|
||||||
static std::mt19937 gen(rd());
|
|
||||||
static std::uniform_int_distribution<int> uni(0, static_cast<int>(charset.size() - 1));
|
|
||||||
|
|
||||||
std::string randomString;
|
|
||||||
randomString.resize(size);
|
|
||||||
for (auto& e : randomString)
|
|
||||||
e = charset[uni(gen)];
|
|
||||||
|
|
||||||
return randomString;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
int32_t MWR::Utils::TimeSinceEpoch()
|
|
||||||
{
|
|
||||||
return static_cast<int32_t>(std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count());
|
|
||||||
}
|
|
|
@ -4,7 +4,21 @@ namespace MWR::Utils
|
||||||
{
|
{
|
||||||
/// Check if application is 64bit.
|
/// Check if application is 64bit.
|
||||||
/// @return true for x64 process.
|
/// @return true for x64 process.
|
||||||
bool IsProcess64bit();
|
inline bool IsProcess64bit()
|
||||||
|
{
|
||||||
|
# if defined(_WIN64)
|
||||||
|
return true;
|
||||||
|
# elif defined(_WIN32)
|
||||||
|
return false;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template to evaluate if T is one of Ts types.
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
struct IsOneOf
|
||||||
|
{
|
||||||
|
constexpr static bool value = [](bool ret) { return ret; }((std::is_same_v<T, Ts> || ...));
|
||||||
|
};
|
||||||
|
|
||||||
/// Changes value to default if it is out of provided range.
|
/// Changes value to default if it is out of provided range.
|
||||||
/// @param value to be clamped.
|
/// @param value to be clamped.
|
||||||
|
@ -24,7 +38,21 @@ namespace MWR::Utils
|
||||||
|
|
||||||
/// Generate random string.
|
/// Generate random string.
|
||||||
/// @param size of returned string.
|
/// @param size of returned string.
|
||||||
std::string GenerateRandomString(size_t size);
|
template <typename T = std::string, std::enable_if_t<IsOneOf<T, std::string, std::wstring>::value, int> = 0>
|
||||||
|
T GenerateRandomString(size_t size)
|
||||||
|
{
|
||||||
|
constexpr std::string_view charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
static std::random_device rd;
|
||||||
|
static std::mt19937 gen(rd());
|
||||||
|
static std::uniform_int_distribution<int> uni(0, static_cast<int>(charset.size() - 1));
|
||||||
|
|
||||||
|
T randomString;
|
||||||
|
randomString.resize(size);
|
||||||
|
for (auto& e : randomString)
|
||||||
|
e = static_cast<T::value_type>(charset[uni(gen)]);
|
||||||
|
|
||||||
|
return randomString;
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate random unsigned int value.
|
/// Generate random unsigned int value.
|
||||||
/// @param rangeFrom minimal allowed value.
|
/// @param rangeFrom minimal allowed value.
|
||||||
|
@ -67,7 +95,10 @@ namespace MWR::Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Impersonation of Y2038 problem
|
/// Impersonation of Y2038 problem
|
||||||
int32_t TimeSinceEpoch();
|
inline int32_t TimeSinceEpoch()
|
||||||
|
{
|
||||||
|
return static_cast<int32_t>(std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count());
|
||||||
|
}
|
||||||
|
|
||||||
/// Alias for float based seconds
|
/// Alias for float based seconds
|
||||||
using FloatSeconds = std::chrono::duration<float, std::chrono::seconds::period>;
|
using FloatSeconds = std::chrono::duration<float, std::chrono::seconds::period>;
|
||||||
|
@ -114,4 +145,83 @@ namespace MWR::Utils
|
||||||
/// HasFoo<Bar&, int, double>::value
|
/// HasFoo<Bar&, int, double>::value
|
||||||
template<template<class...>class T, class...Ts>
|
template<template<class...>class T, class...Ts>
|
||||||
using CanApply = Details::CanApply<T, void, Ts...>;
|
using CanApply = Details::CanApply<T, void, Ts...>;
|
||||||
|
|
||||||
|
/// Function splitting string.
|
||||||
|
///
|
||||||
|
/// @tparam copy. Indicates should strings be copied.
|
||||||
|
/// @param stringToBeSplitted initial string to be tokenized.
|
||||||
|
/// @param delimiter to be searched in string.
|
||||||
|
/// @throws std::runtime_error if delimiter empty or greatter equal to stringToBeSplitted
|
||||||
|
/// @returns std::vector<std::string> or std::vector<std::string_view> depending on copy flag.
|
||||||
|
template<bool copy = false>
|
||||||
|
std::vector<std::conditional_t<copy, std::string, std::string_view>> Split(std::string_view stringToBeSplitted, std::string_view delimiter)
|
||||||
|
{
|
||||||
|
if (delimiter.empty() && delimiter.size() >= stringToBeSplitted.size())
|
||||||
|
throw std::runtime_error{ OBF("Delimiter size is incorrect") };
|
||||||
|
|
||||||
|
using ReturnType = decltype(Split<copy>(stringToBeSplitted, delimiter));
|
||||||
|
ReturnType splittedString;
|
||||||
|
// startIndex can overflow, endIndex is checked first, and lazy check on startIndex will avoid last empty token.
|
||||||
|
for (size_t startIndex = 0u, endIndex = 0u; endIndex < stringToBeSplitted.size() && startIndex < stringToBeSplitted.size(); startIndex = endIndex + delimiter.size())
|
||||||
|
{
|
||||||
|
endIndex = stringToBeSplitted.find(delimiter, startIndex);
|
||||||
|
|
||||||
|
// skip empty tokens when delimiter is repeated.
|
||||||
|
if (endIndex - startIndex)
|
||||||
|
splittedString.emplace_back(stringToBeSplitted.substr(startIndex, endIndex - startIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return splittedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Proxy to Split<true>
|
||||||
|
///
|
||||||
|
/// @param stringToBeSplitted initial string to be tokenized.
|
||||||
|
/// @param delimiter to be searched in string.
|
||||||
|
/// @throws std::runtime_error if delimiter empty or greatter equal to stringToBeSplitted
|
||||||
|
/// @returns std::vector<std::string> tokenized string.
|
||||||
|
inline std::vector<std::string> SplitAndCopy(std::string_view stringToBeSplitted, std::string_view delimiter)
|
||||||
|
{
|
||||||
|
return Split<true>(stringToBeSplitted, delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Template function allowing structured binding to new std::string or std::string_view variables from text stored in std::string_view.
|
||||||
|
///
|
||||||
|
/// auto [a,b] = ToStringArray<2>(obj);
|
||||||
|
/// @tparam expectedSize number of words that should be returned from function.
|
||||||
|
/// @tparam copy if true words will be copied to std::string variables.
|
||||||
|
/// @returns std::array<std::string, expectedSize> or std::array<std::string_view, expectedSize> array of strings. Size of array is known at compile time.
|
||||||
|
/// @throws std::runtime_error if obj does not consist at least expectedSize numer of space separated strings.
|
||||||
|
template<size_t expectedSize, bool copy = true>
|
||||||
|
std::array<std::conditional_t<copy, std::string, std::string_view>, expectedSize> ToStringArray(std::string_view obj)
|
||||||
|
{
|
||||||
|
auto splited = Split(obj, OBF(" "));
|
||||||
|
if (splited.size() < expectedSize)
|
||||||
|
throw std::runtime_error{ OBF("ByteVector does not consist expected number of strings") };
|
||||||
|
|
||||||
|
using ReturnType = decltype(ToStringArray<expectedSize, copy, modifyByteView>(obj));
|
||||||
|
ReturnType retValue;
|
||||||
|
for (auto i = 0u; i < expectedSize; ++i)
|
||||||
|
retValue[i] = splited[i];
|
||||||
|
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Idiom for detecting tuple types.
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsTuple = false;
|
||||||
|
template<typename ...T>
|
||||||
|
constexpr bool IsTuple<std::tuple<T...>> = true;
|
||||||
|
|
||||||
|
/// Prevents compiler from optimizing out call.
|
||||||
|
inline void* SecureMemzero(void* ptr, size_t n)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
volatile char* p = reinterpret_cast<volatile char*>(ptr);
|
||||||
|
while (n--) *p++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -336,7 +336,7 @@ void MWR::C3::Core::GateRelay::On(ProceduresS2G::InitializeRouteQuery&& query)
|
||||||
m_Profiler->Get().m_Gateway.ConditionalUpdateChannelParameters({ parentRid.GetAgentId(), childSideDid });
|
m_Profiler->Get().m_Gateway.ConditionalUpdateChannelParameters({ parentRid.GetAgentId(), childSideDid });
|
||||||
|
|
||||||
//send update message across route.
|
//send update message across route.
|
||||||
auto&& packet = ProceduresG2X::AddRoute::Create(parentRid, m_Signature, childRid.ToByteVector().Concat(childSideDid));
|
auto&& packet = ProceduresG2X::AddRoute::Create(parentRid, m_Signature, ByteVector::Create(childRid,childSideDid));
|
||||||
LockAndSendPacket(packet->ComposeQueryPacket(), receivedFrom);
|
LockAndSendPacket(packet->ComposeQueryPacket(), receivedFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,7 @@ namespace MWR::C3::Core
|
||||||
static std::unique_ptr<InitializeRouteQuery> Create(RouteId rid, int32_t timestamp, RouteId senderRid, DeviceId senderSideDid, ByteVector encryptedBlob, Crypto::PublicKey gatewayPublicEncryptionKey)
|
static std::unique_ptr<InitializeRouteQuery> Create(RouteId rid, int32_t timestamp, RouteId senderRid, DeviceId senderSideDid, ByteVector encryptedBlob, Crypto::PublicKey gatewayPublicEncryptionKey)
|
||||||
{
|
{
|
||||||
auto query = std::make_unique<InitializeRouteQuery>(rid, timestamp, ResponseType::None);
|
auto query = std::make_unique<InitializeRouteQuery>(rid, timestamp, ResponseType::None);
|
||||||
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Concat(rid.ToByteVector(), timestamp, senderRid.ToByteVector(), senderSideDid.ToByteVector(), encryptedBlob), gatewayPublicEncryptionKey);
|
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Write(rid, timestamp, senderRid, senderSideDid).Concat(encryptedBlob), gatewayPublicEncryptionKey);
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ namespace MWR::C3::Core
|
||||||
{
|
{
|
||||||
auto query = std::make_unique<AddDeviceResponse>(rid, timestamp, ResponseType::None);
|
auto query = std::make_unique<AddDeviceResponse>(rid, timestamp, ResponseType::None);
|
||||||
std::uint8_t flags = static_cast<std::uint8_t>(isChannel) | (static_cast<std::uint8_t>(isNegotiationChannel) << 1);
|
std::uint8_t flags = static_cast<std::uint8_t>(isChannel) | (static_cast<std::uint8_t>(isNegotiationChannel) << 1);
|
||||||
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Concat(rid.ToByteArray(), timestamp, newDeviceId.ToByteVector(), deviceTypeHash, flags), gatewayPublicEncryptionKey);
|
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Write(rid, timestamp, newDeviceId, deviceTypeHash, flags), gatewayPublicEncryptionKey);
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +382,7 @@ namespace MWR::C3::Core
|
||||||
static std::unique_ptr<DeliverToBinder> Create(RouteId rid, int32_t timestamp, DeviceId peripheralId, HashT connectorHash, ByteView blobFromPeripheral, Crypto::PublicKey gatewayPublicEncryptionKey)
|
static std::unique_ptr<DeliverToBinder> Create(RouteId rid, int32_t timestamp, DeviceId peripheralId, HashT connectorHash, ByteView blobFromPeripheral, Crypto::PublicKey gatewayPublicEncryptionKey)
|
||||||
{
|
{
|
||||||
auto query = std::make_unique<DeliverToBinder>(rid, timestamp, ResponseType::None);
|
auto query = std::make_unique<DeliverToBinder>(rid, timestamp, ResponseType::None);
|
||||||
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Concat(rid.ToByteArray(), timestamp, peripheralId.ToByteVector(), connectorHash, blobFromPeripheral), gatewayPublicEncryptionKey);
|
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Write(rid, timestamp, peripheralId, connectorHash).Concat(blobFromPeripheral), gatewayPublicEncryptionKey);
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,19 +416,7 @@ namespace MWR::C3::Core
|
||||||
static std::unique_ptr<NewNegotiatedChannelNotification> Create(RouteId rid, int32_t timestamp, DeviceId newDeviceId, DeviceId negotiatiorId, ByteView inId, ByteView outId, Crypto::PublicKey gatewayPublicEncryptionKey)
|
static std::unique_ptr<NewNegotiatedChannelNotification> Create(RouteId rid, int32_t timestamp, DeviceId newDeviceId, DeviceId negotiatiorId, ByteView inId, ByteView outId, Crypto::PublicKey gatewayPublicEncryptionKey)
|
||||||
{
|
{
|
||||||
auto query = std::make_unique<NewNegotiatedChannelNotification>(rid, timestamp, ResponseType::None);
|
auto query = std::make_unique<NewNegotiatedChannelNotification>(rid, timestamp, ResponseType::None);
|
||||||
query->m_QueryPacketBody = Crypto::EncryptAnonymously
|
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Write(rid, timestamp, newDeviceId, negotiatiorId, inId, outId), gatewayPublicEncryptionKey);
|
||||||
(
|
|
||||||
query->CompileQueryHeader()
|
|
||||||
.Concat(rid.ToByteArray())
|
|
||||||
.Write
|
|
||||||
(
|
|
||||||
timestamp
|
|
||||||
, newDeviceId.ToUnderlyingType()
|
|
||||||
, negotiatiorId.ToUnderlyingType()
|
|
||||||
, inId
|
|
||||||
, outId
|
|
||||||
)
|
|
||||||
, gatewayPublicEncryptionKey);
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,16 +437,7 @@ namespace MWR::C3::Core
|
||||||
static std::unique_ptr<Notification> Create(RouteId rid, int32_t timestamp, MWR::ByteView blob, Crypto::PublicKey gatewayPublicEncryptionKey)
|
static std::unique_ptr<Notification> Create(RouteId rid, int32_t timestamp, MWR::ByteView blob, Crypto::PublicKey gatewayPublicEncryptionKey)
|
||||||
{
|
{
|
||||||
auto query = std::make_unique<Notification>(rid, timestamp, ResponseType::None);
|
auto query = std::make_unique<Notification>(rid, timestamp, ResponseType::None);
|
||||||
query->m_QueryPacketBody = Crypto::EncryptAnonymously
|
query->m_QueryPacketBody = Crypto::EncryptAnonymously(query->CompileQueryHeader().Write(rid, timestamp, blob), gatewayPublicEncryptionKey);
|
||||||
(
|
|
||||||
query->CompileQueryHeader()
|
|
||||||
.Concat(rid.ToByteArray())
|
|
||||||
.Write
|
|
||||||
(
|
|
||||||
timestamp
|
|
||||||
, blob
|
|
||||||
)
|
|
||||||
, gatewayPublicEncryptionKey);
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ uint32_t MWR::C3::Core::Profiler::GetBinderTo(uint32_t id)
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
MWR::ByteVector MWR::C3::Core::Profiler::TranslateCommand(json const& command)
|
MWR::ByteVector MWR::C3::Core::Profiler::TranslateCommand(json const& command)
|
||||||
{
|
{
|
||||||
return ByteVector{}.Concat(command.at("id").get<uint16_t>(), TranslateArguments(command.at("arguments")));
|
return ByteVector::Create(command.at("id").get<uint16_t>()).Concat(TranslateArguments(command.at("arguments")));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -135,7 +135,7 @@ MWR::ByteVector MWR::C3::Core::Profiler::TranslateStartupCommand(json const& jco
|
||||||
if (command == createCommands.cend() || !command->m_IsDevice)
|
if (command == createCommands.cend() || !command->m_IsDevice)
|
||||||
throw std::logic_error{ "Failed to find a create command" };
|
throw std::logic_error{ "Failed to find a create command" };
|
||||||
|
|
||||||
return ByteVector{}.Concat(command->m_IsNegotiableChannel, command->m_Hash, TranslateArguments(jcommand.at("arguments")));
|
return ByteVector::Create(command->m_IsNegotiableChannel, command->m_Hash).Concat(TranslateArguments(jcommand.at("arguments")));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -713,7 +713,7 @@ void MWR::C3::Core::Profiler::Agent::PerformCreateCommand(json const& jCommandEl
|
||||||
// it is a create command
|
// it is a create command
|
||||||
DeviceId newDeviceId = ++m_LastDeviceId;
|
DeviceId newDeviceId = ++m_LastDeviceId;
|
||||||
ByteVector repacked;
|
ByteVector repacked;
|
||||||
repacked.Concat(static_cast<std::underlying_type_t<Command>>(Command::AddDevice), newDeviceId.ToByteVector(), command->m_IsNegotiableChannel, command->m_Hash);
|
repacked.Write(Command::AddDevice, newDeviceId, command->m_IsNegotiableChannel, command->m_Hash);
|
||||||
if (auto binder = profiler->GetBinderTo(command->m_Hash); binder && command->m_IsDevice) // peripheral, check if payload is needed.
|
if (auto binder = profiler->GetBinderTo(command->m_Hash); binder && command->m_IsDevice) // peripheral, check if payload is needed.
|
||||||
{
|
{
|
||||||
auto connector = profiler->m_Gateway->m_Gateway.lock()->GetConnector(binder);
|
auto connector = profiler->m_Gateway->m_Gateway.lock()->GetConnector(binder);
|
||||||
|
|
Loading…
Reference in New Issue