Files
Aaru/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs

999 lines
33 KiB
C#
Raw Normal View History

2020-04-17 21:45:50 +01:00
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : MediaDumpViewModel.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : GUI view models.
//
// --[ Description ] ----------------------------------------------------------
//
// View model and code for the media dump window.
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2024-05-01 04:17:32 +01:00
// Copyright © 2011-2024 Natalia Portillo
2020-04-17 21:45:50 +01:00
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Aaru.CommonTypes;
using Aaru.CommonTypes.AaruMetadata;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Metadata;
using Aaru.Core;
using Aaru.Core.Devices.Dumping;
using Aaru.Core.Logging;
using Aaru.Core.Media.Info;
using Aaru.Devices;
using Aaru.Gui.Models;
using Aaru.Localization;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using DynamicData;
2020-07-22 13:20:25 +01:00
using JetBrains.Annotations;
2023-09-26 01:29:07 +01:00
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using ReactiveUI;
using DeviceInfo = Aaru.Core.Devices.Info.DeviceInfo;
using Dump = Aaru.Core.Devices.Dumping.Dump;
using File = System.IO.File;
using MediaType = Aaru.CommonTypes.MediaType;
namespace Aaru.Gui.ViewModels.Windows;
2022-03-06 13:29:38 +00:00
public sealed class MediaDumpViewModel : ViewModelBase
{
2022-03-06 13:29:38 +00:00
readonly string _devicePath;
readonly Window _view;
bool _closeVisible;
string _destination;
bool _destinationEnabled;
Device _dev;
Dump _dumper;
string _encodingEnabled;
bool _encodingVisible;
bool _existingMetadata;
bool _force;
string _formatReadOnly;
string _log;
bool _optionsVisible;
string _outputPrefix;
bool _persistent;
bool _progress1Visible;
bool _progress2Indeterminate;
double _progress2MaxValue;
string _progress2Text;
double _progress2Value;
bool _progress2Visible;
bool _progressIndeterminate;
double _progressMaxValue;
string _progressText;
double _progressValue;
bool _progressVisible;
Resume _resume;
double _retries;
EncodingModel _selectedEncoding;
ImagePluginModel _selectedPlugin;
Metadata _sidecar;
2022-03-06 13:29:38 +00:00
double _skipped;
bool _startVisible;
bool _stopEnabled;
bool _stopOnError;
bool _stopVisible;
bool _track1Pregap;
bool _track1PregapVisible;
bool _trim;
bool _useResume;
bool _useSidecar;
2023-10-03 23:27:57 +01:00
public MediaDumpViewModel(string devicePath, DeviceInfo deviceInfo, Window view,
2022-03-06 13:29:38 +00:00
[CanBeNull] ScsiInfo scsiInfo = null)
{
_view = view;
DestinationEnabled = true;
StartVisible = true;
CloseVisible = true;
OptionsVisible = true;
StartCommand = ReactiveCommand.Create(ExecuteStartCommand);
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StopCommand = ReactiveCommand.Create(ExecuteStopCommand);
DestinationCommand = ReactiveCommand.Create(ExecuteDestinationCommand);
2024-05-01 04:39:38 +01:00
PluginsList = [];
Encodings = [];
2022-03-06 13:29:38 +00:00
// Defaults
StopOnError = false;
Force = false;
Persistent = true;
Resume = true;
Track1Pregap = false;
Sidecar = true;
Trim = true;
ExistingMetadata = false;
Retries = 5;
Skipped = 512;
MediaType mediaType;
if(scsiInfo != null)
mediaType = scsiInfo.MediaType;
else
2023-10-03 23:27:57 +01:00
{
2022-03-06 13:29:38 +00:00
switch(deviceInfo.Type)
{
case DeviceType.SecureDigital:
mediaType = MediaType.SecureDigital;
2022-03-06 13:29:38 +00:00
break;
case DeviceType.MMC:
mediaType = MediaType.MMC;
2022-03-06 13:29:38 +00:00
break;
default:
if(deviceInfo.IsPcmcia)
mediaType = MediaType.PCCardTypeII;
else if(deviceInfo.IsCompactFlash)
mediaType = MediaType.CompactFlash;
else
mediaType = MediaType.GENERIC_HDD;
2022-03-06 13:29:38 +00:00
break;
}
2023-10-03 23:27:57 +01:00
}
PluginRegister plugins = PluginRegister.Singleton;
foreach(IWritableImage plugin in plugins.WritableImages.Values)
{
2024-05-01 04:05:22 +01:00
if(plugin is null) continue;
if(plugin.SupportedMediaTypes.Contains(mediaType))
2023-10-03 23:27:57 +01:00
{
PluginsList.Add(new ImagePluginModel
{
Plugin = plugin
});
2023-10-03 23:27:57 +01:00
}
}
2024-05-01 04:05:22 +01:00
Encodings.AddRange(Encoding.GetEncodings()
.Select(info => new EncodingModel
{
Name = info.Name,
DisplayName = info.GetEncoding().EncodingName
}));
2024-05-01 04:05:22 +01:00
Encodings.AddRange(Claunia.Encoding.Encoding.GetEncodings()
.Select(info => new EncodingModel
{
Name = info.Name,
DisplayName = info.DisplayName
}));
2022-03-06 13:29:38 +00:00
Track1PregapVisible = mediaType switch
{
MediaType.CD
or MediaType.CDDA
or MediaType.CDG
or MediaType.CDEG
or MediaType.CDI
or MediaType.CDROM
or MediaType.CDROMXA
or MediaType.CDPLUS
or MediaType.CDMO
or MediaType.CDR
or MediaType.CDRW
or MediaType.CDMRW
or MediaType.VCD
or MediaType.SVCD
or MediaType.PCD
or MediaType.DDCD
or MediaType.DDCDR
or MediaType.DDCDRW
or MediaType.DTSCD
or MediaType.CDMIDI
or MediaType.CDV
or MediaType.CDIREADY
or MediaType.FMTOWNS
or MediaType.PS1CD
or MediaType.PS2CD
or MediaType.MEGACD
or MediaType.SATURNCD
or MediaType.GDROM
or MediaType.GDR
or MediaType.MilCD
or MediaType.SuperCDROM2
or MediaType.JaguarCD
or MediaType.ThreeDO
or MediaType.PCFX
or MediaType.NeoGeoCD
or MediaType.CDTV
or MediaType.CD32
or MediaType.Playdia
or MediaType.Pippin
or MediaType.VideoNow
or MediaType.VideoNowColor
or MediaType.VideoNowXp
or MediaType.CVD => true,
_ => false
};
2022-03-06 13:29:38 +00:00
_devicePath = devicePath;
}
public string OutputFormatLabel => UI.Output_format;
public string ChooseLabel => UI.ButtonLabel_Choose;
public string StopOnErrorLabel => UI.Stop_media_dump_on_first_error;
public string ForceLabel => UI.Continue_dumping_whatever_happens;
public string RetriesLabel => UI.Retry_passes;
public string PersistentLabel => UI.Try_to_recover_partial_or_incorrect_data;
2023-10-03 12:59:30 +01:00
public string ResumeLabel => UI.Create_or_use_resume_mapfile;
public string Track1PregapLabel => UI.Try_to_read_track_1_pregap;
public string SkippedLabel => UI.Skipped_sectors_on_error;
public string SidecarLabel => UI.Create_Aaru_Metadata_sidecar;
public string TrimLabel => UI.Trim_errors_from_skipped_sectors;
public string ExistingMetadataLabel => UI.Take_metadata_from_existing_CICM_XML_sidecar;
public string EncodingLabel => UI.Encoding_to_use_on_metadata_sidecar_creation;
public string DestinationLabel => UI.Writing_image_to;
public string LogLabel => UI.Title_Log;
public string StartLabel => UI.ButtonLabel_Start;
public string CloseLabel => UI.ButtonLabel_Close;
public string StopLabel => UI.ButtonLabel_Stop;
2022-03-06 13:29:38 +00:00
public ReactiveCommand<Unit, Unit> StartCommand { get; }
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
public ReactiveCommand<Unit, Unit> StopCommand { get; }
public ReactiveCommand<Unit, Task> DestinationCommand { get; }
2022-03-06 13:29:38 +00:00
public ObservableCollection<ImagePluginModel> PluginsList { get; }
public ObservableCollection<EncodingModel> Encodings { get; }
2022-03-06 13:29:38 +00:00
public string Title { get; }
2022-03-06 13:29:38 +00:00
public bool OptionsVisible
{
get => _optionsVisible;
set => this.RaiseAndSetIfChanged(ref _optionsVisible, value);
}
public ImagePluginModel SelectedPlugin
{
get => _selectedPlugin;
set
{
this.RaiseAndSetIfChanged(ref _selectedPlugin, value);
2022-03-06 13:29:38 +00:00
Destination = "";
2022-03-06 13:29:38 +00:00
if(value is null)
{
DestinationEnabled = false;
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
DestinationEnabled = true;
2022-03-06 13:29:38 +00:00
if(!value.Plugin.SupportedOptions.Any())
{
2022-03-06 13:29:38 +00:00
// Hide options
}
2022-03-06 13:29:38 +00:00
/* TODO: Plugin options
grpOptions.Visible = true;
2022-03-06 13:29:38 +00:00
var stkOptions = new StackLayout
{
Orientation = Orientation.Vertical
};
foreach((string name, Type type, string description, object @default) option in plugin.SupportedOptions)
switch(option.type.ToString())
{
2022-03-06 13:29:38 +00:00
case "System.Boolean":
var optBoolean = new CheckBox();
optBoolean.ID = "opt" + option.name;
optBoolean.Text = option.description;
optBoolean.Checked = (bool)option.@default;
stkOptions.Items.Add(optBoolean);
2022-03-06 13:29:38 +00:00
break;
case "System.SByte":
case "System.Int16":
case "System.Int32":
case "System.Int64":
var stkNumber = new StackLayout();
stkNumber.Orientation = Orientation.Horizontal;
var optNumber = new NumericStepper();
optNumber.ID = "opt" + option.name;
optNumber.Value = Convert.ToDouble(option.@default);
stkNumber.Items.Add(optNumber);
var lblNumber = new Label();
lblNumber.Text = option.description;
stkNumber.Items.Add(lblNumber);
stkOptions.Items.Add(stkNumber);
2022-03-06 13:29:38 +00:00
break;
case "System.Byte":
case "System.UInt16":
case "System.UInt32":
case "System.UInt64":
var stkUnsigned = new StackLayout();
stkUnsigned.Orientation = Orientation.Horizontal;
var optUnsigned = new NumericStepper();
optUnsigned.ID = "opt" + option.name;
optUnsigned.MinValue = 0;
optUnsigned.Value = Convert.ToDouble(option.@default);
stkUnsigned.Items.Add(optUnsigned);
var lblUnsigned = new Label();
lblUnsigned.Text = option.description;
stkUnsigned.Items.Add(lblUnsigned);
stkOptions.Items.Add(stkUnsigned);
2022-03-06 13:29:38 +00:00
break;
case "System.Single":
case "System.Double":
var stkFloat = new StackLayout();
stkFloat.Orientation = Orientation.Horizontal;
var optFloat = new NumericStepper();
optFloat.ID = "opt" + option.name;
optFloat.DecimalPlaces = 2;
optFloat.Value = Convert.ToDouble(option.@default);
stkFloat.Items.Add(optFloat);
var lblFloat = new Label();
lblFloat.Text = option.description;
stkFloat.Items.Add(lblFloat);
stkOptions.Items.Add(stkFloat);
2022-03-06 13:29:38 +00:00
break;
case "System.Guid":
// TODO
break;
case "System.String":
var stkString = new StackLayout();
stkString.Orientation = Orientation.Horizontal;
var lblString = new Label();
lblString.Text = option.description;
stkString.Items.Add(lblString);
var optString = new TextBox();
optString.ID = "opt" + option.name;
optString.Text = (string)option.@default;
stkString.Items.Add(optString);
stkOptions.Items.Add(stkString);
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
grpOptions.Content = stkOptions;
*/
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
public string FormatReadOnly
{
get => _formatReadOnly;
set => this.RaiseAndSetIfChanged(ref _formatReadOnly, value);
}
2022-03-06 13:29:38 +00:00
public string Destination
{
get => _destination;
set => this.RaiseAndSetIfChanged(ref _destination, value);
}
2022-03-06 13:29:38 +00:00
public bool DestinationEnabled
{
get => _destinationEnabled;
set => this.RaiseAndSetIfChanged(ref _destinationEnabled, value);
}
2022-03-06 13:29:38 +00:00
public bool StopOnError
{
get => _stopOnError;
set => this.RaiseAndSetIfChanged(ref _stopOnError, value);
}
public bool Force
{
get => _force;
set => this.RaiseAndSetIfChanged(ref _force, value);
}
public double Retries
{
get => _retries;
set => this.RaiseAndSetIfChanged(ref _retries, value);
}
2022-03-06 13:29:38 +00:00
public bool Persistent
{
get => _persistent;
set => this.RaiseAndSetIfChanged(ref _persistent, value);
}
public bool Resume
{
get => _useResume;
set
{
2022-03-06 13:29:38 +00:00
this.RaiseAndSetIfChanged(ref _useResume, value);
2024-05-01 04:05:22 +01:00
if(!value) return;
2022-03-06 13:29:38 +00:00
2024-05-01 04:05:22 +01:00
if(_outputPrefix != null) CheckResumeFile().GetAwaiter().GetResult();
}
2022-03-06 13:29:38 +00:00
}
public bool Track1Pregap
{
get => _track1Pregap;
set => this.RaiseAndSetIfChanged(ref _track1Pregap, value);
}
public bool Track1PregapVisible
{
get => _track1PregapVisible;
set => this.RaiseAndSetIfChanged(ref _track1PregapVisible, value);
}
public double Skipped
{
get => _skipped;
set => this.RaiseAndSetIfChanged(ref _skipped, value);
}
2022-03-06 13:29:38 +00:00
public bool Sidecar
{
get => _useSidecar;
set
{
2022-03-06 13:29:38 +00:00
this.RaiseAndSetIfChanged(ref _useSidecar, value);
EncodingVisible = value;
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
public bool EncodingVisible
{
get => _encodingVisible;
set => this.RaiseAndSetIfChanged(ref _encodingVisible, value);
}
public bool Trim
{
get => _trim;
set => this.RaiseAndSetIfChanged(ref _trim, value);
}
public bool ExistingMetadata
{
get => _existingMetadata;
set
{
2022-03-06 13:29:38 +00:00
this.RaiseAndSetIfChanged(ref _existingMetadata, value);
2022-03-06 13:29:38 +00:00
if(value == false)
{
_sidecar = null;
2022-03-06 13:29:38 +00:00
return;
}
IReadOnlyList<IStorageFile> result = _view.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = UI.Dialog_Choose_existing_metadata_sidecar,
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
{
FilePickerFileTypes.AaruMetadata
}
})
.Result;
if(result.Count != 1)
{
2022-03-06 13:29:38 +00:00
ExistingMetadata = false;
return;
}
2022-03-06 13:29:38 +00:00
try
{
var fs = new FileStream(result[0].Path.AbsolutePath, FileMode.Open);
_sidecar =
2024-05-01 04:05:22 +01:00
(JsonSerializer.Deserialize(fs, typeof(MetadataJson), MetadataJsonContext.Default) as MetadataJson)
?.AaruMetadata;
fs.Close();
2022-03-06 13:29:38 +00:00
}
catch
{
// ReSharper disable AssignmentIsFullyDiscarded
_ = MessageBoxManager.
// ReSharper restore AssignmentIsFullyDiscarded
2024-05-01 04:05:22 +01:00
GetMessageBoxStandard(UI.Title_Error, UI.Incorrect_metadata_sidecar_file, ButtonEnum.Ok, Icon.Error)
.ShowWindowDialogAsync(_view)
.Result;
2022-03-06 13:29:38 +00:00
ExistingMetadata = false;
}
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
public EncodingModel SelectedEncoding
{
get => _selectedEncoding;
set => this.RaiseAndSetIfChanged(ref _selectedEncoding, value);
}
2022-03-06 13:29:38 +00:00
public string EncodingEnabled
{
get => _encodingEnabled;
set => this.RaiseAndSetIfChanged(ref _encodingEnabled, value);
}
2022-03-06 13:29:38 +00:00
public bool ProgressVisible
{
get => _progressVisible;
set => this.RaiseAndSetIfChanged(ref _progressVisible, value);
}
2022-03-06 13:29:38 +00:00
public string Log
{
get => _log;
set => this.RaiseAndSetIfChanged(ref _log, value);
}
2022-03-06 13:29:38 +00:00
public bool Progress1Visible
{
get => _progress1Visible;
set => this.RaiseAndSetIfChanged(ref _progress1Visible, value);
}
2022-03-06 13:29:38 +00:00
public string ProgressText
{
get => _progressText;
set => this.RaiseAndSetIfChanged(ref _progressText, value);
}
2022-03-06 13:29:38 +00:00
public double ProgressValue
{
get => _progressValue;
set => this.RaiseAndSetIfChanged(ref _progressValue, value);
}
2022-03-06 13:29:38 +00:00
public double ProgressMaxValue
{
get => _progressMaxValue;
set => this.RaiseAndSetIfChanged(ref _progressMaxValue, value);
}
2022-03-06 13:29:38 +00:00
public bool ProgressIndeterminate
{
get => _progressIndeterminate;
set => this.RaiseAndSetIfChanged(ref _progressIndeterminate, value);
}
2022-03-06 13:29:38 +00:00
public bool Progress2Visible
{
get => _progress2Visible;
set => this.RaiseAndSetIfChanged(ref _progress2Visible, value);
}
2022-03-06 13:29:38 +00:00
public string Progress2Text
{
get => _progress2Text;
set => this.RaiseAndSetIfChanged(ref _progress2Text, value);
}
2022-03-06 13:29:38 +00:00
public double Progress2Value
{
get => _progress2Value;
set => this.RaiseAndSetIfChanged(ref _progress2Value, value);
}
2022-03-06 13:29:38 +00:00
public double Progress2MaxValue
{
get => _progress2MaxValue;
set => this.RaiseAndSetIfChanged(ref _progress2MaxValue, value);
}
2022-03-06 13:29:38 +00:00
public bool Progress2Indeterminate
{
get => _progress2Indeterminate;
set => this.RaiseAndSetIfChanged(ref _progress2Indeterminate, value);
}
2022-03-06 13:29:38 +00:00
public bool StartVisible
{
get => _startVisible;
set => this.RaiseAndSetIfChanged(ref _startVisible, value);
}
2022-03-06 13:29:38 +00:00
public bool CloseVisible
{
get => _closeVisible;
set => this.RaiseAndSetIfChanged(ref _closeVisible, value);
}
2022-03-06 13:29:38 +00:00
public bool StopVisible
{
get => _stopVisible;
set => this.RaiseAndSetIfChanged(ref _stopVisible, value);
}
2022-03-06 13:29:38 +00:00
public bool StopEnabled
{
get => _stopEnabled;
set => this.RaiseAndSetIfChanged(ref _stopEnabled, value);
}
async Task ExecuteDestinationCommand()
2022-03-06 13:29:38 +00:00
{
2024-05-01 04:05:22 +01:00
if(SelectedPlugin is null) return;
IStorageFile result = await _view.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
{
Title = UI.Dialog_Choose_destination_file,
FileTypeChoices = new List<FilePickerFileType>
{
new(SelectedPlugin.Plugin.Name)
{
Patterns = SelectedPlugin.Plugin.KnownExtensions.ToList()
}
}
2022-03-06 13:29:38 +00:00
});
2022-03-06 13:29:38 +00:00
if(result is null)
{
2022-03-06 13:29:38 +00:00
Destination = "";
_outputPrefix = null;
2022-03-06 13:29:38 +00:00
return;
}
Destination = result.Path.AbsolutePath;
_outputPrefix = Path.Combine(Path.GetDirectoryName(Destination) ?? "",
Path.GetFileNameWithoutExtension(Destination));
if(string.IsNullOrEmpty(Path.GetExtension(Destination)))
Destination += SelectedPlugin.Plugin.KnownExtensions.First();
2022-03-06 13:29:38 +00:00
Resume = true;
}
async Task CheckResumeFile()
2022-03-06 13:29:38 +00:00
{
_resume = null;
2022-03-06 13:29:38 +00:00
try
{
if(File.Exists(_outputPrefix + ".resume.json"))
{
var fs = new FileStream(_outputPrefix + ".resume.json", FileMode.Open);
_resume =
(await JsonSerializer.DeserializeAsync(fs, typeof(ResumeJson), ResumeJsonContext.Default) as
ResumeJson)?.Resume;
fs.Close();
}
// DEPRECATED: To be removed in Aaru 7
else if(File.Exists(_outputPrefix + ".resume.xml"))
{
// Should be covered by virtue of being the same exact class as the JSON above
2024-05-01 04:05:22 +01:00
#pragma warning disable IL2026
var xs = new XmlSerializer(typeof(Resume));
2024-05-01 04:05:22 +01:00
#pragma warning restore IL2026
var sr = new StreamReader(_outputPrefix + ".resume.xml");
// Should be covered by virtue of being the same exact class as the JSON above
2024-05-01 04:05:22 +01:00
#pragma warning disable IL2026
_resume = (Resume)xs.Deserialize(sr);
2024-05-01 04:05:22 +01:00
#pragma warning restore IL2026
sr.Close();
}
}
2022-03-06 13:29:38 +00:00
catch
{
2024-05-01 04:05:22 +01:00
await MessageBoxManager
.GetMessageBoxStandard(UI.Title_Error,
UI.Incorrect_resume_file_cannot_use_it,
ButtonEnum.Ok,
Icon.Error)
.ShowWindowDialogAsync(_view);
2022-03-06 13:29:38 +00:00
Resume = false;
2022-03-06 13:29:38 +00:00
return;
}
if(_resume == null || _resume.NextBlock <= _resume.LastBlock || _resume.BadBlocks.Count != 0 && !_resume.Tape)
2022-03-06 13:29:38 +00:00
return;
2024-05-01 04:05:22 +01:00
await MessageBoxManager
.GetMessageBoxStandard(UI.Title_Warning,
UI.Media_already_dumped_correctly_please_choose_another_destination,
ButtonEnum.Ok,
Icon.Warning)
.ShowWindowDialogAsync(_view);
2022-03-06 13:29:38 +00:00
Resume = false;
}
2022-03-06 13:29:38 +00:00
void ExecuteCloseCommand() => _view.Close();
2022-03-06 13:29:38 +00:00
internal void ExecuteStopCommand()
{
StopEnabled = false;
_dumper?.Abort();
}
2022-03-06 13:29:38 +00:00
void ExecuteStartCommand()
{
Log = "";
CloseVisible = false;
StartVisible = false;
StopVisible = true;
StopEnabled = true;
ProgressVisible = true;
DestinationEnabled = false;
OptionsVisible = false;
UpdateStatus(UI.Opening_device);
_dev = Device.Create(_devicePath, out ErrorNumber devErrno);
switch(_dev)
{
case null:
StoppingErrorMessage(string.Format(UI.Error_0_opening_device, devErrno));
return;
case Devices.Remote.Device remoteDev:
2024-05-01 04:05:22 +01:00
Statistics.AddRemote(remoteDev.RemoteApplication,
remoteDev.RemoteVersion,
remoteDev.RemoteOperatingSystem,
remoteDev.RemoteOperatingSystemVersion,
remoteDev.RemoteArchitecture);
break;
2022-03-06 13:29:38 +00:00
}
if(_dev.Error)
2022-03-06 13:29:38 +00:00
{
StoppingErrorMessage(string.Format(UI.Error_0_opening_device, _dev.LastError));
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
Statistics.AddDevice(_dev);
Statistics.AddCommand("dump-media");
2022-03-06 13:29:38 +00:00
if(SelectedPlugin is null)
{
StoppingErrorMessage(UI.Cannot_open_output_plugin);
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
Encoding encoding = null;
2022-11-14 01:20:28 +00:00
if(SelectedEncoding is not null)
2023-10-03 23:27:57 +01:00
{
try
{
2022-03-06 13:29:38 +00:00
encoding = Claunia.Encoding.Encoding.GetEncoding(SelectedEncoding.Name);
}
2022-03-06 13:29:38 +00:00
catch(ArgumentException)
{
StoppingErrorMessage(UI.Specified_encoding_is_not_supported);
return;
}
2023-10-03 23:27:57 +01:00
}
Dictionary<string, string> parsedOptions = new();
2022-03-06 13:29:38 +00:00
/* TODO: Options
if(grpOptions.Content is StackLayout stkFormatOptions)
foreach(Control option in stkFormatOptions.Children)
{
2022-03-06 13:29:38 +00:00
string value;
2022-03-06 13:29:38 +00:00
switch(option)
{
2022-03-06 13:29:38 +00:00
case CheckBox optBoolean:
value = optBoolean.Checked?.ToString();
2022-03-06 13:29:38 +00:00
break;
case NumericStepper optNumber:
value = optNumber.Value.ToString(CultureInfo.CurrentCulture);
2022-03-06 13:29:38 +00:00
break;
case TextBox optString:
value = optString.Text;
2022-03-06 13:29:38 +00:00
break;
default: continue;
}
2022-03-06 13:29:38 +00:00
string key = option.ID.Substring(3);
2022-03-06 13:29:38 +00:00
parsedOptions.Add(key, value);
}
*/
2022-03-06 13:29:38 +00:00
var dumpLog = new DumpLog(_outputPrefix + ".log", _dev, false);
dumpLog.WriteLine(UI.Output_image_format_0, SelectedPlugin.Name);
2022-03-06 13:29:38 +00:00
var errorLog = new ErrorLog(_outputPrefix + ".error.log");
2024-05-01 04:05:22 +01:00
_dumper = new Dump(Resume,
_dev,
_devicePath,
SelectedPlugin.Plugin,
(ushort)Retries,
Force,
false,
Persistent,
StopOnError,
_resume,
dumpLog,
encoding,
_outputPrefix,
Destination,
parsedOptions,
_sidecar,
(uint)Skipped,
ExistingMetadata == false,
Trim == false,
Track1Pregap,
true,
false,
DumpSubchannel.Any,
0,
false,
false,
false,
false,
false,
true,
errorLog,
false,
64,
true,
true,
false,
10,
true,
1080);
2022-03-06 13:29:38 +00:00
new Thread(DoWork).Start();
}
2020-07-13 18:54:41 +01:00
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
async void DoWork()
2022-03-06 13:29:38 +00:00
{
_dumper.UpdateStatus += UpdateStatus;
_dumper.ErrorMessage += ErrorMessage;
_dumper.StoppingErrorMessage += StoppingErrorMessage;
_dumper.PulseProgress += PulseProgress;
_dumper.InitProgress += InitProgress;
_dumper.UpdateProgress += UpdateProgress;
_dumper.EndProgress += EndProgress;
_dumper.InitProgress2 += InitProgress2;
_dumper.UpdateProgress2 += UpdateProgress2;
_dumper.EndProgress2 += EndProgress2;
_dumper.Start();
_dev.Close();
await WorkFinished();
2022-03-06 13:29:38 +00:00
}
async Task WorkFinished() => await Dispatcher.UIThread.InvokeAsync(() =>
2022-03-06 13:29:38 +00:00
{
CloseVisible = true;
StopVisible = false;
Progress1Visible = false;
Progress2Visible = false;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void EndProgress2() => await Dispatcher.UIThread.InvokeAsync(() => { Progress2Visible = false; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-07 07:36:44 +00:00
async void UpdateProgress2(string text, long current, long maximum) => await Dispatcher.UIThread.InvokeAsync(() =>
{
Progress2Text = text;
Progress2Indeterminate = false;
2022-03-07 07:36:44 +00:00
Progress2MaxValue = maximum;
Progress2Value = current;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void InitProgress2() => await Dispatcher.UIThread.InvokeAsync(() => { Progress2Visible = true; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void EndProgress() => await Dispatcher.UIThread.InvokeAsync(() => { Progress1Visible = false; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-07 07:36:44 +00:00
async void UpdateProgress(string text, long current, long maximum) => await Dispatcher.UIThread.InvokeAsync(() =>
{
ProgressText = text;
ProgressIndeterminate = false;
2022-03-07 07:36:44 +00:00
ProgressMaxValue = maximum;
ProgressValue = current;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2023-10-03 23:27:57 +01:00
async void InitProgress() => await Dispatcher.UIThread.InvokeAsync(() => { Progress1Visible = true; });
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void PulseProgress(string text) => await Dispatcher.UIThread.InvokeAsync(() =>
{
ProgressText = text;
ProgressIndeterminate = true;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void StoppingErrorMessage(string text) => await Dispatcher.UIThread.InvokeAsync(async () =>
{
ErrorMessage(text);
2024-05-01 04:05:22 +01:00
await MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, $"{text}", ButtonEnum.Ok, Icon.Error)
.ShowWindowDialogAsync(_view);
await WorkFinished();
2022-03-06 13:29:38 +00:00
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void ErrorMessage(string text) => await Dispatcher.UIThread.InvokeAsync(() =>
{
Log += text + Environment.NewLine;
});
[SuppressMessage("ReSharper", "AsyncVoidMethod")]
2022-03-06 13:29:38 +00:00
async void UpdateStatus(string text) => await Dispatcher.UIThread.InvokeAsync(() =>
{
Log += text + Environment.NewLine;
});
}