Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
MUIFileSearcher.cs342 linesDownload Raw Back to help
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Globalization;8using System.IO;9using System.Text.RegularExpressions;10 11namespace System.Management.Automation12{13    internal sealed class MUIFileSearcher14    {15        /// <summary>16        /// Constructor. It is private so that MUIFileSearcher is used only internal for this class.17        /// To access functionality in this class, static api should be used.18        /// </summary>19        /// <param name="target"></param>20        /// <param name="searchPaths"></param>21        /// <param name="searchMode"></param>22        private MUIFileSearcher(string target, Collection<string> searchPaths, SearchMode searchMode)23        {24            Target = target;25            SearchPaths = searchPaths;26            SearchMode = searchMode;27        }28 29        /// <summary>30        /// A constructor to make searchMode optional.31        /// </summary>32        /// <param name="target"></param>33        /// <param name="searchPaths"></param>34        private MUIFileSearcher(string target, Collection<string> searchPaths)35            : this(target, searchPaths, SearchMode.Unique)36        {37        }38 39        #region Basic Properties40 41        /// <summary>42        /// Search target. It can be43        ///     1. a file name44        ///     2. a search pattern45        /// It can also include a path, in that case,46        ///     1. the path will be searched first for the existence of the files.47        /// </summary>48        internal string Target { get; } = null;49 50        /// <summary>51        /// Search path as provided by user.52        /// </summary>53        internal Collection<string> SearchPaths { get; } = null;54 55        /// <summary>56        /// Search mode for this file search.57        /// </summary>58        internal SearchMode SearchMode { get; } = SearchMode.Unique;59 60        private static readonly System.IO.EnumerationOptions _enumerationOptions = new()61        {62            IgnoreInaccessible = false,63            AttributesToSkip = 0,64            MatchType = MatchType.Win32,65            MatchCasing = MatchCasing.CaseInsensitive,66        };67 68        private Collection<string> _result = null;69 70        /// <summary>71        /// Result of the search.72        /// </summary>73        internal Collection<string> Result74        {75            get76            {77                if (_result == null)78                {79                    _result = new Collection<string>();80 81                    // SearchForFiles will fill the result collection.82                    SearchForFiles();83                }84 85                return _result;86            }87        }88 89        #endregion90 91        #region File Search92 93        /// <summary>94        /// _uniqueMatches is used to track matches already found during the search process.95        /// This is useful for ignoring duplicates in the case of unique search.96        /// </summary>97        private readonly Hashtable _uniqueMatches = new Hashtable(StringComparer.OrdinalIgnoreCase);98 99        /// <summary>100        /// Search for files using the target, searchPaths member of this class.101        /// </summary>102        private void SearchForFiles()103        {104            if (string.IsNullOrEmpty(this.Target))105                return;106 107            string pattern = Path.GetFileName(this.Target);108            if (string.IsNullOrEmpty(pattern))109                return;110 111            Collection<string> normalizedSearchPaths = NormalizeSearchPaths(this.Target, this.SearchPaths);112 113            foreach (string directory in normalizedSearchPaths)114            {115                SearchForFiles(pattern, directory);116 117                if (this.SearchMode == SearchMode.First && this.Result.Count > 0)118                {119                    return;120                }121            }122        }123 124        private void AddFiles(string muiDirectory, string directory, string pattern)125        {126            if (Directory.Exists(muiDirectory))127            {128                foreach (string file in Directory.EnumerateFiles(muiDirectory, pattern, _enumerationOptions))129                {130                    string path = Path.Combine(muiDirectory, file);131 132                    switch (this.SearchMode)133                    {134                        case SearchMode.All:135                            _result.Add(path);136                            break;137 138                        case SearchMode.Unique:139                            // Construct a Unique filename for this directory.140                            // Remember the file may belong to one of the sub-culture141                            // directories. In this case we should not be returning142                            // same files that are residing in 2 or more sub-culture143                            // directories.144                            string leafFileName = Path.GetFileName(file);145                            string uniqueToDirectory = Path.Combine(directory, leafFileName);146 147                            if (!_result.Contains(path) && !_uniqueMatches.Contains(uniqueToDirectory))148                            {149                                _result.Add(path);150                                _uniqueMatches[uniqueToDirectory] = true;151                            }152 153                            break;154 155                        case SearchMode.First:156                            _result.Add(path);157                            return;158 159                        default:160                            break;161                    }162                }163            }164        }165 166        /// <summary>167        /// Search for files of a particular pattern under a particular directory.168        /// This will do MUI search in which appropriate language directories are169        /// searched in order.170        /// </summary>171        /// <param name="pattern"></param>172        /// <param name="directory"></param>173        private void SearchForFiles(string pattern, string directory)174        {175            List<string> cultureNameList = new List<string>();176            CultureInfo culture = CultureInfo.CurrentUICulture;177 178            while (culture != null && !string.IsNullOrEmpty(culture.Name))179            {180                cultureNameList.Add(culture.Name);181                culture = culture.Parent;182            }183 184            cultureNameList.Add(string.Empty);185 186            // Add en-US and en as fallback languages187            if (!cultureNameList.Contains("en-US"))188            {189                cultureNameList.Add("en-US");190            }191 192            if (!cultureNameList.Contains("en"))193            {194                cultureNameList.Add("en");195            }196 197            foreach (string name in cultureNameList)198            {199                string muiDirectory = Path.Combine(directory, name);200 201                AddFiles(muiDirectory, directory, pattern);202 203                if (this.SearchMode == SearchMode.First && this.Result.Count > 0)204                {205                    return;206                }207            }208 209            return;210        }211 212        /// <summary>213        /// A help file is located in 3 steps214        ///     1. If file itself contains a path itself, try to locate the file215        ///        from path. LocateFile will fail if this file doesn't exist.216        ///     2. Try to locate the file from searchPaths. Normally the searchPaths will217        ///        contain the cmdlet/provider assembly directory if currently we are searching218        ///        help for cmdlet and providers.219        ///     3. Try to locate the file in the default PowerShell installation directory.220        /// </summary>221        /// <param name="target"></param>222        /// <param name="searchPaths"></param>223        /// <returns></returns>224        private static Collection<string> NormalizeSearchPaths(string target, Collection<string> searchPaths)225        {226            Collection<string> result = new Collection<string>();227 228            // step 1: if target has path attached, directly locate229            //         file from there.230            if (!string.IsNullOrEmpty(target) && !string.IsNullOrEmpty(Path.GetDirectoryName(target)))231            {232                string directory = Path.GetDirectoryName(target);233 234                if (Directory.Exists(directory))235                {236                    result.Add(Path.GetFullPath(directory));237                }238 239                // user specifically wanted to search in a particular directory240                // so return..241                return result;242            }243 244            // step 2: add directories specified in to search path.245            if (searchPaths != null)246            {247                foreach (string directory in searchPaths)248                {249                    if (!result.Contains(directory) && Directory.Exists(directory))250                    {251                        result.Add(directory);252                    }253                }254            }255 256            // step 3: locate the file in the default PowerShell installation directory.257            string defaultPSPath = Utils.GetApplicationBase(Utils.DefaultPowerShellShellID);258            if (defaultPSPath != null &&259                !result.Contains(defaultPSPath) &&260                Directory.Exists(defaultPSPath))261            {262                result.Add(defaultPSPath);263            }264 265            return result;266        }267 268        #endregion269 270        #region Static API's271 272        /// <summary>273        /// Search for files in default search paths.274        /// </summary>275        /// <param name="pattern"></param>276        /// <returns></returns>277        internal static Collection<string> SearchFiles(string pattern)278        {279            return SearchFiles(pattern, new Collection<string>());280        }281 282        /// <summary>283        /// Search for files in specified search paths.284        /// </summary>285        /// <param name="pattern"></param>286        /// <param name="searchPaths"></param>287        /// <returns></returns>288        internal static Collection<string> SearchFiles(string pattern, Collection<string> searchPaths)289        {290            MUIFileSearcher searcher = new MUIFileSearcher(pattern, searchPaths);291 292            return searcher.Result;293        }294 295        /// <summary>296        /// Locate a file in default search paths.297        /// </summary>298        /// <param name="file"></param>299        /// <returns></returns>300        internal static string LocateFile(string file)301        {302            return LocateFile(file, new Collection<string>());303        }304 305        /// <summary>306        /// Get the file in different search paths corresponding to current culture.307        ///308        /// The file name to search is the filename part of path parameter. (Normally path309        /// parameter should contain only the filename part).310        /// </summary>311        /// <param name="file">This is the path to the file. If it has a path, we need to search under that path first.</param>312        /// <param name="searchPaths">Additional search paths.</param>313        /// <returns></returns>314        internal static string LocateFile(string file, Collection<string> searchPaths)315        {316            MUIFileSearcher searcher = new MUIFileSearcher(file, searchPaths, SearchMode.First);317 318            if (searcher.Result == null || searcher.Result.Count == 0)319                return null;320 321            return searcher.Result[0];322        }323 324        #endregion325    }326 327    /// <summary>328    /// This enum defines different search mode for the MUIFileSearcher.329    /// </summary>330    internal enum SearchMode331    {332        // return the first match333        First,334 335        // return all matches, with duplicates allowed336        All,337 338        // return all matches, with duplicates ignored339        Unique340    }341}342