// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : ImageConvertViewModel.cs // Author(s) : Natalia Portillo // // Component : GUI view models. // // --[ Description ] ---------------------------------------------------------- // // View model and code for the image conversion 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 . // // ---------------------------------------------------------------------------- // Copyright © 2011-2023 Natalia Portillo // ****************************************************************************/ 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 Aaru.CommonTypes; using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Metadata; using Aaru.Console; using Aaru.Core; using Aaru.Core.Media; using Aaru.Devices; using Aaru.Gui.Models; using Aaru.Localization; using Avalonia.Controls; using Avalonia.Threading; using MsBox.Avalonia; using MsBox.Avalonia.Enums; using ReactiveUI; using ImageInfo = Aaru.CommonTypes.Structs.ImageInfo; using Track = Aaru.CommonTypes.Structs.Track; using Version = Aaru.CommonTypes.Interop.Version; namespace Aaru.Gui.ViewModels.Windows; [SuppressMessage("ReSharper", "AsyncVoidLambda")] public sealed class ImageConvertViewModel : ViewModelBase { readonly IMediaImage _inputFormat; readonly Window _view; Metadata _aaruMetadata; bool _aaruMetadataFromImageVisible; bool _cancel; bool _closeVisible; string _commentsText; bool _commentsVisible; string _creatorText; bool _creatorVisible; bool _destinationEnabled; string _destinationText; bool _destinationVisible; string _driveFirmwareRevisionText; bool _driveFirmwareRevisionVisible; string _driveManufacturerText; bool _driveManufacturerVisible; string _driveModelText; bool _driveModelVisible; string _driveSerialNumberText; bool _driveSerialNumberVisible; List _dumpHardware; bool _forceChecked; bool _formatReadOnly; double _lastMediaSequenceValue; bool _lastMediaSequenceVisible; string _mediaBarcodeText; bool _mediaBarcodeVisible; string _mediaManufacturerText; bool _mediaManufacturerVisible; string _mediaModelText; bool _mediaModelVisible; string _mediaPartNumberText; bool _mediaPartNumberVisible; double _mediaSequenceValue; bool _mediaSequenceVisible; string _mediaSerialNumberText; bool _mediaSerialNumberVisible; string _mediaTitleText; bool _mediaTitleVisible; string _metadataJsonText; bool _optionsVisible; bool _progress1Visible; bool _progress2Indeterminate; double _progress2MaxValue; string _progress2Text; double _progress2Value; bool _progress2Visible; bool _progressIndeterminate; double _progressMaxValue; string _progressText; double _progressValue; bool _progressVisible; bool _resumeFileFromImageVisible; string _resumeFileText; double _sectorsValue; ImagePluginModel _selectedPlugin; string _sourceText; bool _startVisible; bool _stopEnabled; bool _stopVisible; string _title; public ImageConvertViewModel([JetBrains.Annotations.NotNull] IMediaImage inputFormat, string imageSource, Window view) { _view = view; _inputFormat = inputFormat; _cancel = false; DestinationCommand = ReactiveCommand.Create(ExecuteDestinationCommand); CreatorCommand = ReactiveCommand.Create(ExecuteCreatorCommand); MediaTitleCommand = ReactiveCommand.Create(ExecuteMediaTitleCommand); MediaManufacturerCommand = ReactiveCommand.Create(ExecuteMediaManufacturerCommand); MediaModelCommand = ReactiveCommand.Create(ExecuteMediaModelCommand); MediaSerialNumberCommand = ReactiveCommand.Create(ExecuteMediaSerialNumberCommand); MediaBarcodeCommand = ReactiveCommand.Create(ExecuteMediaBarcodeCommand); MediaPartNumberCommand = ReactiveCommand.Create(ExecuteMediaPartNumberCommand); MediaSequenceCommand = ReactiveCommand.Create(ExecuteMediaSequenceCommand); LastMediaSequenceCommand = ReactiveCommand.Create(ExecuteLastMediaSequenceCommand); DriveManufacturerCommand = ReactiveCommand.Create(ExecuteDriveManufacturerCommand); DriveModelCommand = ReactiveCommand.Create(ExecuteDriveModelCommand); DriveSerialNumberCommand = ReactiveCommand.Create(ExecuteDriveSerialNumberCommand); DriveFirmwareRevisionCommand = ReactiveCommand.Create(ExecuteDriveFirmwareRevisionCommand); CommentsCommand = ReactiveCommand.Create(ExecuteCommentsCommand); AaruMetadataFromImageCommand = ReactiveCommand.Create(ExecuteAaruMetadataFromImageCommand); AaruMetadataCommand = ReactiveCommand.Create(ExecuteAaruMetadataCommand); ResumeFileFromImageCommand = ReactiveCommand.Create(ExecuteResumeFileFromImageCommand); ResumeFileCommand = ReactiveCommand.Create(ExecuteResumeFileCommand); StartCommand = ReactiveCommand.Create(ExecuteStartCommand); CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand); StopCommand = ReactiveCommand.Create(ExecuteStopCommand); SourceText = imageSource; CreatorVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.Creator); MediaTitleVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaTitle); CommentsVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.Comments); MediaManufacturerVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaManufacturer); MediaModelVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaModel); MediaSerialNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaSerialNumber); MediaBarcodeVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaBarcode); MediaPartNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaPartNumber); MediaSequenceVisible = inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0; LastMediaSequenceVisible = inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0; DriveManufacturerVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveManufacturer); DriveModelVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveModel); DriveSerialNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveSerialNumber); DriveFirmwareRevisionVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveFirmwareRevision); PluginRegister plugins = PluginRegister.Singleton; foreach(Type pluginType in plugins.WritableImages.Values) { if(Activator.CreateInstance(pluginType) is not IWritableImage plugin) continue; if(plugin.SupportedMediaTypes.Contains(inputFormat.Info.MediaType)) { PluginsList.Add(new ImagePluginModel { Plugin = plugin }); } } AaruMetadataFromImageVisible = inputFormat.AaruMetadata != null; ResumeFileFromImageVisible = inputFormat.DumpHardware?.Any() == true; _aaruMetadata = inputFormat.AaruMetadata; _dumpHardware = inputFormat.DumpHardware?.Any() == true ? inputFormat.DumpHardware : null; MetadataJsonText = _aaruMetadata == null ? "" : UI._From_image_; ResumeFileText = _dumpHardware == null ? "" : UI._From_image_; } public string SourceImageLabel => UI.Source_image; public string OutputFormatLabel => UI.Output_format; public string ChooseLabel => UI.ButtonLabel_Choose; public string SectorsLabel => UI.How_many_sectors_to_convert_at_once; public string ForceLabel => UI.Continue_conversion_even_if_data_lost; public string CreatorLabel => UI.Who_person_created_the_image; public string GetFromSourceImageLabel => UI.ButtonLabel_Get_from_source_image; public string MetadataLabel => UI.Title_Metadata; public string MediaLabel => UI.Title_Media; public string TitleLabel => UI.Title_Title; public string ManufacturerLabel => UI.Title_Manufacturer; public string ModelLabel => UI.Title_Model; public string SerialNumberLabel => UI.Title_Serial_number; public string BarcodeLabel => UI.Title_Barcode; public string PartNumberLabel => UI.Title_Part_number; public string NumberInSequenceLabel => UI.Title_Number_in_sequence; public string LastMediaOfTheSequenceLabel => UI.Title_Last_media_of_the_sequence; public string DriveLabel => UI.Title_Drive; public string FirmwareRevisionLabel => UI.Title_Firmware_revision; public string CommentsLabel => UI.Title_Comments; public string AaruMetadataLabel => UI.Title_Existing_Aaru_Metadata_sidecar; public string FromImageLabel => UI.Title_From_image; public string ResumeFileLabel => UI.Title_Existing_resume_file; public string StartLabel => UI.ButtonLabel_Start; public string CloseLabel => UI.ButtonLabel_Close; public string StopLabel => UI.ButtonLabel_Stop; public string Title { get => _title; set => this.RaiseAndSetIfChanged(ref _title, value); } public string SourceText { get => _sourceText; set => this.RaiseAndSetIfChanged(ref _sourceText, value); } public ObservableCollection PluginsList { get; } public ImagePluginModel SelectedPlugin { get => _selectedPlugin; set => this.RaiseAndSetIfChanged(ref _selectedPlugin, value); } public string DestinationText { get => _destinationText; set => this.RaiseAndSetIfChanged(ref _destinationText, value); } public bool OptionsVisible { get => _optionsVisible; set => this.RaiseAndSetIfChanged(ref _optionsVisible, value); } public double SectorsValue { get => _sectorsValue; set => this.RaiseAndSetIfChanged(ref _sectorsValue, value); } public bool ForceChecked { get => _forceChecked; set => this.RaiseAndSetIfChanged(ref _forceChecked, value); } public string CreatorText { get => _creatorText; set => this.RaiseAndSetIfChanged(ref _creatorText, value); } public string MediaTitleText { get => _mediaTitleText; set => this.RaiseAndSetIfChanged(ref _mediaTitleText, value); } public string MediaManufacturerText { get => _mediaManufacturerText; set => this.RaiseAndSetIfChanged(ref _mediaManufacturerText, value); } public string MediaModelText { get => _mediaModelText; set => this.RaiseAndSetIfChanged(ref _mediaModelText, value); } public string MediaSerialNumberText { get => _mediaSerialNumberText; set => this.RaiseAndSetIfChanged(ref _mediaSerialNumberText, value); } public string MediaBarcodeText { get => _mediaBarcodeText; set => this.RaiseAndSetIfChanged(ref _mediaBarcodeText, value); } public string MediaPartNumberText { get => _mediaPartNumberText; set => this.RaiseAndSetIfChanged(ref _mediaPartNumberText, value); } public double MediaSequenceValue { get => _mediaSequenceValue; set => this.RaiseAndSetIfChanged(ref _mediaSequenceValue, value); } public double LastMediaSequenceValue { get => _lastMediaSequenceValue; set => this.RaiseAndSetIfChanged(ref _lastMediaSequenceValue, value); } public string DriveManufacturerText { get => _driveManufacturerText; set => this.RaiseAndSetIfChanged(ref _driveManufacturerText, value); } public string DriveModelText { get => _driveModelText; set => this.RaiseAndSetIfChanged(ref _driveModelText, value); } public string DriveSerialNumberText { get => _driveSerialNumberText; set => this.RaiseAndSetIfChanged(ref _driveSerialNumberText, value); } public string DriveFirmwareRevisionText { get => _driveFirmwareRevisionText; set => this.RaiseAndSetIfChanged(ref _driveFirmwareRevisionText, value); } public string CommentsText { get => _commentsText; set => this.RaiseAndSetIfChanged(ref _commentsText, value); } public string MetadataJsonText { get => _metadataJsonText; set => this.RaiseAndSetIfChanged(ref _metadataJsonText, value); } public string ResumeFileText { get => _resumeFileText; set => this.RaiseAndSetIfChanged(ref _resumeFileText, value); } public bool ProgressVisible { get => _progressVisible; set => this.RaiseAndSetIfChanged(ref _progressVisible, value); } public bool Progress1Visible { get => _progress1Visible; set => this.RaiseAndSetIfChanged(ref _progress1Visible, value); } public string ProgressText { get => _progressText; set => this.RaiseAndSetIfChanged(ref _progressText, value); } public double ProgressValue { get => _progressValue; set => this.RaiseAndSetIfChanged(ref _progressValue, value); } public double ProgressMaxValue { get => _progressMaxValue; set => this.RaiseAndSetIfChanged(ref _progressMaxValue, value); } public bool ProgressIndeterminate { get => _progressIndeterminate; set => this.RaiseAndSetIfChanged(ref _progressIndeterminate, value); } public bool Progress2Visible { get => _progress2Visible; set => this.RaiseAndSetIfChanged(ref _progress2Visible, value); } public string Progress2Text { get => _progress2Text; set => this.RaiseAndSetIfChanged(ref _progress2Text, value); } public double Progress2Value { get => _progress2Value; set => this.RaiseAndSetIfChanged(ref _progress2Value, value); } public double Progress2MaxValue { get => _progress2MaxValue; set => this.RaiseAndSetIfChanged(ref _progress2MaxValue, value); } public bool Progress2Indeterminate { get => _progress2Indeterminate; set => this.RaiseAndSetIfChanged(ref _progress2Indeterminate, value); } public bool StartVisible { get => _startVisible; set => this.RaiseAndSetIfChanged(ref _startVisible, value); } public bool CloseVisible { get => _closeVisible; set => this.RaiseAndSetIfChanged(ref _closeVisible, value); } public bool StopVisible { get => _stopVisible; set => this.RaiseAndSetIfChanged(ref _stopVisible, value); } public bool StopEnabled { get => _stopEnabled; set => this.RaiseAndSetIfChanged(ref _stopEnabled, value); } public bool CreatorVisible { get => _creatorVisible; set => this.RaiseAndSetIfChanged(ref _creatorVisible, value); } public bool MediaTitleVisible { get => _mediaTitleVisible; set => this.RaiseAndSetIfChanged(ref _mediaTitleVisible, value); } public bool CommentsVisible { get => _commentsVisible; set => this.RaiseAndSetIfChanged(ref _commentsVisible, value); } public bool MediaManufacturerVisible { get => _mediaManufacturerVisible; set => this.RaiseAndSetIfChanged(ref _mediaManufacturerVisible, value); } public bool MediaModelVisible { get => _mediaModelVisible; set => this.RaiseAndSetIfChanged(ref _mediaModelVisible, value); } public bool MediaSerialNumberVisible { get => _mediaSerialNumberVisible; set => this.RaiseAndSetIfChanged(ref _mediaSerialNumberVisible, value); } public bool MediaBarcodeVisible { get => _mediaBarcodeVisible; set => this.RaiseAndSetIfChanged(ref _mediaBarcodeVisible, value); } public bool MediaPartNumberVisible { get => _mediaPartNumberVisible; set => this.RaiseAndSetIfChanged(ref _mediaPartNumberVisible, value); } public bool MediaSequenceVisible { get => _mediaSequenceVisible; set => this.RaiseAndSetIfChanged(ref _mediaSequenceVisible, value); } public bool LastMediaSequenceVisible { get => _lastMediaSequenceVisible; set => this.RaiseAndSetIfChanged(ref _lastMediaSequenceVisible, value); } public bool DriveManufacturerVisible { get => _driveManufacturerVisible; set => this.RaiseAndSetIfChanged(ref _driveManufacturerVisible, value); } public bool DriveModelVisible { get => _driveModelVisible; set => this.RaiseAndSetIfChanged(ref _driveModelVisible, value); } public bool DriveSerialNumberVisible { get => _driveSerialNumberVisible; set => this.RaiseAndSetIfChanged(ref _driveSerialNumberVisible, value); } public bool DriveFirmwareRevisionVisible { get => _driveFirmwareRevisionVisible; set => this.RaiseAndSetIfChanged(ref _driveFirmwareRevisionVisible, value); } public bool AaruMetadataFromImageVisible { get => _aaruMetadataFromImageVisible; set => this.RaiseAndSetIfChanged(ref _aaruMetadataFromImageVisible, value); } public bool ResumeFileFromImageVisible { get => _resumeFileFromImageVisible; set => this.RaiseAndSetIfChanged(ref _resumeFileFromImageVisible, value); } public bool DestinationEnabled { get => _destinationEnabled; set => this.RaiseAndSetIfChanged(ref _destinationEnabled, value); } public ReactiveCommand DestinationCommand { get; } public ReactiveCommand CreatorCommand { get; } public ReactiveCommand MediaTitleCommand { get; } public ReactiveCommand MediaManufacturerCommand { get; } public ReactiveCommand MediaModelCommand { get; } public ReactiveCommand MediaSerialNumberCommand { get; } public ReactiveCommand MediaBarcodeCommand { get; } public ReactiveCommand MediaPartNumberCommand { get; } public ReactiveCommand MediaSequenceCommand { get; } public ReactiveCommand LastMediaSequenceCommand { get; } public ReactiveCommand DriveManufacturerCommand { get; } public ReactiveCommand DriveModelCommand { get; } public ReactiveCommand DriveSerialNumberCommand { get; } public ReactiveCommand DriveFirmwareRevisionCommand { get; } public ReactiveCommand CommentsCommand { get; } public ReactiveCommand AaruMetadataFromImageCommand { get; } public ReactiveCommand AaruMetadataCommand { get; } public ReactiveCommand ResumeFileFromImageCommand { get; } public ReactiveCommand ResumeFileCommand { get; } public ReactiveCommand StartCommand { get; } public ReactiveCommand CloseCommand { get; } public ReactiveCommand StopCommand { get; } public bool FormatReadOnly { get => _formatReadOnly; set => this.RaiseAndSetIfChanged(ref _formatReadOnly, value); } public bool DestinationVisible { get => _destinationVisible; set => this.RaiseAndSetIfChanged(ref _destinationVisible, value); } async Task ExecuteStartCommand() { if(SelectedPlugin is null) { await MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, UI.Error_trying_to_find_selected_plugin, icon: Icon.Error). ShowWindowDialogAsync(_view); return; } new Thread(DoWork).Start(SelectedPlugin.Plugin); } [SuppressMessage("ReSharper", "AsyncVoidMethod")] async void DoWork(object plugin) { var warning = false; if(plugin is not IWritableImage outputFormat) { await MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, UI.Error_trying_to_find_selected_plugin, icon: Icon.Error). ShowWindowDialogAsync(_view); return; } var inputOptical = _inputFormat as IOpticalMediaImage; var outputOptical = outputFormat as IWritableOpticalImage; List tracks; try { tracks = inputOptical?.Tracks; } catch(Exception) { tracks = null; } // Prepare UI await Dispatcher.UIThread.InvokeAsync(() => { CloseVisible = false; StartVisible = false; StopVisible = true; ProgressVisible = true; OptionsVisible = false; StopEnabled = true; FormatReadOnly = true; DestinationVisible = false; ProgressMaxValue = 1d; ProgressMaxValue += _inputFormat.Info.ReadableMediaTags.Count; ProgressMaxValue++; if(tracks != null) ProgressMaxValue++; if(tracks == null) { ProgressMaxValue += 2; foreach(SectorTagType tag in _inputFormat.Info.ReadableSectorTags) { switch(tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if(ForceChecked && !outputFormat.SupportedSectorTags.Contains(tag)) continue; ProgressMaxValue++; } } else { ProgressMaxValue += tracks.Count; foreach(SectorTagType tag in _inputFormat.Info.ReadableSectorTags.OrderBy(t => t)) { switch(tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if(ForceChecked && !outputFormat.SupportedSectorTags.Contains(tag)) continue; ProgressMaxValue += tracks.Count; } } if(_dumpHardware != null) ProgressMaxValue++; if(_aaruMetadata != null) ProgressMaxValue++; ProgressMaxValue++; }); foreach(MediaTagType mediaTag in _inputFormat.Info.ReadableMediaTags.Where(mediaTag => !outputFormat.SupportedMediaTags.Contains(mediaTag) && !ForceChecked)) { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Converting_image_will_lose_media_tag_0, mediaTag), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } bool useLong = _inputFormat.Info.ReadableSectorTags.Count != 0; foreach(SectorTagType sectorTag in _inputFormat.Info.ReadableSectorTags.Where(sectorTag => !outputFormat.SupportedSectorTags.Contains(sectorTag))) { if(ForceChecked) { if(sectorTag != SectorTagType.CdTrackFlags && sectorTag != SectorTagType.CdTrackIsrc && sectorTag != SectorTagType.CdSectorSubchannel) useLong = false; continue; } await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Converting_image_will_lose_sector_tag_0, sectorTag), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } Dictionary parsedOptions = new(); /* TODO: if(grpOptions.Content is StackLayout stkImageOptions) foreach(Control option in stkImageOptions.Children) { if(cancel) break; string value; switch(option) { case CheckBox optBoolean: value = optBooleanChecked?.ToString(); break; case NumericStepper optNumber: value = optNumber.Value.ToString(CultureInfo.CurrentCulture); break; case TextBox optString: value = optString.Text; break; default: continue; } string key = option.ID.Substring(3); parsedOptions.Add(key, value); } */ await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Creating_output_image; Progress2Text = ""; Progress2Indeterminate = true; }); if(!outputFormat.Create(DestinationText, _inputFormat.Info.MediaType, parsedOptions, _inputFormat.Info.Sectors, _inputFormat.Info.SectorSize)) { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_creating_output_image, outputFormat.ErrorMessage), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_creating_output_image, outputFormat.ErrorMessage); return; } await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Setting_image_metadata; ProgressValue++; Progress2Text = ""; Progress2Indeterminate = true; }); var metadata = new ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion(), Comments = CommentsText, Creator = CreatorText, DriveFirmwareRevision = DriveFirmwareRevisionText, DriveManufacturer = DriveManufacturerText, DriveModel = DriveModelText, DriveSerialNumber = DriveSerialNumberText, LastMediaSequence = (int)LastMediaSequenceValue, MediaBarcode = MediaBarcodeText, MediaManufacturer = MediaManufacturerText, MediaModel = MediaModelText, MediaPartNumber = MediaPartNumberText, MediaSequence = (int)MediaSequenceValue, MediaSerialNumber = MediaSerialNumberText, MediaTitle = MediaTitleText }; if(!_cancel) { if(!outputFormat.SetImageInfo(metadata)) { if(ForceChecked != true) { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_setting_metadata_not_continuing, outputFormat. ErrorMessage), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_setting_metadata_not_continuing, outputFormat.ErrorMessage); return; } warning = true; AaruConsole.ErrorWriteLine(Localization.Core.Error_0_setting_metadata, outputFormat.ErrorMessage); } } if(tracks != null && !_cancel && outputOptical != null) { await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Setting_tracks_list; ProgressValue++; Progress2Text = ""; Progress2Indeterminate = true; }); if(!outputOptical.SetTracks(tracks)) { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_sending_tracks_list_to_output_image, outputFormat. ErrorMessage), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_sending_tracks_list_to_output_image, outputFormat.ErrorMessage); return; } } ErrorNumber errno; foreach(MediaTagType mediaTag in _inputFormat.Info.ReadableMediaTags.TakeWhile(_ => !_cancel)) { await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = string.Format(UI.Converting_media_tag_0, mediaTag); ProgressValue++; Progress2Text = ""; Progress2Indeterminate = true; }); if(ForceChecked && !outputFormat.SupportedMediaTags.Contains(mediaTag)) continue; errno = _inputFormat.ReadMediaTag(mediaTag, out byte[] tag); if(errno == ErrorNumber.NoError && outputFormat.WriteMediaTag(tag, mediaTag)) continue; if(ForceChecked) { warning = true; if(errno == ErrorNumber.NoError) AaruConsole.ErrorWriteLine(UI.Error_0_writing_media_tag, outputFormat.ErrorMessage); else AaruConsole.ErrorWriteLine(UI.Error_0_reading_media_tag, errno); } else { if(errno == ErrorNumber.NoError) { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_writing_media_tag_not_continuing, outputFormat. ErrorMessage), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_writing_media_tag_not_continuing, outputFormat.ErrorMessage); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_media_tag_not_continuing, errno), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_reading_media_tag_not_continuing, errno); } return; } } ulong doneSectors = 0; if(tracks == null && !_cancel) { await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = string.Format(UI.Setting_geometry_to_0_cylinders_1_heads_and_2_sectors_per_track, _inputFormat.Info.Cylinders, _inputFormat.Info.Heads, _inputFormat.Info.SectorsPerTrack); ProgressValue++; Progress2Text = ""; Progress2Indeterminate = true; }); if(!outputFormat.SetGeometry(_inputFormat.Info.Cylinders, _inputFormat.Info.Heads, _inputFormat.Info.SectorsPerTrack)) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_setting_geometry_image_may_be_incorrect_continuing, outputFormat.ErrorMessage); } await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Converting_sectors; ProgressValue++; Progress2Text = ""; Progress2Indeterminate = false; Progress2MaxValue = (int)(_inputFormat.Info.Sectors / SectorsValue); }); while(doneSectors < _inputFormat.Info.Sectors) { if(_cancel) break; byte[] sector; uint sectorsToDo; if(_inputFormat.Info.Sectors - doneSectors >= (ulong)SectorsValue) sectorsToDo = (uint)SectorsValue; else sectorsToDo = (uint)(_inputFormat.Info.Sectors - doneSectors); ulong sectors = doneSectors; await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_sectors_0_to_1_2_done, sectors, sectors + sectorsToDo, sectors / (double)_inputFormat.Info.Sectors); Progress2Value = (int)(sectors / SectorsValue); }); bool result; if(useLong) { errno = sectorsToDo == 1 ? _inputFormat.ReadSectorLong(doneSectors, out sector) : _inputFormat.ReadSectorsLong(doneSectors, sectorsToDo, out sector); if(errno == ErrorNumber.NoError) { result = sectorsToDo == 1 ? outputFormat.WriteSectorLong(sector, doneSectors) : outputFormat.WriteSectorsLong(sector, doneSectors, sectorsToDo); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors); return; } } } else { errno = sectorsToDo == 1 ? _inputFormat.ReadSector(doneSectors, out sector) : _inputFormat.ReadSectors(doneSectors, sectorsToDo, out sector); if(errno == ErrorNumber.NoError) { result = sectorsToDo == 1 ? outputFormat.WriteSector(sector, doneSectors) : outputFormat.WriteSectors(sector, doneSectors, sectorsToDo); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors); return; } } } if(!result) { if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_writing_sector_1_continuing, outputFormat.ErrorMessage, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_writing_sector_1_not_continuing, outputFormat. ErrorMessage, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_writing_sector_1_not_continuing, outputFormat.ErrorMessage, doneSectors); return; } } doneSectors += sectorsToDo; } await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_sectors_0_to_1_2_done, _inputFormat.Info.Sectors, _inputFormat.Info.Sectors, 1.0); Progress2Value = Progress2MaxValue; }); Dictionary isrcs = new(); Dictionary trackFlags = new(); string mcn = null; HashSet subchannelExtents = new(); Dictionary smallestPregapLbaPerTrack = new(); foreach(SectorTagType tag in _inputFormat.Info.ReadableSectorTags. Where(t => t == SectorTagType.CdTrackIsrc). OrderBy(t => t)) { foreach(Track track in inputOptical.Tracks) { errno = _inputFormat.ReadSectorTag(track.Sequence, tag, out byte[] isrc); if(errno != ErrorNumber.NoError) continue; isrcs[(byte)track.Sequence] = Encoding.UTF8.GetString(isrc); } } foreach(SectorTagType tag in _inputFormat.Info.ReadableSectorTags. Where(t => t == SectorTagType.CdTrackFlags). OrderBy(t => t)) { foreach(Track track in inputOptical.Tracks) { errno = _inputFormat.ReadSectorTag(track.Sequence, tag, out byte[] flags); if(errno != ErrorNumber.NoError) continue; trackFlags[(byte)track.Sequence] = flags[0]; } } for(ulong s = 0; s < _inputFormat.Info.Sectors; s++) { if(s > int.MaxValue) break; subchannelExtents.Add((int)s); } foreach(SectorTagType tag in _inputFormat.Info.ReadableSectorTags.TakeWhile(_ => useLong && !_cancel)) { switch(tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if(ForceChecked && !outputFormat.SupportedSectorTags.Contains(tag)) continue; await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = string.Format(UI.Converting_tag_0, tag); ProgressValue++; Progress2Text = ""; Progress2Indeterminate = false; Progress2MaxValue = (int)(_inputFormat.Info.Sectors / SectorsValue); }); doneSectors = 0; while(doneSectors < _inputFormat.Info.Sectors) { if(_cancel) break; byte[] sector; uint sectorsToDo; if(_inputFormat.Info.Sectors - doneSectors >= (ulong)SectorsValue) sectorsToDo = (uint)SectorsValue; else sectorsToDo = (uint)(_inputFormat.Info.Sectors - doneSectors); ulong sectors = doneSectors; await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_tag_0_for_sectors_1_to_2_3_done, sectors / (double)_inputFormat.Info.Sectors, sectors, sectors + sectorsToDo, sectors / (double)_inputFormat.Info.Sectors); Progress2Value = (int)(sectors / SectorsValue); }); bool result; if(sectorsToDo == 1) { errno = _inputFormat.ReadSectorTag(doneSectors, tag, out sector); if(errno == ErrorNumber.NoError) { Track track = tracks.LastOrDefault(t => t.StartSector >= doneSectors); if(tag == SectorTagType.CdSectorSubchannel && track != null) { bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw, MmcSubchannel.Raw, sector, doneSectors, 1, null, isrcs, (byte)track.Sequence, ref mcn, tracks.ToArray(), subchannelExtents, false, outputFormat as IWritableOpticalImage, false, false, null, null, smallestPregapLbaPerTrack, false, out _); if(indexesChanged) outputOptical.SetTracks(tracks.ToList()); result = true; } else result = outputFormat.WriteSectorTag(sector, doneSectors, tag); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors); return; } } } else { errno = _inputFormat.ReadSectorsTag(doneSectors, sectorsToDo, tag, out sector); if(errno == ErrorNumber.NoError) { Track track = tracks.LastOrDefault(t => t.StartSector >= doneSectors); if(tag == SectorTagType.CdSectorSubchannel && track != null) { bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw, MmcSubchannel.Raw, sector, doneSectors, sectorsToDo, null, isrcs, (byte)track.Sequence, ref mcn, tracks.ToArray(), subchannelExtents, false, outputFormat as IWritableOpticalImage, false, false, null, null, smallestPregapLbaPerTrack, false, out _); if(indexesChanged) outputOptical.SetTracks(tracks.ToList()); result = true; } else result = outputFormat.WriteSectorsTag(sector, doneSectors, sectorsToDo, tag); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors); return; } } } if(!result) { if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_writing_sector_1_continuing, outputFormat.ErrorMessage, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_writing_sector_1_not_continuing, outputFormat. ErrorMessage, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); AaruConsole.ErrorWriteLine(UI.Error_0_writing_sector_1_not_continuing, outputFormat.ErrorMessage, doneSectors); return; } } doneSectors += sectorsToDo; } await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_tag_0_for_sectors_1_to_2_3_done, tag, _inputFormat.Info.Sectors, _inputFormat.Info.Sectors, 1.0); Progress2Value = Progress2MaxValue; }); if(isrcs.Count > 0) { foreach(KeyValuePair isrc in isrcs) { outputOptical.WriteSectorTag(Encoding.UTF8.GetBytes(isrc.Value), isrc.Key, SectorTagType.CdTrackIsrc); } } if(trackFlags.Count > 0) { foreach(KeyValuePair flags in trackFlags) { outputOptical.WriteSectorTag(new[] { flags.Value }, flags.Key, SectorTagType.CdTrackFlags); } } if(mcn != null) outputOptical.WriteMediaTag(Encoding.UTF8.GetBytes(mcn), MediaTagType.CD_MCN); } } else { foreach(Track track in tracks.TakeWhile(_ => !_cancel)) { doneSectors = 0; ulong trackSectors = track.EndSector - track.StartSector + 1; await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = string.Format(UI.Converting_sectors_in_track_0, track.Sequence); ProgressValue++; Progress2Text = ""; Progress2Indeterminate = false; Progress2MaxValue = (int)(trackSectors / SectorsValue); }); while(doneSectors < trackSectors) { if(_cancel) break; byte[] sector; uint sectorsToDo; if(trackSectors - doneSectors >= (ulong)SectorsValue) sectorsToDo = (uint)SectorsValue; else sectorsToDo = (uint)(trackSectors - doneSectors); ulong sectors = doneSectors; await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_sectors_0_to_1_in_track_2_3_done, sectors + track.StartSector, sectors + sectorsToDo + track.StartSector, track.Sequence, (sectors + track.StartSector) / (double)_inputFormat.Info.Sectors); Progress2Value = (int)(sectors / SectorsValue); }); bool result; if(useLong) { errno = sectorsToDo == 1 ? _inputFormat.ReadSectorLong(doneSectors + track.StartSector, out sector) : _inputFormat.ReadSectorsLong(doneSectors + track.StartSector, sectorsToDo, out sector); if(errno == ErrorNumber.NoError) { result = sectorsToDo == 1 ? outputFormat.WriteSectorLong(sector, doneSectors + track.StartSector) : outputFormat.WriteSectorsLong(sector, doneSectors + track.StartSector, sectorsToDo); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } } } else { errno = sectorsToDo == 1 ? _inputFormat.ReadSector(doneSectors + track.StartSector, out sector) : _inputFormat.ReadSectors(doneSectors + track.StartSector, sectorsToDo, out sector); if(errno == ErrorNumber.NoError) { result = sectorsToDo == 1 ? outputFormat.WriteSector(sector, doneSectors + track.StartSector) : outputFormat.WriteSectors(sector, doneSectors + track.StartSector, sectorsToDo); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } } } if(!result) { if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_writing_sector_1_continuing, outputFormat.ErrorMessage, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_writing_sector_1_not_continuing, outputFormat. ErrorMessage, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } } doneSectors += sectorsToDo; } } await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_sectors_0_to_1_in_track_2_3_done, _inputFormat.Info.Sectors, _inputFormat.Info.Sectors, tracks.Count, 1.0); Progress2Value = Progress2MaxValue; }); foreach(SectorTagType tag in _inputFormat.Info.ReadableSectorTags.OrderBy(t => t). TakeWhile(_ => useLong && !_cancel)) { switch(tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if(ForceChecked && !outputFormat.SupportedSectorTags.Contains(tag)) continue; foreach(Track track in tracks.TakeWhile(_ => !_cancel)) { doneSectors = 0; ulong trackSectors = track.EndSector - track.StartSector + 1; byte[] sector; bool result; await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = $"Converting tag {tag} in track {track.Sequence}."; ProgressValue++; Progress2Text = ""; Progress2Indeterminate = false; Progress2MaxValue = (int)(trackSectors / SectorsValue); }); switch(tag) { case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: errno = _inputFormat.ReadSectorTag(track.Sequence, tag, out sector); if(errno == ErrorNumber.NoError) result = outputFormat.WriteSectorTag(sector, track.Sequence, tag); else { if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_media_tag, errno); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_media_tag_not_continuing, errno), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } continue; } if(!result) { if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_writing_tag_continuing, outputFormat.ErrorMessage); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_writing_tag_not_continuing, outputFormat. ErrorMessage), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } } continue; } while(doneSectors < trackSectors) { if(_cancel) break; uint sectorsToDo; if(trackSectors - doneSectors >= (ulong)SectorsValue) sectorsToDo = (uint)SectorsValue; else sectorsToDo = (uint)(trackSectors - doneSectors); ulong sectors = doneSectors; await Dispatcher.UIThread.InvokeAsync(() => { Progress2Text = string.Format(UI.Converting_tag_0_for_sectors_1_to_2_in_track_3_4_done, tag, sectors + track.StartSector, sectors + sectorsToDo + track.StartSector, track.Sequence, (sectors + track.StartSector) / (double)_inputFormat.Info.Sectors); Progress2Value = (int)(sectors / SectorsValue); }); errno = sectorsToDo == 1 ? _inputFormat.ReadSectorTag(doneSectors + track.StartSector, tag, out sector) : _inputFormat.ReadSectorsTag(doneSectors + track.StartSector, sectorsToDo, tag, out sector); if(errno == ErrorNumber.NoError) { result = sectorsToDo == 1 ? outputFormat.WriteSectorTag(sector, doneSectors + track.StartSector, tag) : outputFormat.WriteSectorsTag(sector, doneSectors + track.StartSector, sectorsToDo, tag); } else { result = true; if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_reading_tag_for_sector_1_continuing, errno, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_reading_tag_for_sector_1_not_continuing, errno, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } } if(!result) { if(ForceChecked) { warning = true; AaruConsole.ErrorWriteLine(UI.Error_0_writing_tag_for_sector_1_continuing, outputFormat.ErrorMessage, doneSectors); } else { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_writing_tag_for_sector_1_not_continuing, outputFormat. ErrorMessage, doneSectors), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } } doneSectors += sectorsToDo; } } } } await Dispatcher.UIThread.InvokeAsync(() => { Progress2Visible = false; Progress2Visible = false; }); bool ret; if(_dumpHardware != null && !_cancel) { await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Writing_dump_hardware_list; ProgressValue++; }); ret = outputFormat.SetDumpHardware(_dumpHardware); if(!ret) AaruConsole.WriteLine(UI.Error_0_writing_dump_hardware_list_to_output_image, outputFormat.ErrorMessage); } ret = false; if(_aaruMetadata != null && !_cancel) { await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Writing_Aaru_Metadata_to_output_image; ProgressValue++; }); outputFormat.SetMetadata(_aaruMetadata); if(!ret) AaruConsole.WriteLine(UI.Error_0_writing_Aaru_Metadata_to_output_image, outputFormat.ErrorMessage); } await Dispatcher.UIThread.InvokeAsync(() => { ProgressText = UI.Closing_output_image; ProgressIndeterminate = true; }); if(_cancel) { await Dispatcher.UIThread.InvokeAsync(async () => { await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, UI.Operation_canceled_the_output_file_is_not_correct, icon: Icon.Error). ShowWindowDialogAsync(_view); CloseVisible = true; StopVisible = false; ProgressVisible = false; }); return; } if(!outputFormat.Close()) { await Dispatcher.UIThread.InvokeAsync(async () => await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, string. Format(UI.Error_0_closing_output_image_Contents_are_not_correct, outputFormat.ErrorMessage), icon: Icon.Error). ShowWindowDialogAsync(_view)); return; } await Dispatcher.UIThread.InvokeAsync(async () => { await MessageBoxManager.GetMessageBoxStandard(warning ? UI.Title_Warning : UI.Title_Conversion_success, warning ? UI.Some_warnings_happened_Check_console : UI.Image_converted_successfully, icon: warning ? Icon.Warning : Icon.Info). ShowWindowDialogAsync(_view); CloseVisible = true; StopVisible = false; ProgressVisible = false; }); Statistics.AddCommand("convert-image"); } void ExecuteCloseCommand() => _view.Close(); internal void ExecuteStopCommand() { _cancel = true; StopEnabled = false; } /* TODO void OnCmbFormatSelectedIndexChanged() { txtDestination.Text = ""; if(!(cmbFormat.SelectedValue is IWritableImage plugin)) { grpOptions.Visible = false; btnDestination.Enabled = false; return; } btnDestination.Enabled = true; if(!plugin.SupportedOptions.Any()) { grpOptions.Content = null; grpOptions.Visible = false; return; } chkForce.Visible = false; foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { if(plugin.SupportedMediaTags.Contains(mediaTag)) continue; chkForce.Visible = true; ForceChecked = true; break; } foreach(SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags) { if(plugin.SupportedSectorTags.Contains(sectorTag)) continue; chkForce.Visible = true; ForceChecked = true; break; } grpOptions.Visible = true; var stkImageOptions = new StackLayout { Orientation = Orientation.Vertical }; foreach((string name, Type type, string description, object @default) option in plugin.SupportedOptions) switch(option.type.ToString()) { case "System.Boolean": var optBoolean = new CheckBox(); optBoolean.ID = "opt" + option.name; optBoolean.Text = option.description; optBooleanChecked = (bool)option.@default; stkImageOptions.Items.Add(optBoolean); 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); stkImageOptions.Items.Add(stkNumber); 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); stkImageOptions.Items.Add(stkUnsigned); 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); stkImageOptions.Items.Add(stkFloat); 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); stkImageOptions.Items.Add(stkString); break; } grpOptions.Content = stkImageOptions; } */ async Task ExecuteDestinationCommand() { if(SelectedPlugin is null) return; var dlgDestination = new SaveFileDialog { Title = UI.Dialog_Choose_destination_file }; dlgDestination.Filters?.Add(new FileDialogFilter { Name = SelectedPlugin.Plugin.Name, Extensions = SelectedPlugin.Plugin.KnownExtensions.ToList() }); string result = await dlgDestination.ShowAsync(_view); if(result is null || result.Length != 1) { DestinationText = ""; return; } if(string.IsNullOrEmpty(Path.GetExtension(result))) result += SelectedPlugin.Plugin.KnownExtensions.First(); DestinationText = result; } void ExecuteCreatorCommand() => CreatorText = _inputFormat.Info.Creator; void ExecuteMediaTitleCommand() => MediaTitleText = _inputFormat.Info.MediaTitle; void ExecuteCommentsCommand() => CommentsText = _inputFormat.Info.Comments; void ExecuteMediaManufacturerCommand() => MediaManufacturerText = _inputFormat.Info.MediaManufacturer; void ExecuteMediaModelCommand() => MediaModelText = _inputFormat.Info.MediaModel; void ExecuteMediaSerialNumberCommand() => MediaSerialNumberText = _inputFormat.Info.MediaSerialNumber; void ExecuteMediaBarcodeCommand() => MediaBarcodeText = _inputFormat.Info.MediaBarcode; void ExecuteMediaPartNumberCommand() => MediaPartNumberText = _inputFormat.Info.MediaPartNumber; void ExecuteMediaSequenceCommand() => MediaSequenceValue = _inputFormat.Info.MediaSequence; void ExecuteLastMediaSequenceCommand() => LastMediaSequenceValue = _inputFormat.Info.LastMediaSequence; void ExecuteDriveManufacturerCommand() => DriveManufacturerText = _inputFormat.Info.DriveManufacturer; void ExecuteDriveModelCommand() => DriveModelText = _inputFormat.Info.DriveModel; void ExecuteDriveSerialNumberCommand() => DriveSerialNumberText = _inputFormat.Info.DriveSerialNumber; void ExecuteDriveFirmwareRevisionCommand() => DriveFirmwareRevisionText = _inputFormat.Info.DriveFirmwareRevision; void ExecuteAaruMetadataFromImageCommand() { MetadataJsonText = UI._From_image_; _aaruMetadata = _inputFormat.AaruMetadata; } async Task ExecuteAaruMetadataCommand() { _aaruMetadata = null; MetadataJsonText = ""; var dlgMetadata = new OpenFileDialog { Title = UI.Dialog_Choose_existing_metadata_sidecar }; dlgMetadata.Filters?.Add(new FileDialogFilter { Name = UI.Dialog_Aaru_Metadata, Extensions = new List(new[] { ".json" }) }); string[] result = await dlgMetadata.ShowAsync(_view); if(result is null || result.Length != 1) return; try { var fs = new FileStream(result[0], FileMode.Open); _aaruMetadata = (await JsonSerializer.DeserializeAsync(fs, typeof(MetadataJson), MetadataJsonContext.Default) as MetadataJson)?.AaruMetadata; fs.Close(); MetadataJsonText = result[0]; } catch { await MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, UI.Incorrect_metadata_sidecar_file, icon: Icon.Error). ShowWindowDialogAsync(_view); } } void ExecuteResumeFileFromImageCommand() { ResumeFileText = UI._From_image_; _dumpHardware = _inputFormat.DumpHardware; } async Task ExecuteResumeFileCommand() { _dumpHardware = null; ResumeFileText = ""; var dlgMetadata = new OpenFileDialog { Title = UI.Dialog_Choose_existing_resume_file }; dlgMetadata.Filters?.Add(new FileDialogFilter { Name = UI.Dialog_Choose_existing_resume_file, Extensions = new List(new[] { ".json" }) }); string[] result = await dlgMetadata.ShowAsync(_view); if(result is null || result.Length != 1) return; try { var fs = new FileStream(result[0], FileMode.Open); Resume resume = (await JsonSerializer.DeserializeAsync(fs, typeof(ResumeJson), ResumeJsonContext.Default) as ResumeJson)?.Resume; fs.Close(); if(resume?.Tries?.Any() == false) { _dumpHardware = resume.Tries; ResumeFileText = result[0]; } else { await MessageBoxManager. GetMessageBoxStandard(UI.Title_Error, UI.Resume_file_does_not_contain_dump_hardware_information, icon: Icon.Error). ShowWindowDialogAsync(_view); } } catch { await MessageBoxManager.GetMessageBoxStandard(UI.Title_Error, UI.Incorrect_resume_file, icon: Icon.Error). ShowWindowDialogAsync(_view); } } }