コード例 #1
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
def decompile_script(rom_filename, project_path, progress_bar=None):
    if not os.path.isdir(project_path):
        raise RuntimeError("Project directory \"" + project_path +
                           "\" is not a directory.")
    if not os.path.isfile(rom_filename):
        raise RuntimeError("Rom \"" + rom_filename + "\" is not a file.")

    rom = Rom()
    rom.from_file(rom_filename)
    if rom.type != "Earthbound":
        raise CoilSnakeError(
            "Cannot decompile script of a non-Earthbound rom. A {} rom was supplied."
            .format(rom.type))
    del rom

    project_ccscript_path = os.path.join(project_path, "ccscript")

    start_time = time.time()

    rom_file = open(rom_filename, "rb")
    try:
        ccsw = CCScriptWriter(rom_file, project_ccscript_path, False)
        ccsw.loadDialogue(True)
        ccsw.processDialogue()
        ccsw.outputDialogue(True)
    except Exception as inst:
        log.exception("Error")
    else:
        log.info("Decompiled script to {} in {:.2f}s".format(
            project_path,
            time.time() - start_time))
    finally:
        rom_file.close()
コード例 #2
0
ファイル: common.py プロジェクト: LittleCube13/CoilSnake
def decompile_script(rom_filename, project_path, progress_bar=None):
    if not os.path.isdir(project_path):
        raise RuntimeError("Project directory \"" + project_path + "\" is not a directory.")
    if not os.path.isfile(rom_filename):
        raise RuntimeError("Rom \"" + rom_filename + "\" is not a file.")

    rom = Rom()
    rom.from_file(rom_filename)
    if rom.type != "Earthbound":
        raise CoilSnakeError("Cannot decompile script of a non-Earthbound rom. A {} rom was supplied.".format(
            rom.type))
    del rom

    project_ccscript_path = os.path.join(project_path, "ccscript")

    start_time = time.time()

    rom_file = open(rom_filename, "rb")
    try:
        ccsw = CCScriptWriter(rom_file, project_ccscript_path, False)
        ccsw.loadDialogue(True)
        ccsw.processDialogue()
        ccsw.outputDialogue(True)
    except Exception as inst:
        log.exception("Error")
    else:
        log.info("Decompiled script to {} in {:.2f}s".format(project_path, time.time() - start_time))
    finally:
        rom_file.close()
コード例 #3
0
def expand_rom(root, ex=False):
    rom = Rom()
    filename = tkFileDialog.askopenfilename(
        parent=root,
        initialdir=os.path.expanduser("~"),
        title="Select a ROM to expand",
        filetypes=ROM_FILETYPES)
    if filename:
        rom.from_file(filename)
        if (not ex and len(rom) >= 0x400000) or (ex and (len(rom) >= 0x600000)):
            tkMessageBox.showerror(
                parent=root,
                title="Error",
                message="This ROM is already expanded.")
        else:
            if ex:
                rom.expand(0x600000)
            else:
                rom.expand(0x400000)
            rom.to_file(filename)
            del rom
            tkMessageBox.showinfo(
                parent=root,
                title="Expansion Successful",
                message="Your ROM was expanded.")
