Add support for internal decompressor.

This commit is contained in:
2025-07-26 04:17:26 +01:00
parent 8f789484ca
commit 5937e0d83e
8 changed files with 215 additions and 35 deletions

View File

@@ -15,13 +15,15 @@ using RomRepoMgr.Core.Models;
using RomRepoMgr.Core.Resources; using RomRepoMgr.Core.Resources;
using RomRepoMgr.Database; using RomRepoMgr.Database;
using RomRepoMgr.Database.Models; using RomRepoMgr.Database.Models;
using RomRepoMgr.Settings;
using SabreTools.FileTypes.Aaru; using SabreTools.FileTypes.Aaru;
using SabreTools.FileTypes.CHD; using SabreTools.FileTypes.CHD;
using SharpCompress.Common;
using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.LZMA;
using SharpCompress.Readers;
using ZstdSharp; using ZstdSharp;
using ZstdSharp.Unsafe; using ZstdSharp.Unsafe;
using CompressionMode = SharpCompress.Compressors.CompressionMode; using CompressionMode = SharpCompress.Compressors.CompressionMode;
using CompressionType = RomRepoMgr.Settings.CompressionType;
namespace RomRepoMgr.Core.Workers; namespace RomRepoMgr.Core.Workers;
@@ -84,6 +86,77 @@ public sealed class FileImporter
Finished?.Invoke(this, System.EventArgs.Empty); Finished?.Invoke(this, System.EventArgs.Empty);
} }
public void SeparateFilesAndArchivesManaged()
{
SetProgressBounds?.Invoke(this,
new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = Files.Count
});
ConcurrentBag<string> files = [];
ConcurrentBag<string> 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() public void SeparateFilesAndArchives()
{ {
SetProgressBounds?.Invoke(this, 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); SetIndeterminateProgress2?.Invoke(this, System.EventArgs.Empty);
SetMessage2?.Invoke(this, SetMessage2?.Invoke(this,
@@ -291,7 +361,60 @@ public sealed class FileImporter
Message = Localization.CheckingIfFIleIsAnArchive 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 a floppy contains only the archive, unar will recognize it, on its skipping of SFXs.
if(archiveFormat != null && FAT.Identify(archive)) archiveFormat = null; if(archiveFormat != null && FAT.Identify(archive)) archiveFormat = null;

View File

@@ -42,11 +42,12 @@ public enum CompressionType
public sealed class SetSettings public sealed class SetSettings
{ {
public string DatabasePath { get; set; } public string DatabasePath { get; set; }
public string RepositoryPath { get; set; } public string RepositoryPath { get; set; }
public string TemporaryFolder { get; set; } public string TemporaryFolder { get; set; }
public string UnArchiverPath { get; set; } public string UnArchiverPath { get; set; }
public CompressionType Compression { get; set; } public CompressionType Compression { get; set; }
public bool UseInternalDecompressor { get; set; }
} }
/// <summary>Manages statistics</summary> /// <summary>Manages statistics</summary>
@@ -118,6 +119,11 @@ public static class Settings
((NSNumber)obj).ToString()) ((NSNumber)obj).ToString())
: CompressionType.Lzip; : CompressionType.Lzip;
Current.UseInternalDecompressor =
parsedPreferences.TryGetValue("UseInternalDecompressor", out obj) &&
bool.TryParse(((NSString)obj).ToString(), out bool b) &&
b;
prefsFs.Close(); prefsFs.Close();
} }
else else
@@ -159,10 +165,11 @@ public static class Settings
return; return;
} }
Current.DatabasePath = key.GetValue("DatabasePath") as string; Current.DatabasePath = key.GetValue("DatabasePath") as string;
Current.RepositoryPath = key.GetValue("RepositoryPath") as string; Current.RepositoryPath = key.GetValue("RepositoryPath") as string;
Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string; Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string;
Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string; Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string;
Current.UseInternalDecompressor = key.GetValue("UseInternalDecompressor") as int? > 0;
if(key.GetValue("Compression") is int compression) if(key.GetValue("Compression") is int compression)
Current.Compression = (CompressionType)compression; Current.Compression = (CompressionType)compression;
@@ -243,6 +250,9 @@ public static class Settings
}, },
{ {
"Compression", (NSNumber)(int)Current.Compression "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"); RegistryKey key = parentKey?.CreateSubKey("RomRepoMgr");
key?.SetValue("DatabasePath", Current.DatabasePath); key?.SetValue("DatabasePath", Current.DatabasePath);
key?.SetValue("RepositoryPath", Current.RepositoryPath); key?.SetValue("RepositoryPath", Current.RepositoryPath);
key?.SetValue("TemporaryFolder", Current.TemporaryFolder); key?.SetValue("TemporaryFolder", Current.TemporaryFolder);
key?.SetValue("UnArchiverPath", Current.UnArchiverPath); key?.SetValue("UnArchiverPath", Current.UnArchiverPath);
key?.SetValue("Compression", (int)Current.Compression); key?.SetValue("Compression", (int)Current.Compression);
key?.SetValue("UseInternalDecompressor", Current.UseInternalDecompressor ? 1 : 0);
} }
break; break;

