From 3ee1789316ebb25153ec5f02d3daa11e779b1de5 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Mon, 28 Apr 2025 17:43:47 +0100 Subject: [PATCH] Write paths in errors as escaped ASCII text --- src/archive/error.rs | 4 +++- src/error.rs | 4 ++-- src/game.rs | 8 ++++++-- src/lib.rs | 6 ++++++ src/metadata/error.rs | 16 ++++++++++++---- src/plugin/error.rs | 6 ++++-- 6 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/archive/error.rs b/src/archive/error.rs index 565cba01..ca5caa05 100644 --- a/src/archive/error.rs +++ b/src/archive/error.rs @@ -1,5 +1,7 @@ use std::path::PathBuf; +use crate::escape_ascii; + #[derive(Debug)] pub(crate) struct ArchivePathParsingError { path: PathBuf, @@ -24,7 +26,7 @@ impl std::fmt::Display for ArchivePathParsingError { write!( f, "failed to parse the archive at \"{}\"", - self.path.display() + escape_ascii(&self.path) ) } } diff --git a/src/error.rs b/src/error.rs index 28372120..a0b1e707 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,10 +6,10 @@ pub use crate::plugin::error::PluginDataError; use crate::plugin::error::PluginValidationError; pub use crate::sorting::error::GroupsPathError; -use crate::Vertex; use crate::sorting::error::{ BuildGroupsGraphError, PluginGraphValidationError, SortingError, display_cycle, }; +use crate::{Vertex, escape_ascii}; /// Represents an error that occurred while trying to create a [Game][crate::Game]. #[derive(Debug)] @@ -25,7 +25,7 @@ impl std::fmt::Display for GameHandleCreationError { Self::NotADirectory(p) => write!( f, "the path \"{}\" does not resolve to a directory", - p.display() + escape_ascii(p) ), Self::LoadOrderError(_) => { write!(f, "failed to initialise the load order game settings") diff --git a/src/game.rs b/src/game.rs index 3b1fa27b..b18d1cdb 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1784,12 +1784,16 @@ mod tests { Path::new("b").join(BLANK_ESM), ]; + let expected_path = if cfg!(windows) { + "b\\\\Blank.esm" + } else { + "b/Blank.esm" + }; match game.load_plugins_common(&[&paths[0], &paths[1]], LoadScope::HeaderOnly) { Err(LoadPluginsError::PluginValidationError(e)) => { assert_eq!( format!( - "the path \"{}\" has a filename that is not unique", - paths[1].display() + "the path \"{expected_path}\" has a filename that is not unique" ), e.to_string() ); diff --git a/src/lib.rs b/src/lib.rs index 02e698f3..16a612ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,6 +119,8 @@ mod sorting; mod tests; mod version; +use std::{path::Path, slice::EscapeAscii}; + use fancy_regex::{Error as RegexImplError, Regex, RegexBuilder}; pub use database::{Database, WriteMode}; @@ -137,3 +139,7 @@ fn case_insensitive_regex(value: &str) -> Result> { .build() .map_err(Into::into) } + +fn escape_ascii(path: &Path) -> EscapeAscii { + path.as_os_str().as_encoded_bytes().escape_ascii() +} diff --git a/src/metadata/error.rs b/src/metadata/error.rs index 4d25761e..8414955a 100644 --- a/src/metadata/error.rs +++ b/src/metadata/error.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use fancy_regex::Error as RegexImplError; use saphyr::Marker; -use crate::metadata::MessageContent; +use crate::{escape_ascii, metadata::MessageContent}; use super::yaml::{YamlObjectType, to_unmarked_yaml}; @@ -244,7 +244,11 @@ impl LoadMetadataError { impl std::fmt::Display for LoadMetadataError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "failed to parse the file at \"{}\"", self.path.display()) + write!( + f, + "failed to parse the file at \"{}\"", + escape_ascii(&self.path) + ) } } @@ -380,10 +384,14 @@ impl std::fmt::Display for WriteMetadataError { WriteMetadataErrorReason::ParentDirectoryNotFound => write!( f, "the parent directory of the path \"{}\" was not found", - self.path.display() + escape_ascii(&self.path) ), WriteMetadataErrorReason::PathAlreadyExists => { - write!(f, "the path \"{}\" already exists", self.path.display()) + write!( + f, + "the path \"{}\" already exists", + escape_ascii(&self.path) + ) } WriteMetadataErrorReason::IoError(_) => write!(f, "an I/O error occurred"), } diff --git a/src/plugin/error.rs b/src/plugin/error.rs index 7bef946a..376b0db2 100644 --- a/src/plugin/error.rs +++ b/src/plugin/error.rs @@ -2,6 +2,8 @@ use std::path::PathBuf; use fancy_regex::Error as RegexImplError; +use crate::escape_ascii; + /// Represents an error that occurred while reading a parsed plugin's data. #[derive(Debug)] pub struct PluginDataError(esplugin::Error); @@ -121,13 +123,13 @@ impl std::fmt::Display for PluginValidationError { PluginValidationErrorReason::InvalidFilename(i) => write!( f, "the path \"{}\" has a filename that {}", - self.path.display(), + escape_ascii(&self.path), i ), PluginValidationErrorReason::InvalidPluginHeader => write!( f, "the file at \"{}\" does not have a valid plugin header", - self.path.display() + escape_ascii(&self.path) ), } }