コード例 #4
0
ファイル: common.py プロジェクト: Lyrositor/CoilSnake
def decompile_rom(rom_filename, project_path, progress_bar=None):
    modules = load_modules()

    rom = Rom()
    rom.from_file(rom_filename)

    project = Project()
    project.load(os.path.join(project_path, PROJECT_FILENAME), rom.type)

    compatible_modules = [(name, clazz) for name, clazz in modules if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0/(2*len(compatible_modules))

    log.info("Decompiling ROM {}".format(rom_filename))
    decompile_start_time = time.time()

    for module_name, module_class in compatible_modules:
        if not module_class.is_compatible_with_romtype(rom.type):
            continue

        log.info("Decompiling {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.read_from_rom(rom)
            if progress_bar:
                progress_bar.tick(tick_amount)
            module.write_to_project(lambda x, y: project.get_resource(module_name, x, y, 'wb'))
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished decompiling {} in {:.2f}s".format(module_class.NAME, time.time() - start_time))

    log.debug("Saving Project")
    project.write(os.path.join(project_path, PROJECT_FILENAME))

    log.info("Decompiled to {} in {:.2f}s".format(project_path, time.time() - decompile_start_time))
コード例 #5
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
def upgrade_project(project_path, base_rom_filename, progress_bar=None):
    if not os.path.isdir(project_path):
        raise RuntimeError("Project directory \"" + project_path +
                           "\" is not a directory.")
    if not os.path.isfile(base_rom_filename):
        raise RuntimeError("Base Rom \"" + base_rom_filename +
                           "\" is not a file.")

    modules = load_modules()

    # Open project
    project_filename = os.path.join(project_path, PROJECT_FILENAME)

    project = Project()
    project.load(project_filename)
    check_if_project_too_new(project)

    if project.version == FORMAT_VERSION:
        log.info("Project is already up to date.")
        return

    log.info("Upgrading project from version {} to {}".format(
        get_version_name(project.version), get_version_name(FORMAT_VERSION)))
    upgrade_start_time = time.time()

    rom = Rom()
    rom.from_file(base_rom_filename)
    check_if_types_match(project=project, rom=rom)

    compatible_modules = [(name, clazz) for name, clazz in modules
                          if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0 / len(compatible_modules)

    for module_name, module_class in compatible_modules:
        log.info("Upgrading {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.upgrade_project(
                project.version,
                FORMAT_VERSION,
                rom,
                lambda x, y, astext=False: project.get_resource(
                    module_name, x, y, 'rt' if astext else 'rb', 'utf-8'
                    if astext else None),
                lambda x, y, astext=False: project.get_resource(
                    module_name, x, y, 'wt' if astext else 'wb', 'utf-8'
                    if astext else None, '\n' if astext else None),
                lambda x: project.delete_resource(module_name, x))
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished upgrading {} in {:.2f}s".format(
            module_class.NAME,
            time.time() - start_time))

    project.version = FORMAT_VERSION
    project.write(project_filename)

    log.info("Upgraded {} in {:.2f}s".format(project_path,
                                             time.time() - upgrade_start_time))
コード例 #6
0
class TestEbModule(BaseTestCase):
    """
    A test class for the EbModule module
    """

    def setup(self):
        self.rom = Rom()
        self.rom.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_24mbit.smc"))

    @nottest
    def test_decomp(self, decomp):
        onett_map = array.array('B')
        with Rom() as eb_rom:
            eb_rom.from_file(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
            onett_map.fromlist(decomp(eb_rom, 0x2021a8))

        assert_equal(len(onett_map), 18496)
        assert_equal(crc32(onett_map), 739047015)

    @nottest
    def test_comp(self, comp, decomp):
        a = array.array('B')
        with open(os.path.join(TEST_DATA_DIR, "binaries", "compressible.bin"), 'rb') as f:
            a.fromstring(f.read())
        assert_equal(len(a), 18496)

        uncompressed_data = a.tolist()
        compressed_data = comp(uncompressed_data)
        assert_equal(len(compressed_data), 58)

        with Rom() as fake_eb_rom:
            fake_eb_rom.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_32mbit.smc"))
            fake_eb_rom[0x300000:0x300000 + len(compressed_data)] = compressed_data
            reuncompressed_data = decomp(fake_eb_rom, 0x300000)

        assert_equal(len(reuncompressed_data), len(uncompressed_data))
        assert_equal(reuncompressed_data, uncompressed_data)

    @nottest
    def _test_python_comp(self):
        self.test_comp(EbModule._comp, EbModule.decomp)

    @nottest
    def _test_python_decomp(self):
        self.test_decomp(EbModule._decomp)

    def test_native_comp(self):
        self.test_comp(native_comp.comp, native_comp.decomp)

    def test_native_decomp(self):
        self.test_decomp(native_comp.decomp)

    def test_default_comp(self):
        self.test_comp(EbModule.comp, EbModule.decomp)

    def test_default_decomp(self):
        self.test_decomp(EbModule.decomp)
コード例 #7
0
ファイル: gui_util.py プロジェクト: Lyrositor/CoilSnake
def expand_rom(root, ex=False):
    rom = Rom()
    filename = tkFileDialog.askopenfilename(
        parent=root,
        initialdir=os.path.expanduser("~"),
        title="Select a ROM to expand",
        filetypes=ROM_FILETYPES)
    if filename:
        rom.from_file(filename)
        if (not ex and len(rom) >= 0x400000) or (ex and (len(rom) >= 0x600000)):
            tkMessageBox.showerror(
                parent=root,
                title="Error",
                message="This ROM is already expanded.")
        else:
            if ex:
                rom.expand(0x600000)
            else:
                rom.expand(0x400000)
            rom.to_file(filename)
            del rom
            tkMessageBox.showinfo(
                parent=root,
                title="Expansion Successful",
                message="Your ROM was expanded.")
コード例 #8
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
def expand(romfile, ex=False):
    rom = Rom()
    rom.from_file(romfile)
    if (not ex and len(rom) >= 0x400000) or (ex and (len(rom) >= 0x600000)):
        return False
    else:
        if ex:
            rom.expand(0x600000)
        else:
            rom.expand(0x400000)
        rom.to_file(romfile)
        del rom
        return True
コード例 #9
0
ファイル: common.py プロジェクト: LittleCube13/CoilSnake
def upgrade_project(project_path, base_rom_filename, progress_bar=None):
    if not os.path.isdir(project_path):
        raise RuntimeError("Project directory \"" + project_path + "\" is not a directory.")
    if not os.path.isfile(base_rom_filename):
        raise RuntimeError("Base Rom \"" + base_rom_filename + "\" is not a file.")

    modules = load_modules()

    # Open project
    project_filename = os.path.join(project_path, PROJECT_FILENAME)

    project = Project()
    project.load(project_filename)
    check_if_project_too_new(project)

    if project.version == FORMAT_VERSION:
        log.info("Project is already up to date.")
        return

    log.info("Upgrading project from version {} to {}".format(
        get_version_name(project.version),
        get_version_name(FORMAT_VERSION)))
    upgrade_start_time = time.time()

    rom = Rom()
    rom.from_file(base_rom_filename)
    check_if_types_match(project=project, rom=rom)

    compatible_modules = [(name, clazz) for name, clazz in modules if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0/len(compatible_modules)

    for module_name, module_class in compatible_modules:
        log.info("Upgrading {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.upgrade_project(project.version, FORMAT_VERSION, rom,
                                   lambda x, y, astext=False : project.get_resource(module_name, x, y, 'rt' if astext else 'rb', 'utf-8' if astext else None),
                                   lambda x, y, astext=False: 
                                        project.get_resource(module_name, x, y, 
                                            'wt' if astext else 'wb', 
                                            'utf-8' if astext else None,
                                            '\n' if astext else None),
                                   lambda x: project.delete_resource(module_name, x))
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished upgrading {} in {:.2f}s".format(module_class.NAME, time.time() - start_time))

    project.version = FORMAT_VERSION
    project.write(project_filename)

    log.info("Upgraded {} in {:.2f}s".format(project_path, time.time() - upgrade_start_time))
コード例 #10
0
ファイル: gui.py プロジェクト: john-soklaski/CoilSnake
    def do_compile(self, project_entry, base_rom_entry, rom_entry):
        base_rom = base_rom_entry.get()
        rom = rom_entry.get()
        project = project_entry.get()

        if base_rom and rom and project:
            self.save_default_tab()

            base_rom_rom = Rom()
            base_rom_rom.from_file(base_rom)
            if base_rom_rom.type == "Earthbound" and len(base_rom_rom) == 0x300000:
                confirm = tkinter.messagebox.askquestion("Expand Your Base ROM?",
                                                   "You are attempting to compile using a base ROM which is "
                                                   "unexpanded. It is likely that this will not succeed, as CoilSnake "
                                                   "needs the extra space in an expanded ROM to store additional data."
                                                   "\n\n"
                                                   "Would you like to expand this base ROM before proceeding? This "
                                                   "will permanently overwrite your base ROM.",
                                                   icon='warning')
                if confirm == "yes":
                    base_rom_rom.expand(0x400000)
                    base_rom_rom.to_file(base_rom)
            del base_rom_rom

            # Update the GUI
            self.console.clear()
            self.disable_all_components()

            self.progress_bar.clear()

            log.info("Starting compilation...")

            thread = Thread(target=self._do_compile_help, args=(project, base_rom, rom))
            thread.start()
コード例 #11
0
ファイル: common.py プロジェクト: tragicmanner/CoilSnake
def upgrade_project(project_path, base_rom_filename, progress_bar=None):
    modules = load_modules()

    # Open project
    project_filename = os.path.join(project_path, PROJECT_FILENAME)

    project = Project()
    project.load(project_filename)
    check_if_project_too_new(project)

    if project.version == FORMAT_VERSION:
        log.info("Project is already up to date.")
        return

    log.info(
        "Upgrading project from version {} to {}".format(
            get_version_name(project.version), get_version_name(FORMAT_VERSION)
        )
    )
    upgrade_start_time = time.time()

    rom = Rom()
    rom.from_file(base_rom_filename)
    check_if_types_match(project=project, rom=rom)

    compatible_modules = [(name, clazz) for name, clazz in modules if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0 / len(compatible_modules)

    for module_name, module_class in compatible_modules:
        log.info("Upgrading {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.upgrade_project(
                project.version,
                FORMAT_VERSION,
                rom,
                lambda x, y: project.get_resource(module_name, x, y, "rb"),
                lambda x, y: project.get_resource(module_name, x, y, "wb"),
                lambda x: project.delete_resource(module_name, x),
            )
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished upgrading {} in {:.2f}s".format(module_class.NAME, time.time() - start_time))

    project.version = FORMAT_VERSION
    project.write(project_filename)

    log.info("Upgraded {} in {:.2f}s".format(project_path, time.time() - upgrade_start_time))
コード例 #12
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('input',
                        metavar='INPUT',
                        type=argparse.FileType('rb'),
                        help="an unexpanded EarthBound ROM")
    parser.add_argument('output',
                        metavar='OUTPUT',
                        type=argparse.FileType('wb'),
                        help="the expanded EarthBound ROM")
    parser.add_argument('-ex',
                        action="store_true",
                        default=False,
                        help="expand again to 48 megabits")

    args = parser.parse_args()

    r = Rom.Rom()
    r.load(args.input)

    if args.ex:
        r.expand(0x600000)
    else:
        r.expand(0x400000)

    r.save(args.output)
コード例 #13
0
ファイル: common.py プロジェクト: LittleCube13/CoilSnake
def expand(romfile, ex=False):
    rom = Rom()
    rom.from_file(romfile)
    if (not ex and len(rom) >= 0x400000) or (ex and (len(rom) >= 0x600000)):
        return False
    else:
        if ex:
            rom.expand(0x600000)
        else:
            rom.expand(0x400000)
        rom.to_file(romfile)
        del rom
        return True
コード例 #14
0
    def test_write_to_rom(self):
        with Rom() as rom:
            rom.from_file(os.path.join(TEST_DATA_DIR, 'roms', 'real_EarthBound.smc'))
            self.module.read_from_rom(rom)

        def resource_open(a, b):
            return self.temporary_wo_file

        self.module.write_to_project(resource_open)

        self.temporary_wo_file = open(self.temporary_wo_file_name)
        self.module.read_from_project(resource_open)

        with Rom() as rom:
            rom.from_file(os.path.join(TEST_DATA_DIR, 'roms', 'real_EarthBound.smc'))
            self.module.write_to_rom(rom)
            self.test_read_from_rom_using_rom(rom)
コード例 #15
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
def strip_header(romfile):
    if romfile:
        with Rom() as rom:
            rom.from_file(romfile)
            rom.to_file(romfile)
        return True
    else:
        return False
コード例 #16
0
    def test_decomp(self, decomp):
        onett_map = array.array('B')
        with Rom() as eb_rom:
            eb_rom.from_file(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
            onett_map.fromlist(decomp(eb_rom, 0x2021a8))

        assert_equal(len(onett_map), 18496)
        assert_equal(crc32(onett_map), 739047015)
コード例 #17
0
ファイル: gui.py プロジェクト: Lyrositor/CoilSnake
    def do_compile(self, project_entry, base_rom_entry, rom_entry):
        base_rom = base_rom_entry.get()
        rom = rom_entry.get()
        project = project_entry.get()

        if base_rom and rom and project:
            self.save_default_tab()

            base_rom_rom = Rom()
            base_rom_rom.from_file(base_rom)
            if base_rom_rom.type == "Earthbound" and len(base_rom_rom) == 0x300000:
                confirm = tkMessageBox.askquestion("Expand Your Base ROM?",
                                                   "You are attempting to compile using a base ROM which is "
                                                   "unexpanded. It is likely that this will not succeed, as CoilSnake "
                                                   "needs the extra space in an expanded ROM to store additional data."
                                                   "\n\n"
                                                   "Would you like to expand this base ROM before proceeding? This "
                                                   "will permanently overwrite your base ROM.",
                                                   icon='warning')
                if confirm == "yes":
                    base_rom_rom.expand(0x400000)
                    base_rom_rom.to_file(base_rom)
            del base_rom_rom

            # Update the GUI
            self.console.clear()
            self.disable_all_components()

            self.progress_bar.clear()

            log.info("Starting compilation...")

            thread = Thread(target=self._do_compile_help, args=(project, base_rom, rom))
            thread.start()
コード例 #18
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
def decompile_rom(rom_filename, project_path, progress_bar=None):
    if not os.path.isfile(rom_filename):
        raise RuntimeError("Rom \"" + rom_filename + "\" is not a file.")

    modules = load_modules()

    rom = Rom()
    rom.from_file(rom_filename)

    project = Project()
    project.load(os.path.join(project_path, PROJECT_FILENAME), rom.type)

    compatible_modules = [(name, clazz) for name, clazz in modules
                          if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0 / (2 * len(compatible_modules))

    log.info("Decompiling ROM {}".format(rom_filename))
    decompile_start_time = time.time()

    for module_name, module_class in compatible_modules:
        if not module_class.is_compatible_with_romtype(rom.type):
            continue

        log.info("Decompiling {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.read_from_rom(rom)
            if progress_bar:
                progress_bar.tick(tick_amount)
            module.write_to_project(
                lambda x, y, astext=False: project.get_resource(
                    module_name, x, y, 'wt' if astext else 'wb', 'utf-8'
                    if astext else None, '\n' if astext else None))
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished decompiling {} in {:.2f}s".format(
            module_class.NAME,
            time.time() - start_time))

    log.debug("Saving Project")
    project.write(os.path.join(project_path, PROJECT_FILENAME))

    log.info("Decompiled to {} in {:.2f}s".format(
        project_path,
        time.time() - decompile_start_time))
コード例 #19
0
ファイル: test_ebrom.py プロジェクト: kashaiahyah85/CoilSnake
class TestEbRom(BaseTestCase):

    def setup(self):
        self.reference_rom = Rom()
        self.reference_rom.from_file(join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))

    def teardown(self):
        del self.reference_rom

    def test_fixing_rom_variants(self):
        for f in listdir(join(TEST_DATA_DIR, "roms", "variants")):
            if is_rom_filename(f):
                variant = EbRom()
                variant.from_file(join(TEST_DATA_DIR, "roms", "variants", f))

                assert_equal(self.reference_rom.data, variant.data)
                assert_equal(self.reference_rom.size, variant.size)
                assert_equal(EbRom.REFERENCE_MD5, hashlib.md5(variant.data.tostring()).hexdigest())
コード例 #20
0
def strip_header_from_rom(root):
    filename = tkFileDialog.askopenfilename(
        parent=root,
        initialdir=os.path.expanduser("~"),
        title="Select a ROM from which to remove a header",
        filetypes=ROM_FILETYPES)
    if filename:
        with Rom() as rom:
            rom.from_file(filename)
            rom.to_file(filename)
        tkMessageBox.showinfo(parent=root,
                              title="Header Removal Successful",
                              message="Your ROM's header was removed.")
コード例 #21
0
def add_header_to_rom(root):
    filename = tkFileDialog.askopenfilename(
        parent=root,
        initialdir=os.path.expanduser("~"),
        title="Select a ROM to which to add a header",
        filetypes=ROM_FILETYPES)
    if filename:
        with Rom() as rom:
            rom.from_file(filename)
            rom.add_header()
            rom.to_file(filename)
        tkMessageBox.showinfo(parent=root,
                              title="Header Addition Successful",
                              message="Your ROM was given a header.")
コード例 #22
0
    def test_comp(self, comp, decomp):
        a = array.array('B')
        with open(os.path.join(TEST_DATA_DIR, "binaries", "compressible.bin"), 'rb') as f:
            a.fromstring(f.read())
        assert_equal(len(a), 18496)

        uncompressed_data = a.tolist()
        compressed_data = comp(uncompressed_data)
        assert_equal(len(compressed_data), 58)

        with Rom() as fake_eb_rom:
            fake_eb_rom.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_32mbit.smc"))
            fake_eb_rom[0x300000:0x300000 + len(compressed_data)] = compressed_data
            reuncompressed_data = decomp(fake_eb_rom, 0x300000)

        assert_equal(len(reuncompressed_data), len(uncompressed_data))
        assert_equal(reuncompressed_data, uncompressed_data)
コード例 #23
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
def compile_project(project_path,
                    base_rom_filename,
                    output_rom_filename,
                    ccscript_offset=None,
                    progress_bar=None):
    if not os.path.isdir(project_path):
        raise RuntimeError("Project directory \"" + project_path +
                           "\" is not a directory.")
    if not os.path.isfile(base_rom_filename):
        raise RuntimeError("Base Rom \"" + base_rom_filename +
                           "\" is not a file.")

    modules = load_modules()

    project_filename = os.path.join(project_path, PROJECT_FILENAME)
    project = Project()
    project.load(project_filename)
    check_if_project_too_old(project)
    check_if_project_too_new(project)

    if base_rom_filename != output_rom_filename:
        copyfile(base_rom_filename, output_rom_filename)

    # Compile scripts using CCScript
    script_filenames = [
        os.path.join(project_path, "ccscript", x)
        for x in os.listdir(os.path.join(project_path, "ccscript"))
        if x.lower().endswith('.ccs')
    ]

    if script_filenames:
        log.info("Compiling CCScript")
        if not ccscript_offset:
            ccscript_offset = "F10000"
        elif type(ccscript_offset) == int:
            ccscript_offset = "{:x}".format(ccscript_offset)

        ccc_args = [
            "-n", "--libs",
            ccscript_library_path(), "--summary",
            os.path.join(project_path, "ccscript", "summary.txt"), "-s",
            ccscript_offset, "-o", output_rom_filename
        ] + script_filenames
        ccc_returncode, ccc_log = ccc(ccc_args)

        if ccc_returncode == 0:
            log.info("Finished compiling CCScript")
        else:
            raise CCScriptCompilationError(
                "CCScript compilation failed with output:\n" + ccc_log)

    rom = Rom()
    rom.from_file(output_rom_filename)
    check_if_types_match(project=project, rom=rom)

    compatible_modules = [(name, clazz) for name, clazz in modules
                          if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0 / (2 * len(compatible_modules))

    log.info("Compiling Project {}".format(project_path))
    compile_start_time = time.time()

    for module_name, module_class in modules:
        if module_class.is_compatible_with_romtype(rom.type):
            for free_range in module_class.FREE_RANGES:
                rom.deallocate(free_range)

    for module_name, module_class in modules:
        if not module_class.is_compatible_with_romtype(rom.type):
            continue

        log.info("Compiling {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.read_from_project(
                lambda x, y, astext=False: project.get_resource(
                    module_name, x, y, 'rt' if astext else 'rb', 'utf-8'
                    if astext else None))
            if progress_bar:
                progress_bar.tick(tick_amount)
            module.write_to_rom(rom)
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished compiling {} in {:.2f}s".format(
            module_class.NAME,
            time.time() - start_time))

    log.debug("Saving ROM")
    rom.to_file(output_rom_filename)

    log.info("Compiled to {} in {:.2f}s, finished at {}".format(
        output_rom_filename,
        time.time() - compile_start_time,
        datetime.now().strftime('%I:%M:%S %p')))
コード例 #24
0
class TestRom(TestAllocatableBlock):
    def setup(self):
        self.block = Rom()

    def test_detect_rom_type(self):
        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_noheader.smc"))
        assert_equal(self.block.type, "Earthbound")
        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_header.smc"))
        assert_equal(self.block.type, "Earthbound")
        self.block.from_file(os.path.join(TEST_DATA_DIR, "binaries", "empty.bin"))
        assert_equal(self.block.type, ROM_TYPE_NAME_UNKNOWN)
        self.block.from_file(os.path.join(TEST_DATA_DIR, "binaries", "1kb_null.bin"))
        assert_equal(self.block.type, ROM_TYPE_NAME_UNKNOWN)
        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_header.smc"))
        assert_equal(self.block.type, "Earthbound")
        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
        assert_equal(self.block.type, "Earthbound")

    @raises(NotImplementedError)
    def test_add_header_unknown(self):
        self.block.from_list([0])
        self.block.add_header()

    def test_add_header_eb(self):
        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
        assert_equal(self.block.size, 0x300000)
        self.block.add_header()
        assert_equal(self.block.size, 0x300200)
        assert_equal(len(self.block.data), 0x300200)
        assert_equal(self.block[0:0x200].to_list(), [0] * 0x200)

    @raises(NotImplementedError)
    def test_expand_unknown(self):
        self.block.from_list([0])
        self.block.expand(0x123456)

    def test_expand_eb(self):
        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
        assert_raises(InvalidArgumentError, self.block.expand, 0x400200)
        assert_raises(InvalidArgumentError, self.block.expand, 0x300000)
        self.block.expand(0x400000)
        assert_equal(self.block.size, 0x400000)
        assert_equal(len(self.block.data), 0x400000)
        assert_list_equal(self.block[0x300000:0x400000].to_list(), [0] * 0x100000)
        self.block.expand(0x600000)
        assert_equal(self.block.size, 0x600000)
        assert_equal(len(self.block.data), 0x600000)
        assert_equal(self.block[0xffd5], 0x25)
        assert_equal(self.block[0xffd7], 0x0d)

        self.block.from_file(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
        self.block.expand(0x600000)
        assert_equal(self.block.size, 0x600000)
        assert_equal(len(self.block.data), 0x600000)
        assert_equal(self.block[0xffd5], 0x25)
        assert_equal(self.block[0xffd7], 0x0d)
コード例 #25
0
 def setup(self):
     self.block = Rom()
コード例 #26
0
ファイル: common.py プロジェクト: Lyrositor/CoilSnake
def patch_rom(clean_rom_filename, patched_rom_filename, patch_filename, headered, progress_bar=None):
    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))
コード例 #27
0
ファイル: test_ebrom.py プロジェクト: kashaiahyah85/CoilSnake
 def setup(self):
     self.reference_rom = Rom()
     self.reference_rom.from_file(join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))
コード例 #28
0
 def test_read_from_rom(self):
     with Rom() as rom:
         rom.from_file(os.path.join(TEST_DATA_DIR, 'roms', 'real_EarthBound.smc'))
         self.test_read_from_rom_using_rom(rom)
コード例 #29
0
ファイル: common.py プロジェクト: kashaiahyah85/CoilSnake
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))
コード例 #30
0
 def setup(self):
     self.rom = Rom()
     self.rom.from_file(os.path.join(TEST_DATA_DIR, "roms", "EB_fake_24mbit.smc"))
