def patch_rom(clean_rom_filename, patched_rom_filename, patch_filename, headered, progress_bar=None): if not os.path.isfile(clean_rom_filename): raise RuntimeError("Clean Rom \"" + clean_rom_filename + "\" is not a file.") if not os.path.isfile(patch_filename): raise RuntimeError("Patch \"" + patch_filename + "\" is not a file.") if clean_rom_filename != patched_rom_filename: copyfile(clean_rom_filename, patched_rom_filename) log.info("Patching ROM {} with patch {}".format(patched_rom_filename, patch_filename)) patching_start_time = time.time() if patch_filename.endswith(".ips"): output_rom = Rom() output_rom.from_file(clean_rom_filename) patch = IpsPatch() elif patch_filename.endswith(".ebp"): output_rom = EbRom() output_rom.from_file(clean_rom_filename) patch = EbpPatch() else: raise CoilSnakeError("Unknown patch format.") # Load the patch and expand the ROM as needed add_header = headered and not isinstance(patch, EbpPatch) extra = int(add_header)*0x200 # 0x200 if a header will be added, 0 otherwise patch.load(patch_filename) if isinstance(patch, EbpPatch): log.info("Patch: {title} by {author}".format(**patch.metadata)) if patch.last_offset_used > len(output_rom) + extra: if patch.last_offset_used < 0x400000 + extra: output_rom.expand(0x400000) elif patch.last_offset_used < 0x600000 + extra: output_rom.expand(0x600000) else: output_rom.expand(patch.last_offset_used) # If the user specified the patch was made for a headered ROM, add a header # to the ROM if add_header: output_rom.add_header() # Apply the patch and write out the patched ROM patch.apply(output_rom) if add_header: # Remove the header that was added, so that we're always dealing with # unheadered ROMs in the end output_rom.data = output_rom.data[0x200:] output_rom.size -= 0x200 output_rom.to_file(patched_rom_filename) log.info("Patched to {} in {:.2f}s".format(patched_rom_filename, time.time() - patching_start_time))