yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
hex_commands.cc
Go to the documentation of this file.
2
3#include <cctype>
4
5#include "absl/strings/str_format.h"
6#include "absl/strings/str_split.h"
7
8namespace yaze {
9namespace cli {
10namespace handlers {
11
13 Rom* rom, const resources::ArgumentParser& parser,
14 resources::OutputFormatter& formatter) {
15 auto address_str = parser.GetString("address").value();
16 auto length = parser.GetInt("length").value_or(16);
17 auto format = parser.GetString("format").value_or("both");
18
19 // Parse address
20 uint32_t address;
21 try {
22 size_t pos;
23 address = std::stoul(address_str, &pos, 16);
24 if (pos != address_str.size()) {
25 return absl::InvalidArgumentError("Invalid hex address format");
26 }
27 } catch (const std::exception& e) {
28 return absl::InvalidArgumentError(absl::StrFormat(
29 "Failed to parse address '%s': %s", address_str, e.what()));
30 }
31
32 // Validate range
33 if (address + length > rom->size()) {
34 return absl::OutOfRangeError(absl::StrFormat(
35 "Read beyond ROM: 0x%X+%d > %zu", address, length, rom->size()));
36 }
37
38 // Read and format data
39 const uint8_t* data = rom->data() + address;
40
41 formatter.BeginObject("Hex Read");
42 formatter.AddHexField("address", address, 6);
43 formatter.AddField("length", length);
44 formatter.AddField("format", format);
45
46 // Format hex data
47 std::string hex_data;
48 for (int i = 0; i < length; ++i) {
49 absl::StrAppendFormat(&hex_data, "%02X", data[i]);
50 if (i < length - 1)
51 hex_data += " ";
52 }
53 formatter.AddField("hex_data", hex_data);
54
55 // Format ASCII data
56 std::string ascii_data;
57 for (int i = 0; i < length; ++i) {
58 char c = static_cast<char>(data[i]);
59 ascii_data += (std::isprint(c) ? c : '.');
60 }
61 formatter.AddField("ascii_data", ascii_data);
62 formatter.EndObject();
63
64 return absl::OkStatus();
65}
66
68 Rom* rom, const resources::ArgumentParser& parser,
69 resources::OutputFormatter& formatter) {
70 auto address_str = parser.GetString("address").value();
71 auto data_str = parser.GetString("data").value();
72
73 // Parse address
74 uint32_t address;
75 try {
76 size_t pos;
77 address = std::stoul(address_str, &pos, 16);
78 if (pos != address_str.size()) {
79 return absl::InvalidArgumentError("Invalid hex address format");
80 }
81 } catch (const std::exception& e) {
82 return absl::InvalidArgumentError(absl::StrFormat(
83 "Failed to parse address '%s': %s", address_str, e.what()));
84 }
85
86 // Parse data bytes
87 std::vector<std::string> byte_strs = absl::StrSplit(data_str, ' ');
88 std::vector<uint8_t> bytes;
89
90 for (const auto& byte_str : byte_strs) {
91 if (byte_str.empty())
92 continue;
93 try {
94 uint8_t value = static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16));
95 bytes.push_back(value);
96 } catch (const std::exception& e) {
97 return absl::InvalidArgumentError(
98 absl::StrFormat("Invalid byte '%s': %s", byte_str, e.what()));
99 }
100 }
101
102 // Validate range
103 if (address + bytes.size() > rom->size()) {
104 return absl::OutOfRangeError(
105 absl::StrFormat("Write beyond ROM: 0x%X+%zu > %zu", address,
106 bytes.size(), rom->size()));
107 }
108
109 // Write data
110 for (size_t i = 0; i < bytes.size(); ++i) {
111 rom->WriteByte(address + i, bytes[i]);
112 }
113
114 // Format written data
115 std::string hex_data;
116 for (size_t i = 0; i < bytes.size(); ++i) {
117 absl::StrAppendFormat(&hex_data, "%02X", bytes[i]);
118 if (i < bytes.size() - 1)
119 hex_data += " ";
120 }
121
122 formatter.BeginObject("Hex Write");
123 formatter.AddHexField("address", address, 6);
124 formatter.AddField("bytes_written", static_cast<int>(bytes.size()));
125 formatter.AddField("hex_data", hex_data);
126 formatter.EndObject();
127
128 return absl::OkStatus();
129}
130
132 Rom* rom, const resources::ArgumentParser& parser,
133 resources::OutputFormatter& formatter) {
134 auto pattern_str = parser.GetString("pattern").value();
135 auto start_str = parser.GetString("start").value_or("0x000000");
136 auto end_str = parser.GetString("end").value_or(
137 absl::StrFormat("0x%06X", static_cast<int>(rom->size())));
138
139 // Parse addresses
140 uint32_t start_address, end_address;
141 try {
142 start_address = std::stoul(start_str, nullptr, 16);
143 end_address = std::stoul(end_str, nullptr, 16);
144 } catch (const std::exception& e) {
145 return absl::InvalidArgumentError(
146 absl::StrFormat("Invalid address format: %s", e.what()));
147 }
148
149 // Parse pattern
150 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str, ' ');
151 std::vector<std::pair<uint8_t, bool>> pattern; // (value, is_wildcard)
152
153 for (const auto& byte_str : byte_strs) {
154 if (byte_str.empty())
155 continue;
156 if (byte_str == "??" || byte_str == "**") {
157 pattern.push_back({0, true}); // Wildcard
158 } else {
159 try {
160 uint8_t value = static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16));
161 pattern.push_back({value, false});
162 } catch (const std::exception& e) {
163 return absl::InvalidArgumentError(absl::StrFormat(
164 "Invalid pattern byte '%s': %s", byte_str, e.what()));
165 }
166 }
167 }
168
169 if (pattern.empty()) {
170 return absl::InvalidArgumentError("Empty pattern");
171 }
172
173 // Search for pattern
174 std::vector<uint32_t> matches;
175 const uint8_t* rom_data = rom->data();
176
177 for (uint32_t i = start_address; i <= end_address - pattern.size(); ++i) {
178 bool match = true;
179 for (size_t j = 0; j < pattern.size(); ++j) {
180 if (!pattern[j].second && // If not wildcard
181 rom_data[i + j] != pattern[j].first) {
182 match = false;
183 break;
184 }
185 }
186 if (match) {
187 matches.push_back(i);
188 }
189 }
190
191 formatter.BeginObject("Hex Search Results");
192 formatter.AddField("pattern", pattern_str);
193 formatter.AddHexField("start_address", start_address, 6);
194 formatter.AddHexField("end_address", end_address, 6);
195 formatter.AddField("matches_found", static_cast<int>(matches.size()));
196
197 formatter.BeginArray("matches");
198 for (uint32_t match : matches) {
199 formatter.AddArrayItem(absl::StrFormat("0x%06X", match));
200 }
201 formatter.EndArray();
202 formatter.EndObject();
203
204 return absl::OkStatus();
205}
206
207} // namespace handlers
208} // namespace cli
209} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:286
auto data() const
Definition rom.h:135
auto size() const
Definition rom.h:134
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
Utility for consistent output formatting across commands.
void BeginArray(const std::string &key)
Begin an array.
void AddArrayItem(const std::string &item)
Add an item to current array.
void BeginObject(const std::string &title="")
Start a JSON object or text section.
void EndObject()
End a JSON object or text section.
void AddField(const std::string &key, const std::string &value)
Add a key-value pair.
void AddHexField(const std::string &key, uint64_t value, int width=2)
Add a hex-formatted field.