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 "absl/strings/str_format.h"
4#include "absl/strings/str_split.h"
5#include <cctype>
6
7namespace yaze {
8namespace cli {
9namespace handlers {
10
12 resources::OutputFormatter& formatter) {
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");
16
17 // Parse address
18 uint32_t address;
19 try {
20 size_t pos;
21 address = std::stoul(address_str, &pos, 16);
22 if (pos != address_str.size()) {
23 return absl::InvalidArgumentError("Invalid hex address format");
24 }
25 } catch (const std::exception& e) {
26 return absl::InvalidArgumentError(
27 absl::StrFormat("Failed to parse address '%s': %s", address_str, e.what()));
28 }
29
30 // Validate range
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()));
35 }
36
37 // Read and format data
38 const uint8_t* data = rom->data() + address;
39
40 formatter.BeginObject("Hex Read");
41 formatter.AddHexField("address", address, 6);
42 formatter.AddField("length", length);
43 formatter.AddField("format", format);
44
45 // Format hex data
46 std::string hex_data;
47 for (int i = 0; i < length; ++i) {
48 absl::StrAppendFormat(&hex_data, "%02X", data[i]);
49 if (i < length - 1) hex_data += " ";
50 }
51 formatter.AddField("hex_data", hex_data);
52
53 // Format ASCII 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 : '.');
58 }
59 formatter.AddField("ascii_data", ascii_data);
60 formatter.EndObject();
61
62 return absl::OkStatus();
63}
64
66 resources::OutputFormatter& formatter) {
67 auto address_str = parser.GetString("address").value();
68 auto data_str = parser.GetString("data").value();
69
70 // Parse address
71 uint32_t address;
72 try {
73 size_t pos;
74 address = std::stoul(address_str, &pos, 16);
75 if (pos != address_str.size()) {
76 return absl::InvalidArgumentError("Invalid hex address format");
77 }
78 } catch (const std::exception& e) {
79 return absl::InvalidArgumentError(
80 absl::StrFormat("Failed to parse address '%s': %s", address_str, e.what()));
81 }
82
83 // Parse data bytes
84 std::vector<std::string> byte_strs = absl::StrSplit(data_str, ' ');
85 std::vector<uint8_t> bytes;
86
87 for (const auto& byte_str : byte_strs) {
88 if (byte_str.empty()) continue;
89 try {
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()));
95 }
96 }
97
98 // Validate range
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()));
103 }
104
105 // Write data
106 for (size_t i = 0; i < bytes.size(); ++i) {
107 rom->WriteByte(address + i, bytes[i]);
108 }
109
110 // Format written data
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 += " ";
115 }
116
117 formatter.BeginObject("Hex Write");
118 formatter.AddHexField("address", address, 6);
119 formatter.AddField("bytes_written", static_cast<int>(bytes.size()));
120 formatter.AddField("hex_data", hex_data);
121 formatter.EndObject();
122
123 return absl::OkStatus();
124}
125
127 resources::OutputFormatter& formatter) {
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())));
132
133 // Parse addresses
134 uint32_t start_address, end_address;
135 try {
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()));
141 }
142
143 // Parse pattern
144 std::vector<std::string> byte_strs = absl::StrSplit(pattern_str, ' ');
145 std::vector<std::pair<uint8_t, bool>> pattern; // (value, is_wildcard)
146
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}); // Wildcard
151 } else {
152 try {
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()));
158 }
159 }
160 }
161
162 if (pattern.empty()) {
163 return absl::InvalidArgumentError("Empty pattern");
164 }
165
166 // Search for pattern
167 std::vector<uint32_t> matches;
168 const uint8_t* rom_data = rom->data();
169
170 for (uint32_t i = start_address; i <= end_address - pattern.size(); ++i) {
171 bool match = true;
172 for (size_t j = 0; j < pattern.size(); ++j) {
173 if (!pattern[j].second && // If not wildcard
174 rom_data[i + j] != pattern[j].first) {
175 match = false;
176 break;
177 }
178 }
179 if (match) {
180 matches.push_back(i);
181 }
182 }
183
184 formatter.BeginObject("Hex Search Results");
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()));
189
190 formatter.BeginArray("matches");
191 for (uint32_t match : matches) {
192 formatter.AddArrayItem(absl::StrFormat("0x%06X", match));
193 }
194 formatter.EndArray();
195 formatter.EndObject();
196
197 return absl::OkStatus();
198}
199
200} // namespace handlers
201} // namespace cli
202} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:71
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:725
auto data() const
Definition rom.h:203
auto size() const
Definition rom.h:202
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.
Main namespace for the application.