private static List <string> GetFMSupportedLanguagesFromInstDir(string fmInstPath, bool earlyOutOnEnglish) { // Get initial list of base FM dirs the normal way: we don't want to count these as lang dirs even if // they're named such (matching FMSel behavior) var searchList = FastIO.GetDirsTopOnly(fmInstPath, "*", ignoreReparsePoints: true); if (searchList.Count == 0) { return(new List <string>()); } #region Move key dirs to end of list (priority) // Searching folders is horrendously slow, so prioritize folders most likely to contain lang dirs so // if we find English, we end up earlying-out much faster for (int i = 0; i < 3; i++) { string keyDir = i switch { 0 => "/books", 1 => "/intrface", _ => "/strings" }; for (int j = 0; j < searchList.Count; j++) { if (j < searchList.Count - 1 && searchList[j].PathEndsWithI(keyDir)) { string item = searchList[j]; searchList.RemoveAt(j); searchList.Add(item); break; } } } #endregion var langsFoundList = new HashSetI(Supported.Length); while (searchList.Count > 0) { string bdPath = searchList[searchList.Count - 1]; searchList.RemoveAt(searchList.Count - 1); bool englishFound = FastIO.SearchDirForLanguages(SupportedHash, bdPath, searchList, langsFoundList, earlyOutOnEnglish); // Matching FMSel behavior: early-out on English if (earlyOutOnEnglish && englishFound) { return new List <string> { "English" } } ; } return(SortLangsToSpec(langsFoundList)); }
/// <summary> /// Helper for finding language-named subdirectories in an installed FM directory. /// </summary> /// <param name="supportedHash"></param> /// <param name="path"></param> /// <param name="searchList"></param> /// <param name="retList"></param> /// <param name="earlyOutOnEnglish"></param> /// <returns><see langword="true"/> if English was found and we quit the search early</returns> internal static bool SearchDirForLanguages( HashSetI supportedHash, string path, List <string> searchList, HashSetI retList, bool earlyOutOnEnglish) { path = NormalizeAndCheckPath(path, pathIsKnownValid: true); using var findHandle = FindFirstFileExW(@"\\?\" + path + "\\*", FINDEX_INFO_LEVELS.FindExInfoBasic, out WIN32_FIND_DATAW findData, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FIND_FIRST_EX_LARGE_FETCH); if (findHandle.IsInvalid) { int err = Marshal.GetLastWin32Error(); if (err is ERROR_FILE_NOT_FOUND or ERROR_NO_MORE_FILES) { return(false); } ThrowException("*", err, path); } do { if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY && // Just ignore reparse points and sidestep any problems (findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != FILE_ATTRIBUTE_REPARSE_POINT && findData.cFileName != "." && findData.cFileName != "..") { if (supportedHash.Contains(findData.cFileName)) { // Add lang dir to found langs list, but not to search list - don't search within lang // dirs (matching FMSel behavior) retList.Add(findData.cFileName); // Matching FMSel behavior: early-out on English if (earlyOutOnEnglish && findData.cFileName.EqualsI("english")) { return(true); } } else { searchList.Add(Path.Combine(path, findData.cFileName)); } } } while (FindNextFileW(findHandle, out findData)); return(false); }
internal static List <string> SortLangsToSpec(HashSetI langsHash) { var ret = new List <string>(Supported.Length); // Return a list of all found languages, sorted in the same order as FMSupportedLanguages // (matching FMSel behavior) if (langsHash.Count > 0) { for (int i = 0; i < Supported.Length; i++) { string sl = Supported[i]; if (langsHash.Contains(sl)) { ret.Add(sl); } } } return(ret); }
public FMTagsCollection(int capacity) { _list = new List <string>(capacity); _hashSet = new HashSetI(capacity); }
public FMTagsCollection() { _list = new List <string>(); _hashSet = new HashSetI(); }
static FMLanguages() { SupportedHash = Supported.ToHashSetI(); }