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 Mapping = new Dictionary(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 ProvideFileSystemSuggestions(string? path) { var empty = Enumerable.Empty(); 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(); 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 AllDirectories { get; private set; } public IEnumerable AllFiles { get; private set; } public Search() { AllDirectories = Array.Empty(); AllFiles = Array.Empty(); } 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(); AllFiles = Enumerable.Empty(); try { var actualPath = _inputBaseDirectory!.Length == 0 ? "." : _inputBaseDirectory; var directory = new DirectoryInfo(actualPath); if (directory.Exists) { AllDirectories = directory.EnumerateDirectories(); AllFiles = directory.EnumerateFiles(); } } catch { } } } }