5#include "absl/strings/str_format.h"
6#include "absl/strings/str_split.h"
16 auto address_str = parser.
GetString(
"address").value();
17 auto length = parser.
GetInt(
"length").value_or(16);
18 std::string format =
"both";
19 if (
auto data_format = parser.
GetString(
"data-format");
20 data_format.has_value()) {
21 format = *data_format;
22 }
else if (
auto fmt = parser.
GetString(
"format"); fmt.has_value()) {
23 if (*fmt ==
"hex" || *fmt ==
"ascii" || *fmt ==
"both" ||
33 address = std::stoul(address_str, &pos, 16);
34 if (pos != address_str.size()) {
35 return absl::InvalidArgumentError(
"Invalid hex address format");
37 }
catch (
const std::exception& e) {
38 return absl::InvalidArgumentError(absl::StrFormat(
39 "Failed to parse address '%s': %s", address_str, e.what()));
43 if (address + length > rom->
size()) {
44 return absl::OutOfRangeError(absl::StrFormat(
45 "Read beyond ROM: 0x%X+%d > %zu", address, length, rom->
size()));
49 const uint8_t* data = rom->
data() + address;
53 formatter.
AddField(
"length", length);
54 formatter.
AddField(
"format", format);
57 (format ==
"hex" || format ==
"both" || format ==
"binary");
58 bool include_ascii = (format ==
"ascii" || format ==
"both");
62 for (
int i = 0; i < length; ++i) {
63 absl::StrAppendFormat(&hex_data,
"%02X", data[i]);
67 formatter.
AddField(
"hex_data", hex_data);
71 std::string ascii_data;
72 for (
int i = 0; i < length; ++i) {
73 char c =
static_cast<char>(data[i]);
74 ascii_data += (std::isprint(
static_cast<unsigned char>(c)) ? c :
'.');
76 formatter.
AddField(
"ascii_data", ascii_data);
80 return absl::OkStatus();
86 auto address_str = parser.
GetString(
"address").value();
87 auto data_str = parser.
GetString(
"data").value();
93 address = std::stoul(address_str, &pos, 16);
94 if (pos != address_str.size()) {
95 return absl::InvalidArgumentError(
"Invalid hex address format");
97 }
catch (
const std::exception& e) {
98 return absl::InvalidArgumentError(absl::StrFormat(
99 "Failed to parse address '%s': %s", address_str, e.what()));
103 std::vector<std::string> byte_strs = absl::StrSplit(data_str,
' ');
104 std::vector<uint8_t> bytes;
106 for (
const auto& byte_str : byte_strs) {
107 if (byte_str.empty())
110 uint8_t value =
static_cast<uint8_t
>(std::stoul(byte_str,
nullptr, 16));
111 bytes.push_back(value);
112 }
catch (
const std::exception& e) {
113 return absl::InvalidArgumentError(
114 absl::StrFormat(
"Invalid byte '%s': %s", byte_str, e.what()));
127 auto pattern_str = parser.
GetString(
"pattern").value();
128 auto start_str = parser.
GetString(
"start").value_or(
"0x000000");
129 auto end_str = parser.
GetString(
"end").value_or(
130 absl::StrFormat(
"0x%06X",
static_cast<int>(rom->
size())));
133 uint32_t start_address, end_address;
135 start_address = std::stoul(start_str,
nullptr, 16);
136 end_address = std::stoul(end_str,
nullptr, 16);
137 }
catch (
const std::exception& e) {
138 return absl::InvalidArgumentError(
139 absl::StrFormat(
"Invalid address format: %s", e.what()));
143 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str,
' ');
144 std::vector<std::pair<uint8_t, bool>> pattern;
146 for (
const auto& byte_str : byte_strs) {
147 if (byte_str.empty())
149 if (byte_str ==
"??" || byte_str ==
"**") {
150 pattern.push_back({0,
true});
153 uint8_t value =
static_cast<uint8_t
>(std::stoul(byte_str,
nullptr, 16));
154 pattern.push_back({value,
false});
155 }
catch (
const std::exception& e) {
156 return absl::InvalidArgumentError(absl::StrFormat(
157 "Invalid pattern byte '%s': %s", byte_str, e.what()));
162 if (pattern.empty()) {
163 return absl::InvalidArgumentError(
"Empty pattern");
167 std::vector<uint32_t> matches;
168 const uint8_t* rom_data = rom->
data();
170 for (uint32_t i = start_address; i <= end_address - pattern.size(); ++i) {
172 for (
size_t j = 0; j < pattern.size(); ++j) {
173 if (!pattern[j].second &&
174 rom_data[i + j] != pattern[j].first) {
180 matches.push_back(i);
185 formatter.
AddField(
"pattern", pattern_str);
186 formatter.
AddHexField(
"start_address", start_address, 6);
187 formatter.
AddHexField(
"end_address", end_address, 6);
188 formatter.
AddField(
"matches_found",
static_cast<int>(matches.size()));
191 for (uint32_t match : matches) {
192 formatter.
AddArrayItem(absl::StrFormat(
"0x%06X", match));
197 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 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)
absl::Status ApplyRawRomWrite(Rom *rom, uint32_t address, const std::vector< uint8_t > &bytes, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter)
Shared body of rom-write and hex-write.