parser.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #pragma once
  2. #include <Windows.h>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. #include <string_view>
  7. #include "settings.h"
  8. namespace sunrise::core::settings::parser {
  9. /** Fixed-storage JSON reader for the supported Core settings. */
  10. class Parser {
  11. public:
  12. /** @param input Complete JSON text, borrowed and never changed. */
  13. explicit Parser(std::string_view input) noexcept;
  14. /**
  15. * Parses the supported root object and skips unknown top-level values.
  16. * @param output Receives supported settings on top of the caller's defaults.
  17. * @return True when the input matches the supported root settings.
  18. */
  19. [[nodiscard]] bool parse_root(Settings& output) noexcept;
  20. /**
  21. * Parses the supported Core settings object.
  22. * @param output Receives supported Core values.
  23. * @return True when the object is valid JSON.
  24. */
  25. private:
  26. [[nodiscard]] bool core(Settings& output) noexcept;
  27. /**
  28. * Parses Client settings on top of the fixed defaults.
  29. * @param output Receives the complete Client settings after checking.
  30. * @return True when every supported Client object appears at most once.
  31. */
  32. [[nodiscard]] bool client_settings(client::Settings& output) noexcept;
  33. /**
  34. * Parses the in-game UI boot and input policy.
  35. * @param output Receives settings only after the whole object is valid.
  36. * @return True when supported values are unique and use a named Windows key.
  37. */
  38. [[nodiscard]] bool client_ui_settings(ui::runtime::Settings& output) noexcept;
  39. /**
  40. * Parses the external-server block on top of the fixed defaults.
  41. * @param output Receives the settings only after every field is valid.
  42. * @return True when every supported key appears at most once with a usable value.
  43. */
  44. [[nodiscard]] bool client_external_settings(client::external::Settings& output) noexcept;
  45. /**
  46. * Checks the standalone Server settings object.
  47. * @param output Receives the current Server settings after the whole object is valid.
  48. * @return True when the object is valid JSON; unknown future options are skipped.
  49. */
  50. [[nodiscard]] bool server_settings(server::Settings& output) noexcept;
  51. /**
  52. * Parses the gameplay endpoint block on top of the fixed defaults.
  53. * @param output Receives the block only after the whole object is consistent.
  54. * @return True when the topology, addresses, port, and slot reserve agree.
  55. */
  56. [[nodiscard]] bool gameplay_settings(server::gameplay::Settings& output) noexcept;
  57. /**
  58. * Parses the authored entitlement array. Array order is the handle order the Client finds
  59. * definitions by, so entries are kept exactly as configured.
  60. * @param output Receives the whole authored table, replacing the bundled policy.
  61. * @return True when every entry parses and the array fits the table size.
  62. */
  63. [[nodiscard]] bool entitlements(state::entitlements::Table& output) noexcept;
  64. /**
  65. * Parses one authored entitlement definition.
  66. * @param output Receives one filled-in definition.
  67. * @return True when the object carries a bounded name and a supported ownership form.
  68. */
  69. [[nodiscard]] bool entitlement(state::entitlements::Entitlement& output) noexcept;
  70. /**
  71. * Parses Steam settings on top of the fixed defaults.
  72. * @param output Receives the complete Steam settings after checking.
  73. * @return True when every supported Steam object appears at most once.
  74. */
  75. [[nodiscard]] bool steam_settings(steam::Settings& output) noexcept;
  76. /**
  77. * Parses the single local Steam user's fixed identity settings.
  78. * @param output Receives the user settings only after the whole object is valid.
  79. * @return True when the supported persona is unique and bounded.
  80. */
  81. [[nodiscard]] bool steam_user_settings(steam::User& output) noexcept;
  82. [[nodiscard]] bool state_settings(Settings& output) noexcept;
  83. /**
  84. * Parses the optional activity settings object on top of the State defaults.
  85. * @param output Receives one replacement only after its whole row is valid.
  86. * @return True when the object is valid JSON with no repeated supported fields.
  87. */
  88. [[nodiscard]] bool
  89. activity_settings(state::activity::defaults::ActivityDefaults& output) noexcept;
  90. /**
  91. * Parses one local destination and its small numeric launch policy.
  92. * @param output Receives the candidate only after all supported fields are valid together.
  93. * @return True when every required field appears once with a canonical value.
  94. */
  95. [[nodiscard]] bool
  96. default_destination(state::activity::defaults::DefaultDestination& output) noexcept;
  97. /**
  98. * Parses one authored arrival override row.
  99. * @param output Row receiving the candidate only after every supplied field is valid.
  100. * @return True when the object names a destination and at least one value.
  101. */
  102. [[nodiscard]] bool
  103. arrival_override(state::activity::defaults::ArrivalOverride& output) noexcept;
  104. /**
  105. * Parses the authored arrival override table.
  106. * @param output Defaults receiving the rows and their count.
  107. * @return True when every row is valid and the table fits fixed storage.
  108. */
  109. [[nodiscard]] bool
  110. arrival_overrides(state::activity::defaults::ActivityDefaults& output) noexcept;
  111. [[nodiscard]] bool unlocks(state::unlocks::Table& output) noexcept;
  112. [[nodiscard]] bool flag_runs(std::span<std::uint8_t> bank) noexcept;
  113. [[nodiscard]] bool flag_indices(std::span<std::uint8_t> bank) noexcept;
  114. [[nodiscard]] bool objective_values(std::span<std::int32_t> bank) noexcept;
  115. [[nodiscard]] bool progression_values(state::unlocks::ProgressionBank& bank) noexcept;
  116. /**
  117. * Parses the optional authored family-5 override group.
  118. * @param output Receives both override lists; id and gate fields stay default.
  119. * @return True when the object is valid JSON and every row fits its wire bounds.
  120. */
  121. [[nodiscard]] bool investment(state::Family5State& output) noexcept;
  122. /**
  123. * Fills the flag-override list from [slot, value] pairs.
  124. * @param output Receives the flag rows and their count.
  125. * @return True when every slot, value, and the row count fit their bounds.
  126. */
  127. [[nodiscard]] bool unlock_flag_overrides(state::Family5State& output) noexcept;
  128. /**
  129. * Fills the signed value-override list from [slot, value] pairs.
  130. * @param output Receives the value rows and their count.
  131. * @return True when every slot and the row count fit their bounds.
  132. */
  133. [[nodiscard]] bool unlock_value_overrides(state::Family5State& output) noexcept;
  134. [[nodiscard]] bool account(state::AccountState& output) noexcept;
  135. /**
  136. * Parses the authored character array.
  137. * @param output Receives characters in configuration order.
  138. * @return True when every entry is valid and fits the playable size.
  139. */
  140. [[nodiscard]] bool characters(state::AccountState& output) noexcept;
  141. /**
  142. * Parses the authored account-wide item array.
  143. * A profile item names only its definition and quantity. Its slot is not authored: the
  144. * inventory bucket the definition belongs to names the first slot of that bucket's run.
  145. * @param output Receives profile items in configuration order.
  146. * @return True when every entry is complete and the array fits its size.
  147. */
  148. [[nodiscard]] bool profile_items(state::AccountState& output) noexcept;
  149. /** Parses the server-authored, definition-driven ordinary-gear dismantle payout. */
  150. [[nodiscard]] bool dismantle_rewards(state::AccountState& output) noexcept;
  151. /**
  152. * Parses one authored character identity.
  153. * @param output Receives one complete authored character row.
  154. * @return True when the object contains one nonzero SOID.
  155. */
  156. [[nodiscard]] bool character(state::CharacterState& output) noexcept;
  157. /**
  158. * Reads one selectable ability's socket entry.
  159. * @param output Receives the entry only when it is inside the socket-entry bound.
  160. * @return True when the value parses and names a possible entry.
  161. */
  162. [[nodiscard]] bool ability_entry(std::uint8_t& output) noexcept;
  163. /**
  164. * Parses the optional equipment object with its fixed named slots.
  165. * @param output Receives present items only after the whole object is valid.
  166. * @return True when every name is known and appears at most once.
  167. */
  168. [[nodiscard]] bool equipment(state::account::inventory::Equipment& output) noexcept;
  169. /**
  170. * Parses the optional unequipped character inventory array.
  171. * @param output
  172. * Receives items in authored bucket-placement order.
  173. * @return True when every item is
  174. * complete and the fixed array has room.
  175. */
  176. [[nodiscard]] bool
  177. character_inventory(state::account::inventory::CharacterItems& output) noexcept;
  178. /**
  179. * Parses one item only when every required named field appears exactly once.
  180. * @param output Receives the complete item after checking.
  181. * @return True when all fields fit their fixed State form.
  182. */
  183. [[nodiscard]] bool equipment_item(state::account::inventory::Item& output) noexcept;
  184. /**
  185. * Parses the native-default policy or an authored plug-lane array.
  186. * @param output Receives the canonical socket policy after the value is valid.
  187. * @return True for null or an array of at most 12 hash-or-null lanes.
  188. */
  189. [[nodiscard]] bool equipment_plugs(state::account::inventory::Sockets& output) noexcept;
  190. /**
  191. * Parses one unsigned definition hash used by authored inventory.
  192. * @param output Receives any 32-bit hash except the engine no-definition sentinel.
  193. * @return True when the integer or quoted hex value is allowed.
  194. */
  195. [[nodiscard]] bool inventory_definition_hash(std::uint32_t& output) noexcept;
  196. /**
  197. * Parses grouped account settings. Native record offsets stay hidden.
  198. * @param output Receives the complete authored account settings.
  199. * @return True when every supplied group is valid and the migration latch is complete.
  200. */
  201. [[nodiscard]] bool account_settings(state::account::settings::AccountSettings& output) noexcept;
  202. /**
  203. * Parses controller and mouse settings under stable Sunrise-owned names.
  204. * @param output Receives bounded native value types, with no record offsets.
  205. * @return True when the whole controls object is valid JSON.
  206. */
  207. [[nodiscard]] bool controls_settings(state::account::settings::Controls& output) noexcept;
  208. /**
  209. * Parses voice, volume, and migration settings under stable Sunrise-owned names.
  210. * @param output Receives bounded native value types, with no record offsets.
  211. * @return True when the whole audio object is valid JSON.
  212. */
  213. [[nodiscard]] bool audio_settings(state::account::settings::Audio& output) noexcept;
  214. /**
  215. * Parses screen and renderer settings under stable Sunrise-owned names.
  216. * @param output Receives bounded native value types, with no record offsets.
  217. * @return True when the whole display object is valid JSON.
  218. */
  219. [[nodiscard]] bool display_settings(state::account::settings::Display& output) noexcept;
  220. /**
  221. * Parses HUD and text settings under stable Sunrise-owned names.
  222. * @param output Receives bounded native value types, with no record offsets.
  223. * @return True when the whole interface object is valid JSON.
  224. */
  225. [[nodiscard]] bool interface_settings(state::account::settings::Interface& output) noexcept;
  226. /**
  227. * Parses matchmaking and chat settings under stable Sunrise-owned names.
  228. * @param output Receives bounded native value types, with no record offsets.
  229. * @return True when the whole social object is valid JSON.
  230. */
  231. [[nodiscard]] bool social_settings(state::account::settings::Social& output) noexcept;
  232. /**
  233. * Parses the whole fixed action table under named JSON properties.
  234. * @param output Receives primary and secondary inputs for every supported action.
  235. * @return True when all actions appear exactly once with both input halves.
  236. */
  237. [[nodiscard]] bool
  238. key_bindings(state::account::settings::bindings::KeyBindings& output) noexcept;
  239. /**
  240. * Parses one binding with explicit primary and secondary halves.
  241. * @param output Receives optional input codes; null means unbound.
  242. * @return True when both halves appear exactly once.
  243. */
  244. [[nodiscard]] bool key_binding(state::account::settings::bindings::Binding& output) noexcept;
  245. /**
  246. * Parses one optional input name. Numbers are not accepted.
  247. * @param output Receives a code or the unbound null state.
  248. * @return True for null or a name the Client's own input table carries.
  249. */
  250. [[nodiscard]] bool optional_input_code(std::optional<std::uint16_t>& output) noexcept;
  251. /**
  252. * Turns one authored input name into its input code.
  253. * @param name Key name, or one modifier and the key it prefixes joined by "+".
  254. * @param output Receives the input code.
  255. * @return True when every part of the name is in the Client's input table.
  256. */
  257. [[nodiscard]] static bool input_code_value(std::string_view name,
  258. std::uint16_t& output) noexcept;
  259. /**
  260. * Parses logging sinks and channel levels.
  261. * @param output Receives supported logging values.
  262. * @return True when the logging object is valid JSON.
  263. */
  264. [[nodiscard]] bool logging(log::Settings& output) noexcept;
  265. /**
  266. * Parses named channel levels and ignores unknown channels.
  267. * @param output Receives the known channel levels.
  268. * @return True when the levels object is valid JSON.
  269. */
  270. [[nodiscard]] bool levels(log::Settings& output) noexcept;
  271. /**
  272. * Checks and skips one JSON value of any type without allocating.
  273. * @param depth Current object or array nesting depth.
  274. * @return True when one complete value is read within the depth limit.
  275. */
  276. [[nodiscard]] bool skip_value(unsigned depth) noexcept;
  277. /**
  278. * Reads one JSON string and returns the borrowed encoded bytes.
  279. * @param output Receives the bytes between the quotes.
  280. * @return True when quotes, escapes, and control bytes are valid.
  281. */
  282. [[nodiscard]] bool string(std::string_view& output) noexcept;
  283. /**
  284. * Reads a JSON true or false literal.
  285. * @return True when either literal is read.
  286. */
  287. [[nodiscard]] bool boolean(bool& output) noexcept;
  288. /**
  289. * Reads one unsigned decimal integer with no precision loss.
  290. * @param output Receives the parsed 64-bit value.
  291. * @return True when a complete integer token fits the target type.
  292. */
  293. [[nodiscard]] bool unsigned_integer(std::uint64_t& output) noexcept;
  294. /**
  295. * Reads an unsigned id as a JSON integer or a quoted hex token.
  296. * @param output Receives the parsed 64-bit value.
  297. * @return True when the whole value fits with no precision loss.
  298. */
  299. [[nodiscard]] bool unsigned_value(std::uint64_t& output) noexcept;
  300. /**
  301. * Reads one signed JSON integer. Fractions and exponents are refused.
  302. * @param output Receives the parsed 64-bit value.
  303. * @return True when the whole integer token fits the target type.
  304. */
  305. [[nodiscard]] bool signed_integer(std::int64_t& output) noexcept;
  306. /**
  307. * Reads one signed JSON integer into an 8-bit record value.
  308. * @return True when the integer fits the native signed byte.
  309. */
  310. [[nodiscard]] bool signed_byte(std::int8_t& output) noexcept;
  311. /**
  312. * Reads one signed JSON integer into a 32-bit record value.
  313. * @return True when the integer fits the native signed 32-bit value.
  314. */
  315. [[nodiscard]] bool signed_32(std::int32_t& output) noexcept;
  316. /**
  317. * Reads one finite JSON number into an authored float State value.
  318. * @return True when the whole token is finite and fits a float.
  319. */
  320. [[nodiscard]] bool floating_point(float& output) noexcept;
  321. /** @return True when one complete JSON number is read. */
  322. [[nodiscard]] bool number() noexcept;
  323. /**
  324. * Reads one exact JSON literal after leading whitespace.
  325. * @param value Literal bytes to match.
  326. * @return True when the whole literal is read.
  327. */
  328. [[nodiscard]] bool literal(std::string_view value) noexcept;
  329. /**
  330. * Reads one expected structural character after whitespace.
  331. * @return True when the character is read.
  332. */
  333. [[nodiscard]] bool consume(char value) noexcept;
  334. /** @return True when only trailing whitespace remains. */
  335. [[nodiscard]] bool at_end() noexcept;
  336. /** Skips JSON whitespace. Other control bytes are left alone. */
  337. void whitespace() noexcept;
  338. /**
  339. * Turns a JSON level token into the logging enum.
  340. * @param name Borrowed level token.
  341. * @param output Receives the logging level.
  342. * @return True when the token names a supported level.
  343. */
  344. [[nodiscard]] static bool level_value(std::string_view name, log::Level& output) noexcept;
  345. /**
  346. * Turns a JSON channel token into its settings-array index.
  347. * @param name Borrowed channel token.
  348. * @return Channel index, or Channel::count for an unknown token.
  349. */
  350. [[nodiscard]] static std::size_t channel_index(std::string_view name) noexcept;
  351. /**
  352. * Maps one readable setting name to a Windows SDK virtual key.
  353. * @param name Lowercase settings key name.
  354. * @param output Receives the Windows SDK virtual key.
  355. * @return True when the name is in the supported menu-key set.
  356. */
  357. [[nodiscard]] static bool ui_toggle_key_value(std::string_view name, UINT& output) noexcept;
  358. std::string_view input_;
  359. std::size_t position_{};
  360. };
  361. } // namespace sunrise::core::settings::parser