From ec2717c73a87d05ebf88404249a984c2bc5599a7 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Mon, 24 Aug 2020 04:01:55 +0100 Subject: [PATCH] Add exporting DAT files. --- RomRepoMgr.Core/Workers/Compression.cs | 13 ++ RomRepoMgr/ViewModels/ExportDatViewModel.cs | 162 +++++++++++++++++++ RomRepoMgr/ViewModels/MainWindowViewModel.cs | 27 +++- RomRepoMgr/Views/ExportDat.xaml | 53 ++++++ RomRepoMgr/Views/ExportDat.xaml.cs | 45 ++++++ RomRepoMgr/Views/MainWindow.xaml | 1 + 6 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 RomRepoMgr/ViewModels/ExportDatViewModel.cs create mode 100644 RomRepoMgr/Views/ExportDat.xaml create mode 100644 RomRepoMgr/Views/ExportDat.xaml.cs diff --git a/RomRepoMgr.Core/Workers/Compression.cs b/RomRepoMgr.Core/Workers/Compression.cs index f42805b..e80ae89 100644 --- a/RomRepoMgr.Core/Workers/Compression.cs +++ b/RomRepoMgr.Core/Workers/Compression.cs @@ -83,6 +83,19 @@ namespace RomRepoMgr.Core.Workers outFs.Dispose(); } + public void DecompressFile(string source, string destination) + { + var inFs = new FileStream(source, FileMode.Open, FileAccess.Read); + var outFs = new FileStream(destination, FileMode.Create, FileAccess.Write); + Stream zStream = new LZipStream(inFs, CompressionMode.Decompress); + + zStream.CopyTo(outFs); + + outFs.Close(); + zStream.Close(); + inFs.Close(); + } + public bool CheckUnar(string unArPath) { if(string.IsNullOrWhiteSpace(unArPath)) diff --git a/RomRepoMgr/ViewModels/ExportDatViewModel.cs b/RomRepoMgr/ViewModels/ExportDatViewModel.cs new file mode 100644 index 0000000..951fa76 --- /dev/null +++ b/RomRepoMgr/ViewModels/ExportDatViewModel.cs @@ -0,0 +1,162 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +using System.IO; +using System.Reactive; +using System.Threading.Tasks; +using Avalonia.Threading; +using JetBrains.Annotations; +using ReactiveUI; +using RomRepoMgr.Core; +using RomRepoMgr.Core.EventArgs; +using RomRepoMgr.Core.Workers; +using RomRepoMgr.Views; +using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs; + +namespace RomRepoMgr.ViewModels +{ + public sealed class ExportDatViewModel : ViewModelBase + { + readonly string _datHash; + readonly string _outPath; + readonly ExportDat _view; + readonly Compression _worker; + bool _canClose; + string _errorMessage; + bool _errorVisible; + bool _progressVisible; + string _statusMessage; + + public ExportDatViewModel(ExportDat view, string datHash, string outPath) + { + _view = view; + _datHash = datHash; + _outPath = outPath; + CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand); + ProgressVisible = false; + ErrorVisible = false; + _worker = new Compression(); + _worker.FinishedWithText += OnWorkerOnFinishedWithText; + _worker.FailedWithText += OnWorkerOnFailedWithText; + } + + [NotNull] + public string Title => "Exporting DAT file..."; + + public string StatusMessage + { + get => _statusMessage; + set => this.RaiseAndSetIfChanged(ref _statusMessage, value); + } + + public bool ProgressVisible + { + get => _progressVisible; + set => this.RaiseAndSetIfChanged(ref _progressVisible, value); + } + + public bool ErrorVisible + { + get => _errorVisible; + set => this.RaiseAndSetIfChanged(ref _errorVisible, value); + } + + public string ErrorMessage + { + get => _errorMessage; + set => this.RaiseAndSetIfChanged(ref _errorMessage, value); + } + + public bool CanClose + { + get => _canClose; + set => this.RaiseAndSetIfChanged(ref _canClose, value); + } + + public string CloseLabel => "Close"; + public ReactiveCommand CloseCommand { get; } + + void OnWorkerOnFinishedWithText(object sender, MessageEventArgs args) => Dispatcher.UIThread.Post(() => + { + StatusMessage = "Finished"; + ProgressVisible = false; + CanClose = true; + }); + + void OnWorkerOnFailedWithText(object sender, ErrorEventArgs args) => Dispatcher.UIThread.Post(() => + { + ErrorMessage = args.Message; + ProgressVisible = false; + ErrorVisible = true; + CanClose = true; + }); + + void ExecuteCloseCommand() => _view.Close(); + + internal void OnOpened() + { + ProgressVisible = true; + StatusMessage = "Decompressing DAT file..."; + + byte[] sha384Bytes = new byte[48]; + string sha384 = _datHash; + + for(int i = 0; i < 48; i++) + { + if(sha384[i * 2] >= 0x30 && + sha384[i * 2] <= 0x39) + sha384Bytes[i] = (byte)((sha384[i * 2] - 0x30) * 0x10); + else if(sha384[i * 2] >= 0x41 && + sha384[i * 2] <= 0x46) + sha384Bytes[i] = (byte)((sha384[i * 2] - 0x37) * 0x10); + else if(sha384[i * 2] >= 0x61 && + sha384[i * 2] <= 0x66) + sha384Bytes[i] = (byte)((sha384[i * 2] - 0x57) * 0x10); + + if(sha384[(i * 2) + 1] >= 0x30 && + sha384[(i * 2) + 1] <= 0x39) + sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x30); + else if(sha384[(i * 2) + 1] >= 0x41 && + sha384[(i * 2) + 1] <= 0x46) + sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x37); + else if(sha384[(i * 2) + 1] >= 0x61 && + sha384[(i * 2) + 1] <= 0x66) + sha384Bytes[i] += (byte)(sha384[(i * 2) + 1] - 0x57); + } + + string datHash32 = Base32.ToBase32String(sha384Bytes); + string datFilesPath = Path.Combine(Settings.Settings.Current.RepositoryPath, "datfiles"); + string compressedDatPath = Path.Combine(datFilesPath, datHash32 + ".lz"); + + if(!File.Exists(compressedDatPath)) + _view.Close(); + + Task.Run(() => + { + _worker.DecompressFile(compressedDatPath, _outPath); + }); + } + } +} \ No newline at end of file diff --git a/RomRepoMgr/ViewModels/MainWindowViewModel.cs b/RomRepoMgr/ViewModels/MainWindowViewModel.cs index 01a5846..c834a96 100644 --- a/RomRepoMgr/ViewModels/MainWindowViewModel.cs +++ b/RomRepoMgr/ViewModels/MainWindowViewModel.cs @@ -57,6 +57,7 @@ namespace RomRepoMgr.ViewModels ImportRomFolderCommand = ReactiveCommand.Create(ExecuteImportRomFolderCommand); DeleteRomSetCommand = ReactiveCommand.Create(ExecuteDeleteRomSetCommand); EditRomSetCommand = ReactiveCommand.Create(ExecuteEditRomSetCommand); + ExportDatCommand = ReactiveCommand.Create(ExecuteExportDatCommand); RomSets = new ObservableCollection(romSets); } @@ -75,7 +76,6 @@ namespace RomRepoMgr.ViewModels public string RomSetHaveRomsLabel => "Have"; public string RomSetMissRomsLabel => "Miss"; - public string Greeting => "Hello World!"; public bool NativeMenuSupported => NativeMenu.GetIsNativeMenuExported((Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow); @@ -88,6 +88,7 @@ namespace RomRepoMgr.ViewModels public ReactiveCommand ImportRomFolderCommand { get; } public ReactiveCommand DeleteRomSetCommand { get; } public ReactiveCommand EditRomSetCommand { get; } + public ReactiveCommand ExportDatCommand { get; } public RomSetModel SelectedRomSet { @@ -219,6 +220,9 @@ namespace RomRepoMgr.ViewModels void ExecuteEditRomSetCommand() { + if(SelectedRomSet == null) + return; + var window = new EditDat(); var viewModel = new EditDatViewModel(window, SelectedRomSet); @@ -237,5 +241,26 @@ namespace RomRepoMgr.ViewModels window.Show(); } + + async void ExecuteExportDatCommand() + { + if(SelectedRomSet == null) + return; + + var dlgSave = new SaveFileDialog + { + InitialFileName = SelectedRomSet.Filename + }; + + string result = await dlgSave.ShowAsync(_view); + + if(result == null) + return; + + var dialog = new ExportDat(); + var viewModel = new ExportDatViewModel(dialog, SelectedRomSet.Sha384, result); + dialog.DataContext = viewModel; + await dialog.ShowDialog(_view); + } } } \ No newline at end of file diff --git a/RomRepoMgr/Views/ExportDat.xaml b/RomRepoMgr/Views/ExportDat.xaml new file mode 100644 index 0000000..4a9b7b5 --- /dev/null +++ b/RomRepoMgr/Views/ExportDat.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RomRepoMgr/Views/ExportDat.xaml.cs b/RomRepoMgr/Views/ExportDat.xaml.cs new file mode 100644 index 0000000..0e135e4 --- /dev/null +++ b/RomRepoMgr/Views/ExportDat.xaml.cs @@ -0,0 +1,45 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +using System; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using RomRepoMgr.ViewModels; + +namespace RomRepoMgr.Views +{ + public sealed class ExportDat : Window + { + public ExportDat() => InitializeComponent(); + + void InitializeComponent() => AvaloniaXamlLoader.Load(this); + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + (DataContext as ExportDatViewModel)?.OnOpened(); + } + } +} \ No newline at end of file diff --git a/RomRepoMgr/Views/MainWindow.xaml b/RomRepoMgr/Views/MainWindow.xaml index 91608ac..0a9fb3e 100644 --- a/RomRepoMgr/Views/MainWindow.xaml +++ b/RomRepoMgr/Views/MainWindow.xaml @@ -21,6 +21,7 @@ +