96 const std::string& patch_path,
97 std::vector<uint8_t>& rom_data,
98 const std::vector<std::string>& include_paths) {
100 return absl::FailedPreconditionError(
"Asar not initialized");
106#ifdef YAZE_ENABLE_ASAR
110 if (lib_result.ok()) {
122 const std::string& patch_content,
123 std::vector<uint8_t>& rom_data,
124 const std::string& base_path) {
126 return absl::FailedPreconditionError(
"Asar not initialized");
133 fs::path temp_patch_path =
134 fs::temp_directory_path() /
"yaze_asar_temp.asm";
136 std::ofstream temp_patch_file(temp_patch_path);
137 if (!temp_patch_file) {
138 return absl::InternalError(
"Failed to create temporary patch file");
141 temp_patch_file << patch_content;
142 temp_patch_file.close();
145 auto patch_result =
ApplyPatch(temp_patch_path.string(), rom_data, {base_path});
149 fs::remove(temp_patch_path, ec);
155 const std::string& asm_path,
156 const std::vector<std::string>& include_paths) {
157#ifdef YAZE_ENABLE_ASAR
159 return absl::FailedPreconditionError(
"Asar not initialized");
166 std::vector<uint8_t> dummy_rom(1024 * 1024, 0);
168 auto result =
ApplyPatch(asm_path, dummy_rom, include_paths);
170 return result.status();
173 return result->symbols;
177 return absl::UnimplementedError(
178 "ASAR library not enabled - build with YAZE_ENABLE_ASAR=1");
228#ifdef YAZE_ENABLE_ASAR
230 return absl::UnimplementedError(
231 "ASAR library not enabled - build with YAZE_ENABLE_ASAR=1");
235 std::vector<uint8_t> dummy_rom(1024, 0);
237 auto result =
ApplyPatch(asm_path, dummy_rom);
239 return result.status();
242 if (!result->success) {
243 return absl::InvalidArgumentError(absl::StrFormat(
244 "Assembly validation failed: %s",
245 absl::StrJoin(result->errors,
"; ")));
248 return absl::OkStatus();
251 return absl::UnimplementedError(
252 "ASAR library not enabled - build with YAZE_ENABLE_ASAR=1");
283 const std::string& patch_path,
284 std::vector<uint8_t>& rom_data,
285 const std::vector<std::string>& ) {
286#ifdef YAZE_ENABLE_ASAR
288 return absl::FailedPreconditionError(
"Asar library not initialized");
295 int rom_size =
static_cast<int>(rom_data.size());
297 std::max(rom_size, 16 * 1024 * 1024);
300 if (rom_data.size() <
static_cast<size_t>(buffer_size)) {
301 rom_data.resize(buffer_size, 0);
305 bool patch_success = asar_patch(
307 reinterpret_cast<char*
>(rom_data.data()),
321 rom_data.resize(rom_size);
328 result.
symbols.push_back(symbol);
335 return absl::InternalError(absl::StrFormat(
336 "Patch failed: %s", absl::StrJoin(
last_errors_,
"; ")));
341 return absl::UnimplementedError(
342 "ASAR library not enabled - build with YAZE_ENABLE_ASAR=1");
347 const std::string& patch_path,
348 std::vector<uint8_t>& rom_data,
349 const std::vector<std::string>& include_paths) {
354 if (!asar_path_opt) {
355 return absl::FailedPreconditionError(
"Asar CLI path could not be resolved");
358 fs::path patch_fs = fs::absolute(patch_path);
359 fs::path patch_dir = patch_fs.parent_path();
360 fs::path patch_name = patch_fs.filename();
363 auto timestamp = std::chrono::steady_clock::now().time_since_epoch().count();
364 fs::path temp_rom = fs::temp_directory_path() /
365 (
"yaze_asar_cli_" + std::to_string(timestamp) +
".sfc");
367 std::ofstream temp_rom_file(temp_rom, std::ios::binary);
368 if (!temp_rom_file) {
369 return absl::InternalError(
370 "Failed to create temporary ROM file for Asar CLI");
372 temp_rom_file.write(
reinterpret_cast<const char*
>(rom_data.data()),
373 static_cast<std::streamsize
>(rom_data.size()));
374 if (!temp_rom_file) {
375 return absl::InternalError(
"Failed to write temporary ROM file");
380 std::ostringstream cmd;
381 cmd <<
"\"" << *asar_path_opt <<
"\" --no-progress";
382 for (
const auto& include_path : include_paths) {
383 cmd <<
" -I\"" << include_path <<
"\"";
386 cmd <<
" \"" << patch_name.string() <<
"\" \"" << temp_rom.string() <<
"\" 2>&1";
390 fs::path original_cwd = fs::current_path(ec);
391 if (!patch_dir.empty()) {
392 fs::current_path(patch_dir, ec);
396 std::array<char, 128> buffer;
398 std::unique_ptr<FILE,
decltype(&pclose)> pipe(popen(cmd.str().c_str(),
"r"), pclose);
400 fs::remove(temp_rom, ec);
401 if (!patch_dir.empty()) fs::current_path(original_cwd, ec);
402 return absl::InternalError(
"popen() failed for Asar CLI");
404 while (fgets(buffer.data(), buffer.size(), pipe.get()) !=
nullptr) {
405 output += buffer.data();
412 if (!patch_dir.empty()) {
413 fs::current_path(original_cwd, ec);
418 std::istringstream output_stream(output);
420 while (std::getline(output_stream, line)) {
421 if (line.find(
"error: ") != std::string::npos || line.find(
": error:") != std::string::npos) {
423 }
else if (line.find(
"warning: ") != std::string::npos) {
429 fs::remove(temp_rom, ec);
430 return absl::InternalError(
"Asar CLI reported errors during assembly");
434 std::ifstream patched_rom(temp_rom, std::ios::binary);
436 last_errors_.push_back(
"Failed to read patched ROM from Asar CLI");
437 fs::remove(temp_rom, ec);
441 std::vector<uint8_t> new_data(
442 (std::istreambuf_iterator<char>(patched_rom)),
443 std::istreambuf_iterator<char>());
444 rom_data.swap(new_data);
445 fs::remove(temp_rom, ec);
449 result.
rom_size =
static_cast<uint32_t
>(rom_data.size());
479 std::ifstream file(symbol_path);
480 if (!file.is_open()) {
481 return absl::InvalidArgumentError(
482 absl::StrFormat(
"Cannot open symbol file: %s", symbol_path));
487 while (std::getline(file, line)) {
492 if (line.empty() || line[0] ==
'[' || line[0] ==
';')
continue;
494 size_t colon_pos = line.find(
':');
495 if (colon_pos == std::string::npos || colon_pos != 2)
continue;
497 size_t space_pos = line.find(
' ', colon_pos);
498 if (space_pos == std::string::npos)
continue;
501 std::string bank_str = line.substr(0, colon_pos);
502 std::string addr_str = line.substr(colon_pos + 1, space_pos - (colon_pos + 1));
503 std::string name = line.substr(space_pos + 1);
506 name.erase(0, name.find_first_not_of(
" \t\r\n"));
507 name.erase(name.find_last_not_of(
" \t\r\n") + 1);
509 int bank = std::stoi(bank_str,
nullptr, 16);
510 int addr = std::stoi(addr_str,
nullptr, 16);
511 uint32_t full_addr = (bank << 16) | addr;
524 return absl::OkStatus();