yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
asar_wrapper.cc
Go to the documentation of this file.
2
3#include <fstream>
4#include <sstream>
5#include <iostream>
6#include <filesystem>
7
8#include "absl/strings/str_format.h"
9#include "absl/strings/str_join.h"
10
11// Include Asar C bindings
12#include "asar-dll-bindings/c/asar.h"
13
14namespace yaze {
15namespace core {
16
17AsarWrapper::AsarWrapper() : initialized_(false) {}
18
20 if (initialized_) {
21 Shutdown();
22 }
23}
24
26 if (initialized_) {
27 return absl::OkStatus();
28 }
29
30 // Verify API version compatibility
31 int api_version = asar_apiversion();
32 if (api_version < 300) { // Require at least API version 3.0
33 return absl::InternalError(absl::StrFormat(
34 "Asar API version %d is too old (required: 300+)", api_version));
35 }
36
37 initialized_ = true;
38 return absl::OkStatus();
39}
40
42 if (initialized_) {
43 // Note: Static library doesn't have asar_close()
44 initialized_ = false;
45 }
46}
47
48std::string AsarWrapper::GetVersion() const {
49 if (!initialized_) {
50 return "Not initialized";
51 }
52
53 int version = asar_version();
54 int major = version / 10000;
55 int minor = (version / 100) % 100;
56 int patch = version % 100;
57
58 return absl::StrFormat("%d.%d.%d", major, minor, patch);
59}
60
62 if (!initialized_) {
63 return 0;
64 }
65 return asar_apiversion();
66}
67
68absl::StatusOr<AsarPatchResult> AsarWrapper::ApplyPatch(
69 const std::string& patch_path,
70 std::vector<uint8_t>& rom_data,
71 const std::vector<std::string>& include_paths) {
72
73 if (!initialized_) {
74 return absl::FailedPreconditionError("Asar not initialized");
75 }
76
77 // Reset previous state
78 Reset();
79
80 AsarPatchResult result;
81 result.success = false;
82
83 // Prepare ROM data
84 int rom_size = static_cast<int>(rom_data.size());
85 int buffer_size = std::max(rom_size, 16 * 1024 * 1024); // At least 16MB buffer
86
87 // Resize ROM data if needed
88 if (rom_data.size() < buffer_size) {
89 rom_data.resize(buffer_size, 0);
90 }
91
92 // Apply the patch
93 bool patch_success = asar_patch(
94 patch_path.c_str(),
95 reinterpret_cast<char*>(rom_data.data()),
96 buffer_size,
97 &rom_size);
98
99 // Process results
102
103 result.errors = last_errors_;
104 result.warnings = last_warnings_;
105 result.success = patch_success && last_errors_.empty();
106
107 if (result.success) {
108 // Resize ROM data to actual size
109 rom_data.resize(rom_size);
110 result.rom_size = rom_size;
111
112 // Extract symbols
114 result.symbols.reserve(symbol_table_.size());
115 for (const auto& [name, symbol] : symbol_table_) {
116 result.symbols.push_back(symbol);
117 }
118
119 // Calculate CRC32 if available
120 // Note: Asar might provide this, check if function exists
121 result.crc32 = 0; // TODO: Implement CRC32 calculation
122 } else {
123 return absl::InternalError(absl::StrFormat(
124 "Patch failed: %s", absl::StrJoin(last_errors_, "; ")));
125 }
126
127 return result;
128}
129
130absl::StatusOr<AsarPatchResult> AsarWrapper::ApplyPatchFromString(
131 const std::string& patch_content,
132 std::vector<uint8_t>& rom_data,
133 const std::string& base_path) {
134
135 // Create temporary file for patch content
136 std::string temp_path = "/tmp/yaze_temp_patch.asm";
137 if (!base_path.empty()) {
138 // Ensure directory exists
139 std::filesystem::create_directories(base_path);
140 temp_path = base_path + "/temp_patch.asm";
141 }
142
143 std::ofstream temp_file(temp_path);
144 if (!temp_file) {
145 return absl::InternalError(absl::StrFormat(
146 "Failed to create temporary patch file at: %s", temp_path));
147 }
148
149 temp_file << patch_content;
150 temp_file.close();
151
152 auto result = ApplyPatch(temp_path, rom_data);
153
154 // Clean up temporary file
155 std::remove(temp_path.c_str());
156
157 return result;
158}
159
160absl::StatusOr<std::vector<AsarSymbol>> AsarWrapper::ExtractSymbols(
161 const std::string& asm_path,
162 const std::vector<std::string>& include_paths) {
163
164 if (!initialized_) {
165 return absl::FailedPreconditionError("Asar not initialized");
166 }
167
168 // Create a dummy ROM for symbol extraction
169 std::vector<uint8_t> dummy_rom(1024 * 1024, 0); // 1MB dummy ROM
170
171 auto result = ApplyPatch(asm_path, dummy_rom, include_paths);
172 if (!result.ok()) {
173 return result.status();
174 }
175
176 return result->symbols;
177}
178
179std::map<std::string, AsarSymbol> AsarWrapper::GetSymbolTable() const {
180 return symbol_table_;
181}
182
183std::optional<AsarSymbol> AsarWrapper::FindSymbol(const std::string& name) const {
184 auto it = symbol_table_.find(name);
185 if (it != symbol_table_.end()) {
186 return it->second;
187 }
188 return std::nullopt;
189}
190
191std::vector<AsarSymbol> AsarWrapper::GetSymbolsAtAddress(uint32_t address) const {
192 std::vector<AsarSymbol> symbols;
193 for (const auto& [name, symbol] : symbol_table_) {
194 if (symbol.address == address) {
195 symbols.push_back(symbol);
196 }
197 }
198 return symbols;
199}
200
202 if (initialized_) {
203 asar_reset();
204 }
205 symbol_table_.clear();
206 last_errors_.clear();
207 last_warnings_.clear();
208}
209
211 const std::vector<uint8_t>& original_rom,
212 const std::vector<uint8_t>& modified_rom,
213 const std::string& patch_path) {
214
215 // This is a complex operation that would require:
216 // 1. Analyzing differences between ROMs
217 // 2. Generating appropriate assembly code
218 // 3. Writing the patch file
219
220 // For now, return not implemented
221 return absl::UnimplementedError(
222 "Patch creation from ROM differences not yet implemented");
223}
224
225absl::Status AsarWrapper::ValidateAssembly(const std::string& asm_path) {
226 // Create a dummy ROM for validation
227 std::vector<uint8_t> dummy_rom(1024, 0);
228
229 auto result = ApplyPatch(asm_path, dummy_rom);
230 if (!result.ok()) {
231 return result.status();
232 }
233
234 if (!result->success) {
235 return absl::InvalidArgumentError(absl::StrFormat(
236 "Assembly validation failed: %s",
237 absl::StrJoin(result->errors, "; ")));
238 }
239
240 return absl::OkStatus();
241}
242
244 last_errors_.clear();
245
246 int error_count = 0;
247 const errordata* errors = asar_geterrors(&error_count);
248
249 for (int i = 0; i < error_count; ++i) {
250 last_errors_.push_back(std::string(errors[i].fullerrdata));
251 }
252}
253
255 last_warnings_.clear();
256
257 int warning_count = 0;
258 const errordata* warnings = asar_getwarnings(&warning_count);
259
260 for (int i = 0; i < warning_count; ++i) {
261 last_warnings_.push_back(std::string(warnings[i].fullerrdata));
262 }
263}
264
266 symbol_table_.clear();
267
268 // Extract labels using the correct API function
269 int symbol_count = 0;
270 const labeldata* labels = asar_getalllabels(&symbol_count);
271
272 for (int i = 0; i < symbol_count; ++i) {
273 AsarSymbol symbol;
274 symbol.name = std::string(labels[i].name);
275 symbol.address = labels[i].location;
276 symbol.file = ""; // Not available in basic API
277 symbol.line = 0; // Not available in basic API
278 symbol.opcode = ""; // Would need additional processing
279 symbol.comment = "";
280
281 symbol_table_[symbol.name] = symbol;
282 }
283}
284
285AsarSymbol AsarWrapper::ConvertAsarSymbol(const void* asar_symbol_data) const {
286 // This would convert from Asar's internal symbol representation
287 // to our AsarSymbol struct. Implementation depends on Asar's API.
288
289 AsarSymbol symbol;
290 // Placeholder implementation
291 return symbol;
292}
293
294} // namespace core
295} // namespace yaze
absl::StatusOr< AsarPatchResult > ApplyPatchFromString(const std::string &patch_content, std::vector< uint8_t > &rom_data, const std::string &base_path="")
Apply an assembly patch from string content.
AsarSymbol ConvertAsarSymbol(const void *asar_symbol_data) const
Convert Asar symbol data to AsarSymbol struct.
absl::Status CreatePatch(const std::vector< uint8_t > &original_rom, const std::vector< uint8_t > &modified_rom, const std::string &patch_path)
Create a patch that can be applied to transform one ROM to another.
void ProcessWarnings()
Process warnings from Asar and store them.
std::vector< std::string > last_warnings_
absl::Status ValidateAssembly(const std::string &asm_path)
Validate an assembly file for syntax errors.
std::optional< AsarSymbol > FindSymbol(const std::string &name) const
Find a symbol by name.
std::string GetVersion() const
Get Asar version information.
void ExtractSymbolsFromLastOperation()
Extract symbols from the last Asar operation.
void Shutdown()
Clean up and close the Asar library.
std::map< std::string, AsarSymbol > symbol_table_
void Reset()
Reset the Asar state (clear errors, warnings, symbols)
absl::Status Initialize()
Initialize the Asar library.
absl::StatusOr< AsarPatchResult > ApplyPatch(const std::string &patch_path, std::vector< uint8_t > &rom_data, const std::vector< std::string > &include_paths={})
Apply an assembly patch to a ROM.
std::vector< std::string > last_errors_
int GetApiVersion() const
Get Asar API version.
absl::StatusOr< std::vector< AsarSymbol > > ExtractSymbols(const std::string &asm_path, const std::vector< std::string > &include_paths={})
Extract symbols from an assembly file without patching.
void ProcessErrors()
Process errors from Asar and store them.
std::vector< AsarSymbol > GetSymbolsAtAddress(uint32_t address) const
Get symbols at a specific address.
std::map< std::string, AsarSymbol > GetSymbolTable() const
Get all available symbols from the last patch operation.
Main namespace for the application.
Asar patch result information.
std::vector< std::string > errors
std::vector< AsarSymbol > symbols
std::vector< std::string > warnings
Symbol information extracted from Asar assembly.