mirror of
https://github.com/claunia/romrepomgr.git
synced 2025-12-16 19:24:51 +00:00
Add support for internal decompressor.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
6
RomRepoMgr/Resources/Localization.Designer.cs
generated
6
RomRepoMgr/Resources/Localization.Designer.cs
generated
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user