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 <cstddef>
5#include <cstdint>
6#include <map>
7#include <string>
8#include <variant>
9#include <vector>
10
11#include "absl/status/status.h"
12#include "absl/status/statusor.h"
15#include "core/project.h"
17#include "rom/rom_diagnostics.h"
18
19namespace yaze {
20
21namespace rom {
22class WriteFence;
23} // namespace rom
24
26inline constexpr size_t kCopierHeaderSize = 0x200;
27
30 kNone,
31 // File size % 0x8000 == 0x200: the standard copier-header layout.
33 // Nonstandard file size (neither a 32 KB multiple nor one plus 0x200), but
34 // the SNES internal header is valid only 0x200 bytes into the file.
35 // LYRA-v038b.smc (0x10083B bytes) is this case.
37};
38
42CopierHeaderReason DetectCopierHeader(const uint8_t* data, size_t size);
44
49class Rom {
50 public:
51 struct SaveSettings {
52 bool backup = false;
53 bool save_new = false;
54 std::string filename;
55 // Require a successful backup of an existing save target before replacing
56 // it. Unlike the legacy best-effort `backup` flag, backup failure aborts
57 // the save. A new target has no previous bytes to protect. This implies
58 // backup creation when `backup` is false.
59 bool require_backup = false;
60 };
61
62 struct LoadOptions {
63 // Detect a copier header (DetectCopierHeader) and keep it out of the ROM
64 // data. The stripped bytes are kept and SaveToFile writes them back.
65 bool strip_header = true;
67
68 static LoadOptions Defaults() { return LoadOptions{}; }
69 };
70
71 Rom() = default;
72 Rom(const Rom& other);
73 Rom& operator=(const Rom& other);
74 Rom& operator=(Rom&& other);
75 ~Rom() = default;
76
77 absl::Status LoadFromFile(
78 const std::string& filename,
79 const LoadOptions& options = LoadOptions::Defaults());
80 absl::Status LoadFromData(
81 const std::vector<uint8_t>& data,
82 const LoadOptions& options = LoadOptions::Defaults());
83
84 // Writes the ROM data. A ROM loaded with a copier header is written with
85 // that header in front (in place or to a new file), so a save never
86 // silently drops the header and an unedited round trip is byte-identical.
87 absl::Status SaveToFile(const SaveSettings& settings);
88 // Test seam: while set, SaveToFile fails when creating its staging file,
89 // after any backup is written and before the destination is replaced.
90 static void SetStagingFailureForTesting(bool fail);
91
92 void Expand(int size) {
93 const bool size_changed = rom_data_.size() != static_cast<size_t>(size);
94 rom_data_.resize(size);
95 size_ = size;
96 if (size_changed) {
98 }
99 }
100
101 void Close() {
102 const bool had_data = !rom_data_.empty();
103 rom_data_.clear();
104 copier_header_.clear();
107 size_ = 0;
108 if (had_data) {
110 }
111 }
112
113 // Raw access
114 absl::StatusOr<uint8_t> ReadByte(int offset) const;
115 absl::StatusOr<uint16_t> ReadWord(int offset) const;
116 absl::StatusOr<uint32_t> ReadLong(int offset) const;
117 absl::StatusOr<std::vector<uint8_t>> ReadByteVector(uint32_t offset,
118 uint32_t length) const;
119 absl::StatusOr<gfx::Tile16> ReadTile16(uint32_t tile16_id,
121
122 absl::Status WriteTile16(int tile16_id, uint32_t tile16_ptr,
123 const gfx::Tile16& tile);
124 absl::Status WriteByte(int addr, uint8_t value);
125 absl::Status WriteWord(int addr, uint16_t value);
126 absl::Status WriteShort(int addr, uint16_t value);
127 absl::Status WriteLong(uint32_t addr, uint32_t value);
128 absl::Status WriteVector(int addr, std::vector<uint8_t> data);
129 absl::Status WriteColor(uint32_t address, const gfx::SnesColor& color);
130
131 template <typename... Args>
132 absl::Status WriteTransaction(Args... args) {
133 absl::Status status;
134 ((status = WriteHelper(args)), ...);
135 return status;
136 }
137
138 template <typename T, typename... Args>
139 absl::Status ReadTransaction(T& var, int address, Args&&... args) {
140 absl::Status status = ReadHelper<T>(var, address);
141 if (!status.ok()) {
142 return status;
143 }
144 if constexpr (sizeof...(args) > 0) {
145 status = ReadTransaction(std::forward<Args>(args)...);
146 }
147 return status;
148 }
149
150 struct WriteAction {
151 using ValueType =
152 std::variant<int, uint8_t, uint16_t, short, std::vector<uint8_t>,
153 gfx::SnesColor, std::vector<gfx::SnesColor>>;
156 };
157
158 virtual absl::Status WriteHelper(const WriteAction& action);
159
160 template <typename T>
161 absl::Status ReadHelper(T& var, int address) {
162 if constexpr (std::is_same_v<T, uint8_t>) {
163 auto result = ReadByte(address);
164 if (!result.ok())
165 return result.status();
166 var = *result;
167 } else if constexpr (std::is_same_v<T, uint16_t>) {
168 auto result = ReadWord(address);
169 if (!result.ok())
170 return result.status();
171 var = *result;
172 } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
173 auto result = ReadByteVector(address, var.size());
174 if (!result.ok())
175 return result.status();
176 var = *result;
177 }
178 return absl::OkStatus();
179 }
180
181 uint8_t& operator[](unsigned long i) {
182 if (i >= size_)
183 throw std::out_of_range("Rom index out of range");
184 return rom_data_[i];
185 }
186
187 bool is_loaded() const { return !rom_data_.empty(); }
188 bool dirty() const { return dirty_; }
189 void set_dirty(bool dirty) { dirty_ = dirty; }
190 void ClearDirty() { dirty_ = false; }
191
192 // Monotonic generation for RoomObject caches derived from ROM tile tables.
193 // Successful loads, content replacement, a real Close, and real size changes
194 // advance it automatically. Writers that mutate object tile sources must
195 // advance it only after their transaction commits successfully.
198
199 auto title() const { return title_; }
200 auto size() const { return size_; }
201 auto data() const { return rom_data_.data(); }
202 auto mutable_data() { return rom_data_.data(); }
203 auto begin() { return rom_data_.begin(); }
204 auto end() { return rom_data_.end(); }
205 const auto& vector() const { return rom_data_; }
206 auto& mutable_vector() { return rom_data_; }
207 auto filename() const { return filename_; }
208 auto set_filename(std::string_view name) { filename_ = name; }
209 auto short_name() const { return short_name_; }
210
211 // Copier header stripped at load (empty when the file had none). size()
212 // and data() never include it.
213 bool has_copier_header() const { return !copier_header_.empty(); }
214 const std::vector<uint8_t>& copier_header() const { return copier_header_; }
218
219 // The parsed result is derived from this ROM's current bytes. Attribution
220 // captured at load prevents a damaged/erased signature from enabling saves.
222 absl::Status CheckLayoutWritable() const;
223
224 // Resource labels are generic enough to keep here
228
229 // ROM write fence stack.
230 //
231 // When one or more fences are active, Rom::Write* calls must be allowed by
232 // every fence (logical AND). This is used for strict save-time guardrails so
233 // feature writers can't clobber reserved regions.
236 size_t write_fence_depth() const { return write_fence_stack_.size(); }
237
238 private:
239 // Size of the ROM data.
240 unsigned long size_ = 0;
241
242 // Title of the ROM loaded from the header
243 std::string title_ = "ROM not loaded";
244
245 // Filename of the ROM
246 std::string filename_;
247
248 // Short name of the ROM
249 std::string short_name_;
250
251 // Full contiguous rom space
252 std::vector<uint8_t> rom_data_;
253
254 // Copier header bytes removed from the front of the file at load.
255 std::vector<uint8_t> copier_header_;
258
259 // Label manager for unique resource names.
261
262 // True if there are unsaved changes
263 bool dirty_ = false;
264
265 // Generation of object-tile data visible to RoomObject parser caches.
267
268 // Active write fences (not owned).
269 std::vector<rom::WriteFence*> write_fence_stack_;
270};
271
272} // namespace yaze
273
274#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:49
absl::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length) const
Definition rom.cc:808
CopierHeaderReason copier_header_reason() const
Definition rom.h:215
void PushWriteFence(rom::WriteFence *fence)
Definition rom.cc:757
uint64_t object_tile_revision() const
Definition rom.h:196
~Rom()=default
project::ResourceLabelManager * resource_label()
Definition rom.h:225
absl::Status ReadTransaction(T &var, int address, Args &&... args)
Definition rom.h:139
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:491
auto begin()
Definition rom.h:203
void ClearDirty()
Definition rom.h:190
std::vector< uint8_t > rom_data_
Definition rom.h:252
absl::Status CheckLayoutWritable() const
Definition rom.cc:429
absl::StatusOr< gfx::Tile16 > ReadTile16(uint32_t tile16_id, uint32_t tile16_ptr)
Definition rom.cc:821
absl::Status WriteColor(uint32_t address, const gfx::SnesColor &color)
Definition rom.cc:959
auto filename() const
Definition rom.h:207
void PopWriteFence(rom::WriteFence *fence)
Definition rom.cc:764
auto end()
Definition rom.h:204
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:853
rom::LyraLayoutInspection InspectLyraLayout() const
Definition rom.cc:418
absl::StatusOr< uint8_t > ReadByte(int offset) const
Definition rom.cc:785
absl::Status WriteTile16(int tile16_id, uint32_t tile16_ptr, const gfx::Tile16 &tile)
Definition rom.cc:840
void set_dirty(bool dirty)
Definition rom.h:189
auto mutable_data()
Definition rom.h:202
const auto & vector() const
Definition rom.h:205
std::vector< uint8_t > copier_header_
Definition rom.h:255
absl::Status WriteVector(int addr, std::vector< uint8_t > data)
Definition rom.cc:928
std::string title_
Definition rom.h:243
void Expand(int size)
Definition rom.h:92
absl::Status WriteTransaction(Args... args)
Definition rom.h:132
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:648
absl::StatusOr< uint16_t > ReadWord(int offset) const
Definition rom.cc:793
static void SetStagingFailureForTesting(bool fail)
Definition rom.cc:414
CopierHeaderReason copier_header_reason_
Definition rom.h:256
const std::vector< uint8_t > & copier_header() const
Definition rom.h:214
Rom()=default
auto data() const
Definition rom.h:201
auto size() const
Definition rom.h:200
std::vector< rom::WriteFence * > write_fence_stack_
Definition rom.h:269
Rom & operator=(const Rom &other)
Definition rom.cc:458
bool dirty() const
Definition rom.h:188
bool dirty_
Definition rom.h:263
auto & mutable_vector()
Definition rom.h:206
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:606
auto short_name() const
Definition rom.h:209
void AdvanceObjectTileRevision()
Definition rom.h:197
absl::Status ReadHelper(T &var, int address)
Definition rom.h:161
std::string filename_
Definition rom.h:246
unsigned long size_
Definition rom.h:240
absl::Status WriteShort(int addr, uint16_t value)
Definition rom.cc:897
project::ResourceLabelManager resource_label_manager_
Definition rom.h:260
void Close()
Definition rom.h:101
uint8_t & operator[](unsigned long i)
Definition rom.h:181
bool has_copier_header() const
Definition rom.h:213
auto set_filename(std::string_view name)
Definition rom.h:208
std::string short_name_
Definition rom.h:249
uint64_t object_tile_revision_
Definition rom.h:266
bool is_loaded() const
Definition rom.h:187
absl::Status WriteWord(int addr, uint16_t value)
Definition rom.cc:873
virtual absl::Status WriteHelper(const WriteAction &action)
Definition rom.cc:965
size_t write_fence_depth() const
Definition rom.h:236
absl::Status WriteLong(uint32_t addr, uint32_t value)
Definition rom.cc:901
auto title() const
Definition rom.h:199
absl::StatusOr< uint32_t > ReadLong(int offset) const
Definition rom.cc:800
bool lyra_attributed_at_load_
Definition rom.h:257
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:378
CopierHeaderReason
Why a copier header was recognized at the start of a ROM file.
Definition rom.h:29
constexpr size_t kCopierHeaderSize
Size of the SMC/SWC copier header that some ROM dumps start with.
Definition rom.h:26
const char * CopierHeaderReasonName(CopierHeaderReason reason)
Definition rom.cc:402
static LoadOptions Defaults()
Definition rom.h:68
bool load_resource_labels
Definition rom.h:66
std::string filename
Definition rom.h:54
std::variant< int, uint8_t, uint16_t, short, std::vector< uint8_t >, gfx::SnesColor, std::vector< gfx::SnesColor > > ValueType
Definition rom.h:151
ValueType value
Definition rom.h:155