HashCalculator.GUI/FileSystemSuggestions.cs

193 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Diagnostics.CodeAnalysis;
namespace HashCalculator.GUI
{
internal class FileSystemSuggestions
{
private static readonly Dictionary<string, InputEntryType> Mapping = new Dictionary<string, InputEntryType>(StringComparer.OrdinalIgnoreCase)
{
{ ".big", InputEntryType.BigFile },
{ ".xml", InputEntryType.XmlFile },
{ ".w3x", InputEntryType.XmlFile },
{ ".manifest", InputEntryType.ManifestFile },
};
private Search _search = new Search();
[SuppressMessage("Microsoft.Performance", "CA1031")]
public IEnumerable<InputEntry> ProvideFileSystemSuggestions(string? path)
{
var empty = Enumerable.Empty<InputEntry>();
if (string.IsNullOrWhiteSpace(path) || path == null)
{
return empty;
}
path = Environment.ExpandEnvironmentVariables(path);
if (path.IndexOfAny(Path.GetInvalidPathChars()) != -1)
{
return empty;
}
_search.Update(path);
if (!_search.IsValidPath)
{
return empty;
}
var currentFiles = new List<InputEntry>();
string? fileName;
string? currentFullPath = null;
try
{
var currentFile = new FileInfo(path);
fileName = currentFile.Name;
if (currentFile.Exists)
{
currentFullPath = currentFile.FullName;
var type = CheckExtension(currentFile);
if (type is InputEntryType entryType)
{
currentFiles.Add(new InputEntry(entryType, path, currentFullPath));
}
currentFiles.Add(new InputEntry(InputEntryType.BinaryFile, path, currentFullPath));
}
}
catch
{
return empty;
}
var alternatives = empty;
try
{
var directories = from directory in _search.AllDirectories
where directory.Name.StartsWith(fileName, StringComparison.OrdinalIgnoreCase)
select new InputEntry(InputEntryType.Path, _search.GetInputStyleName(directory), directory.FullName);
var otherFiles = from file in _search.AllFiles
where file.Name.StartsWith(fileName, StringComparison.OrdinalIgnoreCase)
where file.FullName != currentFullPath
select file;
var supportedFiles = from file in otherFiles
let type = CheckExtension(file)
where type.HasValue
select new InputEntry(type.Value, _search.GetInputStyleName(file), file.FullName);
var binaryFiles = from file in otherFiles
select new InputEntry(InputEntryType.BinaryFile, _search.GetInputStyleName(file), file.FullName);
alternatives = supportedFiles.Concat(directories).Concat(binaryFiles).ToArray();
}
catch { }
return currentFiles.Concat(alternatives);
}
private static InputEntryType? CheckExtension(FileInfo info)
{
if (Mapping.TryGetValue(info.Extension, out var type))
{
return type;
}
return null;
}
}
internal sealed class Search
{
private string? _inputBaseDirectory;
public bool IsValidPath => _inputBaseDirectory != null;
public IEnumerable<DirectoryInfo> AllDirectories { get; private set; }
public IEnumerable<FileInfo> AllFiles { get; private set; }
public Search()
{
AllDirectories = Array.Empty<DirectoryInfo>();
AllFiles = Array.Empty<FileInfo>();
}
public string GetInputStyleName(FileSystemInfo entry)
{
if (_inputBaseDirectory == null)
{
throw new InvalidOperationException();
}
return Path.Combine(_inputBaseDirectory, entry.Name);
}
[SuppressMessage("Microsoft.Performance", "CA1031")]
public void Update(string path)
{
string? newBaseDirectory = null;
try
{
if (Path.GetFileName(path).IndexOfAny(Path.GetInvalidFileNameChars()) != -1)
{
_inputBaseDirectory = null;
return;
}
newBaseDirectory = Path.GetDirectoryName(path);
var rootDirectory = Path.GetPathRoot(path);
if(string.IsNullOrEmpty(newBaseDirectory) && !string.IsNullOrEmpty(rootDirectory))
{
var last = rootDirectory.LastOrDefault();
if (last != Path.DirectorySeparatorChar && last != Path.AltDirectorySeparatorChar)
{
rootDirectory += Path.DirectorySeparatorChar;
}
newBaseDirectory = rootDirectory;
}
}
catch
{
_inputBaseDirectory = null;
}
if (newBaseDirectory == null)
{
return;
}
if (newBaseDirectory == _inputBaseDirectory)
{
return;
}
_inputBaseDirectory = newBaseDirectory;
Update();
}
[SuppressMessage("Microsoft.Performance", "CA1031")]
private void Update()
{
AllDirectories = Enumerable.Empty<DirectoryInfo>();
AllFiles = Enumerable.Empty<FileInfo>();
try
{
var actualPath = _inputBaseDirectory!.Length == 0
? "."
: _inputBaseDirectory;
var directory = new DirectoryInfo(actualPath);
if (directory.Exists)
{
AllDirectories = directory.EnumerateDirectories();
AllFiles = directory.EnumerateFiles();
}
}
catch { }
}
}
}