5#include "absl/strings/str_format.h"
6#include "absl/strings/str_split.h"
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" ||
32 address = std::stoul(address_str, &pos, 16);
33 if (pos != address_str.size()) {
34 return absl::InvalidArgumentError(
"Invalid hex address format");
36 }
catch (
const std::exception& e) {
37 return absl::InvalidArgumentError(absl::StrFormat(
38 "Failed to parse address '%s': %s", address_str, e.what()));
42 if (address + length > rom->
size()) {
43 return absl::OutOfRangeError(absl::StrFormat(
44 "Read beyond ROM: 0x%X+%d > %zu", address, length, rom->
size()));
48 const uint8_t* data = rom->
data() + address;
52 formatter.
AddField(
"length", length);
53 formatter.
AddField(
"format", format);
55 bool include_hex = (format ==
"hex" || format ==
"both" || format ==
"binary");
56 bool include_ascii = (format ==
"ascii" || format ==
"both");
60 for (
int i = 0; i < length; ++i) {
61 absl::StrAppendFormat(&hex_data,
"%02X", data[i]);
65 formatter.
AddField(
"hex_data", hex_data);
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 :
'.');
74 formatter.
AddField(
"ascii_data", ascii_data);
78 return absl::OkStatus();
84 auto address_str = parser.
GetString(
"address").value();
85 auto data_str = parser.
GetString(
"data").value();
91 address = std::stoul(address_str, &pos, 16);
92 if (pos != address_str.size()) {
93 return absl::InvalidArgumentError(
"Invalid hex address format");
95 }
catch (
const std::exception& e) {
96 return absl::InvalidArgumentError(absl::StrFormat(
97 "Failed to parse address '%s': %s", address_str, e.what()));
101 std::vector<std::string> byte_strs = absl::StrSplit(data_str,
' ');
102 std::vector<uint8_t> bytes;
104 for (
const auto& byte_str : byte_strs) {
105 if (byte_str.empty())
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()));
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()));
124 for (
size_t i = 0; i < bytes.size(); ++i) {
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)
138 formatter.
AddField(
"bytes_written",
static_cast<int>(bytes.size()));
139 formatter.
AddField(
"hex_data", hex_data);
142 return absl::OkStatus();
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())));
154 uint32_t start_address, end_address;
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()));
164 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str,
' ');
165 std::vector<std::pair<uint8_t, bool>> pattern;
167 for (
const auto& byte_str : byte_strs) {
168 if (byte_str.empty())
170 if (byte_str ==
"??" || byte_str ==
"**") {
171 pattern.push_back({0,
true});
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()));
183 if (pattern.empty()) {
184 return absl::InvalidArgumentError(
"Empty pattern");
188 std::vector<uint32_t> matches;
189 const uint8_t* rom_data = rom->
data();
191 for (uint32_t i = start_address; i <= end_address - pattern.size(); ++i) {
193 for (
size_t j = 0; j < pattern.size(); ++j) {
194 if (!pattern[j].second &&
195 rom_data[i + j] != pattern[j].first) {
201 matches.push_back(i);
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()));
212 for (uint32_t match : matches) {
213 formatter.
AddArrayItem(absl::StrFormat(
"0x%06X", match));
218 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status WriteByte(int addr, uint8_t value)
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)