コード例 #31
0
ファイル: common.py プロジェクト: Lyrositor/CoilSnake
def compile_project(project_path, base_rom_filename, output_rom_filename, ccscript_offset=None, progress_bar=None):
    modules = load_modules()

    project_filename = os.path.join(project_path, PROJECT_FILENAME)
    project = Project()
    project.load(project_filename)
    check_if_project_too_old(project)
    check_if_project_too_new(project)

    if base_rom_filename != output_rom_filename:
        copyfile(base_rom_filename, output_rom_filename)

    # Compile scripts using CCScript
    script_filenames = [os.path.join(project_path, "ccscript", x)
                        for x in os.listdir(os.path.join(project_path, "ccscript"))
                        if x.lower().endswith('.ccs')]

    if script_filenames:
        log.info("Compiling CCScript")
        if not ccscript_offset:
            ccscript_offset = "F10000"
        elif type(ccscript_offset) == int:
            ccscript_offset = "{:x}".format(ccscript_offset)

        ccc_args = ["-n",
                    "--libs", ccscript_library_path(),
                    "--summary", os.path.join(project_path, "ccscript", "summary.txt"),
                    "-s", ccscript_offset,
                    "-o", output_rom_filename] + script_filenames
        ccc_returncode, ccc_log = ccc(ccc_args)

        if ccc_returncode == 0:
            log.info("Finished compiling CCScript")
        else:
            raise CCScriptCompilationError("CCScript compilation failed with output:\n" + ccc_log)

    rom = Rom()
    rom.from_file(output_rom_filename)
    check_if_types_match(project=project, rom=rom)

    compatible_modules = [(name, clazz) for name, clazz in modules if clazz.is_compatible_with_romtype(rom.type)]
    tick_amount = 1.0/(2*len(compatible_modules))

    log.info("Compiling Project {}".format(project_path))
    compile_start_time = time.time()

    for module_name, module_class in modules:
        if module_class.is_compatible_with_romtype(rom.type):
            for free_range in module_class.FREE_RANGES:
                rom.deallocate(free_range)

    for module_name, module_class in modules:
        if not module_class.is_compatible_with_romtype(rom.type):
            continue

        log.info("Compiling {}...".format(module_class.NAME))
        start_time = time.time()
        with module_class() as module:
            module.read_from_project(lambda x, y: project.get_resource(module_name, x, y, 'rb'))
            if progress_bar:
                progress_bar.tick(tick_amount)
            module.write_to_rom(rom)
            if progress_bar:
                progress_bar.tick(tick_amount)
        log.info("Finished compiling {} in {:.2f}s".format(module_class.NAME, time.time() - start_time))

    log.debug("Saving ROM")
    rom.to_file(output_rom_filename)

    log.info("Compiled to {} in {:.2f}s, finished at {}".format(
        output_rom_filename, time.time() - compile_start_time, datetime.now().strftime('%I:%M:%S %p')))
