diff --git a/Source/FileManager/ReplacementCharacters.cs b/Source/FileManager/ReplacementCharacters.cs index cc93451b..8c11b10d 100644 --- a/Source/FileManager/ReplacementCharacters.cs +++ b/Source/FileManager/ReplacementCharacters.cs @@ -61,59 +61,97 @@ namespace FileManager [JsonConverter(typeof(ReplacementCharactersConverter))] public class ReplacementCharacters { - public static readonly ReplacementCharacters Default = new() + static ReplacementCharacters() { - Replacements = new List() - { - Replacement.OtherInvalid("_"), - Replacement.FilenameForwardSlash("∕"), - Replacement.FilenameBackSlash(""), - Replacement.OpenQuote("“"), - Replacement.CloseQuote("”"), - Replacement.OtherQuote("""), - Replacement.OpenAngleBracket("<"), - Replacement.CloseAngleBracket(">"), - Replacement.Colon("꞉"), - Replacement.Asterisk("✱"), - Replacement.QuestionMark("?"), - Replacement.Pipe("⏐"), - } - }; - public static readonly ReplacementCharacters LoFiDefault = new() - { - Replacements = new List() + } + public static readonly ReplacementCharacters Default + = IsWindows + ? new() { - Replacement.OtherInvalid("_"), - Replacement.FilenameForwardSlash("_"), - Replacement.FilenameBackSlash("_"), - Replacement.OpenQuote("'"), - Replacement.CloseQuote("'"), - Replacement.OtherQuote("'"), - Replacement.OpenAngleBracket("{"), - Replacement.CloseAngleBracket("}"), - Replacement.Colon("-"), + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("∕"), + Replacement.FilenameBackSlash(""), + Replacement.OpenQuote("“"), + Replacement.CloseQuote("”"), + Replacement.OtherQuote("""), + Replacement.OpenAngleBracket("<"), + Replacement.CloseAngleBracket(">"), + Replacement.Colon("꞉"), + Replacement.Asterisk("✱"), + Replacement.QuestionMark("?"), + Replacement.Pipe("⏐"), + } } - }; - - public static readonly ReplacementCharacters Barebones = new() - { - Replacements = new List() + : new() { - Replacement.OtherInvalid("_"), - Replacement.FilenameForwardSlash("_"), - Replacement.FilenameBackSlash("_"), - Replacement.OpenQuote("_"), - Replacement.CloseQuote("_"), - Replacement.OtherQuote("_"), - } - }; + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("∕"), + Replacement.FilenameBackSlash(""), + Replacement.OpenQuote("“"), + Replacement.CloseQuote("”"), + Replacement.OtherQuote(""") + } + }; - private static readonly char[] invalidChars = Path.GetInvalidPathChars().Union(new[] { - '*', '?', ':', - // these are weird. If you run Path.GetInvalidPathChars() in Visual Studio's "C# Interactive", then these characters are included. - // In live code, Path.GetInvalidPathChars() does not include them - '"', '<', '>' + public static readonly ReplacementCharacters LoFiDefault + = IsWindows + ? new() + { + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("_"), + Replacement.OpenQuote("'"), + Replacement.CloseQuote("'"), + Replacement.OtherQuote("'"), + Replacement.OpenAngleBracket("{"), + Replacement.CloseAngleBracket("}"), + Replacement.Colon("-"), + } + } + : Barebones; + + public static readonly ReplacementCharacters Barebones + = IsWindows + ? new () + { + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("_"), + Replacement.OpenQuote("_"), + Replacement.CloseQuote("_"), + Replacement.OtherQuote("_") + } + } + : new () + { + Replacements = new List() + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("\\"), + Replacement.OpenQuote("\""), + Replacement.CloseQuote("\""), + Replacement.OtherQuote("\"") + } + }; + + private static bool IsWindows => Environment.OSVersion.Platform is PlatformID.Win32NT; + + private static readonly char[] invalidPathChars = Path.GetInvalidFileNameChars().Except(new[] { + '\\', '/' + }).ToArray(); + + private static readonly char[] invalidSlashes = Path.GetInvalidFileNameChars().Intersect(new[] { + '\\', '/' }).ToArray(); public IReadOnlyList Replacements { get; init; } @@ -126,10 +164,13 @@ namespace FileManager private string GetFilenameCharReplacement(char toReplace, char preceding, char succeding) { - if (toReplace == ForwardSlash.CharacterToReplace) - return ForwardSlash.ReplacementString; - else if (toReplace == BackSlash.CharacterToReplace) - return BackSlash.ReplacementString; + if (invalidSlashes.Contains(toReplace)) + { + if (toReplace == ForwardSlash.CharacterToReplace) + return ForwardSlash.ReplacementString; + else + return BackSlash.ReplacementString; + } else return GetPathCharReplacement(toReplace, preceding, succeding); } private string GetPathCharReplacement(char toReplace, char preceding, char succeding) @@ -158,6 +199,7 @@ namespace FileManager return OtherQuote; } + //Replace any other non-mandatory characters for (int i = Replacement.FIXED_COUNT; i < Replacements.Count; i++) { var r = Replacements[i]; @@ -167,11 +209,10 @@ namespace FileManager return DefaultReplacement; } - public static bool ContainsInvalidPathChar(string path) - => path.Any(c => invalidChars?.Contains(c) == true); + => path.Any(c => invalidPathChars.Contains(c)); public static bool ContainsInvalidFilenameChar(string path) - => path.Any(c => invalidChars?.Concat(new char[] { '\\', '/' })?.Contains(c) == true); + => ContainsInvalidPathChar(path) || path.Any(c => invalidSlashes.Contains(c)); public string ReplaceInvalidFilenameChars(string fileName) { @@ -181,7 +222,7 @@ namespace FileManager { var c = fileName[i]; - if (invalidChars.Contains(c) || c == ForwardSlash.CharacterToReplace || c == BackSlash.CharacterToReplace) + if (invalidPathChars.Contains(c) || invalidSlashes.Contains(c)) { char preceding = i > 0 ? fileName[i - 1] : default; char succeeding = i < fileName.Length - 1 ? fileName[i + 1] : default; @@ -204,7 +245,7 @@ namespace FileManager { var c = pathStr[i]; - if (!invalidChars.Contains(c) || (c == ':' && i == 1 && Path.IsPathRooted(pathStr))) + if (!invalidPathChars.Contains(c) || (c == ':' && i == 1 && Path.IsPathRooted(pathStr))) builder.Append(c); else { @@ -212,7 +253,6 @@ namespace FileManager char succeeding = i < pathStr.Length - 1 ? pathStr[i + 1] : default; builder.Append(GetPathCharReplacement(c, preceding, succeeding)); } - } return builder.ToString(); } @@ -248,7 +288,7 @@ namespace FileManager dict[3].CharacterToReplace != default3.CharacterToReplace || dict[3].Description != default3.Description || dict[4].CharacterToReplace != default4.CharacterToReplace || dict[4].Description != default4.Description || dict[5].CharacterToReplace != default5.CharacterToReplace || dict[5].Description != default5.Description || - dict.Any(r => ReplacementCharacters.ContainsInvalidPathChar(r.ReplacementString)) + dict.Any(r => ReplacementCharacters.ContainsInvalidFilenameChar(r.ReplacementString)) ) { dict = ReplacementCharacters.Default.Replacements; diff --git a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs index 5524678e..d6905e9e 100644 --- a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs @@ -143,7 +143,7 @@ namespace LibationAvalonia.Dialogs get => _replacementText; set { - if (ReplacementCharacters.ContainsInvalidPathChar(value)) + if (ReplacementCharacters.ContainsInvalidFilenameChar(value)) this.RaisePropertyChanged(nameof(ReplacementText)); else this.RaiseAndSetIfChanged(ref _replacementText, value); @@ -158,7 +158,7 @@ namespace LibationAvalonia.Dialogs set { - if (value?.Length != 1 || !ReplacementCharacters.ContainsInvalidPathChar(value)) + if (value?.Length != 1 || !ReplacementCharacters.ContainsInvalidFilenameChar(value)) this.RaisePropertyChanged(nameof(CharacterToReplace)); else { diff --git a/Source/LibationWinForms/Dialogs/EditReplacementChars.cs b/Source/LibationWinForms/Dialogs/EditReplacementChars.cs index a24b4371..75762a90 100644 --- a/Source/LibationWinForms/Dialogs/EditReplacementChars.cs +++ b/Source/LibationWinForms/Dialogs/EditReplacementChars.cs @@ -101,7 +101,7 @@ namespace LibationWinForms.Dialogs { dataGridView1.Rows[e.RowIndex].ErrorText = $"The {charToReplaceStr[0]} character is already being replaced"; } - else if (ReplacementCharacters.ContainsInvalidPathChar(replacement)) + else if (ReplacementCharacters.ContainsInvalidFilenameChar(replacement)) { dataGridView1.Rows[e.RowIndex].ErrorText = $"Your {replacementStringCol.HeaderText} contains illegal characters"; }