diff --git a/Source/FileManager/FileNamingTemplate.cs b/Source/FileManager/FileNamingTemplate.cs index d951d8a0..49270c3b 100644 --- a/Source/FileManager/FileNamingTemplate.cs +++ b/Source/FileManager/FileNamingTemplate.cs @@ -62,16 +62,6 @@ namespace FileManager private static string replaceFileName(string filename, Dictionary paramReplacements, int maxFilenameLength) { - //Filename limits on NTFS and FAT filesystems are based on characters, - //but on ext* filesystems they're based on bytes. The ext* filesystems - //don't care about encoding, so how unicode characters are encoded is - ///a choice made by the linux kernel. As best as I can tell, pretty - //much everyone uses UTF-8. - int getFilesystemStringLength(StringBuilder str) - => LongPath.IsWindows ? - str.Length - : Encoding.UTF8.GetByteCount(str.ToString()); - List filenameParts = new(); //Build the filename in parts, replacing replacement parameters with //their values, and storing the parts in a list. @@ -106,7 +96,7 @@ namespace FileManager //Remove 1 character from the end of the longest filename part until //the total filename is less than max filename length - while (filenameParts.Sum(p => getFilesystemStringLength(p)) > maxFilenameLength) + while (filenameParts.Sum(p => LongPath.GetFilesystemStringLength(p)) > maxFilenameLength) { int maxLength = filenameParts.Max(p => p.Length); var maxEntry = filenameParts.First(p => p.Length == maxLength); diff --git a/Source/FileManager/LongPath.cs b/Source/FileManager/LongPath.cs index 11002cd7..3c10a56f 100644 --- a/Source/FileManager/LongPath.cs +++ b/Source/FileManager/LongPath.cs @@ -13,6 +13,13 @@ namespace FileManager public const int MaxFilenameLength = 255; public static readonly int MaxDirectoryLength; public static readonly int MaxPathLength; + private const int WIN_MAX_PATH = 260; + private const string WIN_LONG_PATH_PREFIX = @"\\?\"; + internal static readonly bool IsWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + internal static readonly bool IsLinux = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + internal static readonly bool IsOSX = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + public string Path { get; } static LongPath() { @@ -33,25 +40,26 @@ namespace FileManager } } - private const int WIN_MAX_PATH = 260; - private const string WIN_LONG_PATH_PREFIX = @"\\?\"; - private LongPath(string path) { if (IsWindows && path.Length > MaxPathLength) throw new System.IO.PathTooLongException($"Path exceeds {MaxPathLength} character limit. ({path})"); - if ((!IsWindows && Encoding.UTF8.GetByteCount(path) > MaxPathLength)) + if (!IsWindows && Encoding.UTF8.GetByteCount(path) > MaxPathLength) throw new System.IO.PathTooLongException($"Path exceeds {MaxPathLength} byte limit. ({path})"); - + Path = path; } - public string Path { get; } - public override string ToString() => Path; + + //Filename limits on NTFS and FAT filesystems are based on characters, + //but on ext* filesystems they're based on bytes. The ext* filesystems + //don't care about encoding, so how unicode characters are encoded is + ///a choice made by the linux kernel. As best as I can tell, pretty + //much everyone uses UTF-8. + public static int GetFilesystemStringLength(StringBuilder filename) + => LongPath.IsWindows ? + filename.Length + : Encoding.UTF8.GetByteCount(filename.ToString()); - internal static readonly bool IsWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - internal static readonly bool IsLinux = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - internal static readonly bool IsOSX = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - public static implicit operator LongPath(string path) { if (!IsWindows) return new LongPath(path); @@ -153,6 +161,9 @@ namespace FileManager } } + public override string ToString() => Path; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] private static extern int GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder shortPath, int shortPathLength);