yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
rom.h
Go to the documentation of this file.
1#ifndef YAZE_ROM_ROM_H
2#define YAZE_ROM_ROM_H
3
4#include <array>
5#include <cstddef>
6#include <cstdint>
7#include <map>
8#include <memory>
9#include <string>
10#include <variant>
11#include <vector>
12
13#include "absl/status/status.h"
14#include "absl/status/statusor.h"
17#include "core/project.h"
19#include "rom/rom_diagnostics.h"
20
21namespace yaze {
22
23namespace rom {
24class WriteFence;
25} // namespace rom
26class ScopedRomReadOnly;
27
29inline constexpr size_t kCopierHeaderSize = 0x200;
30
33 kNone,
34 // File size % 0x8000 == 0x200: the standard copier-header layout.
36 // Nonstandard file size (neither a 32 KB multiple nor one plus 0x200), but
37 // the SNES internal header is valid only 0x200 bytes into the file.
38 // LYRA-v038b.smc (0x10083B bytes) is this case.
40};
41
45CopierHeaderReason DetectCopierHeader(const uint8_t* data, size_t size);
47
52class Rom {
53 public:
54 struct SaveSettings {
55 bool backup = false;
56 bool save_new = false;
57 std::string filename;
58 // Require a successful backup of an existing save target before replacing
59 // it. Unlike the legacy best-effort `backup` flag, backup failure aborts
60 // the save. A new target has no previous bytes to protect. This implies
61 // backup creation when `backup` is false.
62 bool require_backup = false;
63 };
64
65 struct LoadOptions {
66 // Detect a copier header (DetectCopierHeader) and keep it out of the ROM
67 // data. The stripped bytes are kept and SaveToFile writes them back.
68 bool strip_header = true;
70
71 static LoadOptions Defaults() { return LoadOptions{}; }
72 };
73
74 Rom() = default;
75 Rom(const Rom& other);
76 Rom& operator=(const Rom& other);
77 Rom& operator=(Rom&& other);
78 ~Rom() = default;
79
80 absl::Status LoadFromFile(
81 const std::string& filename,
82 const LoadOptions& options = LoadOptions::Defaults());
83 absl::Status LoadFromData(
84 const std::vector<uint8_t>& data,
85 const LoadOptions& options = LoadOptions::Defaults());
86
87 // Writes the ROM data. A ROM loaded with a copier header is written with
88 // that header in front (in place or to a new file), so a save never
89 // silently drops the header and an unedited round trip is byte-identical.
90 absl::Status SaveToFile(const SaveSettings& settings);
91 // The only Lyra writer: dedicated A0 terrain, exact loaded-image guard,
92 // atomic Save As to a different backing file. Generic writes stay refused.
93 absl::Status SaveLyraA0TerrainAs(const std::array<uint16_t, 256>& tiles,
94 const std::string& filename);
95 // Test seam: while set, SaveToFile fails when creating its staging file,
96 // after any backup is written and before the destination is replaced.
97 static void SetStagingFailureForTesting(bool fail);
98
99 void Expand(int size) {
100 // This exact-save transfer cannot be resized by a native producer.
102 (size != 0x400000 || rom_data_.size() != 0x400000))
103 return;
104 const bool size_changed = rom_data_.size() != static_cast<size_t>(size);
105 rom_data_.resize(size);
106 size_ = size;
107 if (size_changed) {
109 }
110 }
111
112 void Close() {
113 const bool had_data = !rom_data_.empty();
114 rom_data_.clear();
115 copier_header_.clear();
119 size_ = 0;
120 if (had_data) {
122 }
123 }
124
125 // Raw access
126 absl::StatusOr<uint8_t> ReadByte(int offset) const;
127 absl::StatusOr<uint16_t> ReadWord(int offset) const;
128 absl::StatusOr<uint32_t> ReadLong(int offset) const;
129 absl::StatusOr<std::vector<uint8_t>> ReadByteVector(uint32_t offset,
130 uint32_t length) const;
131 absl::StatusOr<gfx::Tile16> ReadTile16(uint32_t tile16_id,
133
134 absl::Status WriteTile16(int tile16_id, uint32_t tile16_ptr,
135 const gfx::Tile16& tile);
136 absl::Status WriteByte(int addr, uint8_t value);
137 absl::Status WriteWord(int addr, uint16_t value);
138 absl::Status WriteShort(int addr, uint16_t value);
139 absl::Status WriteLong(uint32_t addr, uint32_t value);
140 absl::Status WriteVector(int addr, std::vector<uint8_t> data);
141 absl::Status WriteColor(uint32_t address, const gfx::SnesColor& color);
142
143 template <typename... Args>
144 absl::Status WriteTransaction(Args... args) {
145 absl::Status status;
146 ((status = WriteHelper(args)), ...);
147 return status;
148 }
149
150 template <typename T, typename... Args>
151 absl::Status ReadTransaction(T& var, int address, Args&&... args) {
152 absl::Status status = ReadHelper<T>(var, address);
153 if (!status.ok()) {
154 return status;
155 }
156 if constexpr (sizeof...(args) > 0) {
157 status = ReadTransaction(std::forward<Args>(args)...);
158 }
159 return status;
160 }
161
162 struct WriteAction {
163 using ValueType =
164 std::variant<int, uint8_t, uint16_t, short, std::vector<uint8_t>,
165 gfx::SnesColor, std::vector<gfx::SnesColor>>;
168 };
169
170 virtual absl::Status WriteHelper(const WriteAction& action);
171
172 template <typename T>
173 absl::Status ReadHelper(T& var, int address) {
174 if constexpr (std::is_same_v<T, uint8_t>) {
175 auto result = ReadByte(address);
176 if (!result.ok())
177 return result.status();
178 var = *result;
179 } else if constexpr (std::is_same_v<T, uint16_t>) {
180 auto result = ReadWord(address);
181 if (!result.ok())
182 return result.status();
183 var = *result;
184 } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
185 auto result = ReadByteVector(address, var.size());
186 if (!result.ok())
187 return result.status();
188 var = *result;
189 }
190 return absl::OkStatus();
191 }
192
193 uint8_t& operator[](unsigned long i) {
194 if (i >= size_)
195 throw std::out_of_range("Rom index out of range");
196 return rom_data_[i];
197 }
198
199 bool is_loaded() const { return !rom_data_.empty(); }
200 bool dirty() const { return dirty_; }
201 void set_dirty(bool dirty) { dirty_ = dirty; }
202 void ClearDirty() { dirty_ = false; }
203
204 // Monotonic generation for RoomObject caches derived from ROM tile tables.
205 // Successful loads, content replacement, a real Close, and real size changes
206 // advance it automatically. Writers that mutate object tile sources must
207 // advance it only after their transaction commits successfully.
210
211 auto title() const { return title_; }
212 auto size() const { return size_; }
213 auto data() const { return rom_data_.data(); }
214 auto mutable_data() { return rom_data_.data(); }
215 auto begin() { return rom_data_.begin(); }
216 auto end() { return rom_data_.end(); }
217 const auto& vector() const { return rom_data_; }
218 auto& mutable_vector() { return rom_data_; }
219 auto filename() const { return filename_; }
220 auto set_filename(std::string_view name) { filename_ = name; }
221 auto short_name() const { return short_name_; }
222
223 // Copier header stripped at load (empty when the file had none). size()
224 // and data() never include it.
225 bool has_copier_header() const { return !copier_header_.empty(); }
226 const std::vector<uint8_t>& copier_header() const { return copier_header_; }
230
231 // The parsed result is derived from this ROM's current bytes. Attribution
232 // captured at load prevents a damaged/erased signature from enabling saves.
234 absl::Status CheckLayoutWritable() const;
235
236 // Sticky, value-owned exact-save reservation. No public detach capability.
237 absl::Status AttachLyraPrivateReservation(const core::HackManifest& manifest);
239 absl::Status ValidateLyraPrivateReservation() const;
240
241 // Resource labels are generic enough to keep here
245
246 // ROM write fence stack.
247 //
248 // When one or more fences are active, Rom::Write* calls must be allowed by
249 // every fence (logical AND). This is used for strict save-time guardrails so
250 // feature writers can't clobber reserved regions.
253 size_t write_fence_depth() const { return write_fence_stack_.size(); }
254
255 private:
256 absl::Status SaveToFileUnchecked(const SaveSettings& settings);
258 absl::Status CapturePrivateLyraReservation();
259 absl::Status ValidatePrivateLyraImage(
260 const std::vector<uint8_t>& image) const;
261 absl::Status CheckPrivateLyraWrite(uint32_t pc, const uint8_t* bytes,
262 size_t size) const;
264 std::vector<std::pair<uint32_t, std::vector<uint8_t>>>
266 std::shared_ptr<rom::WriteFence> private_lyra_fence_;
267
268 friend class ScopedRomReadOnly;
269
270 // Instance-local command scopes, like write fences. Copies do not inherit
271 // this state; assignment preserves the destination's active scopes.
273
274 // Size of the ROM data.
275 unsigned long size_ = 0;
276
277 // Title of the ROM loaded from the header
278 std::string title_ = "ROM not loaded";
279
280 // Filename of the ROM
281 std::string filename_;
282
283 // Short name of the ROM
284 std::string short_name_;
285
286 // Full contiguous rom space
287 std::vector<uint8_t> rom_data_;
288 // Held only for the explicit revision-2 terrain capability. Direct mutable
289 // access must not smuggle unrelated bytes through the dedicated Save As.
290 std::vector<uint8_t> lyra_terrain_baseline_;
291
292 // Copier header bytes removed from the front of the file at load.
293 std::vector<uint8_t> copier_header_;
296
297 // Label manager for unique resource names.
299
300 // True if there are unsaved changes
301 bool dirty_ = false;
302
303 // Generation of object-tile data visible to RoomObject parser caches.
305
306 // Active write fences (not owned).
307 std::vector<rom::WriteFence*> write_fence_stack_;
308};
309
310// Refuse normal ROM writes and file saves for this instance while the scope is
311// alive. Independent ROM copies remain usable for dry-run simulations.
327
328} // namespace yaze
329
330#endif // YAZE_ROM_ROM_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:52
absl::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length) const
Definition rom.cc:1059
CopierHeaderReason copier_header_reason() const
Definition rom.h:227
void PushWriteFence(rom::WriteFence *fence)
Definition rom.cc:1008
uint64_t object_tile_revision() const
Definition rom.h:208
~Rom()=default
project::ResourceLabelManager * resource_label()
Definition rom.h:242
absl::Status ReadTransaction(T &var, int address, Args &&... args)
Definition rom.h:151
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:632
auto begin()
Definition rom.h:215
void ClearDirty()
Definition rom.h:202
std::vector< uint8_t > rom_data_
Definition rom.h:287
absl::Status CheckLayoutWritable() const
Definition rom.cc:432
absl::Status AttachLyraPrivateReservation(const core::HackManifest &manifest)
Definition rom.cc:518
absl::StatusOr< gfx::Tile16 > ReadTile16(uint32_t tile16_id, uint32_t tile16_ptr)
Definition rom.cc:1072
absl::Status WriteColor(uint32_t address, const gfx::SnesColor &color)
Definition rom.cc:1220
auto filename() const
Definition rom.h:219
void PopWriteFence(rom::WriteFence *fence)
Definition rom.cc:1015
auto end()
Definition rom.h:216
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:1104
rom::LyraLayoutInspection InspectLyraLayout() const
Definition rom.cc:421
absl::StatusOr< uint8_t > ReadByte(int offset) const
Definition rom.cc:1036
absl::Status WriteTile16(int tile16_id, uint32_t tile16_ptr, const gfx::Tile16 &tile)
Definition rom.cc:1091
void set_dirty(bool dirty)
Definition rom.h:201
auto mutable_data()
Definition rom.h:214
std::vector< std::pair< uint32_t, std::vector< uint8_t > > > private_lyra_preimages_
Definition rom.h:265
const auto & vector() const
Definition rom.h:217
std::shared_ptr< rom::WriteFence > private_lyra_fence_
Definition rom.h:266
std::vector< uint8_t > copier_header_
Definition rom.h:293
absl::Status WriteVector(int addr, std::vector< uint8_t > data)
Definition rom.cc:1188
std::string title_
Definition rom.h:278
absl::Status CapturePrivateLyraReservation()
Definition rom.cc:451
void Expand(int size)
Definition rom.h:99
absl::Status WriteTransaction(Args... args)
Definition rom.h:144
bool private_lyra_attached_
Definition rom.h:263
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:893
absl::StatusOr< uint16_t > ReadWord(int offset) const
Definition rom.cc:1044
static void SetStagingFailureForTesting(bool fail)
Definition rom.cc:417
CopierHeaderReason copier_header_reason_
Definition rom.h:294
const std::vector< uint8_t > & copier_header() const
Definition rom.h:226
Rom()=default
auto data() const
Definition rom.h:213
auto size() const
Definition rom.h:212
std::vector< rom::WriteFence * > write_fence_stack_
Definition rom.h:307
absl::Status SaveToFileUnchecked(const SaveSettings &settings)
Definition rom.cc:899
Rom & operator=(const Rom &other)
Definition rom.cc:593
bool dirty() const
Definition rom.h:200
bool dirty_
Definition rom.h:301
auto & mutable_vector()
Definition rom.h:218
void CaptureLyraTerrainBaseline()
Definition rom.cc:833
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:781
auto short_name() const
Definition rom.h:221
void AdvanceObjectTileRevision()
Definition rom.h:209
std::vector< uint8_t > lyra_terrain_baseline_
Definition rom.h:290
absl::Status ReadHelper(T &var, int address)
Definition rom.h:173
std::string filename_
Definition rom.h:281
unsigned long size_
Definition rom.h:275
absl::Status ValidateLyraPrivateReservation() const
Definition rom.cc:555
absl::Status WriteShort(int addr, uint16_t value)
Definition rom.cc:1153
absl::Status ValidatePrivateLyraImage(const std::vector< uint8_t > &image) const
Definition rom.cc:537
project::ResourceLabelManager resource_label_manager_
Definition rom.h:298
void Close()
Definition rom.h:112
absl::Status SaveLyraA0TerrainAs(const std::array< uint16_t, 256 > &tiles, const std::string &filename)
Definition rom.cc:842
uint8_t & operator[](unsigned long i)
Definition rom.h:193
bool has_copier_header() const
Definition rom.h:225
absl::Status CheckPrivateLyraWrite(uint32_t pc, const uint8_t *bytes, size_t size) const
Definition rom.cc:559
size_t read_only_scope_depth_
Definition rom.h:272
auto set_filename(std::string_view name)
Definition rom.h:220
std::string short_name_
Definition rom.h:284
uint64_t object_tile_revision_
Definition rom.h:304
bool is_loaded() const
Definition rom.h:199
absl::Status WriteWord(int addr, uint16_t value)
Definition rom.cc:1125
virtual absl::Status WriteHelper(const WriteAction &action)
Definition rom.cc:1226
bool has_lyra_private_reservation() const
Definition rom.h:238
size_t write_fence_depth() const
Definition rom.h:253
absl::Status WriteLong(uint32_t addr, uint32_t value)
Definition rom.cc:1157
auto title() const
Definition rom.h:211
absl::StatusOr< uint32_t > ReadLong(int offset) const
Definition rom.cc:1051
bool lyra_attributed_at_load_
Definition rom.h:295
ScopedRomReadOnly & operator=(const ScopedRomReadOnly &)=delete
ScopedRomReadOnly(const ScopedRomReadOnly &)=delete
ScopedRomReadOnly & operator=(ScopedRomReadOnly &&)=delete
ScopedRomReadOnly(Rom &rom)
Definition rom.h:314
ScopedRomReadOnly(ScopedRomReadOnly &&)=delete
Loads and queries the hack manifest JSON for yaze-ASM integration.
SNES Color container.
Definition snes_color.h:110
Tile composition of four 8x8 tiles.
Definition snes_tile.h:142
Rom * rom()
Get the current ROM instance.
CopierHeaderReason DetectCopierHeader(const uint8_t *data, size_t size)
Definition rom.cc:381
CopierHeaderReason
Why a copier header was recognized at the start of a ROM file.
Definition rom.h:32
constexpr size_t kCopierHeaderSize
Size of the SMC/SWC copier header that some ROM dumps start with.
Definition rom.h:29
const char * CopierHeaderReasonName(CopierHeaderReason reason)
Definition rom.cc:405
static LoadOptions Defaults()
Definition rom.h:71
bool load_resource_labels
Definition rom.h:69
std::string filename
Definition rom.h:57
std::variant< int, uint8_t, uint16_t, short, std::vector< uint8_t >, gfx::SnesColor, std::vector< gfx::SnesColor > > ValueType
Definition rom.h:163
ValueType value
Definition rom.h:167