| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- #pragma once
- #include <Windows.h>
- #include <array>
- #include <cstddef>
- #include <cstdint>
- #include <cstring>
- #include <map>
- #include <span>
- #include <vector>
- #include "../../../middleware/content/packages/reader/reader.h"
- #include "../../../middleware/crypto/sha256.h"
- #include "activity_sdk_decode_plans.h"
- namespace sunrise::client::content::activity::sdk_generation::decode_plans::internal {
- namespace reader = middleware::content::packages::reader;
- using Digest = middleware::crypto::sha256::Digest;
- /** Absent handle or index in package and reflection data. */
- inline constexpr std::uint32_t kAbsent = 0xFFFFFFFFU;
- /** Reflection record block chain marker and the generic-argument marker before it. */
- inline constexpr std::uint32_t kReflectionMarker = 0x80800050U;
- inline constexpr std::uint32_t kGenericMarker = 0x8080001DU;
- /** Reflection block classes: field codec, property list, method list, empty tail. */
- inline constexpr std::uint32_t kCodecBlock = 0x8080010AU;
- inline constexpr std::uint32_t kPropertyBlock = 0x8080012FU;
- inline constexpr std::uint32_t kMethodBlock = 0x8080010DU;
- inline constexpr std::uint32_t kTailBlock = 0x8080004CU;
- /** Generic container kinds a property may declare. */
- inline constexpr std::uint32_t kGenericSimple = 0x80809C37U;
- inline constexpr std::uint32_t kGenericDynamicA = 0x80809FBAU;
- inline constexpr std::uint32_t kGenericDynamicB = 0x80809C38U;
- inline constexpr std::uint32_t kDynamicDeclared = 0x80809FBBU;
- inline constexpr std::uint32_t kGenericInline = 0x80809FFCU;
- inline constexpr std::uint32_t kGenericCounted = 0x80809ED8U;
- /** Package classes: the array marker, a selection child row, metadata, and a selection. */
- inline constexpr std::uint32_t kArrayMarker = 0x80809FBDU;
- inline constexpr std::uint32_t kSelectionChildClass = 0x80808852U;
- inline constexpr std::uint32_t kPackageMetadataClass = 0x80800000U;
- inline constexpr std::uint32_t kSelectionClass = 0x80809BBBU;
- /** Metadata kinds that select a plan branch: plain value and generic container. */
- inline constexpr std::uint8_t kKindValue = 1;
- inline constexpr std::uint8_t kKindContainer = 11;
- /** Field type code of a nested schema; codes above 63 have no primitive size. */
- inline constexpr std::uint8_t kTypeNested = 1;
- inline constexpr std::uint8_t kTypeLimit = 64;
- /** Capacities the runtime decoder shares with the compiler. */
- inline constexpr std::size_t kMaximumDepth = 32;
- inline constexpr std::size_t kMaximumSteps = 65536;
- inline constexpr std::uint32_t kMaximumRepeat = 16384;
- inline constexpr std::uint32_t kMaximumSectionCount = 65536;
- inline constexpr std::uint64_t kMaximumArrayCount = 0x100000U;
- /** Stride of one codec field descriptor. */
- inline constexpr std::size_t kFieldRowSize = 40;
- /** Candidate offsets of the block chain marker inside a reflection record. */
- inline constexpr std::array<std::uint32_t, 4> kMarkerOffsets{0x58, 0x60, 0x68, 0x70};
- /** Header size and row stride of each reflection block class. */
- struct BlockLayout final {
- std::uint32_t header{};
- std::uint32_t stride{};
- };
- /**
- * Looks up the header size and row stride of one reflection block class.
- * @return False for an unknown block class.
- */
- [[nodiscard]] inline bool block_layout(std::uint32_t kind, BlockLayout& output) noexcept {
- switch (kind) {
- case kCodecBlock:
- output = {0x28, 0x28};
- return true;
- case kPropertyBlock:
- output = {0x20, 0x0C};
- return true;
- case kMethodBlock:
- output = {0x10, 0x08};
- return true;
- case kTailBlock:
- output = {0x18, 0x00};
- return true;
- default:
- return false;
- }
- }
- /** Copies one unaligned value. @return False when it does not fit inside `bytes`. */
- template <typename T>
- [[nodiscard]] bool read_at(std::span<const std::byte> bytes, std::size_t at, T& value) noexcept {
- if (at > bytes.size() || bytes.size() - at < sizeof(T)) {
- return false;
- }
- std::memcpy(&value, bytes.data() + at, sizeof(T));
- return true;
- }
- /** One codec field descriptor in reflection or package layout. */
- struct Field final {
- std::uint32_t offset{};
- std::uint32_t alternate{};
- std::uint32_t bit{};
- float half{};
- std::uint8_t type{};
- std::uint8_t presence{};
- std::uint16_t parameter2{};
- std::uint32_t nested{};
- std::int32_t bias{};
- std::int32_t width{};
- std::uint32_t parameter3{};
- std::uint32_t parameter4{};
- };
- /** One field codec block. */
- struct Codec final {
- bool present{};
- std::uint32_t original{};
- std::uint32_t serialized{};
- std::uint32_t flags{};
- std::uint32_t array{};
- std::vector<Field> fields{};
- };
- /** One declared property: name hash, member type handle, byte offset. */
- struct Property final {
- std::uint32_t nameHash{};
- std::uint32_t memberType{};
- std::uint32_t byteOffset{};
- };
- /** One reflection or package metadata record. */
- struct Metadata final {
- bool package{};
- std::uint32_t size{};
- std::uint8_t alignment{};
- std::uint8_t kind{};
- bool hasGeneric{};
- std::uint32_t generic{};
- Codec codec{};
- bool hasProperties{};
- Property base{};
- std::vector<Property> properties{};
- };
- /** One schema row of the cache: handle, serialized size, first field value, field count. */
- struct SchemaRow final {
- std::uint32_t handle{};
- std::uint32_t size{};
- std::uint32_t first{};
- std::uint32_t count{};
- };
- /**
- * The executable's reflection records and slot index.
- * The shipped file is packed and its slot table exists only in memory, so a live build reads the
- * mapped module and hashes the file; an offline build reads and hashes an unpacked dump.
- */
- class Image final {
- public:
- Image() = default;
- Image(const Image&) = delete;
- Image& operator=(const Image&) = delete;
- ~Image() noexcept;
- /** Maps the file at `path`; a non-null `module` base makes the reads come from memory. */
- [[nodiscard]] Status open(const wchar_t* path, const void* module) noexcept;
- /** @return The whole file on disk, for the evidence digest. */
- [[nodiscard]] std::span<const std::byte> file() const noexcept;
- /** @return The bytes the reflection reads go through: the file or the mapped module. */
- [[nodiscard]] std::span<const std::byte> bytes() const noexcept;
- /** Bound handle to reflection record address, first slot wins. */
- [[nodiscard]] const std::map<std::uint32_t, std::uint64_t>& slots() const noexcept {
- return slots_;
- }
- /** Address of the 64-entry primitive size table, one u32 per field type code. */
- [[nodiscard]] std::uint64_t primitive_sizes() const noexcept {
- return primitiveSizes_;
- }
- [[nodiscard]] bool u8(std::uint64_t address, std::uint8_t& value) const noexcept;
- [[nodiscard]] bool u16(std::uint64_t address, std::uint16_t& value) const noexcept;
- [[nodiscard]] bool u32(std::uint64_t address, std::uint32_t& value) const noexcept;
- [[nodiscard]] bool i32(std::uint64_t address, std::int32_t& value) const noexcept;
- [[nodiscard]] bool f32(std::uint64_t address, float& value) const noexcept;
- private:
- struct Section final {
- std::uint64_t virtualAddress{};
- std::uint64_t virtualSize{};
- std::uint64_t rawOffset{};
- std::uint64_t rawSize{};
- bool data{};
- bool code{};
- };
- [[nodiscard]] bool
- offset(std::uint64_t address, std::size_t size, std::size_t& at) const noexcept;
- [[nodiscard]] bool parse_headers(bool mapped) noexcept;
- [[nodiscard]] bool index_slots() noexcept;
- [[nodiscard]] bool resolve_primitive_sizes() noexcept;
- HANDLE file_{INVALID_HANDLE_VALUE};
- HANDLE mapping_{};
- const std::byte* view_{};
- std::size_t viewSize_{};
- /** Read source: the file view, or the module memory with its SizeOfImage. */
- const std::byte* data_{};
- std::size_t size_{};
- std::uint64_t imageBase_{};
- std::uint64_t vmp0Low_{};
- std::uint64_t vmp0High_{};
- std::uint64_t primitiveSizes_{};
- std::vector<Section> sections_{};
- std::map<std::uint32_t, std::uint64_t> slots_{};
- };
- /** Metadata records read so far, plus the package blob digests the evidence needs. */
- class Store final {
- public:
- Store(const Image& image, const reader::Source& source, reader::Scratch& scratch) noexcept
- : image_(image), source_(source), scratch_(scratch) {}
- /** @return The record, or null with the failure named in `error`. */
- [[nodiscard]] const Metadata* get(std::uint32_t handle, const char*& error) noexcept;
- [[nodiscard]] const Image& image() const noexcept {
- return image_;
- }
- [[nodiscard]] std::map<std::uint32_t, Digest>& package_hashes() noexcept {
- return packageHashes_;
- }
- [[nodiscard]] const std::map<std::uint32_t, Metadata>& entries() const noexcept {
- return entries_;
- }
- [[nodiscard]] bool read_package(std::uint32_t tag,
- std::uint32_t expectedClass,
- std::vector<std::byte>& output) noexcept;
- private:
- const Image& image_;
- const reader::Source& source_;
- reader::Scratch& scratch_;
- std::map<std::uint32_t, Metadata> entries_{};
- std::map<std::uint32_t, Digest> packageHashes_{};
- };
- /** One compiled plan entry in cache row order. */
- struct PlanEntry final {
- std::uint32_t schemaHandle{};
- std::uint32_t repeatCount{};
- std::uint32_t guardBit{};
- std::uint32_t firstFieldBit{};
- std::uint32_t fieldBitStride{};
- };
- /** One compiled component and selection pair. */
- struct Plan final {
- std::uint32_t component{};
- std::uint32_t schemaTag{};
- std::vector<PlanEntry> entries{};
- std::uint32_t bitmapBits{};
- bool active{};
- };
- /** Parses one bound reflection record at `address` for the compiler. */
- [[nodiscard]] bool parse_native(const Image& image,
- std::uint64_t address,
- Metadata& output,
- const char*& error) noexcept;
- /** Parses one package metadata blob for the compiler. */
- [[nodiscard]] bool parse_package(std::uint32_t handle,
- std::span<const std::byte> blob,
- Metadata& output,
- const char*& error) noexcept;
- /** Resolves the presence bit guarding `offset` inside `handle`; -1 when no field covers it. */
- [[nodiscard]] bool property_guard(Store& store,
- std::uint32_t handle,
- std::uint64_t offset,
- std::int64_t& guard,
- const char*& error) noexcept;
- /** Compiles one selection blob against its component's reflection metadata. */
- [[nodiscard]] bool compile(Store& store,
- std::uint32_t component,
- std::span<const std::byte> blob,
- Plan& output,
- const char*& error) noexcept;
- /** Indexes every bound codec block into schema rows sorted by handle. */
- [[nodiscard]] bool build_codec_index(const Image& image,
- std::vector<SchemaRow>& rows,
- std::vector<std::uint32_t>& fieldValues,
- const char*& error) noexcept;
- } // namespace sunrise::client::content::activity::sdk_generation::decode_plans::internal
|