Make filename character replacement more xplat and allow replacing any char, not just illegal.

This commit is contained in:
Michael Bucari-Tovo 2022-12-15 15:50:48 -07:00
parent 80bcf60b5b
commit a0dd2ccad6
9 changed files with 1141 additions and 1133 deletions

View file

@ -69,7 +69,7 @@ namespace FileManager
= IsWindows
? new()
{
Replacements = new List<Replacement>()
Replacements = new Replacement[]
{
Replacement.OtherInvalid("_"),
Replacement.FilenameForwardSlash(""),
@ -87,7 +87,7 @@ namespace FileManager
}
: new()
{
Replacements = new List<Replacement>()
Replacements = new Replacement[]
{
Replacement.OtherInvalid("_"),
Replacement.FilenameForwardSlash(""),
@ -102,7 +102,7 @@ namespace FileManager
= IsWindows
? new()
{
Replacements = new List<Replacement>()
Replacements = new Replacement[]
{
Replacement.OtherInvalid("_"),
Replacement.FilenameForwardSlash("_"),
@ -121,7 +121,7 @@ namespace FileManager
= IsWindows
? new ()
{
Replacements = new List<Replacement>()
Replacements = new Replacement[]
{
Replacement.OtherInvalid("_"),
Replacement.FilenameForwardSlash("_"),
@ -133,7 +133,7 @@ namespace FileManager
}
: new ()
{
Replacements = new List<Replacement>()
Replacements = new Replacement[]
{
Replacement.OtherInvalid("_"),
Replacement.FilenameForwardSlash("_"),
@ -147,11 +147,11 @@ namespace FileManager
private static bool IsWindows => Environment.OSVersion.Platform is PlatformID.Win32NT;
private static readonly char[] invalidPathChars = Path.GetInvalidFileNameChars().Except(new[] {
'\\', '/'
Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar
}).ToArray();
private static readonly char[] invalidSlashes = Path.GetInvalidFileNameChars().Intersect(new[] {
'\\', '/'
Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar
}).ToArray();
public IReadOnlyList<Replacement> Replacements { get; init; }
@ -214,7 +214,7 @@ namespace FileManager
public static bool ContainsInvalidFilenameChar(string path)
=> ContainsInvalidPathChar(path) || path.Any(c => invalidSlashes.Contains(c));
public string ReplaceInvalidFilenameChars(string fileName)
public string ReplaceFilenameChars(string fileName)
{
if (string.IsNullOrEmpty(fileName)) return string.Empty;
var builder = new System.Text.StringBuilder();
@ -222,7 +222,9 @@ namespace FileManager
{
var c = fileName[i];
if (invalidPathChars.Contains(c) || invalidSlashes.Contains(c))
if (invalidPathChars.Contains(c)
|| invalidSlashes.Contains(c)
|| Replacements.Any(r => r.CharacterToReplace == c) /* Replace any other legal characters that they user wants. */ )
{
char preceding = i > 0 ? fileName[i - 1] : default;
char succeeding = i < fileName.Length - 1 ? fileName[i + 1] : default;
@ -230,29 +232,42 @@ namespace FileManager
}
else
builder.Append(c);
}
return builder.ToString();
}
public string ReplaceInvalidPathChars(string pathStr)
public string ReplacePathChars(string pathStr)
{
if (string.IsNullOrEmpty(pathStr)) return string.Empty;
// replace all colons except within the first 2 chars
var builder = new System.Text.StringBuilder();
for (var i = 0; i < pathStr.Length; i++)
{
var c = pathStr[i];
if (!invalidPathChars.Contains(c) || (c == ':' && i == 1 && Path.IsPathRooted(pathStr)))
builder.Append(c);
else
if (
(
invalidPathChars.Contains(c)
|| ( // Replace any other legal characters that they user wants.
c != Path.DirectorySeparatorChar
&& c != Path.AltDirectorySeparatorChar
&& Replacements.Any(r => r.CharacterToReplace == c)
)
)
&& !( // replace all colons except drive letter designator on Windows
c == ':'
&& i == 1
&& Path.IsPathRooted(pathStr)
&& IsWindows
)
)
{
char preceding = i > 0 ? pathStr[i - 1] : default;
char succeeding = i < pathStr.Length - 1 ? pathStr[i + 1] : default;
builder.Append(GetPathCharReplacement(c, preceding, succeeding));
char preceding = i > 0 ? pathStr[i - 1] : default;
char succeeding = i < pathStr.Length - 1 ? pathStr[i + 1] : default;
builder.Append(GetPathCharReplacement(c, preceding, succeeding));
}
else
builder.Append(c);
}
return builder.ToString();
}
@ -274,28 +289,19 @@ namespace FileManager
//Ensure that the first 6 replacements are for the expected chars and that all replacement strings are valid.
//If not, reset to default.
var default0 = Replacement.OtherInvalid("");
var default1 = Replacement.FilenameForwardSlash("");
var default2 = Replacement.FilenameBackSlash("");
var default3 = Replacement.OpenQuote("");
var default4 = Replacement.CloseQuote("");
var default5 = Replacement.OtherQuote("");
if (dict.Count < Replacement.FIXED_COUNT ||
dict[0].CharacterToReplace != default0.CharacterToReplace || dict[0].Description != default0.Description ||
dict[1].CharacterToReplace != default1.CharacterToReplace || dict[1].Description != default1.Description ||
dict[2].CharacterToReplace != default2.CharacterToReplace || dict[2].Description != default2.Description ||
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.ContainsInvalidFilenameChar(r.ReplacementString))
)
{
dict = ReplacementCharacters.Default.Replacements;
}
//First FIXED_COUNT are mandatory
for (int i = 0; i < Replacement.FIXED_COUNT; i++)
{
if (dict.Count < Replacement.FIXED_COUNT
|| dict[i].CharacterToReplace != ReplacementCharacters.Barebones.Replacements[i].CharacterToReplace
|| dict[i].Description != ReplacementCharacters.Barebones.Replacements[i].Description)
{
dict = ReplacementCharacters.Default.Replacements;
break;
}
//First FIXED_COUNT are mandatory
dict[i].Mandatory = true;
}
return new ReplacementCharacters { Replacements = dict };
}
@ -305,7 +311,7 @@ namespace FileManager
ReplacementCharacters replacements = (ReplacementCharacters)value;
var propertyNames = replacements.Replacements
.Select(c => JObject.FromObject(c)).ToList();
.Select(JObject.FromObject).ToList();
var prop = new JProperty(nameof(Replacement), new JArray(propertyNames));