pack_writer.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. #include <vector>
  7. #include "../format.h"
  8. namespace sunrise::state::activity_sdk::generation::pack {
  9. /** One SHA-256 value used by the canonical pack envelope. */
  10. using Digest = std::array<std::byte, 32>;
  11. /** The three generated-source identities stored in every runtime-pack header. */
  12. struct Identity final {
  13. Digest sdkBuildSha256{};
  14. Digest contentKeySha256{};
  15. Digest logicalIrSha256{};
  16. };
  17. /** Borrowed canonical tables in the exact current section order. */
  18. struct Tables final {
  19. std::span<const std::byte> strings{};
  20. std::span<const format::Activity> activities{};
  21. std::span<const format::Scenario> scenarios{};
  22. std::span<const format::Bubble> bubbles{};
  23. std::span<const format::State> states{};
  24. std::span<const format::Object> objects{};
  25. std::span<const format::Occurrence> occurrences{};
  26. std::span<const format::Slot> slots{};
  27. std::span<const format::Text> texts{};
  28. std::span<const format::Capability> capabilities{};
  29. std::span<const format::Gate> gates{};
  30. std::span<const format::Refusal> refusals{};
  31. std::span<const format::ActorClass> actorClasses{};
  32. std::span<const format::RsatDescriptor> rsatDescriptors{};
  33. std::span<const format::RsatSchema> rsatSchemas{};
  34. std::span<const format::RsatField> rsatFields{};
  35. std::span<const format::Squad> squads{};
  36. std::span<const format::SquadMember> squadMembers{};
  37. std::span<const format::SquadAnchor> squadAnchors{};
  38. std::span<const format::AuthoredSceneResource> authoredSceneResources{};
  39. std::span<const format::AuthoredSceneSquadEdge> authoredSceneSquadEdges{};
  40. std::span<const format::TaskTarget> taskTargets{};
  41. std::span<const format::DialogueCueText> dialogueCueTexts{};
  42. std::span<const format::DirectiveElement> directiveElements{};
  43. std::span<const format::ActivityBindingTag> activityBindingTags{};
  44. std::span<const format::ActivityBindingLocator> activityBindingLocators{};
  45. std::span<const format::BehaviorProgram> behaviorPrograms{};
  46. std::span<const format::BehaviorInput> behaviorInputs{};
  47. std::span<const format::BehaviorChannelWrite> behaviorChannelWrites{};
  48. std::span<const format::BehaviorOwner> behaviorOwners{};
  49. std::span<const format::BehaviorActivityBinding> behaviorActivityBindings{};
  50. std::span<const format::ActorMessageSchema> actorMessageSchemas{};
  51. std::span<const format::ActorCommandDefinition> actorCommandDefinitions{};
  52. std::span<const format::ActorBehaviorProfile> actorBehaviorProfiles{};
  53. std::span<const format::SimulationEventDefinition> simulationEventDefinitions{};
  54. std::span<const format::RuntimeSchema> runtimeSchemas{};
  55. std::span<const format::RuntimeField> runtimeFields{};
  56. std::span<const format::SobjectRsat> sobjectRsats{};
  57. std::span<const format::SobjectRsatDescriptor> sobjectRsatDescriptors{};
  58. std::span<const format::EntityTypeDefinition> entityTypeDefinitions{};
  59. std::span<const format::SobjectRsatFieldBinding> sobjectRsatFieldBindings{};
  60. std::span<const format::RuntimeTypeDefinition> runtimeTypeDefinitions{};
  61. std::span<const format::ActorStateName> actorStateNames{};
  62. std::span<const format::ActorSequenceTable> actorSequenceTables{};
  63. std::span<const format::ActorSequenceEntry> actorSequenceEntries{};
  64. std::span<const format::ActorSequenceBinding> actorSequenceBindings{};
  65. std::span<const format::DialogueCue> dialogueCues{};
  66. std::span<const format::CombatObjectiveGroup> combatObjectiveGroups{};
  67. std::span<const format::ActorAbility> actorAbilities{};
  68. std::span<const format::ActorAbilityTarget> actorAbilityTargets{};
  69. std::span<const format::AuthoredSceneEventKey> authoredSceneEventKeys{};
  70. };
  71. /** Canonical pack build and publication outcomes. */
  72. enum class Status : std::uint8_t {
  73. ready,
  74. invalidInput,
  75. sizeOverflow,
  76. hashFailure,
  77. invalidPack,
  78. ioFailure,
  79. };
  80. /**
  81. * One identity-independent pack image produced by `prepare` and consumed by `publish`.
  82. * Its bytes stay private so the publication path can trust them without hashing them again.
  83. */
  84. class PreparedImage final {
  85. public:
  86. PreparedImage() noexcept = default;
  87. PreparedImage(const PreparedImage&) = delete;
  88. PreparedImage& operator=(const PreparedImage&) = delete;
  89. PreparedImage(PreparedImage&&) noexcept = default;
  90. PreparedImage& operator=(PreparedImage&&) noexcept = default;
  91. /** @return Exact serialized file size, including the header. */
  92. [[nodiscard]] std::uint64_t file_size() const noexcept {
  93. return static_cast<std::uint64_t>(bytes_.size());
  94. }
  95. /** @return Digest of the identity-independent serialized payload. */
  96. [[nodiscard]] const Digest& payload_sha256() const noexcept {
  97. return payloadSha256_;
  98. }
  99. private:
  100. friend Status prepare(const Tables& tables, PreparedImage& output) noexcept;
  101. friend Status publish(const wchar_t* path,
  102. const Identity& identity,
  103. PreparedImage prepared,
  104. Digest& payloadSha256) noexcept;
  105. friend Status build(const Identity& identity,
  106. const Tables& tables,
  107. std::vector<std::byte>& output,
  108. Digest& payloadSha256) noexcept;
  109. std::vector<std::byte> bytes_{};
  110. Digest payloadSha256_{};
  111. };
  112. /**
  113. * Builds and hashes one identity-independent runtime-pack image exactly once.
  114. * The final header identity can be derived from `payload_sha256` before publication.
  115. * @param tables Borrowed string bytes and fixed-layout rows.
  116. * @param output Replaced only with a complete deterministic image.
  117. * @return Precise build outcome.
  118. */
  119. [[nodiscard]] Status prepare(const Tables& tables, PreparedImage& output) noexcept;
  120. /**
  121. * Binds the final identity and publishes the exact bytes returned by `prepare`.
  122. * The writer checks exact writes, close, and atomic rename. It does not reread trusted bytes;
  123. * `validate` and `validate_file` remain the boundaries for persisted input.
  124. * @param path Null-terminated final pack path.
  125. * @param identity Final source identities derived from the prepared payload.
  126. * @param prepared One-shot image returned by `prepare`.
  127. * @param payloadSha256 Receives the committed payload digest only on success.
  128. * @return Precise publication outcome.
  129. */
  130. [[nodiscard]] Status publish(const wchar_t* path,
  131. const Identity& identity,
  132. PreparedImage prepared,
  133. Digest& payloadSha256) noexcept;
  134. /**
  135. * Builds one deterministic SRSDKP01 runtime-pack file image.
  136. * Input row order and string offsets are already canonical and are copied without translation.
  137. * @param identity Exact source identities for this generated estate.
  138. * @param tables Borrowed string bytes and fixed-layout rows.
  139. * @param output Replaced only with a complete deterministic image.
  140. * @param payloadSha256 Receives the payload digest only on success.
  141. * @return `ready` only for a complete image.
  142. */
  143. [[nodiscard]] Status build(const Identity& identity,
  144. const Tables& tables,
  145. std::vector<std::byte>& output,
  146. Digest& payloadSha256) noexcept;
  147. /**
  148. * Validates one complete runtime-pack envelope without applying catalog relation rules.
  149. * This is the explicit buffer boundary for persisted or otherwise untrusted input.
  150. * @param bytes Complete header and payload bytes.
  151. * @param identity Expected source identities.
  152. * @param payloadSha256 Receives the verified payload digest only on success.
  153. * @return True when the header, sections, identities, and payload hash all match.
  154. */
  155. [[nodiscard]] bool validate(std::span<const std::byte> bytes,
  156. const Identity& identity,
  157. Digest& payloadSha256) noexcept;
  158. /** Reopens and authenticates one complete runtime-pack file. */
  159. [[nodiscard]] bool
  160. validate_file(const wchar_t* path, const Identity& identity, Digest& payloadSha256) noexcept;
  161. /**
  162. * Publishes one complete pack through a writer-owned sibling.
  163. * The parent directory must already exist.
  164. * @param path Null-terminated final pack path.
  165. * @param identity Exact source identities for this generated estate.
  166. * @param tables Borrowed string bytes and fixed-layout rows.
  167. * @param payloadSha256 Receives the committed payload digest only on success.
  168. * @return `ready` only after exact write, close, and atomic rename succeed.
  169. */
  170. [[nodiscard]] Status write(const wchar_t* path,
  171. const Identity& identity,
  172. const Tables& tables,
  173. Digest& payloadSha256) noexcept;
  174. } // namespace sunrise::state::activity_sdk::generation::pack