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 std::string format = "both";
18 if (auto data_format = parser.GetString("data-format");
19 data_format.has_value()) {
20 format = *data_format;
21 } else if (auto fmt = parser.GetString("format"); fmt.has_value()) {
22 if (*fmt == "hex" || *fmt == "ascii" || *fmt == "both" ||
23 *fmt == "binary") {
24 format = *fmt;
25 }
26 }
27
28 // Parse address
29 uint32_t address;
30 try {
31 size_t pos;
32 address = std::stoul(address_str, &pos, 16);
33 if (pos != address_str.size()) {
34 return absl::InvalidArgumentError("Invalid hex address format");
35 }
36 } catch (const std::exception& e) {
37 return absl::InvalidArgumentError(absl::StrFormat(
38 "Failed to parse address '%s': %s", address_str, e.what()));
39 }
40
41 // Validate range
42 if (address + length > rom->size()) {
43 return absl::OutOfRangeError(absl::StrFormat(
44 "Read beyond ROM: 0x%X+%d > %zu", address, length, rom->size()));
45 }
46
47 // Read and format data
48 const uint8_t* data = rom->data() + address;
49
50 formatter.BeginObject("Hex Read");
51 formatter.AddHexField("address", address, 6);
52 formatter.AddField("length", length);
53 formatter.AddField("format", format);
54
55 bool include_hex = (format == "hex" || format == "both" || format == "binary");
56 bool include_ascii = (format == "ascii" || format == "both");
57
58 if (include_hex) {
59 std::string hex_data;
60 for (int i = 0; i < length; ++i) {
61 absl::StrAppendFormat(&hex_data, "%02X", data[i]);
62 if (i < length - 1)
63 hex_data += " ";
64 }
65 formatter.AddField("hex_data", hex_data);
66 }
67
68 if (include_ascii) {
69 std::string ascii_data;
70 for (int i = 0; i < length; ++i) {
71 char c = static_cast<char>(data[i]);
72 ascii_data += (std::isprint(static_cast<unsigned char>(c)) ? c : '.');
73 }
74 formatter.AddField("ascii_data", ascii_data);
75 }
76 formatter.EndObject();
77
78 return absl::OkStatus();
79}
80
82 Rom* rom, const resources::ArgumentParser& parser,
83 resources::OutputFormatter& formatter) {
84 auto address_str = parser.GetString("address").value();
85 auto data_str = parser.GetString("data").value();
86
87 // Parse address
88 uint32_t address;
89 try {
90 size_t pos;
91 address = std::stoul(address_str, &pos, 16);
92 if (pos != address_str.size()) {
93 return absl::InvalidArgumentError("Invalid hex address format");
94 }
95 } catch (const std::exception& e) {
96 return absl::InvalidArgumentError(absl::StrFormat(
97 "Failed to parse address '%s': %s", address_str, e.what()));
98 }
99
100 // Parse data bytes
101 std::vector<std::string> byte_strs = absl::StrSplit(data_str, ' ');
102 std::vector<uint8_t> bytes;
103
104 for (const auto& byte_str : byte_strs) {
105 if (byte_str.empty())
106 continue;
107 try {
108 uint8_t value = static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16));
109 bytes.push_back(value);
110 } catch (const std::exception& e) {
111 return absl::InvalidArgumentError(
112 absl::StrFormat("Invalid byte '%s': %s", byte_str, e.what()));
113 }
114 }
115
116 // Validate range
117 if (address + bytes.size() > rom->size()) {
118 return absl::OutOfRangeError(
119 absl::StrFormat("Write beyond ROM: 0x%X+%zu > %zu", address,
120 bytes.size(), rom->size()));
121 }
122
123 // Write data
124 for (size_t i = 0; i < bytes.size(); ++i) {
125 rom->WriteByte(address + i, bytes[i]);
126 }
127
128 // Format written data
129 std::string hex_data;
130 for (size_t i = 0; i < bytes.size(); ++i) {
131 absl::StrAppendFormat(&hex_data, "%02X", bytes[i]);
132 if (i < bytes.size() - 1)
133 hex_data += " ";
134 }
135
136 formatter.BeginObject("Hex Write");
137 formatter.AddHexField("address", address, 6);
138 formatter.AddField("bytes_written", static_cast<int>(bytes.size()));
139 formatter.AddField("hex_data", hex_data);
140 formatter.EndObject();
141
142 return absl::OkStatus();
143}
144
146 Rom* rom, const resources::ArgumentParser& parser,
147 resources::OutputFormatter& formatter) {
148 auto pattern_str = parser.GetString("pattern").value();
149 auto start_str = parser.GetString("start").value_or("0x000000");
150 auto end_str = parser.GetString("end").value_or(
151 absl::StrFormat("0x%06X", static_cast<int>(rom->size())));
152
153 // Parse addresses
154 uint32_t start_address, end_address;
155 try {
156 start_address = std::stoul(start_str, nullptr, 16);
157 end_address = std::stoul(end_str, nullptr, 16);
158 } catch (const std::exception& e) {
159 return absl::InvalidArgumentError(
160 absl::StrFormat("Invalid address format: %s", e.what()));
161 }
162
163 // Parse pattern
164 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str, ' ');
165 std::vector<std::pair<uint8_t, bool>> pattern; // (value, is_wildcard)
166
167 for (const auto& byte_str : byte_strs) {
168 if (byte_str.empty())
169 continue;
170 if (byte_str == "??" || byte_str == "**") {
171 pattern.push_back({0, true}); // Wildcard
172 } else {
173 try {
174 uint8_t value = static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16));
175 pattern.push_back({value, false});
176 } catch (const std::exception& e) {
177 return absl::InvalidArgumentError(absl::StrFormat(
178 "Invalid pattern byte '%s': %s", byte_str, e.what()));
179 }
180 }
181 }
182
183 if (pattern.empty()) {
184 return absl::InvalidArgumentError("Empty pattern");
185 }
186
187 // Search for pattern
188 std::vector<uint32_t> matches;
189 const uint8_t* rom_data = rom->data();
190
191 for (uint32_t i = start_address; i <= end_address - pattern.size(); ++i) {
192 bool match = true;
193 for (size_t j = 0; j < pattern.size(); ++j) {
194 if (!pattern[j].second && // If not wildcard
195 rom_data[i + j] != pattern[j].first) {
196 match = false;
197 break;
198 }
199 }
200 if (match) {
201 matches.push_back(i);
202 }
203 }
204
205 formatter.BeginObject("Hex Search Results");
206 formatter.AddField("pattern", pattern_str);
207 formatter.AddHexField("start_address", start_address, 6);
208 formatter.AddHexField("end_address", end_address, 6);
209 formatter.AddField("matches_found", static_cast<int>(matches.size()));
210
211 formatter.BeginArray("matches");
212 for (uint32_t match : matches) {
213 formatter.AddArrayItem(absl::StrFormat("0x%06X", match));
214 }
215 formatter.EndArray();
216 formatter.EndObject();
217
218 return absl::OkStatus();
219}
220
221} // namespace handlers
222} // namespace cli
223} // 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:28
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:476
auto data() const
Definition rom.h:139
auto size() const
Definition rom.h:138
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.