opcode701_codec.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. #include "opcode701_codec.h"
  2. #include <array>
  3. #include <bit>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include <limits>
  7. #include "../../../../state/account/settings/native_key_binding_map.h"
  8. #include "../../../../state/account/settings/settings_state.h"
  9. #include "../../../encoding/bit_reader.h"
  10. namespace sunrise::middleware::web_service::messages::opcode701 {
  11. namespace {
  12. using encoding::bits::Reader;
  13. namespace settings = state::account::settings;
  14. // Schema 0x80807603 is presence-driven: an absent node consumes no bits and nothing is byte
  15. // aligned, so every presence flag must be read or later fields land at the wrong offset.
  16. /** Wire primitive widths used by schema 0x80807603. */
  17. constexpr std::uint8_t kPresenceWidthBits = 1;
  18. constexpr std::uint8_t kBooleanWidthBits = 1;
  19. constexpr std::uint8_t kTwoWidthBits = 2;
  20. constexpr std::uint8_t kThreeWidthBits = 3;
  21. constexpr std::uint8_t kFourWidthBits = 4;
  22. constexpr std::uint8_t kFiveWidthBits = 5;
  23. constexpr std::uint8_t kSixWidthBits = 6;
  24. constexpr std::uint8_t kByteWidthBits = 8;
  25. constexpr std::uint8_t kScalar16WidthBits = 16;
  26. constexpr std::uint8_t kScalar32WidthBits = 32;
  27. constexpr std::uint8_t kScalar64WidthBits = 64;
  28. /** Schema array dimensions, kept separate from scalar widths. */
  29. constexpr std::size_t kPublicityExpiryCount = 128;
  30. constexpr std::size_t kSeenMessageCount = 13;
  31. constexpr std::size_t kCalibrationVectorCount = 2;
  32. constexpr std::size_t kCalibrationValuesPerVector = 2;
  33. constexpr std::size_t kPreferenceMatrixRowCount = 3;
  34. constexpr std::size_t kPreferenceMatrixColumnCount = 50;
  35. constexpr std::size_t kGroup_0_1_4OptionalFieldCount = 8;
  36. constexpr std::size_t kGroup_0_1_3ValueCount = 4;
  37. constexpr std::size_t kGroup_0_1_5ValueCount = 22;
  38. constexpr std::size_t kGroup_0_1_6EntryCount = 100;
  39. constexpr std::size_t kGroup_0_1_6FixedWordCount = 2;
  40. constexpr std::size_t kGroup_0_1_12ValueCount = 30;
  41. constexpr std::size_t kGroup_0_1_12FixedWordCount = 2;
  42. constexpr std::size_t kOuterBlobCount = 2;
  43. /** Catalog invariants used to detect accidental table/schema drift at compile time. */
  44. constexpr std::size_t kCatalogPreferenceFieldCount = 62;
  45. constexpr std::size_t kCatalogKeyBindingCount = 60;
  46. constexpr std::size_t kCatalogRootMetadataMaximumBits = 8'739;
  47. constexpr std::size_t kCatalogPreferencesMaximumBits = 5'300;
  48. constexpr std::size_t kCatalogBindingsMaximumBits = 1'996;
  49. constexpr std::size_t kCatalogAccountBranchMaximumBits = 10'956;
  50. constexpr std::size_t kCatalogMaximumBits = 19'695;
  51. /** A packed binding half with this value represents no assigned input. */
  52. constexpr std::uint16_t kUnboundInputCode = settings::bindings::kUnboundInputCode;
  53. /** Each packed binding word stores one primary half followed by one secondary half. */
  54. constexpr unsigned kBindingHalfWidthBits = kScalar16WidthBits;
  55. /** Outer blobs encode their byte length in one unsigned 16-bit field. */
  56. constexpr std::uint8_t kOuterBlobLengthWidthBits = kScalar16WidthBits;
  57. /** A whole unread byte is data, while fewer than eight final bits may be terminal padding. */
  58. constexpr std::size_t kTerminalPaddingLimitBits = kByteWidthBits;
  59. /** Returns the bit count of a required fixed-width array. */
  60. [[nodiscard]] constexpr std::size_t fixed_array_width_bits(std::size_t count,
  61. std::size_t widthBits) noexcept {
  62. return count * widthBits;
  63. }
  64. /** One scalar descriptor's stored width, destination width, and modular wire bias. */
  65. struct ScalarEncoding {
  66. std::uint8_t wireWidthBits;
  67. std::uint8_t nativeWidthBits;
  68. std::uint64_t bias;
  69. };
  70. /** Compact signed selectors store the destination value plus one. */
  71. constexpr std::uint64_t kCompactIntegerBias = 1;
  72. /** Reflected signed 32-bit values store the destination bit pattern plus INT32_MIN. */
  73. constexpr std::uint64_t kSigned32Bias = 0x80000000ULL;
  74. /** Wire width, native width and bias for the bool and the two- and three-bit selectors. */
  75. constexpr ScalarEncoding kBoolEncoding{kBooleanWidthBits, kBooleanWidthBits, 0};
  76. constexpr ScalarEncoding kInt8TwoBitEncoding{kTwoWidthBits, kByteWidthBits, kCompactIntegerBias};
  77. constexpr ScalarEncoding kInt8ThreeBitEncoding{
  78. kThreeWidthBits, kByteWidthBits, kCompactIntegerBias};
  79. /** Same for the four-bit selector and the two reflected 32-bit types. */
  80. constexpr ScalarEncoding kInt8FourBitEncoding{kFourWidthBits, kByteWidthBits, kCompactIntegerBias};
  81. constexpr ScalarEncoding kInt32Encoding{kScalar32WidthBits, kScalar32WidthBits, kSigned32Bias};
  82. constexpr ScalarEncoding kReal32Encoding{kScalar32WidthBits, kScalar32WidthBits, 0};
  83. /** Field and binding counts the catalog fixes; the static_assert below holds them. */
  84. constexpr std::size_t kPreferenceFieldCount = kCatalogPreferenceFieldCount;
  85. constexpr std::size_t kKeyBindingCount = settings::bindings::kActionCount;
  86. static_assert(kKeyBindingCount == kCatalogKeyBindingCount);
  87. /** Reinterprets an already-unbiased byte pattern as its signed destination value. */
  88. [[nodiscard]] constexpr std::int8_t as_int8(std::uint64_t value) noexcept {
  89. return std::bit_cast<std::int8_t>(static_cast<std::uint8_t>(value));
  90. }
  91. /** Reinterprets an already-unbiased 32-bit pattern as its signed destination value. */
  92. [[nodiscard]] constexpr std::int32_t as_int32(std::uint64_t value) noexcept {
  93. return std::bit_cast<std::int32_t>(static_cast<std::uint32_t>(value));
  94. }
  95. /** Reinterprets a raw IEEE-754 32-bit pattern without applying an integer conversion. */
  96. [[nodiscard]] constexpr float as_real32(std::uint64_t value) noexcept {
  97. return std::bit_cast<float>(static_cast<std::uint32_t>(value));
  98. }
  99. /** Typed assignment adapters let each schema descriptor name its exact nested delta member. */
  100. template <auto GroupMember, auto FieldMember>
  101. void assign_bool(std::uint64_t value, Request& output) noexcept {
  102. (output.settings.*GroupMember).*FieldMember = value != 0;
  103. }
  104. template <auto GroupMember, auto FieldMember>
  105. void assign_int8(std::uint64_t value, Request& output) noexcept {
  106. (output.settings.*GroupMember).*FieldMember = as_int8(value);
  107. }
  108. template <auto GroupMember, auto FieldMember>
  109. void assign_int32(std::uint64_t value, Request& output) noexcept {
  110. (output.settings.*GroupMember).*FieldMember = as_int32(value);
  111. }
  112. template <auto GroupMember, auto FieldMember>
  113. void assign_real32(std::uint64_t value, Request& output) noexcept {
  114. (output.settings.*GroupMember).*FieldMember = as_real32(value);
  115. }
  116. /** Preference 0.1.1.0 is the profile-setup marker, which State reads, not the settings delta. */
  117. void assign_profile_setup(std::uint64_t value, Request& output) noexcept {
  118. output.profileSetupCompleted = value != 0;
  119. }
  120. /** A plain function pointer keeps the descriptor table a compile-time constant. */
  121. using PreferenceAssignment = void (*)(std::uint64_t, Request&) noexcept;
  122. /** One schema path's index, wire decoding rule, and optional semantic State destination. */
  123. struct PreferenceDescriptor {
  124. std::size_t schemaIndex;
  125. ScalarEncoding encoding;
  126. PreferenceAssignment assign;
  127. };
  128. /**
  129. * Single source of truth for preference paths 0.1.1.0 through 0.1.1.61.
  130. * A null assignment marks a structurally known field that is intentionally traversal-only.
  131. */
  132. constexpr std::array<PreferenceDescriptor, kPreferenceFieldCount> kPreferenceDescriptors{
  133. PreferenceDescriptor{0, kBoolEncoding, assign_profile_setup},
  134. PreferenceDescriptor{1, kInt32Encoding, nullptr}, // post-processing seed version
  135. PreferenceDescriptor{
  136. 2,
  137. kInt8FourBitEncoding,
  138. assign_int8<&settings::SettingsDelta::controls, &settings::ControlsDelta::buttonLayout>},
  139. PreferenceDescriptor{
  140. 3,
  141. kInt8ThreeBitEncoding,
  142. assign_int8<&settings::SettingsDelta::controls, &settings::ControlsDelta::movementMode>},
  143. PreferenceDescriptor{4,
  144. kInt8FourBitEncoding,
  145. assign_int8<&settings::SettingsDelta::controls,
  146. &settings::ControlsDelta::controllerLookSensitivity>},
  147. PreferenceDescriptor{5,
  148. kInt8ThreeBitEncoding,
  149. assign_int8<&settings::SettingsDelta::controls,
  150. &settings::ControlsDelta::doublePressDelay>},
  151. PreferenceDescriptor{6,
  152. kInt32Encoding,
  153. assign_int32<&settings::SettingsDelta::controls,
  154. &settings::ControlsDelta::mouseLookSensitivity>},
  155. PreferenceDescriptor{7,
  156. kReal32Encoding,
  157. assign_real32<&settings::SettingsDelta::controls,
  158. &settings::ControlsDelta::adsSensitivityModifier>},
  159. PreferenceDescriptor{
  160. 8,
  161. kInt8TwoBitEncoding,
  162. assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::subtitlesMode>},
  163. PreferenceDescriptor{
  164. 9,
  165. kInt8FourBitEncoding,
  166. assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::textSize>},
  167. PreferenceDescriptor{
  168. 10,
  169. kInt8FourBitEncoding,
  170. assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::textColor>},
  171. PreferenceDescriptor{11,
  172. kInt8FourBitEncoding,
  173. assign_int8<&settings::SettingsDelta::interface,
  174. &settings::InterfaceDelta::textBackgroundStyle>},
  175. PreferenceDescriptor{12,
  176. kInt8FourBitEncoding,
  177. assign_int8<&settings::SettingsDelta::interface,
  178. &settings::InterfaceDelta::textBackgroundOpacity>},
  179. PreferenceDescriptor{13,
  180. kInt8FourBitEncoding,
  181. assign_int8<&settings::SettingsDelta::interface,
  182. &settings::InterfaceDelta::reservedTextMode>},
  183. PreferenceDescriptor{14,
  184. kInt8FourBitEncoding,
  185. assign_int8<&settings::SettingsDelta::interface,
  186. &settings::InterfaceDelta::subtitleOptionsEntry>},
  187. PreferenceDescriptor{
  188. 15,
  189. kInt8TwoBitEncoding,
  190. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::voiceOutputMode>},
  191. PreferenceDescriptor{
  192. 16,
  193. kInt8TwoBitEncoding,
  194. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::teamVoiceChannel>},
  195. PreferenceDescriptor{
  196. 17,
  197. kInt8ThreeBitEncoding,
  198. assign_int8<&settings::SettingsDelta::display, &settings::DisplayDelta::brightness>},
  199. PreferenceDescriptor{
  200. 18,
  201. kInt8TwoBitEncoding,
  202. assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::helmetMode>},
  203. PreferenceDescriptor{19,
  204. kInt8ThreeBitEncoding,
  205. assign_int8<&settings::SettingsDelta::interface,
  206. &settings::InterfaceDelta::colorblindMode>},
  207. PreferenceDescriptor{
  208. 20,
  209. kInt8ThreeBitEncoding,
  210. assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::reticleColor>},
  211. PreferenceDescriptor{
  212. 21,
  213. kInt8TwoBitEncoding,
  214. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::reservedMode>},
  215. PreferenceDescriptor{22, kInt8ThreeBitEncoding, nullptr}, // unmapped audio-padding field
  216. PreferenceDescriptor{
  217. 23,
  218. kInt8FourBitEncoding,
  219. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::migrationVersion>},
  220. PreferenceDescriptor{
  221. 24,
  222. kInt8FourBitEncoding,
  223. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::soundEffectsVolume>},
  224. PreferenceDescriptor{
  225. 25,
  226. kInt8FourBitEncoding,
  227. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::dialogueVolume>},
  228. PreferenceDescriptor{
  229. 26,
  230. kInt8FourBitEncoding,
  231. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::musicVolume>},
  232. PreferenceDescriptor{
  233. 27,
  234. kInt8FourBitEncoding,
  235. assign_int8<&settings::SettingsDelta::audio, &settings::AudioDelta::chatVolume>},
  236. PreferenceDescriptor{
  237. 28,
  238. kBoolEncoding,
  239. assign_bool<&settings::SettingsDelta::audio, &settings::AudioDelta::muteWhenUnfocused>},
  240. PreferenceDescriptor{29,
  241. kBoolEncoding,
  242. assign_bool<&settings::SettingsDelta::controls,
  243. &settings::ControlsDelta::controllerInvertVertical>},
  244. PreferenceDescriptor{30,
  245. kBoolEncoding,
  246. assign_bool<&settings::SettingsDelta::controls,
  247. &settings::ControlsDelta::controllerInvertHorizontal>},
  248. PreferenceDescriptor{31,
  249. kBoolEncoding,
  250. assign_bool<&settings::SettingsDelta::controls,
  251. &settings::ControlsDelta::mouseInvertVertical>},
  252. PreferenceDescriptor{32,
  253. kBoolEncoding,
  254. assign_bool<&settings::SettingsDelta::controls,
  255. &settings::ControlsDelta::mouseInvertHorizontal>},
  256. PreferenceDescriptor{33,
  257. kBoolEncoding,
  258. assign_bool<&settings::SettingsDelta::controls,
  259. &settings::ControlsDelta::controllerAutoLookCentering>},
  260. PreferenceDescriptor{34,
  261. kBoolEncoding,
  262. assign_bool<&settings::SettingsDelta::social,
  263. &settings::SocialDelta::preferGoodConnection>},
  264. PreferenceDescriptor{35,
  265. kBoolEncoding,
  266. assign_bool<&settings::SettingsDelta::controls,
  267. &settings::ControlsDelta::controllerVibration>},
  268. PreferenceDescriptor{36,
  269. kBoolEncoding,
  270. assign_bool<&settings::SettingsDelta::controls,
  271. &settings::ControlsDelta::unidentifiedToggle>},
  272. PreferenceDescriptor{37,
  273. kBoolEncoding,
  274. assign_bool<&settings::SettingsDelta::controls,
  275. &settings::ControlsDelta::mouseAimSmoothing>},
  276. PreferenceDescriptor{38,
  277. kBoolEncoding,
  278. assign_bool<&settings::SettingsDelta::controls,
  279. &settings::ControlsDelta::controllerSwapShoulders>},
  280. PreferenceDescriptor{39, kBoolEncoding, nullptr}, // first unmapped identity-padding field
  281. PreferenceDescriptor{40, kBoolEncoding, nullptr}, // second unmapped identity-padding field
  282. PreferenceDescriptor{
  283. 41,
  284. kBoolEncoding,
  285. assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::showRealNames>},
  286. PreferenceDescriptor{
  287. 42,
  288. kBoolEncoding,
  289. assign_bool<&settings::SettingsDelta::interface, &settings::InterfaceDelta::displayHints>},
  290. PreferenceDescriptor{
  291. 43,
  292. kBoolEncoding,
  293. assign_bool<&settings::SettingsDelta::display, &settings::DisplayDelta::showFps>},
  294. PreferenceDescriptor{44,
  295. kInt8TwoBitEncoding,
  296. assign_int8<&settings::SettingsDelta::interface,
  297. &settings::InterfaceDelta::reticleLocation>},
  298. PreferenceDescriptor{45,
  299. kBoolEncoding,
  300. assign_bool<&settings::SettingsDelta::social,
  301. &settings::SocialDelta::clanInviteNotifications>},
  302. PreferenceDescriptor{
  303. 46,
  304. kBoolEncoding,
  305. assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::profanityFilter>},
  306. PreferenceDescriptor{47,
  307. kInt8ThreeBitEncoding,
  308. assign_int8<&settings::SettingsDelta::interface,
  309. &settings::InterfaceDelta::backgroundOpacity>},
  310. PreferenceDescriptor{
  311. 48,
  312. kInt8ThreeBitEncoding,
  313. assign_int8<&settings::SettingsDelta::interface, &settings::InterfaceDelta::hudOpacity>},
  314. PreferenceDescriptor{
  315. 49,
  316. kBoolEncoding,
  317. assign_bool<&settings::SettingsDelta::social, &settings::SocialDelta::voiceChatEnabled>},
  318. PreferenceDescriptor{
  319. 50,
  320. kInt8TwoBitEncoding,
  321. assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::whisperChatMode>},
  322. PreferenceDescriptor{
  323. 51,
  324. kInt8TwoBitEncoding,
  325. assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::teamChatJoinMode>},
  326. PreferenceDescriptor{
  327. 52,
  328. kInt8TwoBitEncoding,
  329. assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::localChatJoinMode>},
  330. PreferenceDescriptor{
  331. 53,
  332. kInt8TwoBitEncoding,
  333. assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::clanChatJoinMode>},
  334. PreferenceDescriptor{
  335. 54,
  336. kInt8TwoBitEncoding,
  337. assign_int8<&settings::SettingsDelta::display, &settings::DisplayDelta::hdrMode>},
  338. PreferenceDescriptor{55,
  339. kReal32Encoding,
  340. assign_real32<&settings::SettingsDelta::display,
  341. &settings::DisplayDelta::calibrationPrimary>},
  342. PreferenceDescriptor{56,
  343. kReal32Encoding,
  344. assign_real32<&settings::SettingsDelta::display,
  345. &settings::DisplayDelta::calibrationAlpha>},
  346. PreferenceDescriptor{
  347. 57,
  348. kInt8ThreeBitEncoding,
  349. assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::textChatMode>},
  350. PreferenceDescriptor{
  351. 58,
  352. kInt8TwoBitEncoding,
  353. assign_int8<&settings::SettingsDelta::social, &settings::SocialDelta::chatAutoHideMode>},
  354. PreferenceDescriptor{59, kBoolEncoding, nullptr}, // motion-blur mirror
  355. PreferenceDescriptor{60, kBoolEncoding, nullptr}, // film-grain mirror
  356. PreferenceDescriptor{61, kBoolEncoding, nullptr}, // chromatic-aberration mirror
  357. };
  358. /** Ensures explicit schema indices stay aligned with descriptor array positions. */
  359. [[nodiscard]] consteval bool valid_preference_descriptors() noexcept {
  360. for (std::size_t index = 0; index < kPreferenceDescriptors.size(); ++index) {
  361. const PreferenceDescriptor& descriptor = kPreferenceDescriptors[index];
  362. if (descriptor.schemaIndex != index || descriptor.encoding.wireWidthBits == 0
  363. || descriptor.encoding.wireWidthBits > kScalar64WidthBits
  364. || descriptor.encoding.nativeWidthBits == 0
  365. || descriptor.encoding.nativeWidthBits > kScalar64WidthBits) {
  366. return false;
  367. }
  368. }
  369. return true;
  370. }
  371. static_assert(valid_preference_descriptors());
  372. /** Optional widths for unknown mixed record path 0.1.4 fields 0 through 7. */
  373. constexpr std::array<std::uint8_t, kGroup_0_1_4OptionalFieldCount> kGroup_0_1_4OptionalWidths{
  374. kScalar64WidthBits,
  375. kScalar64WidthBits,
  376. kScalar64WidthBits,
  377. kTwoWidthBits,
  378. kScalar64WidthBits,
  379. kTwoWidthBits,
  380. kSixWidthBits,
  381. kFiveWidthBits,
  382. };
  383. /** Builds a low-bit mask without evaluating the invalid expression `1 << 64`. */
  384. [[nodiscard]] constexpr std::uint64_t width_mask(std::uint8_t nativeWidthBits) noexcept {
  385. return nativeWidthBits == kScalar64WidthBits ? (std::numeric_limits<std::uint64_t>::max)()
  386. : (std::uint64_t{1} << nativeWidthBits) - 1U;
  387. }
  388. /** Reads the one-bit flag that precedes every optional schema node. */
  389. [[nodiscard]] bool read_presence(Reader& reader, bool& present) noexcept {
  390. std::uint64_t value = 0;
  391. if (!reader.read(kPresenceWidthBits, value)) {
  392. return false;
  393. }
  394. present = value != 0;
  395. return true;
  396. }
  397. /** Reads one stored scalar and removes its bias modulo the destination type width. */
  398. [[nodiscard]] bool
  399. read_scalar(Reader& reader, const ScalarEncoding& encoding, std::uint64_t& value) noexcept {
  400. std::uint64_t stored = 0;
  401. if (!reader.read(encoding.wireWidthBits, stored)) {
  402. return false;
  403. }
  404. const std::uint64_t mask = width_mask(encoding.nativeWidthBits);
  405. value = (stored - (encoding.bias & mask)) & mask;
  406. return true;
  407. }
  408. /** Reads an optional scalar while preserving absent versus present-zero semantics. */
  409. [[nodiscard]] bool read_optional_scalar(Reader& reader,
  410. const ScalarEncoding& encoding,
  411. bool& present,
  412. std::uint64_t& value) noexcept {
  413. present = false;
  414. value = 0;
  415. return read_presence(reader, present) && (!present || read_scalar(reader, encoding, value));
  416. }
  417. /** Consumes one optional field whose value is deliberately not retained. */
  418. [[nodiscard]] bool skip_optional_bits(Reader& reader, std::size_t wireWidthBits) noexcept {
  419. bool present = false;
  420. return read_presence(reader, present) && (!present || reader.skip(wireWidthBits));
  421. }
  422. /** Consumes one optional scalar by its declared encoding without retaining its value. */
  423. [[nodiscard]] bool skip_optional_scalar(Reader& reader, const ScalarEncoding& encoding) noexcept {
  424. return skip_optional_bits(reader, encoding.wireWidthBits);
  425. }
  426. /** Reads one optional group and delegates its body only when the group is present. */
  427. template <typename ReadBody>
  428. [[nodiscard]] bool read_optional_group(Reader& reader, ReadBody readBody) noexcept {
  429. bool present = false;
  430. return read_presence(reader, present) && (!present || readBody(reader));
  431. }
  432. /** Consumes the body of optional publicity-expiry bank path 0.0.0. */
  433. [[nodiscard]] bool skip_publicity_expiry_bank(Reader& reader) noexcept {
  434. for (std::size_t index = 0; index < kPublicityExpiryCount; ++index) {
  435. if (!skip_optional_bits(reader, kScalar64WidthBits)) {
  436. return false;
  437. }
  438. }
  439. return true;
  440. }
  441. /** Consumes the fixed seen-message bank at path 0.0.1. */
  442. [[nodiscard]] bool skip_seen_message_bank(Reader& reader) noexcept {
  443. return reader.skip(fixed_array_width_bits(kSeenMessageCount, kScalar32WidthBits));
  444. }
  445. /** Consumes optional root branch 0.0 in child descriptor order. */
  446. [[nodiscard]] bool skip_publicity_and_seen_messages(Reader& reader) noexcept {
  447. return read_optional_group(reader, skip_publicity_expiry_bank)
  448. && read_optional_group(reader, skip_seen_message_bank);
  449. }
  450. /** Consumes one present two-scalar element under calibration path 0.1.0. */
  451. [[nodiscard]] bool skip_calibration_vector(Reader& reader) noexcept {
  452. return reader.skip(fixed_array_width_bits(kCalibrationValuesPerVector, kScalar32WidthBits));
  453. }
  454. /** Consumes present group 0.1.0, including each element's own presence bit. */
  455. [[nodiscard]] bool skip_group_0_1_0(Reader& reader) noexcept {
  456. for (std::size_t index = 0; index < kCalibrationVectorCount; ++index) {
  457. if (!read_optional_group(reader, skip_calibration_vector)) {
  458. return false;
  459. }
  460. }
  461. return true;
  462. }
  463. /** Consumes present preference matrix path 0.1.1.62 in row-major descriptor order. */
  464. [[nodiscard]] bool skip_preference_matrix(Reader& reader) noexcept {
  465. for (std::size_t row = 0; row < kPreferenceMatrixRowCount; ++row) {
  466. for (std::size_t column = 0; column < kPreferenceMatrixColumnCount; ++column) {
  467. if (!skip_optional_bits(reader, kScalar32WidthBits)) {
  468. return false;
  469. }
  470. }
  471. }
  472. return true;
  473. }
  474. /** Decodes present preference group 0.1.1 and consumes its optional opaque matrix. */
  475. [[nodiscard]] bool read_preference_record(Reader& reader, Request& output) noexcept {
  476. for (const PreferenceDescriptor& descriptor : kPreferenceDescriptors) {
  477. bool present = false;
  478. std::uint64_t value = 0;
  479. if (!read_optional_scalar(reader, descriptor.encoding, present, value)) {
  480. return false;
  481. }
  482. if (present && descriptor.assign != nullptr) {
  483. descriptor.assign(value, output);
  484. }
  485. }
  486. return read_optional_group(reader, skip_preference_matrix);
  487. }
  488. /** Decodes the body of present fixed keybinding table path 0.1.2.5 atomically. */
  489. [[nodiscard]] bool read_key_binding_table(Reader& reader, settings::SettingsDelta& delta) noexcept {
  490. settings::bindings::KeyBindings staged{};
  491. for (std::size_t nativeSlot = 0; nativeSlot < settings::bindings::kActionsByNativeSlot.size();
  492. ++nativeSlot) {
  493. std::uint64_t value = 0;
  494. if (!read_scalar(reader, kInt32Encoding, value)) {
  495. return false;
  496. }
  497. // After bias removal, bits 0-15 are primary and bits 16-31 are secondary. The value
  498. // 0x0074 in either half is the protocol's unbound sentinel, not a bindable input.
  499. const std::uint32_t packed = static_cast<std::uint32_t>(value);
  500. const std::uint16_t primary = static_cast<std::uint16_t>(packed);
  501. const std::uint16_t secondary = static_cast<std::uint16_t>(packed >> kBindingHalfWidthBits);
  502. const auto action = settings::bindings::kActionsByNativeSlot[nativeSlot];
  503. auto& binding = staged.values[static_cast<std::size_t>(action)];
  504. if (primary != kUnboundInputCode) {
  505. binding.primary = primary;
  506. }
  507. if (secondary != kUnboundInputCode) {
  508. binding.secondary = secondary;
  509. }
  510. }
  511. staged.configured = true;
  512. delta.keyBindings = staged;
  513. return true;
  514. }
  515. /** Decodes present binding record 0.1.2 in exact child descriptor order. */
  516. [[nodiscard]] bool read_binding_record(Reader& reader, settings::SettingsDelta& delta) noexcept {
  517. // 0.1.2.0: seed/version marker; structurally consumed but not authoritative.
  518. if (!skip_optional_scalar(reader, kInt32Encoding)) {
  519. return false;
  520. }
  521. bool present = false;
  522. std::uint64_t value = 0;
  523. if (!read_optional_scalar(reader, kBoolEncoding, present, value)) {
  524. return false;
  525. }
  526. if (present && !delta.social.voiceChatEnabled.has_value()) {
  527. delta.social.voiceChatEnabled = value != 0;
  528. }
  529. if (!read_optional_scalar(reader, kInt8ThreeBitEncoding, present, value)) {
  530. return false;
  531. }
  532. if (present) {
  533. delta.display.verticalSyncInterval = static_cast<std::uint8_t>(value);
  534. }
  535. if (!read_optional_scalar(reader, kInt32Encoding, present, value)) {
  536. return false;
  537. }
  538. if (present) {
  539. delta.display.fieldOfView = as_int32(value);
  540. }
  541. // 0.1.2.4: authored keybinding source and routing input for the optional table.
  542. bool sourceSelectorPresent = false;
  543. std::uint64_t sourceSelector = 0;
  544. if (!read_optional_scalar(reader, kBoolEncoding, sourceSelectorPresent, sourceSelector)) {
  545. return false;
  546. }
  547. if (sourceSelectorPresent) {
  548. delta.keyBindingSource = sourceSelector != 0 ? settings::KeyBindingSource::computer
  549. : settings::KeyBindingSource::account;
  550. }
  551. // 0.1.2.5: one presence bit covers the complete 60-entry table.
  552. return read_optional_group(reader, [&delta](Reader& tableReader) noexcept {
  553. return read_key_binding_table(tableReader, delta);
  554. });
  555. }
  556. /** Consumes present fixed-width group 0.1.3. */
  557. [[nodiscard]] bool skip_group_0_1_3(Reader& reader) noexcept {
  558. return reader.skip(fixed_array_width_bits(kGroup_0_1_3ValueCount, kScalar16WidthBits));
  559. }
  560. /** Consumes present mixed-width group 0.1.4 without assigning unknown semantics. */
  561. [[nodiscard]] bool skip_group_0_1_4(Reader& reader) noexcept {
  562. for (const std::uint8_t width : kGroup_0_1_4OptionalWidths) {
  563. if (!skip_optional_bits(reader, width)) {
  564. return false;
  565. }
  566. }
  567. // Field 8 is required u64, field 9 is optional 3-bit, and field 10 is required bool.
  568. return reader.skip(kScalar64WidthBits) && skip_optional_bits(reader, kThreeWidthBits)
  569. && reader.skip(kBooleanWidthBits);
  570. }
  571. /** Reads the profile new-item bitmap carried by group 0.1.5. */
  572. [[nodiscard]] bool read_new_items(Reader& reader, Request& output) noexcept {
  573. state::account::inventory::ProfileNewItems bits{};
  574. for (auto& word : bits) {
  575. std::uint64_t value = 0;
  576. if (!reader.read(kScalar32WidthBits, value)) {
  577. return false;
  578. }
  579. word = static_cast<std::uint32_t>(value);
  580. }
  581. output.newItems = bits;
  582. return true;
  583. }
  584. /** Consumes present nested entry array 0.1.6.0. */
  585. [[nodiscard]] bool skip_group_0_1_6_0(Reader& reader) noexcept {
  586. for (std::size_t index = 0; index < kGroup_0_1_6EntryCount; ++index) {
  587. if (!skip_optional_bits(reader, kScalar16WidthBits)) {
  588. return false;
  589. }
  590. }
  591. return reader.skip(fixed_array_width_bits(kGroup_0_1_6FixedWordCount, kScalar32WidthBits));
  592. }
  593. /** Consumes present group 0.1.6, including optional children 0 and 1. */
  594. [[nodiscard]] bool skip_group_0_1_6(Reader& reader) noexcept {
  595. return read_optional_group(reader, skip_group_0_1_6_0)
  596. && skip_optional_bits(reader, kScalar16WidthBits);
  597. }
  598. /** Consumes present fixed-tail group 0.1.12. */
  599. [[nodiscard]] bool skip_group_0_1_12(Reader& reader) noexcept {
  600. return reader.skip(fixed_array_width_bits(kGroup_0_1_12ValueCount, kScalar16WidthBits))
  601. && reader.skip(fixed_array_width_bits(kGroup_0_1_12FixedWordCount, kScalar32WidthBits));
  602. }
  603. /** Traverses every child of present account branch 0.1 in descriptor order. */
  604. [[nodiscard]] bool read_account_branch(Reader& reader, Request& output) noexcept {
  605. // 0.1.0: calibration vectors.
  606. if (!read_optional_group(reader, skip_group_0_1_0)) {
  607. return false;
  608. }
  609. // 0.1.1: preference scalars and the optional 3-by-50 matrix.
  610. if (!read_optional_group(reader, [&output](Reader& groupReader) noexcept {
  611. return read_preference_record(groupReader, output);
  612. })) {
  613. return false;
  614. }
  615. // 0.1.2: local mirrors, keybinding source, and packed binding table.
  616. if (!read_optional_group(reader, [&output](Reader& groupReader) noexcept {
  617. return read_binding_record(groupReader, output.settings);
  618. })) {
  619. return false;
  620. }
  621. // 0.1.3: four required 16-bit values.
  622. if (!read_optional_group(reader, skip_group_0_1_3)) {
  623. return false;
  624. }
  625. // 0.1.4: mixed-width record with unknown semantics.
  626. if (!read_optional_group(reader, skip_group_0_1_4)) {
  627. return false;
  628. }
  629. // 0.1.5: 22 required 32-bit values.
  630. if (!read_optional_group(reader, [&output](Reader& groupReader) noexcept {
  631. return read_new_items(groupReader, output);
  632. })) {
  633. return false;
  634. }
  635. // 0.1.6: optional 100-entry region, two required words, and optional 16-bit tail.
  636. if (!read_optional_group(reader, skip_group_0_1_6)) {
  637. return false;
  638. }
  639. // 0.1.7: optional Boolean.
  640. if (!skip_optional_bits(reader, kBooleanWidthBits)) {
  641. return false;
  642. }
  643. // 0.1.8: optional Boolean.
  644. if (!skip_optional_bits(reader, kBooleanWidthBits)) {
  645. return false;
  646. }
  647. // 0.1.9: optional Boolean.
  648. if (!skip_optional_bits(reader, kBooleanWidthBits)) {
  649. return false;
  650. }
  651. // 0.1.10: optional 8-bit scalar.
  652. if (!skip_optional_bits(reader, kByteWidthBits)) {
  653. return false;
  654. }
  655. // 0.1.11: optional 32-bit scalar.
  656. if (!skip_optional_bits(reader, kScalar32WidthBits)) {
  657. return false;
  658. }
  659. // 0.1.12: 30 required 16-bit values followed by two required 32-bit words.
  660. if (!read_optional_group(reader, skip_group_0_1_12)) {
  661. return false;
  662. }
  663. // 0.1.13: optional 32-bit scalar.
  664. return skip_optional_bits(reader, kScalar32WidthBits);
  665. }
  666. /** Consumes both optional length-prefixed blobs following the reflected object. */
  667. [[nodiscard]] bool skip_outer_blobs(Reader& reader) noexcept {
  668. for (std::size_t index = 0; index < kOuterBlobCount; ++index) {
  669. bool present = false;
  670. std::uint64_t byteCount = 0;
  671. if (!read_presence(reader, present)) {
  672. return false;
  673. }
  674. if (present
  675. && (!reader.read(kOuterBlobLengthWidthBits, byteCount)
  676. || !reader.skip(static_cast<std::size_t>(byteCount) * kByteWidthBits))) {
  677. return false;
  678. }
  679. }
  680. return true;
  681. }
  682. /** Requires any final partial byte to contain only zero padding. */
  683. [[nodiscard]] bool finish_padding(Reader& reader) noexcept {
  684. const std::size_t remaining = reader.remaining_bits();
  685. if (remaining >= kTerminalPaddingLimitBits) {
  686. return false;
  687. }
  688. std::uint64_t padding = 0;
  689. return reader.read(static_cast<std::uint8_t>(remaining), padding) && padding == 0
  690. && reader.remaining_bits() == 0;
  691. }
  692. /** Compile-time proof that the declared traversal still matches the catalog's maximum form. */
  693. namespace schema_size_proof {
  694. [[nodiscard]] consteval std::size_t optional_scalar(std::size_t widthBits) noexcept {
  695. return kPresenceWidthBits + widthBits;
  696. }
  697. [[nodiscard]] consteval std::size_t optional_group(std::size_t bodyBits) noexcept {
  698. return kPresenceWidthBits + bodyBits;
  699. }
  700. [[nodiscard]] consteval std::size_t optional_scalar_array(std::size_t count,
  701. std::size_t widthBits) noexcept {
  702. return count * optional_scalar(widthBits);
  703. }
  704. [[nodiscard]] consteval std::size_t preference_fields() noexcept {
  705. std::size_t total = 0;
  706. for (const PreferenceDescriptor& descriptor : kPreferenceDescriptors) {
  707. total += optional_scalar(descriptor.encoding.wireWidthBits);
  708. }
  709. return total;
  710. }
  711. [[nodiscard]] consteval std::size_t group_0_1_4_body() noexcept {
  712. std::size_t total = 0;
  713. for (const std::uint8_t widthBits : kGroup_0_1_4OptionalWidths) {
  714. total += optional_scalar(widthBits);
  715. }
  716. // Field 8 is required u64, field 9 is optional 3-bit, and field 10 is required bool.
  717. return total + kScalar64WidthBits + optional_scalar(kThreeWidthBits) + kBooleanWidthBits;
  718. }
  719. // Largest form of the publicity-expiry bank.
  720. constexpr std::size_t kPublicityExpiryBankBits =
  721. optional_group(optional_scalar_array(kPublicityExpiryCount, kScalar64WidthBits));
  722. // Largest form of the seen-message bank.
  723. constexpr std::size_t kSeenMessageBankBits =
  724. optional_group(fixed_array_width_bits(kSeenMessageCount, kScalar32WidthBits));
  725. // Largest form of the root metadata group.
  726. constexpr std::size_t kRootMetadataBits =
  727. optional_group(kPublicityExpiryBankBits + kSeenMessageBankBits);
  728. // Largest form of the calibration group.
  729. constexpr std::size_t kCalibrationGroupBits = optional_group(
  730. kCalibrationVectorCount
  731. * optional_group(fixed_array_width_bits(kCalibrationValuesPerVector, kScalar32WidthBits)));
  732. // Largest form of the preference matrix.
  733. constexpr std::size_t kPreferenceMatrixBits = optional_group(optional_scalar_array(
  734. kPreferenceMatrixRowCount * kPreferenceMatrixColumnCount, kScalar32WidthBits));
  735. // Largest form of the preferences group.
  736. constexpr std::size_t kPreferencesBits =
  737. optional_group(preference_fields() + kPreferenceMatrixBits);
  738. // Largest form of the bindings group.
  739. constexpr std::size_t kBindingsBits =
  740. optional_group(optional_scalar(kScalar32WidthBits) + optional_scalar(kBooleanWidthBits)
  741. + optional_scalar(kThreeWidthBits) + optional_scalar(kScalar32WidthBits)
  742. + optional_scalar(kBooleanWidthBits)
  743. + optional_group(fixed_array_width_bits(kKeyBindingCount, kScalar32WidthBits)));
  744. // Largest form of group 0.1.3.
  745. constexpr std::size_t kGroup_0_1_3Bits =
  746. optional_group(fixed_array_width_bits(kGroup_0_1_3ValueCount, kScalar16WidthBits));
  747. // Largest form of groups 0.1.4 and 0.1.5.
  748. constexpr std::size_t kGroup_0_1_4Bits = optional_group(group_0_1_4_body());
  749. constexpr std::size_t kGroup_0_1_5Bits =
  750. optional_group(fixed_array_width_bits(kGroup_0_1_5ValueCount, kScalar32WidthBits));
  751. // Largest form of group 0.1.6.
  752. constexpr std::size_t kGroup_0_1_6Bits = optional_group(
  753. optional_group(optional_scalar_array(kGroup_0_1_6EntryCount, kScalar16WidthBits)
  754. + fixed_array_width_bits(kGroup_0_1_6FixedWordCount, kScalar32WidthBits))
  755. + optional_scalar(kScalar16WidthBits));
  756. // Largest form of the account tail fields.
  757. constexpr std::size_t kAccountTailBits =
  758. optional_scalar(kBooleanWidthBits) + optional_scalar(kBooleanWidthBits)
  759. + optional_scalar(kBooleanWidthBits) + optional_scalar(kByteWidthBits)
  760. + optional_scalar(kScalar32WidthBits);
  761. // Largest form of group 0.1.12.
  762. constexpr std::size_t kGroup_0_1_12Bits =
  763. optional_group(fixed_array_width_bits(kGroup_0_1_12ValueCount, kScalar16WidthBits)
  764. + fixed_array_width_bits(kGroup_0_1_12FixedWordCount, kScalar32WidthBits));
  765. // Largest form of group 0.1.13.
  766. constexpr std::size_t kGroup_0_1_13Bits = optional_scalar(kScalar32WidthBits);
  767. // Largest form of the account branch.
  768. constexpr std::size_t kAccountBranchBits =
  769. optional_group(kCalibrationGroupBits + kPreferencesBits + kBindingsBits + kGroup_0_1_3Bits
  770. + kGroup_0_1_4Bits + kGroup_0_1_5Bits + kGroup_0_1_6Bits + kAccountTailBits
  771. + kGroup_0_1_12Bits + kGroup_0_1_13Bits);
  772. // Largest form of the whole body.
  773. constexpr std::size_t kSchemaBits = kRootMetadataBits + kAccountBranchBits;
  774. static_assert(kRootMetadataBits == kCatalogRootMetadataMaximumBits);
  775. static_assert(kPreferencesBits == kCatalogPreferencesMaximumBits);
  776. static_assert(kBindingsBits == kCatalogBindingsMaximumBits);
  777. static_assert(kAccountBranchBits == kCatalogAccountBranchMaximumBits);
  778. static_assert(kSchemaBits == kCatalogMaximumBits);
  779. } // namespace schema_size_proof
  780. } // namespace
  781. /** Decodes the complete schema-0x80807603 request without touching authoritative State. */
  782. bool parse_request(const Message& message, Request& output) noexcept {
  783. output = {};
  784. if (message.opcode != kOpcode) {
  785. return false;
  786. }
  787. Reader reader(message.payload);
  788. Request candidate{};
  789. if (!read_optional_group(reader, skip_publicity_and_seen_messages)
  790. || !read_optional_group(reader,
  791. [&candidate](Reader& groupReader) noexcept {
  792. return read_account_branch(groupReader, candidate);
  793. })
  794. || !skip_outer_blobs(reader) || !finish_padding(reader)) {
  795. return false;
  796. }
  797. output = candidate;
  798. return true;
  799. }
  800. } // namespace sunrise::middleware::web_service::messages::opcode701