def copy_whdload_kickstart(self, base_dir, name, checksums): dest = os.path.join(base_dir, "Devs", "Kickstarts") if not os.path.exists(dest): os.makedirs(dest) dest = os.path.join(dest, name) for checksum in checksums: # print("find kickstart with sha1", checksum) path = self.fsgs.file.find_by_sha1(checksum) if path: # and os.path.exists(path): print("found kickstart for", name, "at", path) archive = Archive(path) if archive.exists(path): with open(dest, "wb") as f: ROMManager.decrypt_archive_rom(archive, path, file=f) print(repr(dest)) break else: stream = self.fsgs.file.open(path) if stream is None: raise Exception("Cannot find kickstart " + repr(path)) with open(dest, "wb") as f: f.write(stream.read()) else: print("did not find kickstart for", name)
def unpack_archive(self, path, destination): print("unpack", path, "to", destination) archive = Archive(path) print(archive) print(archive.get_handler()) for name in archive.list_files(): if self.stop_flag: return print(name) n = name[len(path) + 2:] out_path = os.path.join(destination, n) print("out path", out_path) if name.endswith("/"): os.makedirs(out_path) else: if not os.path.exists(os.path.dirname(out_path)): os.makedirs(os.path.dirname(out_path)) f = archive.open(name) with open(out_path, "wb") as out_f: while True: data = f.read(65536) if not data: break out_f.write(data)
def multi_select(cls, parent=None): default_dir = FSGSDirectories.get_floppies_dir() dialog = LauncherFilePicker(parent, gettext("Select Multiple Floppies"), "floppy", multiple=True) if not dialog.show_modal(): return original_paths = dialog.get_paths() original_paths.sort() paths = [] for path in original_paths: path = Paths.get_real_case(path) embedded_files = [] if path.endswith(".zip"): archive = Archive(path) files = archive.list_files() for file in files: name, ext = os.path.splitext(file) # FIXME: get list of floppy extensions from a central # place if ext in [".adf", ".ipf"]: embedded_files.append(file) if len(embedded_files) > 0: embedded_files.sort() print("found embedded floppy images:") print(embedded_files) for file in embedded_files: paths.append(file) else: paths.append(path) checksum_tool = ChecksumTool(parent) for i, path in enumerate(paths): sha1 = checksum_tool.checksum(path) path = Paths.contract_path(path, default_dir, force_real_case=False) if i < 4: LauncherConfig.set_multiple([ ("floppy_drive_{0}".format(i), path), ("x_floppy_drive_{0}_sha1".format(i), sha1) ]) LauncherConfig.set_multiple([("floppy_image_{0}".format(i), path), ("x_floppy_image_{0}_sha1".format(i), sha1)]) # blank the rest of the drives for i in range(len(paths), 4): LauncherConfig.set_multiple([("floppy_drive_{0}".format(i), ""), ("x_floppy_drive_{0}_sha1".format(i), "")]) # blank the rest of the image list for i in range(len(paths), 20): LauncherConfig.set_multiple([("floppy_image_{0}".format(i), ""), ("x_floppy_image_{0}_sha1".format(i), "")])
def scan_file(self, database, path): name = os.path.basename(path) # path = os.path.normcase(os.path.normpath(path)) self.scan_count += 1 self.set_status( gettext("Scanning files ({count} scanned)").format( count=self.scan_count), name) try: st = os.stat(path) except: print("error stat-ing file", repr(path)) return size = st.st_size mtime = int(st.st_mtime) result = database.find_file(path=path) # print(result) if result["path"]: if size == result["size"] and mtime == result["mtime"]: self.database_file_ids.remove(result["id"]) # self.database_file_ids.difference_update( # database.get_file_hierarchy_ids(path + "#")) # self.database_file_ids.difference_update( # database.get_child_ids(id=result["id"])) return archive = Archive(path) # if archive.is_archive(): file_id = self.scan_archive_stream(database, archive, path, name, size, mtime) for p in archive.list_files(): if p.endswith("/"): # don't index archive directory entries continue # print(p) if self.stop_check(): return # n = p.replace("\\", "/").replace("|", "/").split("/")[-1] n = os.path.basename(p) self.scan_count += 1 self.scan_archive_stream(database, archive, p, n, size, mtime, parent=file_id) if self.stop_check(): return
def multiselect(cls, parent=None): default_dir = FSGSDirectories.get_floppies_dir() dialog = LauncherFilePicker( parent, gettext("Select Multiple Floppies"), "floppy", multiple=True) if not dialog.show_modal(): return original_paths = dialog.get_paths() original_paths.sort() paths = [] for path in original_paths: path = Paths.get_real_case(path) embedded_files = [] if path.endswith(".zip"): archive = Archive(path) files = archive.list_files() for file in files: name, ext = os.path.splitext(file) # FIXME: get list of floppy extensions from a central # place if ext in [".adf", ".ipf"]: embedded_files.append(file) if len(embedded_files) > 0: embedded_files.sort() print("found embedded floppy images:") print(embedded_files) for file in embedded_files: paths.append(file) else: paths.append(path) checksum_tool = ChecksumTool(parent) for i, path in enumerate(paths): sha1 = checksum_tool.checksum(path) path = Paths.contract_path( path, default_dir, force_real_case=False) if i < 4: LauncherConfig.set_multiple([ ("floppy_drive_{0}".format(i), path), ("x_floppy_drive_{0}_sha1".format(i), sha1)]) LauncherConfig.set_multiple([ ("floppy_image_{0}".format(i), path), ("x_floppy_image_{0}_sha1".format(i), sha1)]) # blank the rest of the drives for i in range(len(paths), 4): LauncherConfig.set_multiple([ ("floppy_drive_{0}".format(i), ""), ("x_floppy_drive_{0}_sha1".format(i), "")]) # blank the rest of the image list for i in range(len(paths), 20): LauncherConfig.set_multiple([ ("floppy_image_{0}".format(i), ""), ("x_floppy_image_{0}_sha1".format(i), "")])
def decrypt_archive_rom(cls, archive, path, file=None): print("decrypt_archive_rom", path) result = {} f = archive.open(path) data = f.read(len("AMIROMTYPE1")) out_data = b"" sha1 = hashlib.sha1() if data != b"AMIROMTYPE1": # not encrypted, write raw data sha1.update(data) out_data += data data = f.read() sha1.update(data) out_data += data result["data"] = out_data result["sha1"] = sha1.hexdigest() cls.patch_rom(result) if file is not None: file.write(result["data"]) return result key_path = archive.join(archive.dirname(path), "rom.key") key_archive = Archive(key_path) try: f2 = key_archive.open(key_path) except Exception: raise Exception("did not find rom.key to decrypt ROM with") print("using key file", key_path) # if not os.path.exists(key_file): # raise Exception("did not find rom.key to decrypt ROM with") key_data = f2.read() f2.close() while True: data = f.read(len(key_data)) if not data: break dec = [] for i in range(len(data)): dec.append(data[i] ^ key_data[i]) dec_data = bytes(dec) # if file is not None: # file.write(dec_data) out_data += dec_data if sha1 is not None: sha1.update(dec_data) result["data"] = out_data result["sha1"] = sha1.hexdigest() cls.patch_rom(result) if file is not None: file.write(result["data"]) return result
def scan_file(self, database, path): name = os.path.basename(path) # path = os.path.normcase(os.path.normpath(path)) self.scan_count += 1 self.set_status( gettext("Scanning files ({count} scanned)").format( count=self.scan_count), name) try: st = os.stat(path) except: print("error stat-ing file", repr(path)) return size = st.st_size mtime = int(st.st_mtime) result = database.find_file(path=path) # print(result) if result["path"]: if size == result["size"] and mtime == result["mtime"]: self.database_file_ids.remove(result["id"]) # self.database_file_ids.difference_update( # database.get_file_hierarchy_ids(path + "#")) # self.database_file_ids.difference_update( # database.get_child_ids(id=result["id"])) return archive = Archive(path) # if archive.is_archive(): file_id = self.scan_archive_stream( database, archive, path, name, size, mtime) for p in archive.list_files(): if p.endswith("/"): # don't index archive directory entries continue # print(p) if self.stop_check(): return # n = p.replace("\\", "/").replace("|", "/").split("/")[-1] n = os.path.basename(p) self.scan_count += 1 self.scan_archive_stream( database, archive, p, n, size, mtime, parent=file_id) if self.stop_check(): return
def calculate_whdload_args(cls, archive_path): archive = Archive(archive_path) slave = "" for path in archive.list_files(): name = os.path.basename(path) name_lower = name.lower() if name_lower.endswith(".slave"): if slave: print("already found one slave, don't know which " "one to choose") return "" slave = name elif name_lower == "startup-sequence": print("found startup-sequence, assuming non-whdload " "archive") return slave
def insert_multiple_floppies(self, insert_paths): paths = [] for path in insert_paths: embedded_files = [] if path.endswith(".zip"): archive = Archive(path) files = archive.list_files() for file in files: name, ext = os.path.splitext(file) # FIXME: get list of floppy extensions from a central # place if ext in [".adf", ".ipf"]: embedded_files.append(file) if len(embedded_files) > 0: embedded_files.sort() print("found embedded floppy images:") print(embedded_files) for file in embedded_files: paths.append(file) else: paths.append(path) default_dir = FSGSDirectories.get_floppies_dir() checksum_tool = ChecksumTool() for i, path in enumerate(paths): sha1 = checksum_tool.checksum(path) path = Paths.contract_path(path, default_dir) if i < 4: self.set_config([ ("floppy_drive_{0}".format(i), path), ("x_floppy_drive_{0}_sha1".format(i), sha1)]) self.set_config([ ("floppy_image_{0}".format(i), path), ("x_floppy_image_{0}_sha1".format(i), sha1)]) # blank the rest of the drives for i in range(len(paths), 4): self.set_config([ ("floppy_drive_{0}".format(i), ""), ("x_floppy_drive_{0}_sha1".format(i), "")]) # blank the rest of the image list for i in range(len(paths), 20): self.set_config([ ("floppy_image_{0}".format(i), ""), ("x_floppy_image_{0}_sha1".format(i), "")])
def upload_prefix(self, prefix): self.stop_check() result = self.upload_check(prefix) print(len(result)) for k in range(0, len(result), 20): self.stop_check() sha1 = result[k:k + 20] path = fsgs.file.find_by_sha1(bytes_to_hex(sha1)) if not path: continue try: # this is done to properly handle encrypted ROMs archive = Archive(path) data = ROMManager.decrypt_archive_rom(archive, path)["data"] except Exception: traceback.print_exc() uri = "sha1://{0}".format(bytes_to_hex(sha1)) print(uri) try: input_stream = fsgs.file.open(uri) data = input_stream.read() except Exception: continue assert not input_stream.read() print("uploading file of size ", len(data)) # self.progressed(gettext("Verifying {name}").format( # name=bytes_to_hex(sha1))) self.progressed( gettext("Uploading {name}").format(name=bytes_to_hex(sha1))) import hashlib new_hash = hashlib.sha1(data).hexdigest() print(new_hash, "vs", bytes_to_hex(sha1)) if hashlib.sha1(data).hexdigest() != bytes_to_hex(sha1): print("hash mismatch, probably Cloanto ROM...") continue retry_seconds = 1 while True: try: self.client.post("/api/locker-upload-file", data=data) except OGDClient.NonRetryableHTTPError as e: raise e except Exception: traceback.print_exc() self.progressed( gettext("Re-trying in {0} seconds...").format( retry_seconds)) for _ in range(retry_seconds): self.stop_check() time.sleep(1.0) retry_seconds = min(retry_seconds * 2, 60 * 10) else: break
def insert_multiple_floppies(self, insert_paths): paths = [] for path in insert_paths: embedded_files = [] if path.endswith(".zip"): archive = Archive(path) files = archive.list_files() for file in files: name, ext = os.path.splitext(file) # FIXME: get list of floppy extensions from a central # place if ext in [".adf", ".ipf"]: embedded_files.append(file) if len(embedded_files) > 0: embedded_files.sort() print("found embedded floppy images:") print(embedded_files) for file in embedded_files: paths.append(file) else: paths.append(path) default_dir = FSGSDirectories.get_floppies_dir() checksum_tool = ChecksumTool() for i, path in enumerate(paths): sha1 = checksum_tool.checksum(path) path = Paths.contract_path(path, default_dir) if i < 4: self.set_config([("floppy_drive_{0}".format(i), path), ("x_floppy_drive_{0}_sha1".format(i), sha1)]) self.set_config([("floppy_image_{0}".format(i), path), ("x_floppy_image_{0}_sha1".format(i), sha1)]) # blank the rest of the drives for i in range(len(paths), 4): self.set_config([("floppy_drive_{0}".format(i), ""), ("x_floppy_drive_{0}_sha1".format(i), "")]) # blank the rest of the image list for i in range(len(paths), 20): self.set_config([("floppy_image_{0}".format(i), ""), ("x_floppy_image_{0}_sha1".format(i), "")])
def download_game_file_archive(self, url): print("\ndownload_game_file_archive", url) archive_path = Downloader.cache_file_from_url(url) archive = Archive(archive_path) archive_files = archive.list_files() print(archive_files) for name in archive_files: print(name) ifs = archive.open(name) data = ifs.read() Downloader.cache_data(data) if len(archive_files) == 0: # might not be an archive then with open(archive_path, "rb") as f: data = f.read() Downloader.cache_data(data) # the downloaded archive is no longer needed, now that we have # extracted all the files os.remove(archive_path) print("\n")
def checksum(self, path): print("checksum", repr(path)) archive = Archive(path) if os.path.exists(path): size = os.path.getsize(path) if size == 0: # either a real 0-byte file or a device node on a BSD # system (could be large). To reliably get the size we could # use ioctl, but we simply return the checksum for a 0-byte # file anyway return ZERO_SHA1 s = hashlib.sha1() f = archive.open(path) while True: data = f.read(65536) if not data: break s.update(data) return s.hexdigest()
def convert_uri(self, uri, prefer_path=False): if uri.startswith("sha1://"): return self.open_sha1_uri(uri) elif uri.startswith("db://"): # old name for sha1:// return self.open_sha1_uri(uri) elif is_http_url(uri): return self.open_url(uri) elif uri.startswith("locker://"): return open_locker_uri(uri, opener_cache_dict=self.opener_cache_dict) else: if prefer_path and os.path.exists(uri): # return helper object so isinstance does not match with str return File(uri) return Archive(uri).open(uri)
def expand_default_path(self, src, default_dir): if "://" in src: return src, None src = Paths.expand_path(src, default_dir) archive = Archive(src) # if not archive.exists(src): # dirs = [default_dir] # for dir in dirs: # path = os.path.join(dir, src) # print("checking", repr(path)) # archive = Archive(path) # if archive.exists(path): # #if os.path.exists(path): # src = path # break # else: # raise Exception("Cannot find path for " + repr(src)) return src, archive
def add_rom_to_database(cls, path, database, log_function=None): if log_function is None: log_function = print try: archive = Archive(path) rom = ROMManager.decrypt_archive_rom(archive, path) except Exception: import traceback traceback.print_exc() return try: st = os.stat(path) except: log_function("Error stat-ing file {0}".format(repr(path))) return size = st.st_size mtime = int(st.st_mtime) log_function("Adding ROM \"{0}\" to database (SHA-1: {1})".format( path, rom["sha1"])) database.delete_file(path=path) database.add_file(path=path, sha1=rom["sha1"], mtime=mtime, size=size)
def run_config_or_game(cls): config_path = None archive_path = None floppy_image_paths = [] cdrom_image_paths = [] config_uuid = None floppy_exts = (".adf", ".ipf", ".dms", ".adz") cdrom_exts = (".cue", ".iso") archive_exts = (".zip", ".lha") # FIXME: replace argument "parsing" with use of argparse module # at some point last_arg = sys.argv[-1] file_ext = os.path.splitext(last_arg)[-1].lower() if file_ext == ".fs-uae": config_path = last_arg elif file_ext in archive_exts: archive_path = last_arg # elif file_ext in floppy_exts: # floppy_image_paths = [last_arg] elif is_uuid(last_arg): config_uuid = last_arg.lower() for arg in sys.argv[1:]: if not arg.startswith("--"): _, ext = os.path.splitext(arg) if ext in floppy_exts: floppy_image_paths.append(arg) elif ext in cdrom_exts: cdrom_image_paths.append(arg) if config_path: print("config path given:", config_path) if not os.path.exists(config_path): print("config path does not exist", file=sys.stderr) return True LauncherConfig.load_file(config_path) fsgs.config.add_from_argv() return cls.run_config_directly() if archive_path: print("archive path given:", archive_path) if not os.path.exists(archive_path): print("archive path does not exist", file=sys.stderr) return True archive = Archive(os.path.realpath(archive_path)) # We want to exclude pure directory entries when checking for # archives with only floppies. arc_files = [x for x in archive.list_files() if not x.endswith("/")] if all(map(lambda f: f.lower().endswith(floppy_exts), arc_files)): print("archive contains floppy disk images only") floppy_image_paths = arc_files else: values = HardDriveGroup.generate_config_for_archive( archive_path) values["hard_drive_0"] = archive_path values.update(fsgs.config.config_from_argv()) return cls.run_config_directly_with_values(values) if floppy_image_paths: enum_paths = tuple(enumerate(floppy_image_paths)) values = {} values.update(fsgs.config.config_from_argv()) max_drives = int(values.get("floppy_drive_count", "4")) values.update({"floppy_drive_{0}".format(k): v for k, v in enum_paths[:max_drives]}) values.update({"floppy_image_{0}".format(k): v for k, v in enum_paths[:20]}) return cls.run_config_directly_with_values(values) if cdrom_image_paths: enum_paths = tuple(enumerate(cdrom_image_paths)) values = {"amiga_model": "CD32"} values.update(fsgs.config.config_from_argv()) max_drives = int(values.get("cdrom_drive_count", "1")) values.update({"cdrom_drive_{0}".format(k): v for k, v in enum_paths[:max_drives]}) values.update({"cdrom_image_{0}".format(k): v for k, v in enum_paths[:20]}) return cls.run_config_directly_with_values(values) if config_uuid: print("config uuid given:", config_uuid) variant_uuid = config_uuid # values = fsgs.game.set_from_variant_uuid(variant_uuid) if fsgs.load_game_variant(variant_uuid): print("loaded variant") else: print("could not load variant, try to load game") game_uuid = config_uuid variant_uuid = fsgs.find_preferred_game_variant(game_uuid) print("preferred variant:", variant_uuid) fsgs.load_game_variant(variant_uuid) fsgs.config.add_from_argv() LauncherConfig.post_load_values(fsgs.config) return cls.run_config_directly()
def checksum_rom(self, path): print("checksum_rom", repr(path)) archive = Archive(path) return ROMManager.decrypt_archive_rom(archive, path)["sha1"]
def prepare_roms(self): print("LaunchHandler.prepare_roms") current_task.set_progress(gettext("Preparing kickstart ROMs...")) amiga_model = self.config.get("amiga_model", "A500") model_config = Amiga.get_model_config(amiga_model) roms = [("kickstart_file", model_config["kickstarts"])] if self.config["kickstart_ext_file"] or model_config["ext_roms"]: # not all Amigas have extended ROMs roms.append(("kickstart_ext_file", model_config["ext_roms"])) if amiga_model.lower() == "cd32/fmv": roms.append(("fvm_rom", [CD32_FMV_ROM])) if self.config["graphics_card"].lower().startswith("picasso-iv"): roms.append(("graphics_card_rom", [PICASSO_IV_74_ROM])) if self.config["accelerator"].lower() == "cyberstorm-ppc": roms.append(("accelerator_rom", ["cyberstormppc.rom"])) if self.config["freezer_cartridge"] == "action-replay-2": # Ideally, we would want to recognize ROMs based on zeroing the # first four bytes, but right now we simply recognize a common # additional version. freezer_cartridge_rom isn't a real option, # we just want to copy the rom file and let FS-UAE find it roms.append(("[freezer_cartridge]", [ACTION_REPLAY_MK_II_2_14_ROM.sha1, ACTION_REPLAY_MK_II_2_14_MOD_ROM.sha1])) elif self.config["freezer_cartridge"] == "action-replay-3": roms.append(("[freezer_cartridge]", [ACTION_REPLAY_MK_III_3_17_ROM.sha1, ACTION_REPLAY_MK_III_3_17_MOD_ROM.sha1])) for config_key, default_roms in roms: print("ROM:", config_key, default_roms) src = self.config[config_key] if not src: for sha1 in default_roms: if is_sha1(sha1): rom_src = self.fsgs.file.find_by_sha1(sha1) if rom_src: src = rom_src break else: # roms_dir = FSGSDirectories.get_kickstarts_dir() # src = os.path.join(roms_dir, sha1) # if os.path.exists(src): # break # loop up file in roms dir instead src = sha1 elif src == "internal": continue elif src: src = Paths.expand_path(src) if not src: raise TaskFailure( gettext("Did not find required Kickstart or " "ROM for {}. Wanted one of these files: {}".format( config_key, repr(default_roms)))) use_temp_kickstarts_dir = False dest = os.path.join(self.temp_dir, os.path.basename(src)) archive = Archive(src) stream = None if not archive.exists(src): dirs = [self.fsgs.amiga.get_kickstarts_dir()] for dir in dirs: path = os.path.join(dir, src) print("checking", repr(path)) archive = Archive(path) if archive.exists(path): src = path break else: try: stream = self.fsgs.file.open(src) if stream is None: raise FileNotFoundError(src) except FileNotFoundError: raise TaskFailure(gettext( "Cannot find required ROM " "file: {name}".format(name=repr(src)))) with open(dest, "wb") as f: if stream: f.write(stream.read()) else: ROMManager.decrypt_archive_rom(archive, src, file=f) if use_temp_kickstarts_dir: self.config[config_key] = os.path.basename(src) else: self.config[config_key] = dest if use_temp_kickstarts_dir: self.config["kickstarts_dir"] = self.temp_dir