// SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #pragma once #include namespace skyline::service::hosbinder { /** * @brief This allows easy access and efficient serialization of an Android Parcel object * @url https://switchbrew.org/wiki/Display_services#Parcel */ class Parcel { private: struct ParcelHeader { u32 dataSize; u32 dataOffset; u32 objectsSize; u32 objectsOffset; } header{}; static_assert(sizeof(ParcelHeader) == 0x10); const DeviceState &state; public: std::vector data; std::vector objects; size_t dataOffset{}; //!< The offset of the data read from the parcel /** * @brief This constructor fills in the Parcel object with data from a IPC buffer * @param buffer The buffer that contains the parcel * @param hasToken If the parcel starts with a token, it's skipped if this flag is true */ Parcel(span buffer, const DeviceState &state, bool hasToken = false); /** * @brief This constructor is used to create an empty parcel then write to a process */ Parcel(const DeviceState &state); /** * @return A reference to an item from the top of data */ template ValueType &Pop() { ValueType &value{*reinterpret_cast(data.data() + dataOffset)}; dataOffset += sizeof(ValueType); return value; } /** * @return A reference to an item from the top of data */ template ValueType &PopFlattenable() { auto size{Pop()}; if (size != sizeof(ValueType)) throw exception("Popping flattenable of size 0x{:X} with type size 0x{:X}", size, sizeof(ValueType)); return Pop(); } /** * @return A pointer to an optional flattenable from the top of data, nullptr will be returned if the object doesn't exist */ template ValueType *PopOptionalFlattenable() { bool hasObject{Pop() != 0}; if (hasObject) return &PopFlattenable(); else return nullptr; } template void Push(const ValueType &value) { auto offset{data.size()}; data.resize(offset + sizeof(ValueType)); std::memcpy(data.data() + offset, &value, sizeof(ValueType)); } /** * @brief Writes a 32-bit boolean flag denoting if an object exists alongside the object if it exists */ template void PushOptionalFlattenable(ObjectType *pointer) { Push(pointer != nullptr); if (pointer) { Push(sizeof(ObjectType)); // Object Size Push(*pointer); } } template void PushOptionalFlattenable(std::optional object) { Push(object.has_value()); if (object) { Push(sizeof(ObjectType)); Push(*object); } } template void PushObject(const ObjectType &object) { auto offset{objects.size()}; objects.resize(offset + sizeof(ObjectType)); std::memcpy(objects.data() + offset, &object, sizeof(ObjectType)); } /** * @param buffer The buffer to write the flattened Parcel into * @return The total size of the Parcel */ u64 WriteParcel(span buffer); }; }