Files
Aaru/DiscImageChef.Gui/Forms/frmImageConvert.xeto.cs

1262 lines
53 KiB
C#

// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : frmImageConvert.xeto.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Image conversion window.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements converting media image.
//
// --[ 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/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2019 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.Serialization;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Metadata;
using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Console;
using DiscImageChef.Core;
using Eto.Forms;
using Eto.Serialization.Xaml;
using Schemas;
using ImageInfo = DiscImageChef.CommonTypes.Structs.ImageInfo;
using Version = DiscImageChef.CommonTypes.Interop.Version;
namespace DiscImageChef.Gui.Forms
{
public class frmImageConvert : Form
{
bool cancel;
CICMMetadataType cicmMetadata;
List<DumpHardwareType> dumpHardware;
IMediaImage inputFormat;
public frmImageConvert(IMediaImage inputFormat, string imageSource)
{
this.inputFormat = inputFormat;
XamlReader.Load(this);
cancel = false;
txtSource.Text = imageSource;
btnCreator.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.Creator);
btnMediaTitle.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaTitle);
btnComments.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.Comments);
btnMediaManufacturer.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaManufacturer);
btnMediaModel.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaModel);
btnMediaSerialNumber.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaSerialNumber);
btnMediaBarcode.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaBarcode);
btnMediaPartNumber.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaPartNumber);
btnMediaSequence.Visible =
inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0;
btnLastMediaSequence.Visible =
inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0;
btnDriveManufacturer.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveManufacturer);
btnDriveModel.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveModel);
btnDriveSerialNumber.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveSerialNumber);
btnDriveFirmwareRevision.Visible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveFirmwareRevision);
ObservableCollection<IWritableImage> lstPlugins = new ObservableCollection<IWritableImage>();
PluginBase plugins = GetPluginBase.Instance;
foreach(IWritableImage plugin in
plugins.WritableImages.Values.Where(p => p.SupportedMediaTypes.Contains(inputFormat.Info.MediaType)))
lstPlugins.Add(plugin);
cmbFormat.ItemTextBinding = Binding.Property((IWritableImage p) => p.Name);
cmbFormat.ItemKeyBinding = Binding.Property((IWritableImage p) => p.Id.ToString());
cmbFormat.DataStore = lstPlugins;
btnCicmXmlFromImage.Visible = inputFormat.CicmMetadata != null;
btnResumeFileFromImage.Visible = inputFormat.DumpHardware != null && inputFormat.DumpHardware.Any();
cicmMetadata = inputFormat.CicmMetadata;
dumpHardware = inputFormat.DumpHardware != null && inputFormat.DumpHardware.Any()
? inputFormat.DumpHardware
: null;
txtCicmXml.Text = cicmMetadata == null ? "" : "<From image>";
txtResumeFile.Text = dumpHardware == null ? "" : "<From image>";
}
protected void OnBtnStart(object sender, EventArgs e)
{
if(!(cmbFormat.SelectedValue is IWritableImage plugin))
{
MessageBox.Show("Error trying to find selected plugin", MessageBoxType.Error);
return;
}
new Thread(DoWork).Start(plugin);
}
void DoWork(object plugin)
{
bool warning = false;
if(!(plugin is IWritableImage outputFormat))
{
MessageBox.Show("Error trying to find selected plugin", MessageBoxType.Error);
return;
}
IOpticalMediaImage inputOptical = inputFormat as IOpticalMediaImage;
IWritableOpticalImage outputOptical = outputFormat as IWritableOpticalImage;
List<Track> tracks;
try { tracks = inputOptical?.Tracks; }
catch(Exception) { tracks = null; }
// Prepare UI
Application.Instance.Invoke(() =>
{
btnClose.Visible = false;
btnStart.Visible = false;
btnStop.Visible = true;
stkProgress.Visible = true;
stkOptions.Visible = false;
btnStop.Enabled = true;
cmbFormat.ReadOnly = true;
btnDestination.Visible = false;
prgProgress.MaxValue = 1;
prgProgress.MaxValue += inputFormat.Info.ReadableMediaTags.Count;
prgProgress.MaxValue++;
if(tracks != null) prgProgress.MaxValue++;
if(tracks == null)
{
prgProgress.MaxValue += 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(chkForce.Checked == true && !outputFormat.SupportedSectorTags.Contains(tag)) continue;
prgProgress.MaxValue++;
}
}
else
{
prgProgress.MaxValue += 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(chkForce.Checked == true && !outputFormat.SupportedSectorTags.Contains(tag)) continue;
prgProgress.MaxValue += tracks.Count;
}
}
if(dumpHardware != null) prgProgress.MaxValue++;
if(cicmMetadata != null) prgProgress.MaxValue++;
prgProgress.MaxValue++;
});
foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
{
if(outputFormat.SupportedMediaTags.Contains(mediaTag) || chkForce.Checked == true) continue;
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Converting image will lose media tag {mediaTag}, not continuing...",
MessageBoxType.Error);
});
return;
}
bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0;
foreach(SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags)
{
if(outputFormat.SupportedSectorTags.Contains(sectorTag)) continue;
if(chkForce.Checked == true)
{
if(sectorTag != SectorTagType.CdTrackFlags && sectorTag != SectorTagType.CdTrackIsrc &&
sectorTag != SectorTagType.CdSectorSubchannel) useLong = false;
continue;
}
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Converting image will lose sector tag {sectorTag}, not continuing...",
MessageBoxType.Error);
});
return;
}
Dictionary<string, string> parsedOptions = new Dictionary<string, string>();
if(grpOptions.Content is StackLayout stkImageOptions)
foreach(Control option in stkImageOptions.Children)
{
if(cancel) break;
string value;
switch(option)
{
case CheckBox optBoolean:
value = optBoolean.Checked?.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);
}
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Creating output image";
lblProgress2.Text = "";
prgProgress2.Indeterminate = true;
});
if(!outputFormat.Create(txtDestination.Text, inputFormat.Info.MediaType, parsedOptions,
inputFormat.Info.Sectors, inputFormat.Info.SectorSize))
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} creating output image.",
MessageBoxType.Error);
});
DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage);
return;
}
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Setting image metadata";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = true;
});
ImageInfo metadata = new ImageInfo
{
Application = "DiscImageChef",
ApplicationVersion = Version.GetVersion(),
Comments = txtComments.Text,
Creator = txtCreator.Text,
DriveFirmwareRevision = txtDriveFirmwareRevision.Text,
DriveManufacturer = txtDriveManufacturer.Text,
DriveModel = txtDriveModel.Text,
DriveSerialNumber = txtDriveSerialNumber.Text,
LastMediaSequence = (int)numLastMediaSequence.Value,
MediaBarcode = txtMediaBarcode.Text,
MediaManufacturer = txtMediaManufacturer.Text,
MediaModel = txtMediaModel.Text,
MediaPartNumber = txtMediaPartNumber.Text,
MediaSequence = (int)numMediaSequence.Value,
MediaSerialNumber = txtMediaSerialNumber.Text,
MediaTitle = txtMediaTitle.Text
};
if(!cancel)
if(!outputFormat.SetMetadata(metadata))
{
DicConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage);
if(chkForce.Checked != true)
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} setting metadata, not continuing...",
MessageBoxType.Error);
});
DicConsole.ErrorWriteLine("not continuing...");
return;
}
warning = true;
DicConsole.ErrorWriteLine("continuing...");
}
if(tracks != null && !cancel && outputOptical != null)
{
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Setting tracks list";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = true;
});
if(!outputOptical.SetTracks(tracks))
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} sending tracks list to output image.",
MessageBoxType.Error);
});
DicConsole.ErrorWriteLine("Error {0} sending tracks list to output image.",
outputFormat.ErrorMessage);
return;
}
}
foreach(MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
{
if(cancel) break;
Application.Instance.Invoke(() =>
{
lblProgress.Text = $"Converting media tag {mediaTag}";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = true;
});
if(chkForce.Checked == true && !outputFormat.SupportedMediaTags.Contains(mediaTag)) continue;
byte[] tag = inputFormat.ReadDiskTag(mediaTag);
if(outputFormat.WriteMediaTag(tag, mediaTag)) continue;
if(chkForce.Checked == true)
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage);
}
else
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} writing media tag, not continuing...",
MessageBoxType.Error);
});
DicConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...",
outputFormat.ErrorMessage);
return;
}
}
ulong doneSectors = 0;
if(tracks == null && !cancel)
{
Application.Instance.Invoke(() =>
{
lblProgress.Text =
$"Setting geometry to {inputFormat.Info.Cylinders} cylinders, {inputFormat.Info.Heads} heads and {inputFormat.Info.SectorsPerTrack} sectors per track";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = true;
});
if(!outputFormat.SetGeometry(inputFormat.Info.Cylinders, inputFormat.Info.Heads,
inputFormat.Info.SectorsPerTrack))
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} setting geometry, image may be incorrect, continuing...",
outputFormat.ErrorMessage);
}
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Converting sectors";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = false;
prgProgress2.MaxValue = (int)(inputFormat.Info.Sectors / numCount.Value);
});
while(doneSectors < inputFormat.Info.Sectors)
{
if(cancel) break;
byte[] sector;
uint sectorsToDo;
if(inputFormat.Info.Sectors - doneSectors >= (ulong)numCount.Value)
sectorsToDo = (uint)numCount.Value;
else sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors);
ulong sectors = doneSectors;
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting sectors {sectors} to {sectors + sectorsToDo} ({sectors / (double)inputFormat.Info.Sectors:P2} done)";
;
prgProgress2.Value = (int)(sectors / numCount.Value);
});
bool result;
if(useLong)
if(sectorsToDo == 1)
{
sector = inputFormat.ReadSectorLong(doneSectors);
result = outputFormat.WriteSectorLong(sector, doneSectors);
}
else
{
sector = inputFormat.ReadSectorsLong(doneSectors, sectorsToDo);
result = outputFormat.WriteSectorsLong(sector, doneSectors, sectorsToDo);
}
else
{
if(sectorsToDo == 1)
{
sector = inputFormat.ReadSector(doneSectors);
result = outputFormat.WriteSector(sector, doneSectors);
}
else
{
sector = inputFormat.ReadSectors(doneSectors, sectorsToDo);
result = outputFormat.WriteSectors(sector, doneSectors, sectorsToDo);
}
}
if(!result)
if(chkForce.Checked == true)
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...",
outputFormat.ErrorMessage, doneSectors);
}
else
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} writing sector {doneSectors}, not continuing...",
MessageBoxType.Error);
});
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...",
outputFormat.ErrorMessage, doneSectors);
return;
}
doneSectors += sectorsToDo;
}
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting sectors {inputFormat.Info.Sectors} to {inputFormat.Info.Sectors} ({1.0:P2} done)";
;
prgProgress2.Value = prgProgress2.MaxValue;
});
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
{
if(!useLong || cancel) break;
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(chkForce.Checked == true && !outputFormat.SupportedSectorTags.Contains(tag)) continue;
Application.Instance.Invoke(() =>
{
lblProgress.Text = $"Converting tag {tag}";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = false;
prgProgress2.MaxValue = (int)(inputFormat.Info.Sectors / numCount.Value);
});
doneSectors = 0;
while(doneSectors < inputFormat.Info.Sectors)
{
if(cancel) break;
byte[] sector;
uint sectorsToDo;
if(inputFormat.Info.Sectors - doneSectors >= (ulong)numCount.Value)
sectorsToDo = (uint)numCount.Value;
else sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors);
ulong sectors = doneSectors;
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting tag {sectors / (double)inputFormat.Info.Sectors} for sectors {sectors} to {sectors + sectorsToDo} ({sectors / (double)inputFormat.Info.Sectors:P2} done)";
prgProgress2.Value = (int)(sectors / numCount.Value);
});
bool result;
if(sectorsToDo == 1)
{
sector = inputFormat.ReadSectorTag(doneSectors, tag);
result = outputFormat.WriteSectorTag(sector, doneSectors, tag);
}
else
{
sector = inputFormat.ReadSectorsTag(doneSectors, sectorsToDo, tag);
result = outputFormat.WriteSectorsTag(sector, doneSectors, sectorsToDo, tag);
}
if(!result)
if(chkForce.Checked == true)
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...",
outputFormat.ErrorMessage, doneSectors);
}
else
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} writing sector {doneSectors}, not continuing...",
MessageBoxType.Error);
});
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...",
outputFormat.ErrorMessage, doneSectors);
return;
}
doneSectors += sectorsToDo;
}
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting tag {tag} for sectors {inputFormat.Info.Sectors} to {inputFormat.Info.Sectors} ({1.0:P2} done)";
prgProgress2.Value = prgProgress2.MaxValue;
});
}
}
else
{
foreach(Track track in tracks)
{
if(cancel) break;
doneSectors = 0;
ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1;
Application.Instance.Invoke(() =>
{
lblProgress.Text = $"Converting sectors in track {track.TrackSequence}";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = false;
prgProgress2.MaxValue = (int)(trackSectors / numCount.Value);
});
while(doneSectors < trackSectors)
{
if(cancel) break;
byte[] sector;
uint sectorsToDo;
if(trackSectors - doneSectors >= (ulong)numCount.Value) sectorsToDo = (uint)numCount.Value;
else
sectorsToDo =
(uint)(trackSectors - doneSectors);
ulong sectors = doneSectors;
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting sectors {sectors + track.TrackStartSector} to {sectors + sectorsToDo + track.TrackStartSector} in track {track.TrackSequence} ({(sectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors:P2} done)";
prgProgress2.Value = (int)(sectors / numCount.Value);
});
bool result;
if(useLong)
if(sectorsToDo == 1)
{
sector = inputFormat.ReadSectorLong(doneSectors + track.TrackStartSector);
result = outputFormat.WriteSectorLong(sector, doneSectors + track.TrackStartSector);
}
else
{
sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo);
result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector,
sectorsToDo);
}
else
{
if(sectorsToDo == 1)
{
sector = inputFormat.ReadSector(doneSectors + track.TrackStartSector);
result = outputFormat.WriteSector(sector, doneSectors + track.TrackStartSector);
}
else
{
sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo);
result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector,
sectorsToDo);
}
}
if(!result)
if(chkForce.Checked == true)
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...",
outputFormat.ErrorMessage, doneSectors);
}
else
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} writing sector {doneSectors}, not continuing...",
MessageBoxType.Error);
});
return;
}
doneSectors += sectorsToDo;
}
}
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting sectors {inputFormat.Info.Sectors} to {inputFormat.Info.Sectors} in track {tracks.Count} ({1.0:P2} done)";
prgProgress2.Value = prgProgress2.MaxValue;
});
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t))
{
if(!useLong || cancel) break;
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(chkForce.Checked == true && !outputFormat.SupportedSectorTags.Contains(tag)) continue;
foreach(Track track in tracks)
{
if(cancel) break;
doneSectors = 0;
ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1;
byte[] sector;
bool result;
Application.Instance.Invoke(() =>
{
lblProgress.Text = $"Converting tag {tag} in track {track.TrackSequence}.";
prgProgress.Value++;
lblProgress2.Text = "";
prgProgress2.Indeterminate = false;
prgProgress2.MaxValue = (int)(trackSectors / numCount.Value);
});
switch(tag)
{
case SectorTagType.CdTrackFlags:
case SectorTagType.CdTrackIsrc:
sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag);
result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag);
if(!result)
if(chkForce.Checked == true)
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} writing tag, continuing...",
outputFormat.ErrorMessage);
}
else
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} writing tag, not continuing...",
MessageBoxType.Error);
});
return;
}
continue;
}
while(doneSectors < trackSectors)
{
if(cancel) break;
uint sectorsToDo;
if(trackSectors - doneSectors >= (ulong)numCount.Value) sectorsToDo = (uint)numCount.Value;
else
sectorsToDo =
(uint)(trackSectors - doneSectors);
ulong sectors = doneSectors;
Application.Instance.Invoke(() =>
{
lblProgress2.Text =
$"Converting tag {tag} for sectors {sectors + track.TrackStartSector} to {sectors + sectorsToDo + track.TrackStartSector} in track {track.TrackSequence} ({(sectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors:P2} done)";
prgProgress2.Value = (int)(sectors / numCount.Value);
});
if(sectorsToDo == 1)
{
sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag);
result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector, tag);
}
else
{
sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo,
tag);
result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector,
sectorsToDo, tag);
}
if(!result)
if(chkForce.Checked == true)
{
warning = true;
DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, continuing...",
outputFormat.ErrorMessage, doneSectors);
}
else
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} writing tag for sector {doneSectors}, not continuing...",
MessageBoxType.Error);
});
return;
}
doneSectors += sectorsToDo;
}
}
}
}
Application.Instance.Invoke(() =>
{
lblProgress2.Visible = false;
prgProgress2.Visible = false;
});
bool ret = false;
if(dumpHardware != null && !cancel)
{
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Writing dump hardware list to output image.";
prgProgress.Value++;
});
ret = outputFormat.SetDumpHardware(dumpHardware);
if(!ret)
DicConsole.WriteLine("Error {0} writing dump hardware list to output image.",
outputFormat.ErrorMessage);
}
ret = false;
if(cicmMetadata != null && !cancel)
{
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Writing CICM XML metadata to output image.";
prgProgress.Value++;
});
outputFormat.SetCicmMetadata(cicmMetadata);
if(!ret)
DicConsole.WriteLine("Error {0} writing CICM XML metadata to output image.",
outputFormat.ErrorMessage);
}
Application.Instance.Invoke(() =>
{
lblProgress.Text = "Closing output image.";
prgProgress.Indeterminate = true;
});
if(cancel)
{
Application.Instance.Invoke(() =>
{
MessageBox.Show("Operation canceled, the output file is not correct.", MessageBoxType.Error);
btnClose.Visible = true;
btnStop.Visible = false;
stkProgress.Visible = false;
});
return;
}
if(!outputFormat.Close())
{
Application.Instance.Invoke(() =>
{
MessageBox
.Show($"Error {outputFormat.ErrorMessage} closing output image... Contents are not correct.",
MessageBoxType.Error);
});
return;
}
Application.Instance.Invoke(() =>
{
MessageBox.Show(warning
? "Some warnings happened. Check console for more information. Image should be correct."
: "Image converted successfully.");
btnClose.Visible = true;
btnStop.Visible = false;
stkProgress.Visible = false;
});
Statistics.AddCommand("convert-image");
}
protected void OnBtnClose(object sender, EventArgs e)
{
Close();
}
protected void OnBtnStop(object sender, EventArgs e)
{
cancel = true;
btnStop.Enabled = false;
}
void OnCmbFormatSelectedIndexChanged(object sender, EventArgs e)
{
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;
chkForce.Checked = true;
break;
}
foreach(SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags)
{
if(plugin.SupportedSectorTags.Contains(sectorTag)) continue;
chkForce.Visible = true;
chkForce.Checked = true;
break;
}
grpOptions.Visible = true;
StackLayout 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":
CheckBox optBoolean = new CheckBox();
optBoolean.ID = "opt" + option.name;
optBoolean.Text = option.description;
optBoolean.Checked = (bool)option.@default;
stkImageOptions.Items.Add(optBoolean);
break;
case "System.SByte":
case "System.Int16":
case "System.Int32":
case "System.Int64":
StackLayout stkNumber = new StackLayout();
stkNumber.Orientation = Orientation.Horizontal;
NumericStepper optNumber = new NumericStepper();
optNumber.ID = "opt" + option.name;
optNumber.Value = Convert.ToDouble(option.@default);
stkNumber.Items.Add(optNumber);
Label 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":
StackLayout stkUnsigned = new StackLayout();
stkUnsigned.Orientation = Orientation.Horizontal;
NumericStepper optUnsigned = new NumericStepper();
optUnsigned.ID = "opt" + option.name;
optUnsigned.MinValue = 0;
optUnsigned.Value = Convert.ToDouble(option.@default);
stkUnsigned.Items.Add(optUnsigned);
Label lblUnsigned = new Label();
lblUnsigned.Text = option.description;
stkUnsigned.Items.Add(lblUnsigned);
stkImageOptions.Items.Add(stkUnsigned);
break;
case "System.Single":
case "System.Double":
StackLayout stkFloat = new StackLayout();
stkFloat.Orientation = Orientation.Horizontal;
NumericStepper optFloat = new NumericStepper();
optFloat.ID = "opt" + option.name;
optFloat.DecimalPlaces = 2;
optFloat.Value = Convert.ToDouble(option.@default);
stkFloat.Items.Add(optFloat);
Label lblFloat = new Label();
lblFloat.Text = option.description;
stkFloat.Items.Add(lblFloat);
stkImageOptions.Items.Add(stkFloat);
break;
case "System.Guid":
// TODO
break;
case "System.String":
StackLayout stkString = new StackLayout();
stkString.Orientation = Orientation.Horizontal;
Label lblString = new Label();
lblString.Text = option.description;
stkString.Items.Add(lblString);
TextBox 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;
}
void OnBtnDestinationClick(object sender, EventArgs e)
{
if(!(cmbFormat.SelectedValue is IWritableImage plugin)) return;
SaveFileDialog dlgDestination = new SaveFileDialog {Title = "Choose destination file"};
dlgDestination.Filters.Add(new FileFilter(plugin.Name, plugin.KnownExtensions.ToArray()));
DialogResult result = dlgDestination.ShowDialog(this);
if(result != DialogResult.Ok)
{
txtDestination.Text = "";
return;
}
if(string.IsNullOrEmpty(Path.GetExtension(dlgDestination.FileName)))
dlgDestination.FileName += plugin.KnownExtensions.First();
txtDestination.Text = dlgDestination.FileName;
}
void OnBtnCreator(object sender, EventArgs e)
{
txtCreator.Text = inputFormat.Info.Creator;
}
void OnBtnMediaTitle(object sender, EventArgs e)
{
txtMediaTitle.Text = inputFormat.Info.MediaTitle;
}
void OnBtnComments(object sender, EventArgs e)
{
txtComments.Text = inputFormat.Info.Comments;
}
void OnBtnMediaManufacturer(object sender, EventArgs e)
{
txtMediaManufacturer.Text = inputFormat.Info.MediaManufacturer;
}
void OnBtnMediaModel(object sender, EventArgs e)
{
txtMediaModel.Text = inputFormat.Info.MediaModel;
}
void OnBtnMediaSerialNumber(object sender, EventArgs e)
{
txtMediaSerialNumber.Text = inputFormat.Info.MediaSerialNumber;
}
void OnBtnMediaBarcode(object sender, EventArgs e)
{
txtMediaBarcode.Text = inputFormat.Info.MediaBarcode;
}
void OnBtnMediaPartNumber(object sender, EventArgs e)
{
txtMediaPartNumber.Text = inputFormat.Info.MediaPartNumber;
}
void OnBtnMediaSequence(object sender, EventArgs e)
{
numMediaSequence.Value = inputFormat.Info.MediaSequence;
}
void OnBtnLastMediaSequence(object sender, EventArgs e)
{
numLastMediaSequence.Value = inputFormat.Info.LastMediaSequence;
}
void OnBtnDriveManufacturer(object sender, EventArgs e)
{
txtDriveManufacturer.Text = inputFormat.Info.DriveManufacturer;
}
void OnBtnDriveModel(object sender, EventArgs e)
{
txtDriveModel.Text = inputFormat.Info.DriveModel;
}
void OnBtnDriveSerialNumber(object sender, EventArgs e)
{
txtDriveSerialNumber.Text = inputFormat.Info.DriveSerialNumber;
}
void OnBtnDriveFirmwareRevision(object sender, EventArgs e)
{
txtDriveFirmwareRevision.Text = inputFormat.Info.DriveFirmwareRevision;
}
void OnBtnCicmXmlFromImageClick(object sender, EventArgs e)
{
txtCicmXml.Text = "<From image>";
cicmMetadata = inputFormat.CicmMetadata;
}
void OnBtnCicmXmlClick(object sender, EventArgs e)
{
cicmMetadata = null;
txtCicmXml.Text = "";
OpenFileDialog dlgMetadata =
new OpenFileDialog {Title = "Choose existing metadata sidecar", CheckFileExists = true};
dlgMetadata.Filters.Add(new FileFilter("CICM XML metadata", ".xml"));
DialogResult result = dlgMetadata.ShowDialog(this);
if(result != DialogResult.Ok) return;
XmlSerializer sidecarXs = new XmlSerializer(typeof(CICMMetadataType));
try
{
StreamReader sr = new StreamReader(dlgMetadata.FileName);
cicmMetadata = (CICMMetadataType)sidecarXs.Deserialize(sr);
sr.Close();
txtCicmXml.Text = dlgMetadata.FileName;
}
catch { MessageBox.Show("Incorrect metadata sidecar file...", MessageBoxType.Error); }
}
void OnBtnResumeFileFromImageClick(object sender, EventArgs e)
{
txtResumeFile.Text = "<From image>";
dumpHardware = inputFormat.DumpHardware;
}
void OnBtnResumeFileClick(object sender, EventArgs e)
{
dumpHardware = null;
txtResumeFile.Text = "";
OpenFileDialog dlgMetadata =
new OpenFileDialog {Title = "Choose existing resume file", CheckFileExists = true};
dlgMetadata.Filters.Add(new FileFilter("CICM XML metadata", ".xml"));
DialogResult result = dlgMetadata.ShowDialog(this);
if(result != DialogResult.Ok) return;
XmlSerializer sidecarXs = new XmlSerializer(typeof(Resume));
try
{
StreamReader sr = new StreamReader(dlgMetadata.FileName);
Resume resume = (Resume)sidecarXs.Deserialize(sr);
if(resume.Tries != null && !resume.Tries.Any())
{
dumpHardware = resume.Tries;
txtResumeFile.Text = dlgMetadata.FileName;
}
else MessageBox.Show("Resume file does not contain dump hardware information...", MessageBoxType.Error);
sr.Close();
}
catch { MessageBox.Show("Incorrect resume file...", MessageBoxType.Error); }
}
#region XAML IDs
TextBox txtSource;
ComboBox cmbFormat;
TextBox txtDestination;
Button btnDestination;
StackLayout stkOptions;
NumericStepper numCount;
Label txtCount;
CheckBox chkForce;
Label lblCreator;
TextBox txtCreator;
Button btnCreator;
GroupBox grpMetadata;
Label lblMediaTitle;
TextBox txtMediaTitle;
Button btnMediaTitle;
Label lblMediaManufacturer;
TextBox txtMediaManufacturer;
Button btnMediaManufacturer;
Label lblMediaModel;
TextBox txtMediaModel;
Button btnMediaModel;
Label lblMediaSerialNumber;
TextBox txtMediaSerialNumber;
Button btnMediaSerialNumber;
Label lblMediaBarcode;
TextBox txtMediaBarcode;
Button btnMediaBarcode;
Label lblMediaPartNumber;
TextBox txtMediaPartNumber;
Button btnMediaPartNumber;
Label lblMediaSequence;
NumericStepper numMediaSequence;
Button btnMediaSequence;
Label lblLastMediaSequence;
NumericStepper numLastMediaSequence;
Button btnLastMediaSequence;
Label lblDriveManufacturer;
TextBox txtDriveManufacturer;
Button btnDriveManufacturer;
Label lblDriveModel;
TextBox txtDriveModel;
Button btnDriveModel;
Label lblDriveSerialNumber;
TextBox txtDriveSerialNumber;
Button btnDriveSerialNumber;
Label lblDriveFirmwareRevision;
TextBox txtDriveFirmwareRevision;
Button btnDriveFirmwareRevision;
TextArea txtComments;
Button btnComments;
TextBox txtCicmXml;
Button btnCicmXmlFromImage;
Button btnCicmXml;
TextBox txtResumeFile;
Button btnResumeFileFromImage;
Button btnResumeFile;
GroupBox grpOptions;
StackLayout stkProgress;
StackLayout stkProgress1;
Label lblProgress;
ProgressBar prgProgress;
StackLayout stkProgress2;
Label lblProgress2;
ProgressBar prgProgress2;
Button btnStart;
Button btnClose;
Button btnStop;
#endregion
}
}