From d9389c2b5342d06dfce3ca45bdb24d960195ff8d Mon Sep 17 00:00:00 2001 From: Adrien Ufferte Date: Fri, 24 Oct 2025 12:02:39 +0200 Subject: [PATCH] Check filename is not invalid for windows platform --- folder_unzipper.gd | 41 +++++++++++++++++--------- sources/utils/autoloads/database.gd | 45 ++++++++++++++++++----------- sources/utils/autoloads/utils.gd | 30 +++++++++++++++++++ 3 files changed, 86 insertions(+), 30 deletions(-) diff --git a/folder_unzipper.gd b/folder_unzipper.gd index d083fed5..549b5d66 100644 --- a/folder_unzipper.gd +++ b/folder_unzipper.gd @@ -14,9 +14,10 @@ func extract(zip_path: String, extract_path: String, extract_in_subfolder: bool Log.trace("FolderUnzipper: Extracting %s to %s" % [zip_path, extract_path]) var err: Error = open(zip_path) if err != OK: - Log.error("FolderUnzipper: Error " + error_string(err) + " while opening file: %s" % zip_path) + Log.error("FolderUnzipper: Error %s while opening %s" % [error_string(err), zip_path]) close() return "" + var extract_folder: String = extract_path.path_join(zip_path.get_file().get_basename()) if extract_in_subfolder else extract_path var all_files: PackedStringArray = get_files() @@ -26,32 +27,46 @@ func extract(zip_path: String, extract_path: String, extract_in_subfolder: bool var copied_file: int = 0 var first_folder: String = "" var last_sub_path: String = "" + for sub_path: String in all_files: last_sub_path = sub_path if _is_directory_path(sub_path): first_folder = sub_path.trim_suffix("/") break + if not first_folder and last_sub_path != "": first_folder = last_sub_path.split("/")[0] + for sub_path: String in all_files: - var file_name: String = extract_folder.path_join(sub_path) - var folder_name: String = file_name.get_base_dir() - if not DirAccess.dir_exists_absolute(folder_name): - DirAccess.make_dir_recursive_absolute(folder_name) if _is_directory_path(sub_path): continue + + var file_name: String = extract_folder.path_join(sub_path) + file_name = Utils.get_safe_file_path(file_name) + + var folder_name: String = file_name.get_base_dir() + if not DirAccess.dir_exists_absolute(folder_name): + var mkdir_err: Error = DirAccess.make_dir_recursive_absolute(folder_name) + if mkdir_err != OK: + Log.error("FolderUnzipper: Cannot create directory %s. Error: %s" % [folder_name, error_string(mkdir_err)]) + continue + var file: FileAccess = FileAccess.open(file_name, FileAccess.WRITE) var error: Error = FileAccess.get_open_error() - if error != OK: + + if error != OK or file == null: Log.error("FolderUnzipper: Extract: Cannot open file %s. Error: %s" % [file_name, error_string(error)]) - close() - return "" - if file == null: - Log.error("FolderUnzipper: Extract: Cannot open file %s. File is null" % file_name) - close() - return "" - file.store_buffer(read_file(sub_path)) + continue + + var data: PackedByteArray = read_file(sub_path) + if typeof(data) != TYPE_PACKED_BYTE_ARRAY or data.is_empty(): + Log.warn("FolderUnzipper: Empty or invalid data for %s" % sub_path) + file.close() + continue + + file.store_buffer(data) file.close() + Log.trace("FolderUnzipper: Copied %s" % file_name) copied_file += 1 file_copied.emit(copied_file, file_name) diff --git a/sources/utils/autoloads/database.gd b/sources/utils/autoloads/database.gd index 68622fa7..3d7b9c73 100644 --- a/sources/utils/autoloads/database.gd +++ b/sources/utils/autoloads/database.gd @@ -596,35 +596,46 @@ func get_kalulu_speech_path(speech_category: String, speech_name: String) -> Str func load_external_sound(path: String) -> AudioStreamMP3: Log.trace("Database: Load External Sound: %s" % path) + + path = Utils.get_safe_file_path(path) + if not FileAccess.file_exists(path): path = UnicodeNormalizer.to_nfd_basic(path) - Log.trace("Database: Load External Sound: file not found: trying to normalize path to unicode NFD: %s" % path) + Log.trace("Database: Load External Sound: File not found, retrying with Unicode NFD: %s" % path) if not FileAccess.file_exists(path): path = UnicodeNormalizer.to_nfd_extended(path) - Log.trace("Database: Load External Sound: file not found: trying to normalize path to unicode NFD extended: %s" % path) + Log.trace("Database: Load External Sound: File not found, retrying with Unicode NFD extended: %s" % path) if not FileAccess.file_exists(path): - Log.error("Database: Load External Sound: file not found even after unicode normalization") + Log.error("Database: Load External Sound: File not found after normalization attempts") return null - Log.trace("Database: Load External Sound: file found.") - Log.trace("Database: Load External Sound: Opening file.") + var file: FileAccess = FileAccess.open(path, FileAccess.READ) var error: Error = FileAccess.get_open_error() - if error != OK: + if error != OK or file == null: Log.error("Database: Load External Sound: Cannot open file %s. Error: %s" % [path, error_string(error)]) return null - if file == null: - Log.error("Database: Load External Sound: Cannot open file %s. File is null") - return null + var file_length: int = file.get_length() - Log.trace("Database: Load External Sound: File length = %d" % file_length) - Log.trace("Database: Load External Sound: Creating audio stream") - var audio_stream: AudioStreamMP3 = AudioStreamMP3.new() - audio_stream.data = file.get_buffer(file_length) + if file_length <= 0: + Log.error("Database: Load External Sound: Invalid file length for %s" % path) + file.close() + return null + + var data: PackedByteArray = file.get_buffer(file_length) file.close() - if not audio_stream: - Log.error("Database: Load External Sound: Audio stream is not valid") - elif audio_stream == null: - Log.error("Database: Load External Sound: Audio stream is null") + + if data.is_empty(): + Log.error("Database: Load External Sound: Empty buffer read for %s" % path) + return null + + var audio_stream: AudioStreamMP3 = AudioStreamMP3.new() + audio_stream.data = data + + if not audio_stream or audio_stream == null: + Log.error("Database: Load External Sound: Failed to create AudioStreamMP3 for %s" % path) + return null + + Log.trace("Database: Load External Sound: Loaded %s successfully (%d bytes)" % [path, file_length]) return audio_stream diff --git a/sources/utils/autoloads/utils.gd b/sources/utils/autoloads/utils.gd index 0de9c0fe..3c24ea43 100644 --- a/sources/utils/autoloads/utils.gd +++ b/sources/utils/autoloads/utils.gd @@ -61,3 +61,33 @@ func compare_versions(version_a: String, version_b: String) -> int: elif ai > bi: return 1 return 0 + + +func get_safe_file_path(file_path: String) -> String: + var dir: String = file_path.get_base_dir() + var file: String = file_path.get_file() + var base: String = file.get_basename() + var ext: String = file.get_extension() + + var reserved_names: Array[String] = [ + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" + ] + + var invalid_chars: Array[String] = ["/", "\\", ":", "*", "?", "\"", "<", ">", "|"] + for chara: String in invalid_chars: + base = base.replace(chara, "_") + + var modified: bool = false + if base.to_upper() in reserved_names: + base = "_" + base + modified = true + + var new_name: String = "%s.%s" % [base, ext] if ext != "" else base + var new_path: String = dir.path_join(new_name) if dir != "" else new_name + + if modified or new_path != file_path: + Log.trace("Utils: GetSafeFilePath: Renamed invalid file path: '%s' → '%s'" % [file_path, new_path]) + + return new_path