#include "opcode701_codec.h" #include #include #include #include #include #include "../../../../state/account/settings/native_key_binding_map.h" #include "../../../../state/account/settings/settings_state.h" #include "../../../encoding/bit_reader.h" namespace sunrise::middleware::web_service::messages::opcode701 { namespace { using encoding::bits::Reader; namespace settings = state::account::settings; // Schema 0x80807603 is presence-driven: an absent node consumes no bits and nothing is byte // aligned, so every presence flag must be read or later fields land at the wrong offset. /** Wire primitive widths used by schema 0x80807603. */ constexpr std::uint8_t kPresenceWidthBits = 1; constexpr std::uint8_t kBooleanWidthBits = 1; constexpr std::uint8_t kTwoWidthBits = 2; constexpr std::uint8_t kThreeWidthBits = 3; constexpr std::uint8_t kFourWidthBits = 4; constexpr std::uint8_t kFiveWidthBits = 5; constexpr std::uint8_t kSixWidthBits = 6; constexpr std::uint8_t kByteWidthBits = 8; constexpr std::uint8_t kScalar16WidthBits = 16; constexpr std::uint8_t kScalar32WidthBits = 32; constexpr std::uint8_t kScalar64WidthBits = 64; /** Schema array dimensions, kept separate from scalar widths. */ constexpr std::size_t kPublicityExpiryCount = 128; constexpr std::size_t kSeenMessageCount = 13; constexpr std::size_t kCalibrationVectorCount = 2; constexpr std::size_t kCalibrationValuesPerVector = 2; constexpr std::size_t kPreferenceMatrixRowCount = 3; constexpr std::size_t kPreferenceMatrixColumnCount = 50; constexpr std::size_t kGroup_0_1_4OptionalFieldCount = 8; constexpr std::size_t kGroup_0_1_3ValueCount = 4; constexpr std::size_t kGroup_0_1_5ValueCount = 22; constexpr std::size_t kGroup_0_1_6EntryCount = 100; constexpr std::size_t kGroup_0_1_6FixedWordCount = 2; constexpr std::size_t kGroup_0_1_12ValueCount = 30; constexpr std::size_t kGroup_0_1_12FixedWordCount = 2; constexpr std::size_t kOuterBlobCount = 2; /** Catalog invariants used to detect accidental table/schema drift at compile time. */ constexpr std::size_t kCatalogPreferenceFieldCount = 62; constexpr std::size_t kCatalogKeyBindingCount = 60; constexpr std::size_t kCatalogRootMetadataMaximumBits = 8'739; constexpr std::size_t kCatalogPreferencesMaximumBits = 5'300; constexpr std::size_t kCatalogBindingsMaximumBits = 1'996; constexpr std::size_t kCatalogAccountBranchMaximumBits = 10'956; constexpr std::size_t kCatalogMaximumBits = 19'695; /** A packed binding half with this value represents no assigned input. */ constexpr std::uint16_t kUnboundInputCode = settings::bindings::kUnboundInputCode; /** Each packed binding word stores one primary half followed by one secondary half. */ constexpr unsigned kBindingHalfWidthBits = kScalar16WidthBits; /** Outer blobs encode their byte length in one unsigned 16-bit field. */ constexpr std::uint8_t kOuterBlobLengthWidthBits = kScalar16WidthBits; /** A whole unread byte is data, while fewer than eight final bits may be terminal padding. */ constexpr std::size_t kTerminalPaddingLimitBits = kByteWidthBits; /** Returns the bit count of a required fixed-width array. */ [[nodiscard]] constexpr std::size_t fixed_array_width_bits(std::size_t count, std::size_t widthBits) noexcept { return count * widthBits; } /** One scalar descriptor's stored width, destination width, and modular wire bias. */ struct ScalarEncoding { std::uint8_t wireWidthBits; std::uint8_t nativeWidthBits; std::uint64_t bias; }; /** Compact signed selectors store the destination value plus one. */ constexpr std::uint64_t kCompactIntegerBias = 1; /** Reflected signed 32-bit values store the destination bit pattern plus INT32_MIN. */ constexpr std::uint64_t kSigned32Bias = 0x80000000ULL; /** Wire width, native width and bias for the bool and the two- and three-bit selectors. */ constexpr ScalarEncoding kBoolEncoding{kBooleanWidthBits, kBooleanWidthBits, 0}; constexpr ScalarEncoding kInt8TwoBitEncoding{kTwoWidthBits, kByteWidthBits, kCompactIntegerBias}; constexpr ScalarEncoding kInt8ThreeBitEncoding{ kThreeWidthBits, kByteWidthBits, kCompactIntegerBias}; /** Same for the four-bit selector and the two reflected 32-bit types. */ constexpr ScalarEncoding kInt8FourBitEncoding{kFourWidthBits, kByteWidthBits, kCompactIntegerBias}; constexpr ScalarEncoding kInt32Encoding{kScalar32WidthBits, kScalar32WidthBits, kSigned32Bias}; constexpr ScalarEncoding kReal32Encoding{kScalar32WidthBits, kScalar32WidthBits, 0}; /** Field and binding counts the catalog fixes; the static_assert below holds them. */ constexpr std::size_t kPreferenceFieldCount = kCatalogPreferenceFieldCount; constexpr std::size_t kKeyBindingCount = settings::bindings::kActionCount; static_assert(kKeyBindingCount == kCatalogKeyBindingCount); /** Reinterprets an already-unbiased byte pattern as its signed destination value. */ [[nodiscard]] constexpr std::int8_t as_int8(std::uint64_t value) noexcept { return std::bit_cast(static_cast(value)); } /** Reinterprets an already-unbiased 32-bit pattern as its signed destination value. */ [[nodiscard]] constexpr std::int32_t as_int32(std::uint64_t value) noexcept { return std::bit_cast(static_cast(value)); } /** Reinterprets a raw IEEE-754 32-bit pattern without applying an integer conversion. */ [[nodiscard]] constexpr float as_real32(std::uint64_t value) noexcept { return std::bit_cast(static_cast(value)); } /** Typed assignment adapters let each schema descriptor name its exact nested delta member. */ template void assign_bool(std::uint64_t value, Request& output) noexcept { (output.settings.*GroupMember).*FieldMember = value != 0; } template void assign_int8(std::uint64_t value, Request& output) noexcept { (output.settings.*GroupMember).*FieldMember = as_int8(value); } template void assign_int32(std::uint64_t value, Request& output) noexcept { (output.settings.*GroupMember).*FieldMember = as_int32(value); } template void assign_real32(std::uint64_t value, Request& output) noexcept { (output.settings.*GroupMember).*FieldMember = as_real32(value); } /** Preference 0.1.1.0 is the profile-setup marker, which State reads, not the settings delta. */ void assign_profile_setup(std::uint64_t value, Request& output) noexcept { output.profileSetupCompleted = value != 0; } /** A plain function pointer keeps the descriptor table a compile-time constant. */ using PreferenceAssignment = void (*)(std::uint64_t, Request&) noexcept; /** One schema path's index, wire decoding rule, and optional semantic State destination. */ struct PreferenceDescriptor { std::size_t schemaIndex; ScalarEncoding encoding; PreferenceAssignment assign; }; /** * Single source of truth for preference paths 0.1.1.0 through 0.1.1.61. * A null assignment marks a structurally known field that is intentionally traversal-only. */ constexpr std::array kPreferenceDescriptors{ PreferenceDescriptor{0, kBoolEncoding, assign_profile_setup}, PreferenceDescriptor{1, kInt32Encoding, nullptr}, // post-processing seed version PreferenceDescriptor{ 2, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::controls, &settings::ControlsDelta::buttonLayout>}, PreferenceDescriptor{ 3, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::controls, &settings::ControlsDelta::movementMode>}, PreferenceDescriptor{4, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::controls, &settings::ControlsDelta::controllerLookSensitivity>}, PreferenceDescriptor{5, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::controls, &settings::ControlsDelta::doublePressDelay>}, PreferenceDescriptor{6, kInt32Encoding, assign_int32<&settings::SettingsDelta::controls, &settings::ControlsDelta::mouseLookSensitivity>}, PreferenceDescriptor{7, kReal32Encoding, assign_real32<&settings::SettingsDelta::controls, &settings::ControlsDelta::adsSensitivityModifier>}, PreferenceDescriptor{ 8, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::subtitlesMode>}, PreferenceDescriptor{ 9, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::textSize>}, PreferenceDescriptor{ 10, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::textColor>}, PreferenceDescriptor{11, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::textBackgroundStyle>}, PreferenceDescriptor{12, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::textBackgroundOpacity>}, PreferenceDescriptor{13, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::reservedTextMode>}, PreferenceDescriptor{14, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::subtitleOptionsEntry>}, PreferenceDescriptor{ 15, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::voiceOutputMode>}, PreferenceDescriptor{ 16, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::teamVoiceChannel>}, PreferenceDescriptor{ 17, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::display, &settings::DisplayDelta::brightness>}, PreferenceDescriptor{ 18, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::helmetMode>}, PreferenceDescriptor{19, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::colorblindMode>}, PreferenceDescriptor{ 20, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::reticleColor>}, PreferenceDescriptor{ 21, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::reservedMode>}, PreferenceDescriptor{22, kInt8ThreeBitEncoding, nullptr}, // unmapped audio-padding field PreferenceDescriptor{ 23, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::migrationVersion>}, PreferenceDescriptor{ 24, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::soundEffectsVolume>}, PreferenceDescriptor{ 25, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::dialogueVolume>}, PreferenceDescriptor{ 26, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::musicVolume>}, PreferenceDescriptor{ 27, kInt8FourBitEncoding, assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::chatVolume>}, PreferenceDescriptor{ 28, kBoolEncoding, assign_bool<&settings::SettingsDelta::audio, &settings::AudioDelta::muteWhenUnfocused>}, PreferenceDescriptor{29, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::controllerInvertVertical>}, PreferenceDescriptor{30, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::controllerInvertHorizontal>}, PreferenceDescriptor{31, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::mouseInvertVertical>}, PreferenceDescriptor{32, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::mouseInvertHorizontal>}, PreferenceDescriptor{33, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::controllerAutoLookCentering>}, PreferenceDescriptor{34, kBoolEncoding, assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::preferGoodConnection>}, PreferenceDescriptor{35, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::controllerVibration>}, PreferenceDescriptor{36, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::unidentifiedToggle>}, PreferenceDescriptor{37, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::mouseAimSmoothing>}, PreferenceDescriptor{38, kBoolEncoding, assign_bool<&settings::SettingsDelta::controls, &settings::ControlsDelta::controllerSwapShoulders>}, PreferenceDescriptor{39, kBoolEncoding, nullptr}, // first unmapped identity-padding field PreferenceDescriptor{40, kBoolEncoding, nullptr}, // second unmapped identity-padding field PreferenceDescriptor{ 41, kBoolEncoding, assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::showRealNames>}, PreferenceDescriptor{ 42, kBoolEncoding, assign_bool<&settings::SettingsDelta::interface, &settings::InterfaceDelta::displayHints>}, PreferenceDescriptor{ 43, kBoolEncoding, assign_bool<&settings::SettingsDelta::display, &settings::DisplayDelta::showFps>}, PreferenceDescriptor{44, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::reticleLocation>}, PreferenceDescriptor{45, kBoolEncoding, assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::clanInviteNotifications>}, PreferenceDescriptor{ 46, kBoolEncoding, assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::profanityFilter>}, PreferenceDescriptor{47, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::backgroundOpacity>}, PreferenceDescriptor{ 48, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::hudOpacity>}, PreferenceDescriptor{ 49, kBoolEncoding, assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::voiceChatEnabled>}, PreferenceDescriptor{ 50, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::whisperChatMode>}, PreferenceDescriptor{ 51, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::teamChatJoinMode>}, PreferenceDescriptor{ 52, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::localChatJoinMode>}, PreferenceDescriptor{ 53, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::clanChatJoinMode>}, PreferenceDescriptor{ 54, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::display, &settings::DisplayDelta::hdrMode>}, PreferenceDescriptor{55, kReal32Encoding, assign_real32<&settings::SettingsDelta::display, &settings::DisplayDelta::calibrationPrimary>}, PreferenceDescriptor{56, kReal32Encoding, assign_real32<&settings::SettingsDelta::display, &settings::DisplayDelta::calibrationAlpha>}, PreferenceDescriptor{ 57, kInt8ThreeBitEncoding, assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::textChatMode>}, PreferenceDescriptor{ 58, kInt8TwoBitEncoding, assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::chatAutoHideMode>}, PreferenceDescriptor{59, kBoolEncoding, nullptr}, // motion-blur mirror PreferenceDescriptor{60, kBoolEncoding, nullptr}, // film-grain mirror PreferenceDescriptor{61, kBoolEncoding, nullptr}, // chromatic-aberration mirror }; /** Ensures explicit schema indices stay aligned with descriptor array positions. */ [[nodiscard]] consteval bool valid_preference_descriptors() noexcept { for (std::size_t index = 0; index < kPreferenceDescriptors.size(); ++index) { const PreferenceDescriptor& descriptor = kPreferenceDescriptors[index]; if (descriptor.schemaIndex != index || descriptor.encoding.wireWidthBits == 0 || descriptor.encoding.wireWidthBits > kScalar64WidthBits || descriptor.encoding.nativeWidthBits == 0 || descriptor.encoding.nativeWidthBits > kScalar64WidthBits) { return false; } } return true; } static_assert(valid_preference_descriptors()); /** Optional widths for unknown mixed record path 0.1.4 fields 0 through 7. */ constexpr std::array kGroup_0_1_4OptionalWidths{ kScalar64WidthBits, kScalar64WidthBits, kScalar64WidthBits, kTwoWidthBits, kScalar64WidthBits, kTwoWidthBits, kSixWidthBits, kFiveWidthBits, }; /** Builds a low-bit mask without evaluating the invalid expression `1 << 64`. */ [[nodiscard]] constexpr std::uint64_t width_mask(std::uint8_t nativeWidthBits) noexcept { return nativeWidthBits == kScalar64WidthBits ? (std::numeric_limits::max)() : (std::uint64_t{1} << nativeWidthBits) - 1U; } /** Reads the one-bit flag that precedes every optional schema node. */ [[nodiscard]] bool read_presence(Reader& reader, bool& present) noexcept { std::uint64_t value = 0; if (!reader.read(kPresenceWidthBits, value)) { return false; } present = value != 0; return true; } /** Reads one stored scalar and removes its bias modulo the destination type width. */ [[nodiscard]] bool read_scalar(Reader& reader, const ScalarEncoding& encoding, std::uint64_t& value) noexcept { std::uint64_t stored = 0; if (!reader.read(encoding.wireWidthBits, stored)) { return false; } const std::uint64_t mask = width_mask(encoding.nativeWidthBits); value = (stored - (encoding.bias & mask)) & mask; return true; } /** Reads an optional scalar while preserving absent versus present-zero semantics. */ [[nodiscard]] bool read_optional_scalar(Reader& reader, const ScalarEncoding& encoding, bool& present, std::uint64_t& value) noexcept { present = false; value = 0; return read_presence(reader, present) && (!present || read_scalar(reader, encoding, value)); } /** Consumes one optional field whose value is deliberately not retained. */ [[nodiscard]] bool skip_optional_bits(Reader& reader, std::size_t wireWidthBits) noexcept { bool present = false; return read_presence(reader, present) && (!present || reader.skip(wireWidthBits)); } /** Consumes one optional scalar by its declared encoding without retaining its value. */ [[nodiscard]] bool skip_optional_scalar(Reader& reader, const ScalarEncoding& encoding) noexcept { return skip_optional_bits(reader, encoding.wireWidthBits); } /** Reads one optional group and delegates its body only when the group is present. */ template [[nodiscard]] bool read_optional_group(Reader& reader, ReadBody readBody) noexcept { bool present = false; return read_presence(reader, present) && (!present || readBody(reader)); } /** Consumes the body of optional publicity-expiry bank path 0.0.0. */ [[nodiscard]] bool skip_publicity_expiry_bank(Reader& reader) noexcept { for (std::size_t index = 0; index < kPublicityExpiryCount; ++index) { if (!skip_optional_bits(reader, kScalar64WidthBits)) { return false; } } return true; } /** Consumes the fixed seen-message bank at path 0.0.1. */ [[nodiscard]] bool skip_seen_message_bank(Reader& reader) noexcept { return reader.skip(fixed_array_width_bits(kSeenMessageCount, kScalar32WidthBits)); } /** Consumes optional root branch 0.0 in child descriptor order. */ [[nodiscard]] bool skip_publicity_and_seen_messages(Reader& reader) noexcept { return read_optional_group(reader, skip_publicity_expiry_bank) && read_optional_group(reader, skip_seen_message_bank); } /** Consumes one present two-scalar element under calibration path 0.1.0. */ [[nodiscard]] bool skip_calibration_vector(Reader& reader) noexcept { return reader.skip(fixed_array_width_bits(kCalibrationValuesPerVector, kScalar32WidthBits)); } /** Consumes present group 0.1.0, including each element's own presence bit. */ [[nodiscard]] bool skip_group_0_1_0(Reader& reader) noexcept { for (std::size_t index = 0; index < kCalibrationVectorCount; ++index) { if (!read_optional_group(reader, skip_calibration_vector)) { return false; } } return true; } /** Consumes present preference matrix path 0.1.1.62 in row-major descriptor order. */ [[nodiscard]] bool skip_preference_matrix(Reader& reader) noexcept { for (std::size_t row = 0; row < kPreferenceMatrixRowCount; ++row) { for (std::size_t column = 0; column < kPreferenceMatrixColumnCount; ++column) { if (!skip_optional_bits(reader, kScalar32WidthBits)) { return false; } } } return true; } /** Decodes present preference group 0.1.1 and consumes its optional opaque matrix. */ [[nodiscard]] bool read_preference_record(Reader& reader, Request& output) noexcept { for (const PreferenceDescriptor& descriptor : kPreferenceDescriptors) { bool present = false; std::uint64_t value = 0; if (!read_optional_scalar(reader, descriptor.encoding, present, value)) { return false; } if (present && descriptor.assign != nullptr) { descriptor.assign(value, output); } } return read_optional_group(reader, skip_preference_matrix); } /** Decodes the body of present fixed keybinding table path 0.1.2.5 atomically. */ [[nodiscard]] bool read_key_binding_table(Reader& reader, settings::SettingsDelta& delta) noexcept { settings::bindings::KeyBindings staged{}; for (std::size_t nativeSlot = 0; nativeSlot < settings::bindings::kActionsByNativeSlot.size(); ++nativeSlot) { std::uint64_t value = 0; if (!read_scalar(reader, kInt32Encoding, value)) { return false; } // After bias removal, bits 0-15 are primary and bits 16-31 are secondary. The value // 0x0074 in either half is the protocol's unbound sentinel, not a bindable input. const std::uint32_t packed = static_cast(value); const std::uint16_t primary = static_cast(packed); const std::uint16_t secondary = static_cast(packed >> kBindingHalfWidthBits); const auto action = settings::bindings::kActionsByNativeSlot[nativeSlot]; auto& binding = staged.values[static_cast(action)]; if (primary != kUnboundInputCode) { binding.primary = primary; } if (secondary != kUnboundInputCode) { binding.secondary = secondary; } } staged.configured = true; delta.keyBindings = staged; return true; } /** Decodes present binding record 0.1.2 in exact child descriptor order. */ [[nodiscard]] bool read_binding_record(Reader& reader, settings::SettingsDelta& delta) noexcept { // 0.1.2.0: seed/version marker; structurally consumed but not authoritative. if (!skip_optional_scalar(reader, kInt32Encoding)) { return false; } bool present = false; std::uint64_t value = 0; if (!read_optional_scalar(reader, kBoolEncoding, present, value)) { return false; } if (present && !delta.social.voiceChatEnabled.has_value()) { delta.social.voiceChatEnabled = value != 0; } if (!read_optional_scalar(reader, kInt8ThreeBitEncoding, present, value)) { return false; } if (present) { delta.display.verticalSyncInterval = static_cast(value); } if (!read_optional_scalar(reader, kInt32Encoding, present, value)) { return false; } if (present) { delta.display.fieldOfView = as_int32(value); } // 0.1.2.4: authored keybinding source and routing input for the optional table. bool sourceSelectorPresent = false; std::uint64_t sourceSelector = 0; if (!read_optional_scalar(reader, kBoolEncoding, sourceSelectorPresent, sourceSelector)) { return false; } if (sourceSelectorPresent) { delta.keyBindingSource = sourceSelector != 0 ? settings::KeyBindingSource::computer : settings::KeyBindingSource::account; } // 0.1.2.5: one presence bit covers the complete 60-entry table. return read_optional_group(reader, [&delta](Reader& tableReader) noexcept { return read_key_binding_table(tableReader, delta); }); } /** Consumes present fixed-width group 0.1.3. */ [[nodiscard]] bool skip_group_0_1_3(Reader& reader) noexcept { return reader.skip(fixed_array_width_bits(kGroup_0_1_3ValueCount, kScalar16WidthBits)); } /** Consumes present mixed-width group 0.1.4 without assigning unknown semantics. */ [[nodiscard]] bool skip_group_0_1_4(Reader& reader) noexcept { for (const std::uint8_t width : kGroup_0_1_4OptionalWidths) { if (!skip_optional_bits(reader, width)) { return false; } } // Field 8 is required u64, field 9 is optional 3-bit, and field 10 is required bool. return reader.skip(kScalar64WidthBits) && skip_optional_bits(reader, kThreeWidthBits) && reader.skip(kBooleanWidthBits); } /** Reads the profile new-item bitmap carried by group 0.1.5. */ [[nodiscard]] bool read_new_items(Reader& reader, Request& output) noexcept { state::account::inventory::ProfileNewItems bits{}; for (auto& word : bits) { std::uint64_t value = 0; if (!reader.read(kScalar32WidthBits, value)) { return false; } word = static_cast(value); } output.newItems = bits; return true; } /** Consumes present nested entry array 0.1.6.0. */ [[nodiscard]] bool skip_group_0_1_6_0(Reader& reader) noexcept { for (std::size_t index = 0; index < kGroup_0_1_6EntryCount; ++index) { if (!skip_optional_bits(reader, kScalar16WidthBits)) { return false; } } return reader.skip(fixed_array_width_bits(kGroup_0_1_6FixedWordCount, kScalar32WidthBits)); } /** Consumes present group 0.1.6, including optional children 0 and 1. */ [[nodiscard]] bool skip_group_0_1_6(Reader& reader) noexcept { return read_optional_group(reader, skip_group_0_1_6_0) && skip_optional_bits(reader, kScalar16WidthBits); } /** Consumes present fixed-tail group 0.1.12. */ [[nodiscard]] bool skip_group_0_1_12(Reader& reader) noexcept { return reader.skip(fixed_array_width_bits(kGroup_0_1_12ValueCount, kScalar16WidthBits)) && reader.skip(fixed_array_width_bits(kGroup_0_1_12FixedWordCount, kScalar32WidthBits)); } /** Traverses every child of present account branch 0.1 in descriptor order. */ [[nodiscard]] bool read_account_branch(Reader& reader, Request& output) noexcept { // 0.1.0: calibration vectors. if (!read_optional_group(reader, skip_group_0_1_0)) { return false; } // 0.1.1: preference scalars and the optional 3-by-50 matrix. if (!read_optional_group(reader, [&output](Reader& groupReader) noexcept { return read_preference_record(groupReader, output); })) { return false; } // 0.1.2: local mirrors, keybinding source, and packed binding table. if (!read_optional_group(reader, [&output](Reader& groupReader) noexcept { return read_binding_record(groupReader, output.settings); })) { return false; } // 0.1.3: four required 16-bit values. if (!read_optional_group(reader, skip_group_0_1_3)) { return false; } // 0.1.4: mixed-width record with unknown semantics. if (!read_optional_group(reader, skip_group_0_1_4)) { return false; } // 0.1.5: 22 required 32-bit values. if (!read_optional_group(reader, [&output](Reader& groupReader) noexcept { return read_new_items(groupReader, output); })) { return false; } // 0.1.6: optional 100-entry region, two required words, and optional 16-bit tail. if (!read_optional_group(reader, skip_group_0_1_6)) { return false; } // 0.1.7: optional Boolean. if (!skip_optional_bits(reader, kBooleanWidthBits)) { return false; } // 0.1.8: optional Boolean. if (!skip_optional_bits(reader, kBooleanWidthBits)) { return false; } // 0.1.9: optional Boolean. if (!skip_optional_bits(reader, kBooleanWidthBits)) { return false; } // 0.1.10: optional 8-bit scalar. if (!skip_optional_bits(reader, kByteWidthBits)) { return false; } // 0.1.11: optional 32-bit scalar. if (!skip_optional_bits(reader, kScalar32WidthBits)) { return false; } // 0.1.12: 30 required 16-bit values followed by two required 32-bit words. if (!read_optional_group(reader, skip_group_0_1_12)) { return false; } // 0.1.13: optional 32-bit scalar. return skip_optional_bits(reader, kScalar32WidthBits); } /** Consumes both optional length-prefixed blobs following the reflected object. */ [[nodiscard]] bool skip_outer_blobs(Reader& reader) noexcept { for (std::size_t index = 0; index < kOuterBlobCount; ++index) { bool present = false; std::uint64_t byteCount = 0; if (!read_presence(reader, present)) { return false; } if (present && (!reader.read(kOuterBlobLengthWidthBits, byteCount) || !reader.skip(static_cast(byteCount) * kByteWidthBits))) { return false; } } return true; } /** Requires any final partial byte to contain only zero padding. */ [[nodiscard]] bool finish_padding(Reader& reader) noexcept { const std::size_t remaining = reader.remaining_bits(); if (remaining >= kTerminalPaddingLimitBits) { return false; } std::uint64_t padding = 0; return reader.read(static_cast(remaining), padding) && padding == 0 && reader.remaining_bits() == 0; } /** Compile-time proof that the declared traversal still matches the catalog's maximum form. */ namespace schema_size_proof { [[nodiscard]] consteval std::size_t optional_scalar(std::size_t widthBits) noexcept { return kPresenceWidthBits + widthBits; } [[nodiscard]] consteval std::size_t optional_group(std::size_t bodyBits) noexcept { return kPresenceWidthBits + bodyBits; } [[nodiscard]] consteval std::size_t optional_scalar_array(std::size_t count, std::size_t widthBits) noexcept { return count * optional_scalar(widthBits); } [[nodiscard]] consteval std::size_t preference_fields() noexcept { std::size_t total = 0; for (const PreferenceDescriptor& descriptor : kPreferenceDescriptors) { total += optional_scalar(descriptor.encoding.wireWidthBits); } return total; } [[nodiscard]] consteval std::size_t group_0_1_4_body() noexcept { std::size_t total = 0; for (const std::uint8_t widthBits : kGroup_0_1_4OptionalWidths) { total += optional_scalar(widthBits); } // Field 8 is required u64, field 9 is optional 3-bit, and field 10 is required bool. return total + kScalar64WidthBits + optional_scalar(kThreeWidthBits) + kBooleanWidthBits; } // Largest form of the publicity-expiry bank. constexpr std::size_t kPublicityExpiryBankBits = optional_group(optional_scalar_array(kPublicityExpiryCount, kScalar64WidthBits)); // Largest form of the seen-message bank. constexpr std::size_t kSeenMessageBankBits = optional_group(fixed_array_width_bits(kSeenMessageCount, kScalar32WidthBits)); // Largest form of the root metadata group. constexpr std::size_t kRootMetadataBits = optional_group(kPublicityExpiryBankBits + kSeenMessageBankBits); // Largest form of the calibration group. constexpr std::size_t kCalibrationGroupBits = optional_group( kCalibrationVectorCount * optional_group(fixed_array_width_bits(kCalibrationValuesPerVector, kScalar32WidthBits))); // Largest form of the preference matrix. constexpr std::size_t kPreferenceMatrixBits = optional_group(optional_scalar_array( kPreferenceMatrixRowCount * kPreferenceMatrixColumnCount, kScalar32WidthBits)); // Largest form of the preferences group. constexpr std::size_t kPreferencesBits = optional_group(preference_fields() + kPreferenceMatrixBits); // Largest form of the bindings group. constexpr std::size_t kBindingsBits = optional_group(optional_scalar(kScalar32WidthBits) + optional_scalar(kBooleanWidthBits) + optional_scalar(kThreeWidthBits) + optional_scalar(kScalar32WidthBits) + optional_scalar(kBooleanWidthBits) + optional_group(fixed_array_width_bits(kKeyBindingCount, kScalar32WidthBits))); // Largest form of group 0.1.3. constexpr std::size_t kGroup_0_1_3Bits = optional_group(fixed_array_width_bits(kGroup_0_1_3ValueCount, kScalar16WidthBits)); // Largest form of groups 0.1.4 and 0.1.5. constexpr std::size_t kGroup_0_1_4Bits = optional_group(group_0_1_4_body()); constexpr std::size_t kGroup_0_1_5Bits = optional_group(fixed_array_width_bits(kGroup_0_1_5ValueCount, kScalar32WidthBits)); // Largest form of group 0.1.6. constexpr std::size_t kGroup_0_1_6Bits = optional_group( optional_group(optional_scalar_array(kGroup_0_1_6EntryCount, kScalar16WidthBits) + fixed_array_width_bits(kGroup_0_1_6FixedWordCount, kScalar32WidthBits)) + optional_scalar(kScalar16WidthBits)); // Largest form of the account tail fields. constexpr std::size_t kAccountTailBits = optional_scalar(kBooleanWidthBits) + optional_scalar(kBooleanWidthBits) + optional_scalar(kBooleanWidthBits) + optional_scalar(kByteWidthBits) + optional_scalar(kScalar32WidthBits); // Largest form of group 0.1.12. constexpr std::size_t kGroup_0_1_12Bits = optional_group(fixed_array_width_bits(kGroup_0_1_12ValueCount, kScalar16WidthBits) + fixed_array_width_bits(kGroup_0_1_12FixedWordCount, kScalar32WidthBits)); // Largest form of group 0.1.13. constexpr std::size_t kGroup_0_1_13Bits = optional_scalar(kScalar32WidthBits); // Largest form of the account branch. constexpr std::size_t kAccountBranchBits = optional_group(kCalibrationGroupBits + kPreferencesBits + kBindingsBits + kGroup_0_1_3Bits + kGroup_0_1_4Bits + kGroup_0_1_5Bits + kGroup_0_1_6Bits + kAccountTailBits + kGroup_0_1_12Bits + kGroup_0_1_13Bits); // Largest form of the whole body. constexpr std::size_t kSchemaBits = kRootMetadataBits + kAccountBranchBits; static_assert(kRootMetadataBits == kCatalogRootMetadataMaximumBits); static_assert(kPreferencesBits == kCatalogPreferencesMaximumBits); static_assert(kBindingsBits == kCatalogBindingsMaximumBits); static_assert(kAccountBranchBits == kCatalogAccountBranchMaximumBits); static_assert(kSchemaBits == kCatalogMaximumBits); } // namespace schema_size_proof } // namespace /** Decodes the complete schema-0x80807603 request without touching authoritative State. */ bool parse_request(const Message& message, Request& output) noexcept { output = {}; if (message.opcode != kOpcode) { return false; } Reader reader(message.payload); Request candidate{}; if (!read_optional_group(reader, skip_publicity_and_seen_messages) || !read_optional_group(reader, [&candidate](Reader& groupReader) noexcept { return read_account_branch(groupReader, candidate); }) || !skip_outer_blobs(reader) || !finish_padding(reader)) { return false; } output = candidate; return true; } } // namespace sunrise::middleware::web_service::messages::opcode701