summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2018-06-07 11:38:47 +0200
committerOdd Stranne <odd@mullvad.net>2018-06-18 08:45:16 +0200
commitbc557d2a36dafcb0c7cba8e0dd43fcb7e5613e6f (patch)
treec37acd88f7a9c75ab1095424af82e6ef79d9bcb8
parentef99f821022c35eec1f2a4feb1f0f348d340f9f3 (diff)
downloadmullvadvpn-bc557d2a36dafcb0c7cba8e0dd43fcb7e5613e6f.tar.xz
mullvadvpn-bc557d2a36dafcb0c7cba8e0dd43fcb7e5613e6f.zip
Add serialization classes
-rw-r--r--windows/windns/src/windns/serialization/deserializer.cpp108
-rw-r--r--windows/windns/src/windns/serialization/deserializer.h34
-rw-r--r--windows/windns/src/windns/serialization/serializer.cpp111
-rw-r--r--windows/windns/src/windns/serialization/serializer.h33
-rw-r--r--windows/windns/src/windns/serialization/typetag.h21
-rw-r--r--windows/windns/src/windns/windns.vcxproj5
-rw-r--r--windows/windns/src/windns/windns.vcxproj.filters18
7 files changed, 330 insertions, 0 deletions
diff --git a/windows/windns/src/windns/serialization/deserializer.cpp b/windows/windns/src/windns/serialization/deserializer.cpp
new file mode 100644
index 0000000000..dce6ada950
--- /dev/null
+++ b/windows/windns/src/windns/serialization/deserializer.cpp
@@ -0,0 +1,108 @@
+#include "stdafx.h"
+#include "deserializer.h"
+#include <stdexcept>
+
+namespace common::serialization
+{
+
+Deserializer::Deserializer(const uint8_t *blob, size_t size)
+ : m_blob(blob, blob + size)
+ , m_offset(0)
+{
+}
+
+void Deserializer::operator>>(uint8_t &data)
+{
+ validateType(TypeTag::Uint8);
+
+ read(&data, sizeof(data));
+}
+
+void Deserializer::operator>>(uint16_t &data)
+{
+ validateType(TypeTag::Uint16);
+
+ read(&data, sizeof(data));
+}
+
+void Deserializer::operator>>(uint32_t &data)
+{
+ validateType(TypeTag::Uint32);
+
+ read(&data, sizeof(data));
+}
+
+void Deserializer::operator>>(GUID &data)
+{
+ validateType(TypeTag::Guid);
+
+ read(&data, sizeof(data));
+}
+
+void Deserializer::operator>>(std::wstring &data)
+{
+ validateType(TypeTag::String);
+
+ uint32_t strByteLength;
+
+ read(&strByteLength, sizeof(strByteLength));
+
+ if (0 == strByteLength)
+ {
+ data.clear();
+ return;
+ }
+
+ std::vector<uint8_t> raw(strByteLength);
+
+ read(&raw[0], strByteLength);
+
+ data = std::wstring
+ (
+ reinterpret_cast<wchar_t *>(&raw[0]),
+ reinterpret_cast<wchar_t *>(&raw[0]) + (strByteLength / sizeof(wchar_t))
+ );
+}
+
+void Deserializer::operator>>(std::vector<std::wstring> &data)
+{
+ validateType(TypeTag::StringArray);
+
+ uint32_t elements;
+
+ read(&elements, sizeof(elements));
+
+ data.clear();
+
+ for (uint32_t i = 0; i < elements; ++i)
+ {
+ data.emplace_back(std::wstring());
+ *this >> *data.rbegin();
+ }
+}
+
+void Deserializer::validateType(TypeTag type)
+{
+ uint8_t readType;
+
+ read(&readType, sizeof(uint8_t));
+
+ if (readType != static_cast<uint8_t>(type))
+ {
+ throw std::runtime_error("Unexpected data type in stream");
+ }
+}
+
+void Deserializer::read(void *data, size_t length)
+{
+ if (m_offset + length > m_blob.size())
+ {
+ throw std::runtime_error("Read probe passed end of stream");
+ }
+
+ memcpy(data, &m_blob[m_offset], length);
+
+ m_offset += length;
+}
+
+}
diff --git a/windows/windns/src/windns/serialization/deserializer.h b/windows/windns/src/windns/serialization/deserializer.h
new file mode 100644
index 0000000000..a2c59400fd
--- /dev/null
+++ b/windows/windns/src/windns/serialization/deserializer.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "typetag.h"
+#include <vector>
+#include <string>
+#include <cstdint>
+#include <guiddef.h>
+
+namespace common::serialization
+{
+
+class Deserializer
+{
+public:
+
+ Deserializer(const uint8_t *blob, size_t size);
+
+ void operator>>(uint8_t &data);
+ void operator>>(uint16_t &data);
+ void operator>>(uint32_t &data);
+ void operator>>(GUID &data);
+ void operator>>(std::wstring &data);
+ void operator>>(std::vector<std::wstring> &data);
+
+private:
+
+ std::vector<uint8_t> m_blob;
+ size_t m_offset;
+
+ void validateType(TypeTag type);
+ void read(void *data, size_t length);
+};
+
+}
diff --git a/windows/windns/src/windns/serialization/serializer.cpp b/windows/windns/src/windns/serialization/serializer.cpp
new file mode 100644
index 0000000000..e4af65db98
--- /dev/null
+++ b/windows/windns/src/windns/serialization/serializer.cpp
@@ -0,0 +1,111 @@
+#include "stdafx.h"
+#include "serializer.h"
+#include <algorithm>
+
+namespace
+{
+
+void Append(std::vector<uint8_t> &v, const void *data, size_t length)
+{
+ if (0 == length)
+ {
+ return;
+ }
+
+ const auto oldSize = v.size();
+
+ v.resize(oldSize + length);
+ memcpy(&v[oldSize], data, length);
+}
+
+std::vector<uint8_t> PackageString(const wchar_t *str)
+{
+ const auto strByteLength = static_cast<uint32_t>(wcslen(str) * sizeof(wchar_t));
+
+ std::vector<uint8_t> data;
+
+ Append(data, &strByteLength, sizeof(strByteLength));
+ Append(data, str, strByteLength);
+
+ return data;
+}
+
+} // anonymous namespace
+
+namespace common::serialization
+{
+
+void Serializer::operator<<(uint8_t data)
+{
+ append(TypeTag::Uint8, &data, sizeof(uint8_t));
+}
+
+void Serializer::operator<<(uint16_t data)
+{
+ append(TypeTag::Uint16, &data, sizeof(uint16_t));
+}
+
+void Serializer::operator<<(uint32_t data)
+{
+ append(TypeTag::Uint32, &data, sizeof(uint32_t));
+}
+
+void Serializer::operator<<(const GUID &data)
+{
+ append(TypeTag::Guid, &data, sizeof(GUID));
+}
+
+void Serializer::operator<<(const std::wstring &data)
+{
+ auto packaged = PackageString(data.c_str());
+
+ append(TypeTag::String, &packaged[0], packaged.size());
+}
+
+void Serializer::operator<<(const wchar_t *data)
+{
+ auto packaged = PackageString(data);
+
+ append(TypeTag::String, &packaged[0], packaged.size());
+}
+
+void Serializer::operator<<(const std::vector<std::wstring> &data)
+{
+ std::vector<uint8_t> arrayBlob;
+
+ uint32_t count = static_cast<uint32_t>(data.size());
+
+ Append(arrayBlob, &count, sizeof(count));
+
+ std::for_each(data.begin(), data.end(), [&](const std::wstring &str)
+ {
+ auto packagedStr = PackageString(str.c_str());
+
+ // Hack? Makes parsing a lot simpler
+ arrayBlob.push_back(static_cast<uint8_t>(TypeTag::String));
+
+ Append(arrayBlob, &packagedStr[0], packagedStr.size());
+ });
+
+ append(TypeTag::StringArray, &arrayBlob[0], arrayBlob.size());
+}
+
+const std::vector<uint8_t> &Serializer::blob() const
+{
+ return m_blob;
+}
+
+void Serializer::append(TypeTag type, const void *data, size_t length)
+{
+ const auto elementSize = sizeof(uint8_t) + length;
+ const auto oldSize = m_blob.size();
+
+ m_blob.resize(oldSize + elementSize);
+
+ auto dest = &m_blob[oldSize];
+
+ *dest++ = static_cast<uint8_t>(type);
+ memcpy(dest, data, length);
+}
+
+}
diff --git a/windows/windns/src/windns/serialization/serializer.h b/windows/windns/src/windns/serialization/serializer.h
new file mode 100644
index 0000000000..63e9fdd5bb
--- /dev/null
+++ b/windows/windns/src/windns/serialization/serializer.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "typetag.h"
+#include <vector>
+#include <string>
+#include <cstdint>
+#include <guiddef.h>
+
+namespace common::serialization
+{
+
+class Serializer
+{
+public:
+
+ void operator<<(uint8_t data);
+ void operator<<(uint16_t data);
+ void operator<<(uint32_t data);
+ void operator<<(const GUID &data);
+ void operator<<(const std::wstring &data);
+ void operator<<(const wchar_t *data);
+ void operator<<(const std::vector<std::wstring> &data);
+
+ const std::vector<uint8_t> &blob() const;
+
+private:
+
+ std::vector<uint8_t> m_blob;
+
+ void append(TypeTag type, const void *data, size_t length);
+};
+
+}
diff --git a/windows/windns/src/windns/serialization/typetag.h b/windows/windns/src/windns/serialization/typetag.h
new file mode 100644
index 0000000000..a2ab3cccc3
--- /dev/null
+++ b/windows/windns/src/windns/serialization/typetag.h
@@ -0,0 +1,21 @@
+#pragma once
+
+namespace common::serialization
+{
+
+enum class TypeTag
+{
+ Uint8,
+ Uint16,
+ Uint32,
+ Guid, // data = binary 16 bytes
+ String, // data = [uint32: byte length], [UCS-2 string], [NOT zero terminated]
+ StringArray // data = [uint32: count], count * String
+};
+
+//
+// Each entry is serialized as:
+// [uint8: type], [data]
+//
+
+}
diff --git a/windows/windns/src/windns/windns.vcxproj b/windows/windns/src/windns/windns.vcxproj
index 6444255869..89d5c89d33 100644
--- a/windows/windns/src/windns/windns.vcxproj
+++ b/windows/windns/src/windns/windns.vcxproj
@@ -186,6 +186,9 @@
<ClInclude Include="netconfigeventsink.h" />
<ClInclude Include="netconfighelpers.h" />
<ClInclude Include="netsh.h" />
+ <ClInclude Include="serialization\deserializer.h" />
+ <ClInclude Include="serialization\serializer.h" />
+ <ClInclude Include="serialization\typetag.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="windns.h" />
@@ -208,6 +211,8 @@
<ClCompile Include="netconfigeventsink.cpp" />
<ClCompile Include="netconfighelpers.cpp" />
<ClCompile Include="netsh.cpp" />
+ <ClCompile Include="serialization\deserializer.cpp" />
+ <ClCompile Include="serialization\serializer.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
diff --git a/windows/windns/src/windns/windns.vcxproj.filters b/windows/windns/src/windns/windns.vcxproj.filters
index fcfb5045bc..ff323bfefa 100644
--- a/windows/windns/src/windns/windns.vcxproj.filters
+++ b/windows/windns/src/windns/windns.vcxproj.filters
@@ -37,6 +37,15 @@
</ClInclude>
<ClInclude Include="netsh.h" />
<ClInclude Include="interfaceconfig.h" />
+ <ClInclude Include="serialization\deserializer.h">
+ <Filter>serialization</Filter>
+ </ClInclude>
+ <ClInclude Include="serialization\serializer.h">
+ <Filter>serialization</Filter>
+ </ClInclude>
+ <ClInclude Include="serialization\typetag.h">
+ <Filter>serialization</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
@@ -66,10 +75,19 @@
</ClCompile>
<ClCompile Include="netsh.cpp" />
<ClCompile Include="interfaceconfig.cpp" />
+ <ClCompile Include="serialization\deserializer.cpp">
+ <Filter>serialization</Filter>
+ </ClCompile>
+ <ClCompile Include="serialization\serializer.cpp">
+ <Filter>serialization</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="wmi">
<UniqueIdentifier>{5deb73ee-53cc-49ac-bcdd-0a4b38914f0e}</UniqueIdentifier>
</Filter>
+ <Filter Include="serialization">
+ <UniqueIdentifier>{94b59808-58b6-431c-9b5a-e0bd5315a7af}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project> \ No newline at end of file