View File

@@ -776,5 +776,11 @@ namespace RomRepoMgr.Resources {
return ResourceManager.GetString("CompressionType", resourceCulture); return ResourceManager.GetString("CompressionType", resourceCulture);
} }
} }
public static string UseInternalDecompressorLabel {
get {
return ResourceManager.GetString("UseInternalDecompressorLabel", resourceCulture);
}
}
} }
} }

View File

@@ -384,4 +384,7 @@ Tardará mucho tiempo...</value>
<data name="CompressionType" xml:space="preserve"> <data name="CompressionType" xml:space="preserve">
<value>Compresión</value> <value>Compresión</value>
</data> </data>
<data name="UseInternalDecompressorLabel" xml:space="preserve">
<value>Usar decompresor interno (soporta menos formatos)</value>
</data>
</root> </root>

View File

@@ -392,4 +392,7 @@ This will take a long time...</value>
<data name="CompressionType" xml:space="preserve"> <data name="CompressionType" xml:space="preserve">
<value>Compression</value> <value>Compression</value>
</data> </data>
<data name="UseInternalDecompressorLabel" xml:space="preserve">
<value>Use internal decompressor (supports less formats)</value>
</data>
</root> </root>

View File

@@ -184,7 +184,11 @@ public sealed partial class ImportRomFolderViewModel : ViewModelBase
_ = Task.Run(() => _ = Task.Run(() =>
{ {
_stopwatch.Restart(); _stopwatch.Restart();
_rootImporter.SeparateFilesAndArchives();
if(Settings.Settings.Current.UseInternalDecompressor)
_rootImporter.SeparateFilesAndArchivesManaged();
else
_rootImporter.SeparateFilesAndArchives();
}); });
} }
else else
@@ -291,7 +295,9 @@ public sealed partial class ImportRomFolderViewModel : ViewModelBase
RemoveFilesChecked); RemoveFilesChecked);
// Extract archive // Extract archive
bool ret = archiveImporter.ExtractArchive(archive); bool ret = Settings.Settings.Current.UseInternalDecompressor
? archiveImporter.ExtractArchiveManaged(archive)
: archiveImporter.ExtractArchive(archive);
if(!ret) return; if(!ret) return;

View File

