Initial version
This commit is contained in:
commit
e5b6226a85
68 changed files with 7338 additions and 0 deletions
54
DataTransfer.Client/Services/FileNameSanitizer.cs
Normal file
54
DataTransfer.Client/Services/FileNameSanitizer.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace DataTransfer.Client.Services;
|
||||
|
||||
public static class FileNameSanitizer
|
||||
{
|
||||
private const int MaxLength = 255;
|
||||
private const string Fallback = "file";
|
||||
|
||||
// Characters invalid in file names on Windows, macOS or Linux. Path.GetInvalidFileNameChars() returns only the
|
||||
// Unix set in WebAssembly, but the file is saved on any operating system.
|
||||
private const string InvalidCharacters = "<>:\"/\\|?*";
|
||||
|
||||
/// <summary>
|
||||
/// Makes a file name received from the peer safe to display and save. Invisible formatting characters are removed,
|
||||
/// so for example a right-to-left override can't disguise <c>invoice‮fdp.exe</c> as <c>invoiceexe.pdf</c>.
|
||||
/// </summary>
|
||||
public static string Sanitize(string? name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return Fallback;
|
||||
}
|
||||
|
||||
var builder = new StringBuilder(Math.Min(name.Length, MaxLength));
|
||||
foreach (var rune in name.EnumerateRunes())
|
||||
{
|
||||
switch (Rune.GetUnicodeCategory(rune))
|
||||
{
|
||||
case UnicodeCategory.Format:
|
||||
continue;
|
||||
case UnicodeCategory.Control:
|
||||
Append(builder, new Rune('_'));
|
||||
continue;
|
||||
}
|
||||
|
||||
Append(builder, rune.IsAscii && InvalidCharacters.Contains((char)rune.Value) ? new Rune('_') : rune);
|
||||
}
|
||||
|
||||
// Windows silently drops trailing dots and spaces, which could change the extension.
|
||||
var cleaned = builder.ToString().Trim().TrimEnd('.');
|
||||
return cleaned.Length == 0 ? Fallback : cleaned;
|
||||
}
|
||||
|
||||
// Appends whole runes only, so truncation never splits a surrogate pair.
|
||||
private static void Append(StringBuilder builder, Rune rune)
|
||||
{
|
||||
if (builder.Length + rune.Utf16SequenceLength <= MaxLength)
|
||||
{
|
||||
builder.Append(rune.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue