3#include "absl/strings/str_format.h"
4#include "absl/strings/str_split.h"
13 auto address_str = parser.
GetString(
"address").value();
14 auto length = parser.
GetInt(
"length").value_or(16);
15 auto format = parser.
GetString(
"format").value_or(
"both");
21 address = std::stoul(address_str, &pos, 16);
22 if (pos != address_str.size()) {
23 return absl::InvalidArgumentError(
"Invalid hex address format");
25 }
catch (
const std::exception& e) {
26 return absl::InvalidArgumentError(
27 absl::StrFormat(
"Failed to parse address '%s': %s", address_str, e.what()));
31 if (address + length > rom->
size()) {
32 return absl::OutOfRangeError(
33 absl::StrFormat(
"Read beyond ROM: 0x%X+%d > %zu",
34 address, length, rom->
size()));
38 const uint8_t* data = rom->
data() + address;
42 formatter.
AddField(
"length", length);
43 formatter.
AddField(
"format", format);
47 for (
int i = 0; i < length; ++i) {
48 absl::StrAppendFormat(&hex_data,
"%02X", data[i]);
49 if (i < length - 1) hex_data +=
" ";
51 formatter.
AddField(
"hex_data", hex_data);
54 std::string ascii_data;
55 for (
int i = 0; i < length; ++i) {
56 char c =
static_cast<char>(data[i]);
57 ascii_data += (std::isprint(c) ? c :
'.');
59 formatter.
AddField(
"ascii_data", ascii_data);
62 return absl::OkStatus();
67 auto address_str = parser.
GetString(
"address").value();
68 auto data_str = parser.
GetString(
"data").value();
74 address = std::stoul(address_str, &pos, 16);
75 if (pos != address_str.size()) {
76 return absl::InvalidArgumentError(
"Invalid hex address format");
78 }
catch (
const std::exception& e) {
79 return absl::InvalidArgumentError(
80 absl::StrFormat(
"Failed to parse address '%s': %s", address_str, e.what()));
84 std::vector<std::string> byte_strs = absl::StrSplit(data_str,
' ');
85 std::vector<uint8_t> bytes;
87 for (
const auto& byte_str : byte_strs) {
88 if (byte_str.empty())
continue;
90 uint8_t value =
static_cast<uint8_t
>(std::stoul(byte_str,
nullptr, 16));
91 bytes.push_back(value);
92 }
catch (
const std::exception& e) {
93 return absl::InvalidArgumentError(
94 absl::StrFormat(
"Invalid byte '%s': %s", byte_str, e.what()));
99 if (address + bytes.size() > rom->
size()) {
100 return absl::OutOfRangeError(
101 absl::StrFormat(
"Write beyond ROM: 0x%X+%zu > %zu",
102 address, bytes.size(), rom->
size()));
106 for (
size_t i = 0; i < bytes.size(); ++i) {
111 std::string hex_data;
112 for (
size_t i = 0; i < bytes.size(); ++i) {
113 absl::StrAppendFormat(&hex_data,
"%02X", bytes[i]);
114 if (i < bytes.size() - 1) hex_data +=
" ";
119 formatter.
AddField(
"bytes_written",
static_cast<int>(bytes.size()));
120 formatter.
AddField(
"hex_data", hex_data);
123 return absl::OkStatus();
128 auto pattern_str = parser.
GetString(
"pattern").value();
129 auto start_str = parser.
GetString(
"start").value_or(
"0x000000");
130 auto end_str = parser.
GetString(
"end").value_or(
131 absl::StrFormat(
"0x%06X",
static_cast<int>(rom->
size())));
134 uint32_t start_address, end_address;
136 start_address = std::stoul(start_str,
nullptr, 16);
137 end_address = std::stoul(end_str,
nullptr, 16);
138 }
catch (
const std::exception& e) {
139 return absl::InvalidArgumentError(
140 absl::StrFormat(
"Invalid address format: %s", e.what()));
144 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str,
' ');
145 std::vector<std::pair<uint8_t, bool>> pattern;
147 for (
const auto& byte_str : byte_strs) {
148 if (byte_str.empty())
continue;
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(
157 absl::StrFormat(
"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.
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)
Main namespace for the application.