2 changed files with 172 additions and 0 deletions
@ -0,0 +1,171 @@ |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
// Copyright 2021 yuzu Emulator Project |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <vector> |
|||
|
|||
#include "common/alignment.h" |
|||
#include "common/assert.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace android { |
|||
|
|||
class Parcel final { |
|||
public: |
|||
static constexpr std::size_t DefaultBufferSize = 0x40; |
|||
|
|||
Parcel() : buffer(DefaultBufferSize) {} |
|||
|
|||
template <typename T> |
|||
explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) { |
|||
Write(out_data); |
|||
} |
|||
|
|||
explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) { |
|||
DeserializeHeader(); |
|||
[[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
|||
} |
|||
|
|||
template <typename T> |
|||
void Read(T& val) { |
|||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); |
|||
ASSERT(read_index + sizeof(T) <= buffer.size()); |
|||
|
|||
std::memcpy(&val, buffer.data() + read_index, sizeof(T)); |
|||
read_index += sizeof(T); |
|||
read_index = Common::AlignUp(read_index, 4); |
|||
} |
|||
|
|||
template <typename T> |
|||
T Read() { |
|||
T val; |
|||
Read(val); |
|||
return val; |
|||
} |
|||
|
|||
template <typename T> |
|||
void ReadFlattened(T& val) { |
|||
const auto flattened_size = Read<s64>(); |
|||
ASSERT(sizeof(T) == flattened_size); |
|||
Read(val); |
|||
} |
|||
|
|||
template <typename T> |
|||
T ReadFlattened() { |
|||
T val; |
|||
ReadFlattened(val); |
|||
return val; |
|||
} |
|||
|
|||
template <typename T> |
|||
T ReadUnaligned() { |
|||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); |
|||
ASSERT(read_index + sizeof(T) <= buffer.size()); |
|||
|
|||
T val; |
|||
std::memcpy(&val, buffer.data() + read_index, sizeof(T)); |
|||
read_index += sizeof(T); |
|||
return val; |
|||
} |
|||
|
|||
template <typename T> |
|||
const std::shared_ptr<T> ReadObject() { |
|||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); |
|||
|
|||
const auto is_valid{Read<bool>()}; |
|||
|
|||
if (is_valid) { |
|||
auto result = std::make_shared<T>(); |
|||
ReadFlattened(*result); |
|||
return result; |
|||
} |
|||
|
|||
return {}; |
|||
} |
|||
|
|||
std::u16string ReadInterfaceToken() { |
|||
[[maybe_unused]] const u32 unknown = Read<u32>(); |
|||
const u32 length = Read<u32>(); |
|||
|
|||
std::u16string token{}; |
|||
|
|||
for (u32 ch = 0; ch < length + 1; ++ch) { |
|||
token.push_back(ReadUnaligned<u16>()); |
|||
} |
|||
|
|||
read_index = Common::AlignUp(read_index, 4); |
|||
|
|||
return token; |
|||
} |
|||
|
|||
template <typename T> |
|||
void Write(const T& val) { |
|||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); |
|||
|
|||
if (buffer.size() < write_index + sizeof(T)) { |
|||
buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize); |
|||
} |
|||
|
|||
std::memcpy(buffer.data() + write_index, &val, sizeof(T)); |
|||
write_index += sizeof(T); |
|||
write_index = Common::AlignUp(write_index, 4); |
|||
} |
|||
|
|||
template <typename T> |
|||
void WriteObject(const T* ptr) { |
|||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); |
|||
|
|||
if (!ptr) { |
|||
Write<u32>(0); |
|||
return; |
|||
} |
|||
|
|||
Write<u32>(1); |
|||
Write<s64>(sizeof(T)); |
|||
Write(*ptr); |
|||
} |
|||
|
|||
template <typename T> |
|||
void WriteObject(const std::shared_ptr<T> ptr) { |
|||
WriteObject(ptr.get()); |
|||
} |
|||
|
|||
void DeserializeHeader() { |
|||
ASSERT(buffer.size() > sizeof(Header)); |
|||
|
|||
Header header{}; |
|||
std::memcpy(&header, buffer.data(), sizeof(Header)); |
|||
|
|||
read_index = header.data_offset; |
|||
} |
|||
|
|||
std::vector<u8> Serialize() const { |
|||
ASSERT(read_index == 0); |
|||
|
|||
Header header{}; |
|||
header.data_size = static_cast<u32>(write_index - sizeof(Header)); |
|||
header.data_offset = sizeof(Header); |
|||
header.objects_size = 4; |
|||
header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size); |
|||
std::memcpy(buffer.data(), &header, sizeof(Header)); |
|||
|
|||
return buffer; |
|||
} |
|||
|
|||
private: |
|||
struct Header { |
|||
u32 data_size; |
|||
u32 data_offset; |
|||
u32 objects_size; |
|||
u32 objects_offset; |
|||
}; |
|||
static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); |
|||
|
|||
mutable std::vector<u8> buffer; |
|||
std::size_t read_index = 0; |
|||
std::size_t write_index = sizeof(Header); |
|||
}; |
|||
|
|||
} // namespace android |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue