From 579f80f18f69765b50eccbb43a9da07514116770 Mon Sep 17 00:00:00 2001 From: jopohl Date: Wed, 8 Jul 2020 13:01:47 +0200 Subject: [PATCH 1/3] refactor FileOperator --- src/urh/controller/CompareFrameController.py | 2 +- src/urh/controller/GeneratorTabController.py | 4 +- src/urh/controller/SimulatorTabController.py | 2 +- src/urh/controller/dialogs/ReceiveDialog.py | 4 +- src/urh/controller/dialogs/SendDialog.py | 2 +- src/urh/controller/dialogs/SimulatorDialog.py | 4 +- src/urh/controller/widgets/SignalFrame.py | 8 +- src/urh/util/FileOperator.py | 182 +++++++++--------- 8 files changed, 107 insertions(+), 101 deletions(-) diff --git a/src/urh/controller/CompareFrameController.py b/src/urh/controller/CompareFrameController.py index ed7cadeee9..32777d3182 100644 --- a/src/urh/controller/CompareFrameController.py +++ b/src/urh/controller/CompareFrameController.py @@ -857,7 +857,7 @@ def save_protocol(self): break text = "protocol" - filename = FileOperator.get_save_file_name("{0}.proto.xml".format(text), caption="Save protocol") + filename = FileOperator.ask_save_file_name("{0}.proto.xml".format(text), caption="Save protocol") if not filename: return diff --git a/src/urh/controller/GeneratorTabController.py b/src/urh/controller/GeneratorTabController.py index 8298695e4a..84e64a85c1 100644 --- a/src/urh/controller/GeneratorTabController.py +++ b/src/urh/controller/GeneratorTabController.py @@ -384,7 +384,7 @@ def generate_file(self): except Exception as e: logger.exception(e) sample_rate = 1e6 - FileOperator.save_data_dialog("generated", modulated_samples, sample_rate=sample_rate, parent=self) + FileOperator.ask_signal_file_name_and_save("generated", modulated_samples, sample_rate=sample_rate, parent=self) except Exception as e: Errors.exception(e) self.unsetCursor() @@ -608,7 +608,7 @@ def on_btn_send_clicked(self): @pyqtSlot() def on_btn_save_clicked(self): - filename = FileOperator.get_save_file_name("profile.fuzz.xml", caption="Save fuzz profile") + filename = FileOperator.ask_save_file_name("profile.fuzz.xml", caption="Save fuzzing profile") if filename: self.table_model.protocol.to_xml_file(filename, decoders=self.project_manager.decodings, diff --git a/src/urh/controller/SimulatorTabController.py b/src/urh/controller/SimulatorTabController.py index 947d148d01..1ec7f07ca7 100644 --- a/src/urh/controller/SimulatorTabController.py +++ b/src/urh/controller/SimulatorTabController.py @@ -507,7 +507,7 @@ def refresh_tree(self): @pyqtSlot() def on_btn_save_clicked(self): - filename = FileOperator.get_save_file_name(initial_name="myprofile.sim.xml", caption="Save simulator profile") + filename = FileOperator.ask_save_file_name(initial_name="myprofile.sim.xml", caption="Save simulator profile") if filename: self.save_simulator_file(filename) diff --git a/src/urh/controller/dialogs/ReceiveDialog.py b/src/urh/controller/dialogs/ReceiveDialog.py index 5124f1b504..4338b3aa5c 100644 --- a/src/urh/controller/dialogs/ReceiveDialog.py +++ b/src/urh/controller/dialogs/ReceiveDialog.py @@ -103,8 +103,8 @@ def on_save_clicked(self): initial_name = initial_name.replace(Formatter.local_decimal_seperator(), "_").replace("_000", "") - filename = FileOperator.save_data_dialog(initial_name, data, - sample_rate=dev.sample_rate, parent=self) + filename = FileOperator.ask_signal_file_name_and_save(initial_name, data, + sample_rate=dev.sample_rate, parent=self) self.already_saved = True if filename is not None and filename not in self.recorded_files: self.recorded_files.append(filename) diff --git a/src/urh/controller/dialogs/SendDialog.py b/src/urh/controller/dialogs/SendDialog.py index 26d448dc0a..550b59fc76 100644 --- a/src/urh/controller/dialogs/SendDialog.py +++ b/src/urh/controller/dialogs/SendDialog.py @@ -94,7 +94,7 @@ def init_device(self): @pyqtSlot() def on_graphics_view_save_as_clicked(self): - filename = FileOperator.get_save_file_name("signal.complex") + filename = FileOperator.ask_save_file_name("signal.complex") if filename: try: try: diff --git a/src/urh/controller/dialogs/SimulatorDialog.py b/src/urh/controller/dialogs/SimulatorDialog.py index fe00c634f3..4cb6cbd36e 100644 --- a/src/urh/controller/dialogs/SimulatorDialog.py +++ b/src/urh/controller/dialogs/SimulatorDialog.py @@ -418,8 +418,8 @@ def on_btn_save_rx_clicked(self): rx_device = self.simulator.sniffer.rcv_device if isinstance(rx_device.data, np.ndarray) or isinstance(rx_device.data, IQArray): data = IQArray(rx_device.data[:rx_device.current_index]) - filename = FileOperator.save_data_dialog("simulation_capture", data, - sample_rate=rx_device.sample_rate, parent=self) + filename = FileOperator.ask_signal_file_name_and_save("simulation_capture", data, + sample_rate=rx_device.sample_rate, parent=self) if filename: data.tofile(filename) self.rx_file_saved.emit(filename) diff --git a/src/urh/controller/widgets/SignalFrame.py b/src/urh/controller/widgets/SignalFrame.py index 41108317ac..61def6d0d8 100644 --- a/src/urh/controller/widgets/SignalFrame.py +++ b/src/urh/controller/widgets/SignalFrame.py @@ -448,8 +448,8 @@ def save_signal(self): def save_signal_as(self): try: - FileOperator.save_data_dialog(self.signal.name, self.signal.iq_array, self.signal.sample_rate, - self.signal.wav_mode) + FileOperator.ask_signal_file_name_and_save(self.signal.name, self.signal.iq_array, self.signal.sample_rate, + self.signal.wav_mode) except Exception as e: Errors.exception(e) @@ -460,7 +460,7 @@ def export_demodulated(self): logger.exception(e) initial_name = "demodulated.complex" - filename = FileOperator.get_save_file_name(initial_name) + filename = FileOperator.ask_save_file_name(initial_name) if filename: try: self.setCursor(Qt.WaitCursor) @@ -1314,7 +1314,7 @@ def on_export_fta_wanted(self): logger.exception(e) initial_name = "spectrogram.ft" - filename = FileOperator.get_save_file_name(initial_name, caption="Export spectrogram") + filename = FileOperator.ask_save_file_name(initial_name, caption="Export spectrogram") if not filename: return QApplication.setOverrideCursor(Qt.WaitCursor) diff --git a/src/urh/util/FileOperator.py b/src/urh/util/FileOperator.py index 8ada1b1a1b..9aa25c1b93 100644 --- a/src/urh/util/FileOperator.py +++ b/src/urh/util/FileOperator.py @@ -19,17 +19,45 @@ RECENT_PATH = QDir.homePath() -EXT = {np.int8: ".complex16s", np.uint8: ".complex16u", np.int16: ".complex32s", np.uint16: ".complex32u", - np.float32: ".complex", np.complex64: ".complex"} -FILTER = {np.int8: "Complex16 signed (*.complex16s *.cs8)", np.uint8: "Complex16 unsigned (*.complex16u *.cu8)", - np.uint16: "Complex32 unsigned (*.complex32u *.cu16)", np.int16: "Complex32 signed (*.complex32s *.cs16)", - np.float32: "Complex (*.complex)", np.complex64: "Complex (*.complex)"} +SIGNAL_FILE_EXTENSIONS_BY_TYPE = { + np.int8: ".complex16s", + np.uint8: ".complex16u", + np.int16: ".complex32s", + np.uint16: ".complex32u", + np.float32: ".complex", + np.complex64: ".complex" +} + +SIGNAL_NAME_FILTERS_BY_TYPE = { + np.int8: "Complex16 signed (*.complex16s *.cs8)", + np.uint8: "Complex16 unsigned (*.complex16u *.cu8)", + np.uint16: "Complex32 unsigned (*.complex32u *.cu16)", + np.int16: "Complex32 signed (*.complex32s *.cs16)", + np.float32: "Complex (*.complex)", + np.complex64: "Complex (*.complex)" +} + +EVERYTHING_FILE_FILTER = "All Files (*)" + +SIGNAL_NAME_FILTERS = list(sorted(set(SIGNAL_NAME_FILTERS_BY_TYPE.values()))) + +COMPRESSED_COMPLEX_FILE_FILTER = "Compressed Complex File (*.coco)" +WAV_FILE_FILTER = "Waveform Audio File Format (*.wav *.wave)" +PROTOCOL_FILE_FILTER = "Protocol (*.proto.xml *.proto)" +BINARY_PROTOCOL_FILE_FILTER = "Binary Protocol (*.bin)" +PLAIN_BITS_FILE_FILTER = "Plain Bits (*.txt)" +FUZZING_FILE_FILTER = "Fuzzing Profile (*.fuzz.xml *.fuzz)" +SIMULATOR_FILE_FILTER = "Simulator Profile (*.sim.xml *.sim)" +TAR_FILE_FILTER = "Tar Archive (*.tar *.tar.gz *.tar.bz2)" +ZIP_FILE_FILTER = "Zip Archive (*.zip)" + + +def __get__name_filter_for_signals() -> str: + return ";;".join([EVERYTHING_FILE_FILTER] + SIGNAL_NAME_FILTERS + [COMPRESSED_COMPLEX_FILE_FILTER, WAV_FILE_FILTER]) def get_open_dialog(directory_mode=False, parent=None, name_filter="full") -> QFileDialog: - fip = FileIconProvider() dialog = QFileDialog(parent=parent, directory=RECENT_PATH) - dialog.setIconProvider(fip) if directory_mode: dialog.setFileMode(QFileDialog.Directory) @@ -38,98 +66,41 @@ def get_open_dialog(directory_mode=False, parent=None, name_filter="full") -> QF dialog.setFileMode(QFileDialog.ExistingFiles) dialog.setWindowTitle("Open Files") if name_filter == "full": - name_filter = "All Files (*);;" \ - "Complex (*.complex);;" \ - "Complex16 unsigned (*.complex16u *.cu8);;" \ - "Complex16 signed (*.complex16s *.cs8);;" \ - "Complex32 unsigned (*.complex32u *.cu16);;" \ - "Complex32 signed (*.complex32s *.cs16);;" \ - "WAV (*.wav);;" \ - "Protocols (*.proto.xml *.proto);;" \ - "Binary Protocols (*.bin);;" \ - "Fuzzing Profiles (*.fuzz.xml *.fuzz);;" \ - "Simulator (*.sim.xml *.sim)" \ - "Plain Bits (*.txt);;" \ - "Tar Archives (*.tar *.tar.gz *.tar.bz2);;" \ - "Zip Archives (*.zip)" + name_filter = __get__name_filter_for_signals() + ";;" \ + + ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER, PLAIN_BITS_FILE_FILTER, + FUZZING_FILE_FILTER, SIMULATOR_FILE_FILTER, TAR_FILE_FILTER, ZIP_FILE_FILTER]) elif name_filter == "proto": - name_filter = "Protocols (*.proto.xml *.proto);; Binary Protocols (*.bin)" + name_filter = ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER]) elif name_filter == "fuzz": - name_filter = "Fuzzprofiles (*.fuzz.xml *.fuzz)" + name_filter = FUZZING_FILE_FILTER elif name_filter == "simulator": - name_filter = "Simulator (*.sim.xml *.sim)" + name_filter = SIMULATOR_FILE_FILTER dialog.setNameFilter(name_filter) - dialog.setOptions(QFileDialog.DontResolveSymlinks) - dialog.setViewMode(QFileDialog.Detail) - return dialog -def uncompress_archives(file_names, temp_dir): - """ - Extract each archive from the list of filenames. - Normal files stay untouched. - Add all files to the Recent Files. - :type file_names: list of str - :type temp_dir: str - :rtype: list of str - """ - result = [] - for filename in file_names: - if filename.endswith(".tar") or filename.endswith(".tar.gz") or filename.endswith(".tar.bz2"): - obj = tarfile.open(filename, "r") - extracted_file_names = [] - for j, member in enumerate(obj.getmembers()): - obj.extract(member, temp_dir) - extracted_filename = os.path.join(temp_dir, obj.getnames()[j]) - extracted_file_names.append(extracted_filename) - archives[extracted_filename] = filename - result.extend(extracted_file_names[:]) - elif filename.endswith(".zip"): - obj = zipfile.ZipFile(filename) - extracted_file_names = [] - for j, info in enumerate(obj.infolist()): - obj.extract(info, path=temp_dir) - extracted_filename = os.path.join(temp_dir, obj.namelist()[j]) - extracted_file_names.append(extracted_filename) - archives[extracted_filename] = filename - result.extend(extracted_file_names[:]) - else: - result.append(filename) - - return result - - -def get_save_file_name(initial_name: str, wav_only=False, caption="Save signal", selected_name_filter=None): +def ask_save_file_name(initial_name: str, caption="Save signal", selected_name_filter=None): global RECENT_PATH if caption == "Save signal": - name_filter = "Complex (*.complex);;" \ - "Complex16 unsigned (*.complex16u *.cu8);;" \ - "Complex16 signed (*.complex16s *.cs8);;" \ - "Complex32 unsigned (*.complex32u *.cu16);;" \ - "Complex32 signed (*.complex32s *.cs16);;" \ - "Complex compressed (*.coco);;" \ - "WAV (*.wav);;" \ - "All Files (*)" - if wav_only: - name_filter = "WAV (*.wav);;All Files (*)" - elif caption == "Save fuzz profile": - name_filter = "Fuzzing Profile (*.fuzz.xml *.fuzz);;All Files (*)" + name_filter = __get__name_filter_for_signals() + elif caption == "Save fuzzing profile": + name_filter = FUZZING_FILE_FILTER elif caption == "Save encoding": name_filter = "" elif caption == "Save simulator profile": - name_filter = "Simulator (*.sim.xml *.sim);;All Files (*)" + name_filter = SIMULATOR_FILE_FILTER elif caption == "Export spectrogram": name_filter = "Frequency Time (*.ft);;Frequency Time Amplitude (*.fta)" + elif caption == "Save protocol": + name_filter = ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER]) else: - name_filter = "Protocols (*.proto.xml *.proto);;Binary Protocol (*.bin);;All Files (*)" + name_filter = EVERYTHING_FILE_FILTER filename = None dialog = QFileDialog(directory=RECENT_PATH, caption=caption, filter=name_filter) dialog.setFileMode(QFileDialog.AnyFile) - dialog.setViewMode(QFileDialog.Detail) dialog.setLabelText(QFileDialog.Accept, "Save") dialog.setAcceptMode(QFileDialog.AcceptSave) @@ -147,23 +118,23 @@ def get_save_file_name(initial_name: str, wav_only=False, caption="Save signal", return filename -def save_data_dialog(signal_name: str, data, sample_rate=1e6, wav_only=False, parent=None) -> str: +def ask_signal_file_name_and_save(signal_name: str, data, sample_rate=1e6, wav_only=False, parent=None) -> str: if wav_only: - if not signal_name.endswith(".wav"): + if not signal_name.endswith(".wav") and not signal_name.endswith(".wave"): signal_name += ".wav" - name_filter = "WAV (*.wav)" + selected_name_filter = WAV_FILE_FILTER else: - if not any(signal_name.endswith(e) for e in FILTER.values()): + if not any(signal_name.endswith(e) for e in SIGNAL_NAME_FILTERS_BY_TYPE.values()): try: - dtype = next(d for d in EXT.keys() if d == data.dtype) - signal_name += EXT[dtype] - name_filter = FILTER[dtype] + dtype = next(d for d in SIGNAL_FILE_EXTENSIONS_BY_TYPE.keys() if d == data.dtype) + signal_name += SIGNAL_FILE_EXTENSIONS_BY_TYPE[dtype] + selected_name_filter = SIGNAL_NAME_FILTERS_BY_TYPE[dtype] except StopIteration: - name_filter = None + selected_name_filter = None else: - name_filter = None + selected_name_filter = None - filename = get_save_file_name(signal_name, wav_only, selected_name_filter=name_filter) + filename = ask_save_file_name(signal_name, selected_name_filter=selected_name_filter) if filename: try: @@ -232,6 +203,41 @@ def rewrite_tar(tar_name: str): shutil.rmtree(tempdir) +def uncompress_archives(file_names, temp_dir): + """ + Extract each archive from the list of filenames. + Normal files stay untouched. + Add all files to the Recent Files. + :type file_names: list of str + :type temp_dir: str + :rtype: list of str + """ + result = [] + for filename in file_names: + if filename.endswith(".tar") or filename.endswith(".tar.gz") or filename.endswith(".tar.bz2"): + obj = tarfile.open(filename, "r") + extracted_file_names = [] + for j, member in enumerate(obj.getmembers()): + obj.extract(member, temp_dir) + extracted_filename = os.path.join(temp_dir, obj.getnames()[j]) + extracted_file_names.append(extracted_filename) + archives[extracted_filename] = filename + result.extend(extracted_file_names[:]) + elif filename.endswith(".zip"): + obj = zipfile.ZipFile(filename) + extracted_file_names = [] + for j, info in enumerate(obj.infolist()): + obj.extract(info, path=temp_dir) + extracted_filename = os.path.join(temp_dir, obj.namelist()[j]) + extracted_file_names.append(extracted_filename) + archives[extracted_filename] = filename + result.extend(extracted_file_names[:]) + else: + result.append(filename) + + return result + + def get_directory(): directory = QFileDialog.getExistingDirectory(None, "Choose Directory", QDir.homePath(), QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) From 70de910152c5813047c1aab6355d787b44f82252 Mon Sep 17 00:00:00 2001 From: jopohl Date: Wed, 8 Jul 2020 13:03:58 +0200 Subject: [PATCH 2/3] remove unused variable and import --- src/urh/util/FileOperator.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/urh/util/FileOperator.py b/src/urh/util/FileOperator.py index 9aa25c1b93..336f5d91ff 100644 --- a/src/urh/util/FileOperator.py +++ b/src/urh/util/FileOperator.py @@ -8,11 +8,8 @@ from PyQt5.QtCore import QDir from PyQt5.QtWidgets import QFileDialog, QMessageBox -from urh.models.FileIconProvider import FileIconProvider from urh.signalprocessing.IQArray import IQArray -VIEW_TYPES = ["Bits", "Hex", "ASCII"] - archives = {} """:type: dict of [str, str] :param: archives[extracted_filename] = filename""" From 76b04fc0424a3bea28dfea6baa455d8909d617a1 Mon Sep 17 00:00:00 2001 From: jopohl Date: Wed, 8 Jul 2020 13:16:29 +0200 Subject: [PATCH 3/3] add signals_only name filter --- src/urh/util/FileOperator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/urh/util/FileOperator.py b/src/urh/util/FileOperator.py index 336f5d91ff..fca4f03c95 100644 --- a/src/urh/util/FileOperator.py +++ b/src/urh/util/FileOperator.py @@ -66,6 +66,8 @@ def get_open_dialog(directory_mode=False, parent=None, name_filter="full") -> QF name_filter = __get__name_filter_for_signals() + ";;" \ + ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER, PLAIN_BITS_FILE_FILTER, FUZZING_FILE_FILTER, SIMULATOR_FILE_FILTER, TAR_FILE_FILTER, ZIP_FILE_FILTER]) + elif name_filter == "signals_only": + name_filter = __get__name_filter_for_signals() elif name_filter == "proto": name_filter = ";;".join([PROTOCOL_FILE_FILTER, BINARY_PROTOCOL_FILE_FILTER]) elif name_filter == "fuzz":