diff --git a/CHANGELOG.md b/CHANGELOG.md index 83a4d9fdb..6f2969b8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file. ## v1.35.1 +### Bugfixes +- [Core] Skip corrupted .acf files in Steam library (#4200 by: HebaruSan) ## v1.35.0 (Oberth) diff --git a/Core/Extensions/EnumerableExtensions.cs b/Core/Extensions/EnumerableExtensions.cs index 76dd1da99..64a38025b 100644 --- a/Core/Extensions/EnumerableExtensions.cs +++ b/Core/Extensions/EnumerableExtensions.cs @@ -262,6 +262,22 @@ public static IEnumerable WithMatches(this IEnumerable source, Re => source.Select(val => pattern.TryMatch(val, out Match? match) ? match : null) .OfType(); + /// + /// Apply a function to a sequence and handle any exceptions that are thrown + /// + /// Type of source sequence + /// Type of destination sequence + /// Source sequence + /// Function to apply to each item + /// Function to call if there's an exception + /// Sequence of return values of given function + public static IEnumerable SelectWithCatch(this IEnumerable source, + Func func, + Func onThrow) + where TDest : class + => source.Select(item => Utilities.DefaultIfThrows(() => func(item), + exc => onThrow(item, exc))); + } /// diff --git a/Core/SteamLibrary.cs b/Core/SteamLibrary.cs index 284352f82..71531046f 100644 --- a/Core/SteamLibrary.cs +++ b/Core/SteamLibrary.cs @@ -5,6 +5,7 @@ using log4net; using ValveKeyValue; +using CKAN.Extensions; namespace CKAN { @@ -57,8 +58,14 @@ public IEnumerable GameAppURLs(DirectoryInfo gameDir) private static IEnumerable LibraryPathGames(KVSerializer acfParser, string appPath) => Directory.EnumerateFiles(appPath, "*.acf") - .Select(acfFile => acfParser.Deserialize(File.OpenRead(acfFile)) - .NormalizeDir(Path.Combine(appPath, "common"))); + .SelectWithCatch(acfFile => acfParser.Deserialize(File.OpenRead(acfFile)) + .NormalizeDir(Path.Combine(appPath, "common")), + (acfFile, exc) => + { + log.Warn($"Failed to parse {acfFile}:", exc); + return default; + }) + .OfType(); private static IEnumerable ShortcutsFileGames(KVSerializer vdfParser, string path) diff --git a/Core/Utilities.cs b/Core/Utilities.cs index 2d48cf846..c0db6e563 100644 --- a/Core/Utilities.cs +++ b/Core/Utilities.cs @@ -28,15 +28,23 @@ public static class Utilities "nl-NL", }; - public static T? DefaultIfThrows(Func func) where T : class + /// + /// Call a function and take a default action if it throws an exception + /// + /// Return type of the function + /// Function to call + /// Function to call if an exception is thrown + /// Return value of the function + public static T? DefaultIfThrows(Func func, + Func? onThrow = null) where T : class { try { return func(); } - catch + catch (Exception exc) { - return default; + return onThrow?.Invoke(exc) ?? default; } }