コード例 #32
0
ファイル: ips.py プロジェクト: kashaiahyah85/CoilSnake
    def create(self, clean_rom, hacked_rom, patch_path):
        """Creates an IPS patch from the source and target ROMs."""

        with Rom() as cr, Rom() as hr:
            cr.from_file(clean_rom)
            hr.from_file(hacked_rom)

            if cr.__len__() > hr.__len__():
                if hr.__len__() <= 0x400000 and hr.__len__() > 0x300000:
                    raise CoilSnakeError(
                        "Clean ROM greater in size than hacked ROM. Please use a 3 Megabyte or 4 Megabyte clean ROM."
                    )
                if hr.__len__() <= 0x300000:
                    raise CoilSnakeError(
                        "Clean ROM greater in size than hacked ROM. Please use a 3 Megabyte clean ROM."
                    )

            # Expand clean ROM as necessary.
            if cr.__len__() < hr.__len__():
                if hr.__len__() == 0x400000:
                    cr.expand(0x400000)
                elif hr.__len__() == 0x600000:
                    cr.expand(0x600000)
                else:
                    cr.expand(patch.last_offset_used)

            # Create the records.
            i = None
            records = {}
            index = 0
            # Get the first byte of each ROM so that the loop works correctly.
            s = cr.__getitem__(index).to_bytes(1, byteorder='big')
            t = hr.__getitem__(index).to_bytes(1, byteorder='big')
            index += 1
            while index <= cr.__len__() and index <= hr.__len__():
                if t == s and i is not None:
                    i = None
                elif t != s:
                    if i is not None:
                        # Check that the record's size can fit in 2 bytes.
                        if index - 1 - i == 0xFFFF:
                            i = None
                            continue
                        records[i] += t
                    else:
                        i = index - 1
                        # Check that the offset isn't EOF. If it is, go back one
                        # byte to work around this IPS limitation.
                        if i.to_bytes(3, byteorder='big') != b"EOF":
                            records[i] = t
                        else:
                            i -= 1
                            records[i] = hr.to_list()[i]
                if index < cr.__len__() and index < hr.__len__():
                    s = cr.__getitem__(index).to_bytes(1, byteorder='big')
                    t = hr.__getitem__(index).to_bytes(1, byteorder='big')
                index += 1

        # Write the patch.
        with open(patch_path, "wb") as pfile:
            pfile.seek(0)
            pfile.write(b"PATCH")
            for r in sorted(records):
                pfile.write(r.to_bytes(3, byteorder='big'))
                pfile.write(len(records[r]).to_bytes(2, byteorder='big'))
                pfile.write(records[r])
            pfile.write(b"EOF")
            pfile.close()