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 auto format = parser.
GetString(
"format").value_or(
"both");
23 address = std::stoul(address_str, &pos, 16);
24 if (pos != address_str.size()) {
25 return absl::InvalidArgumentError(
"Invalid hex address format");
27 }
catch (
const std::exception& e) {
28 return absl::InvalidArgumentError(absl::StrFormat(
29 "Failed to parse address '%s': %s", address_str, e.what()));
33 if (address + length > rom->
size()) {
34 return absl::OutOfRangeError(absl::StrFormat(
35 "Read beyond ROM: 0x%X+%d > %zu", address, length, rom->
size()));
39 const uint8_t* data = rom->
data() + address;
43 formatter.
AddField(
"length", length);
44 formatter.
AddField(
"format", format);
48 for (
int i = 0; i < length; ++i) {
49 absl::StrAppendFormat(&hex_data,
"%02X", data[i]);
53 formatter.
AddField(
"hex_data", hex_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 :
'.');
61 formatter.
AddField(
"ascii_data", ascii_data);
64 return absl::OkStatus();
70 auto address_str = parser.
GetString(
"address").value();
71 auto data_str = parser.
GetString(
"data").value();
77 address = std::stoul(address_str, &pos, 16);
78 if (pos != address_str.size()) {
79 return absl::InvalidArgumentError(
"Invalid hex address format");
81 }
catch (
const std::exception& e) {
82 return absl::InvalidArgumentError(absl::StrFormat(
83 "Failed to parse address '%s': %s", address_str, e.what()));
87 std::vector<std::string> byte_strs = absl::StrSplit(data_str,
' ');
88 std::vector<uint8_t> bytes;
90 for (
const auto& byte_str : byte_strs) {
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()));
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()));
110 for (
size_t i = 0; i < bytes.size(); ++i) {
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)
124 formatter.
AddField(
"bytes_written",
static_cast<int>(bytes.size()));
125 formatter.
AddField(
"hex_data", hex_data);
128 return absl::OkStatus();
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())));
140 uint32_t start_address, end_address;
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()));
150 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str,
' ');
151 std::vector<std::pair<uint8_t, bool>> pattern;
153 for (
const auto& byte_str : byte_strs) {
154 if (byte_str.empty())
156 if (byte_str ==
"??" || byte_str ==
"**") {
157 pattern.push_back({0,
true});
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()));
169 if (pattern.empty()) {
170 return absl::InvalidArgumentError(
"Empty pattern");
174 std::vector<uint32_t> matches;
175 const uint8_t* rom_data = rom->
data();
177 for (uint32_t i = start_address; i <= end_address - pattern.size(); ++i) {
179 for (
size_t j = 0; j < pattern.size(); ++j) {
180 if (!pattern[j].second &&
181 rom_data[i + j] != pattern[j].first) {
187 matches.push_back(i);
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()));
198 for (uint32_t match : matches) {
199 formatter.
AddArrayItem(absl::StrFormat(
"0x%06X", match));
204 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)