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); _search.Update(path); if (!_search.IsValidPath) { return empty; } var currentFiles = empty; string? fileName; string? currentFullPath; try { currentFullPath = Path.GetFullPath(path); fileName = Path.GetFileName(path); if (File.Exists(currentFullPath)) { var type = CheckExtension(currentFullPath); if (type.HasValue) { currentFiles.Append(new InputEntry(type.Value, path, currentFullPath)); } currentFiles.Append(new InputEntry(InputEntryType.BinaryFile, path, currentFullPath)); } } catch { return empty; } 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 = empty; try { supportedFiles = from file in otherFiles let type = CheckExtension(file.Extension) where type.HasValue select new InputEntry(type.Value, _search.GetInputStyleName(file), file.FullName); } catch { } var binaryFiles = empty; try { binaryFiles = from file in otherFiles select new InputEntry(InputEntryType.BinaryFile, _search.GetInputStyleName(file), file.FullName); } catch { } return currentFiles.Concat(supportedFiles).Concat(directories).Concat(binaryFiles); } private static InputEntryType? CheckExtension(string path) { if (Mapping.TryGetValue(path, 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 { 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 { } } } }