@@ -65,6 +65,8 @@ public sealed partial class SettingsViewModel : ViewModelBase
string _unArPath; string _unArPath;
[ObservableProperty] [ObservableProperty]
string _unArVersion; string _unArVersion;
bool _useInternalDecompressor;
bool _useInternalDecompressorChanged;
// Mock // Mock
public SettingsViewModel() {} public SettingsViewModel() {}
@@ -84,11 +86,12 @@ public sealed partial class SettingsViewModel : ViewModelBase
DatabaseCommand = new AsyncRelayCommand(ExecuteDatabaseCommandAsync); DatabaseCommand = new AsyncRelayCommand(ExecuteDatabaseCommandAsync);
SaveCommand = new RelayCommand(ExecuteSaveCommand); SaveCommand = new RelayCommand(ExecuteSaveCommand);
DatabasePath = Settings.Settings.Current.DatabasePath; DatabasePath = Settings.Settings.Current.DatabasePath;
RepositoryPath = Settings.Settings.Current.RepositoryPath; RepositoryPath = Settings.Settings.Current.RepositoryPath;
TemporaryPath = Settings.Settings.Current.TemporaryFolder; TemporaryPath = Settings.Settings.Current.TemporaryFolder;
UnArPath = Settings.Settings.Current.UnArchiverPath; UnArPath = Settings.Settings.Current.UnArchiverPath;
Compression = Settings.Settings.Current.Compression; Compression = Settings.Settings.Current.Compression;
UseInternalDecompressor = Settings.Settings.Current.UseInternalDecompressor;
if(!string.IsNullOrWhiteSpace(UnArPath)) CheckUnAr(); 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() void CheckUnAr()
{ {
var worker = new Compression(); var worker = new Compression();
@@ -352,7 +365,14 @@ public sealed partial class SettingsViewModel : ViewModelBase
if(_compressionChanged) Settings.Settings.Current.Compression = Compression; 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(); Settings.Settings.SaveSettings();
_view.Close(); _view.Close();

View File

@@ -41,7 +41,7 @@
<vm:SettingsViewModel /> <vm:SettingsViewModel />
</Design.DataContext> </Design.DataContext>
<Border Padding="15"> <Border Padding="15">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto"> <Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Grid Grid.Row="0" <Grid Grid.Row="0"
ColumnDefinitions="*,250,Auto"> ColumnDefinitions="*,250,Auto">
<TextBlock Grid.Column="0" <TextBlock Grid.Column="0"
@@ -108,8 +108,15 @@
<TextBlock Text="{x:Static resources:Localization.ChooseLabel}" /> <TextBlock Text="{x:Static resources:Localization.ChooseLabel}" />
</Button> </Button>
</Grid> </Grid>
<Grid Grid.Row="3" <CheckBox Grid.Row="2"
ColumnDefinitions="*,250,Auto"> IsChecked="{Binding UseInternalDecompressor, Mode=TwoWay}">
<CheckBox.Content>
<TextBlock Text="{x:Static resources:Localization.UseInternalDecompressorLabel}" />
</CheckBox.Content>
</CheckBox>
<Grid Grid.Row="4"
ColumnDefinitions="*,250,Auto"
IsVisible="{Binding !UseInternalDecompressor}">
<TextBlock Grid.Column="0" <TextBlock Grid.Column="0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -130,12 +137,13 @@
<TextBlock Text="{x:Static resources:Localization.ChooseLabel}" /> <TextBlock Text="{x:Static resources:Localization.ChooseLabel}" />
</Button> </Button>
</Grid> </Grid>
<TextBlock Grid.Row="4" <TextBlock Grid.Row="5"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding UnArVersion, Mode=OneWay}" Text="{Binding UnArVersion, Mode=OneWay}"
FontWeight="Bold" /> FontWeight="Bold"
<Grid Grid.Row="5" IsVisible="{Binding !UseInternalDecompressor}" />
<Grid Grid.Row="6"
ColumnDefinitions="Auto, *"> ColumnDefinitions="Auto, *">
<TextBlock Grid.Column="0" <TextBlock Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -149,7 +157,7 @@
ItemsSource="{Binding CompressionTypes, Mode=OneWay}" ItemsSource="{Binding CompressionTypes, Mode=OneWay}"
Padding="5" /> Padding="5" />
</Grid> </Grid>
<StackPanel Grid.Row="6" <StackPanel Grid.Row="7"
Orientation="Horizontal" Orientation="Horizontal"
HorizontalAlignment="Right"> HorizontalAlignment="Right">
<Button HorizontalAlignment="Right" <Button HorizontalAlignment="Right"