From 5937e0d83e4c2316586dc5a84956d26b77b229ec Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 26 Jul 2025 04:17:26 +0100 Subject: [PATCH] Add support for internal decompressor. --- RomRepoMgr.Core/Workers/FileImporter.cs | 135 +++++++++++++++++- RomRepoMgr.Settings/Settings.cs | 39 +++-- RomRepoMgr/Resources/Localization.Designer.cs | 6 + RomRepoMgr/Resources/Localization.es.resx | 3 + RomRepoMgr/Resources/Localization.resx | 3 + .../ViewModels/ImportRomFolderViewModel.cs | 10 +- RomRepoMgr/ViewModels/SettingsViewModel.cs | 32 ++++- RomRepoMgr/Views/SettingsDialog.axaml | 22 ++- 8 files changed, 215 insertions(+), 35 deletions(-) diff --git a/RomRepoMgr.Core/Workers/FileImporter.cs b/RomRepoMgr.Core/Workers/FileImporter.cs index 9d31e2f..d1df0d3 100644 --- a/RomRepoMgr.Core/Workers/FileImporter.cs +++ b/RomRepoMgr.Core/Workers/FileImporter.cs @@ -15,13 +15,15 @@ using RomRepoMgr.Core.Models; using RomRepoMgr.Core.Resources; using RomRepoMgr.Database; using RomRepoMgr.Database.Models; -using RomRepoMgr.Settings; using SabreTools.FileTypes.Aaru; using SabreTools.FileTypes.CHD; +using SharpCompress.Common; using SharpCompress.Compressors.LZMA; +using SharpCompress.Readers; using ZstdSharp; using ZstdSharp.Unsafe; using CompressionMode = SharpCompress.Compressors.CompressionMode; +using CompressionType = RomRepoMgr.Settings.CompressionType; namespace RomRepoMgr.Core.Workers; @@ -84,6 +86,77 @@ public sealed class FileImporter Finished?.Invoke(this, System.EventArgs.Empty); } + public void SeparateFilesAndArchivesManaged() + { + SetProgressBounds?.Invoke(this, + new ProgressBoundsEventArgs + { + Minimum = 0, + Maximum = Files.Count + }); + + ConcurrentBag files = []; + ConcurrentBag archives = []; + + Parallel.ForEach(Files, + file => + { + SetProgress?.Invoke(this, + new ProgressEventArgs + { + Value = _position + }); + + SetMessage?.Invoke(this, + new MessageEventArgs + { + Message = "Checking archives. Found " + + archives.Count + + " archives and " + + files.Count + + " files." + }); + + SetMessage2?.Invoke(this, + new MessageEventArgs + { + Message = + $"Checking if file {Path.GetFileName(file)} is an archive..." + }); + + SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); + + try + { + using var fs = new FileStream(file, FileMode.Open, FileAccess.Read); + using IReader reader = ReaderFactory.Open(fs); + + archives.Add(file); + } + catch(InvalidOperationException) + { + files.Add(file); + } + + Interlocked.Increment(ref _position); + }); + + Files = files.Order().ToList(); + Archives = archives.Order().ToList(); + + SetMessage?.Invoke(this, + new MessageEventArgs + { + Message = "Finished checking archives. Found " + + Archives.Count + + " archives and " + + Files.Count + + " files." + }); + + Finished?.Invoke(this, System.EventArgs.Empty); + } + public void SeparateFilesAndArchives() { SetProgressBounds?.Invoke(this, @@ -278,11 +351,8 @@ public sealed class FileImporter } } - public bool ExtractArchive(string archive) + public bool ExtractArchiveManaged(string archive) { - string archiveFormat = null; - long archiveFiles = 0; - SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); SetMessage2?.Invoke(this, @@ -291,7 +361,60 @@ public sealed class FileImporter Message = Localization.CheckingIfFIleIsAnArchive }); - archiveFormat = GetArchiveFormat(archive, out archiveFiles); + try + { + using var fs = new FileStream(archive, FileMode.Open, FileAccess.Read); + using IReader reader = ReaderFactory.Open(fs); + + if(!Directory.Exists(Settings.Settings.Current.TemporaryFolder)) + Directory.CreateDirectory(Settings.Settings.Current.TemporaryFolder); + + _archiveFolder = Path.Combine(Settings.Settings.Current.TemporaryFolder, Path.GetRandomFileName()); + + Directory.CreateDirectory(_archiveFolder); + + SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); + + SetMessage2?.Invoke(this, + new MessageEventArgs + { + Message = Localization.ExtractingArchive + }); + + reader.WriteAllToDirectory(_archiveFolder, + new ExtractionOptions + { + ExtractFullPath = true, + Overwrite = true + }); + + Files = Directory.GetFiles(_archiveFolder, "*", SearchOption.AllDirectories).Order().ToList(); + + SetMessage2?.Invoke(this, + new MessageEventArgs + { + Message = "Finished extracting files. Extracted " + Files.Count + " files." + }); + + return true; + } + catch(InvalidOperationException) + { + return false; + } + } + + public bool ExtractArchive(string archive) + { + SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty); + + SetMessage2?.Invoke(this, + new MessageEventArgs + { + Message = Localization.CheckingIfFIleIsAnArchive + }); + + string archiveFormat = GetArchiveFormat(archive, out long archiveFiles); // If a floppy contains only the archive, unar will recognize it, on its skipping of SFXs. if(archiveFormat != null && FAT.Identify(archive)) archiveFormat = null; diff --git a/RomRepoMgr.Settings/Settings.cs b/RomRepoMgr.Settings/Settings.cs index 0d6bd8b..cabca67 100644 --- a/RomRepoMgr.Settings/Settings.cs +++ b/RomRepoMgr.Settings/Settings.cs @@ -42,11 +42,12 @@ public enum CompressionType public sealed class SetSettings { - public string DatabasePath { get; set; } - public string RepositoryPath { get; set; } - public string TemporaryFolder { get; set; } - public string UnArchiverPath { get; set; } - public CompressionType Compression { get; set; } + public string DatabasePath { get; set; } + public string RepositoryPath { get; set; } + public string TemporaryFolder { get; set; } + public string UnArchiverPath { get; set; } + public CompressionType Compression { get; set; } + public bool UseInternalDecompressor { get; set; } } /// Manages statistics @@ -118,6 +119,11 @@ public static class Settings ((NSNumber)obj).ToString()) : CompressionType.Lzip; + Current.UseInternalDecompressor = + parsedPreferences.TryGetValue("UseInternalDecompressor", out obj) && + bool.TryParse(((NSString)obj).ToString(), out bool b) && + b; + prefsFs.Close(); } else @@ -159,10 +165,11 @@ public static class Settings return; } - Current.DatabasePath = key.GetValue("DatabasePath") as string; - Current.RepositoryPath = key.GetValue("RepositoryPath") as string; - Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string; - Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string; + Current.DatabasePath = key.GetValue("DatabasePath") as string; + Current.RepositoryPath = key.GetValue("RepositoryPath") as string; + Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string; + Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string; + Current.UseInternalDecompressor = key.GetValue("UseInternalDecompressor") as int? > 0; if(key.GetValue("Compression") is int compression) Current.Compression = (CompressionType)compression; @@ -243,6 +250,9 @@ public static class Settings }, { "Compression", (NSNumber)(int)Current.Compression + }, + { + "UseInternalDecompressor", new NSNumber(Current.UseInternalDecompressor ? 1 : 0) } }; @@ -273,11 +283,12 @@ public static class Settings RegistryKey key = parentKey?.CreateSubKey("RomRepoMgr"); - key?.SetValue("DatabasePath", Current.DatabasePath); - key?.SetValue("RepositoryPath", Current.RepositoryPath); - key?.SetValue("TemporaryFolder", Current.TemporaryFolder); - key?.SetValue("UnArchiverPath", Current.UnArchiverPath); - key?.SetValue("Compression", (int)Current.Compression); + key?.SetValue("DatabasePath", Current.DatabasePath); + key?.SetValue("RepositoryPath", Current.RepositoryPath); + key?.SetValue("TemporaryFolder", Current.TemporaryFolder); + key?.SetValue("UnArchiverPath", Current.UnArchiverPath); + key?.SetValue("Compression", (int)Current.Compression); + key?.SetValue("UseInternalDecompressor", Current.UseInternalDecompressor ? 1 : 0); } break; diff --git a/RomRepoMgr/Resources/Localization.Designer.cs b/RomRepoMgr/Resources/Localization.Designer.cs index d066071..e430422 100644 --- a/RomRepoMgr/Resources/Localization.Designer.cs +++ b/RomRepoMgr/Resources/Localization.Designer.cs @@ -776,5 +776,11 @@ namespace RomRepoMgr.Resources { return ResourceManager.GetString("CompressionType", resourceCulture); } } + + public static string UseInternalDecompressorLabel { + get { + return ResourceManager.GetString("UseInternalDecompressorLabel", resourceCulture); + } + } } } diff --git a/RomRepoMgr/Resources/Localization.es.resx b/RomRepoMgr/Resources/Localization.es.resx index 428df29..322f73d 100644 --- a/RomRepoMgr/Resources/Localization.es.resx +++ b/RomRepoMgr/Resources/Localization.es.resx @@ -384,4 +384,7 @@ Tardará mucho tiempo... Compresión + + Usar decompresor interno (soporta menos formatos) + \ No newline at end of file diff --git a/RomRepoMgr/Resources/Localization.resx b/RomRepoMgr/Resources/Localization.resx index 45c6aa7..d0ce6cd 100644 --- a/RomRepoMgr/Resources/Localization.resx +++ b/RomRepoMgr/Resources/Localization.resx @@ -392,4 +392,7 @@ This will take a long time... Compression + + Use internal decompressor (supports less formats) + \ No newline at end of file diff --git a/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs b/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs index 70084e5..fe15d6e 100644 --- a/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs +++ b/RomRepoMgr/ViewModels/ImportRomFolderViewModel.cs @@ -184,7 +184,11 @@ public sealed partial class ImportRomFolderViewModel : ViewModelBase _ = Task.Run(() => { _stopwatch.Restart(); - _rootImporter.SeparateFilesAndArchives(); + + if(Settings.Settings.Current.UseInternalDecompressor) + _rootImporter.SeparateFilesAndArchivesManaged(); + else + _rootImporter.SeparateFilesAndArchives(); }); } else @@ -291,7 +295,9 @@ public sealed partial class ImportRomFolderViewModel : ViewModelBase RemoveFilesChecked); // Extract archive - bool ret = archiveImporter.ExtractArchive(archive); + bool ret = Settings.Settings.Current.UseInternalDecompressor + ? archiveImporter.ExtractArchiveManaged(archive) + : archiveImporter.ExtractArchive(archive); if(!ret) return; diff --git a/RomRepoMgr/ViewModels/SettingsViewModel.cs b/RomRepoMgr/ViewModels/SettingsViewModel.cs index 092de10..f0eeb1d 100644 --- a/RomRepoMgr/ViewModels/SettingsViewModel.cs +++ b/RomRepoMgr/ViewModels/SettingsViewModel.cs @@ -65,6 +65,8 @@ public sealed partial class SettingsViewModel : ViewModelBase string _unArPath; [ObservableProperty] string _unArVersion; + bool _useInternalDecompressor; + bool _useInternalDecompressorChanged; // Mock public SettingsViewModel() {} @@ -84,11 +86,12 @@ public sealed partial class SettingsViewModel : ViewModelBase DatabaseCommand = new AsyncRelayCommand(ExecuteDatabaseCommandAsync); SaveCommand = new RelayCommand(ExecuteSaveCommand); - DatabasePath = Settings.Settings.Current.DatabasePath; - RepositoryPath = Settings.Settings.Current.RepositoryPath; - TemporaryPath = Settings.Settings.Current.TemporaryFolder; - UnArPath = Settings.Settings.Current.UnArchiverPath; - Compression = Settings.Settings.Current.Compression; + DatabasePath = Settings.Settings.Current.DatabasePath; + RepositoryPath = Settings.Settings.Current.RepositoryPath; + TemporaryPath = Settings.Settings.Current.TemporaryFolder; + UnArPath = Settings.Settings.Current.UnArchiverPath; + Compression = Settings.Settings.Current.Compression; + UseInternalDecompressor = Settings.Settings.Current.UseInternalDecompressor; if(!string.IsNullOrWhiteSpace(UnArPath)) CheckUnAr(); } @@ -145,6 +148,16 @@ public sealed partial class SettingsViewModel : ViewModelBase } } + public bool UseInternalDecompressor + { + get => _useInternalDecompressor; + set + { + SetProperty(ref _useInternalDecompressor, value); + _useInternalDecompressorChanged = true; + } + } + void CheckUnAr() { var worker = new Compression(); @@ -352,7 +365,14 @@ public sealed partial class SettingsViewModel : ViewModelBase if(_compressionChanged) Settings.Settings.Current.Compression = Compression; - if(_databaseChanged || _repositoryChanged || _temporaryChanged || _unArChanged || _compressionChanged) + if(_useInternalDecompressorChanged) Settings.Settings.Current.UseInternalDecompressor = UseInternalDecompressor; + + if(_databaseChanged || + _repositoryChanged || + _temporaryChanged || + _unArChanged || + _compressionChanged || + _useInternalDecompressorChanged) Settings.Settings.SaveSettings(); _view.Close(); diff --git a/RomRepoMgr/Views/SettingsDialog.axaml b/RomRepoMgr/Views/SettingsDialog.axaml index 25d0c68..de3bbb6 100644 --- a/RomRepoMgr/Views/SettingsDialog.axaml +++ b/RomRepoMgr/Views/SettingsDialog.axaml @@ -41,7 +41,7 @@ - + - + + + + + + - - + -