diff --git a/rslib/src/media/files.rs b/rslib/src/media/files.rs index a72fd45d3..0a1070bc1 100644 --- a/rslib/src/media/files.rs +++ b/rslib/src/media/files.rs @@ -192,14 +192,25 @@ fn truncate_filename(fname: &str, max_bytes: usize) -> Cow { let (stem, ext) = split_and_truncate_filename(fname, max_bytes); - format!("{}.{}", stem, ext).into() + let mut new_name = if ext.is_empty() { + stem.to_string() + } else { + format!("{}.{}", stem, ext) + }; + + // make sure we don't break Windows by ending with a space or dot + if WINDOWS_TRAILING_CHAR.is_match(&new_name) { + new_name.push('_'); + } + + new_name.into() } /// Split filename into stem and extension, and trim both so the /// resulting filename would be under max_bytes. /// Returns (stem, extension) fn split_and_truncate_filename(fname: &str, max_bytes: usize) -> (&str, &str) { - // the code assumes the length will be at least 11 + // the code assumes max_bytes will be at least 11 debug_assert!(max_bytes > 10); let mut iter = fname.rsplitn(2, '.'); @@ -216,8 +227,8 @@ fn split_and_truncate_filename(fname: &str, max_bytes: usize) -> (&str, &str) { // cap extension to 10 bytes so stem_len can't be negative ext = truncate_to_char_boundary(ext, 10); - // cap stem, allowing for the . - let stem_len = max_bytes - ext.len() - 1; + // cap stem, allowing for the . and a trailing _ + let stem_len = max_bytes - ext.len() - 2; stem = truncate_to_char_boundary(stem, stem_len); (stem, ext) @@ -394,7 +405,7 @@ pub(super) fn data_for_file(media_folder: &Path, fname: &str) -> Result::Owned("x".repeat(MAX_FILENAME_LENGTH - 2)) + ); + assert_eq!( + truncate_filename(&" ".repeat(MAX_FILENAME_LENGTH + 1), MAX_FILENAME_LENGTH), + Cow::::Owned(format!("{}_", " ".repeat(MAX_FILENAME_LENGTH - 2))) + ); + } }