Add options to fix subchannels on image conversion.

This commit is contained in:
2020-07-14 02:16:53 +01:00
parent f1244d543c
commit 4759a73679
2 changed files with 282 additions and 73 deletions

View File

@@ -36,6 +36,7 @@ using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reactive; using System.Reactive;
using System.Text;
using System.Threading; using System.Threading;
using System.Xml.Serialization; using System.Xml.Serialization;
using Aaru.CommonTypes; using Aaru.CommonTypes;
@@ -45,6 +46,8 @@ using Aaru.CommonTypes.Metadata;
using Aaru.CommonTypes.Structs; using Aaru.CommonTypes.Structs;
using Aaru.Console; using Aaru.Console;
using Aaru.Core; using Aaru.Core;
using Aaru.Core.Media;
using Aaru.Devices;
using Aaru.Gui.Models; using Aaru.Gui.Models;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Threading; using Avalonia.Threading;
@@ -67,11 +70,9 @@ namespace Aaru.Gui.ViewModels.Windows
string _commentsText; string _commentsText;
bool _commentsVisible; bool _commentsVisible;
string _creatorText; string _creatorText;
bool _creatorVisible; bool _creatorVisible;
bool _destinationEnabled; bool _destinationEnabled;
string _destinationText; string _destinationText;
bool _destinationVisible; bool _destinationVisible;
string _driveFirmwareRevisionText; string _driveFirmwareRevisionText;
bool _driveFirmwareRevisionVisible; bool _driveFirmwareRevisionVisible;
@@ -82,7 +83,6 @@ namespace Aaru.Gui.ViewModels.Windows
string _driveSerialNumberText; string _driveSerialNumberText;
bool _driveSerialNumberVisible; bool _driveSerialNumberVisible;
bool _forceChecked; bool _forceChecked;
bool _formatReadOnly; bool _formatReadOnly;
double _lastMediaSequenceValue; double _lastMediaSequenceValue;
bool _lastMediaSequenceVisible; bool _lastMediaSequenceVisible;
@@ -152,7 +152,6 @@ namespace Aaru.Gui.ViewModels.Windows
StartCommand = ReactiveCommand.Create(ExecuteStartCommand); StartCommand = ReactiveCommand.Create(ExecuteStartCommand);
CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand); CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand);
StopCommand = ReactiveCommand.Create(ExecuteStopCommand); StopCommand = ReactiveCommand.Create(ExecuteStopCommand);
SourceText = imageSource; SourceText = imageSource;
CreatorVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.Creator); CreatorVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.Creator);
MediaTitleVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaTitle); MediaTitleVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaTitle);
@@ -162,11 +161,8 @@ namespace Aaru.Gui.ViewModels.Windows
MediaSerialNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaSerialNumber); MediaSerialNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaSerialNumber);
MediaBarcodeVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaBarcode); MediaBarcodeVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaBarcode);
MediaPartNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaPartNumber); MediaPartNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.MediaPartNumber);
MediaSequenceVisible = inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0; MediaSequenceVisible = inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0;
LastMediaSequenceVisible = inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0; LastMediaSequenceVisible = inputFormat.Info.MediaSequence != 0 && inputFormat.Info.LastMediaSequence != 0;
DriveManufacturerVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveManufacturer); DriveManufacturerVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveManufacturer);
DriveModelVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveModel); DriveModelVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveModel);
DriveSerialNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveSerialNumber); DriveSerialNumberVisible = !string.IsNullOrWhiteSpace(inputFormat.Info.DriveSerialNumber);
@@ -1014,6 +1010,47 @@ namespace Aaru.Gui.ViewModels.Windows
Progress2Value = Progress2MaxValue; Progress2Value = Progress2MaxValue;
}); });
Dictionary<byte, string> isrcs = new Dictionary<byte, string>();
Dictionary<byte, byte> trackFlags = new Dictionary<byte, byte>();
string mcn = null;
HashSet<int> subchannelExtents = new HashSet<int>();
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.
Where(t => t == SectorTagType.CdTrackIsrc).OrderBy(t => t))
{
foreach(Track track in inputOptical.Tracks)
{
byte[] isrc = inputFormat.ReadSectorTag(track.TrackSequence, tag);
if(isrc is null)
continue;
isrcs[(byte)track.TrackSequence] = 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)
{
byte[] flags = inputFormat.ReadSectorTag(track.TrackSequence, tag);
if(flags is null)
continue;
trackFlags[(byte)track.TrackSequence] = 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) foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags)
{ {
if(!useLong || cancel) if(!useLong || cancel)
@@ -1076,11 +1113,44 @@ namespace Aaru.Gui.ViewModels.Windows
if(sectorsToDo == 1) if(sectorsToDo == 1)
{ {
sector = inputFormat.ReadSectorTag(doneSectors, tag); sector = inputFormat.ReadSectorTag(doneSectors, tag);
Track track = tracks.LastOrDefault(t => t.TrackStartSector >= doneSectors);
if(tag == SectorTagType.CdSectorSubchannel &&
track != null)
{
bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw,
MmcSubchannel.Raw, sector, doneSectors, 1, null, isrcs,
(byte)track.TrackSequence, ref mcn, tracks.ToArray(), subchannelExtents, false,
outputFormat, false, false, null, null);
if(indexesChanged)
outputOptical.SetTracks(tracks.ToList());
result = true;
}
else
result = outputFormat.WriteSectorTag(sector, doneSectors, tag); result = outputFormat.WriteSectorTag(sector, doneSectors, tag);
} }
else else
{ {
sector = inputFormat.ReadSectorsTag(doneSectors, sectorsToDo, tag); sector = inputFormat.ReadSectorsTag(doneSectors, sectorsToDo, tag);
Track track = tracks.LastOrDefault(t => t.TrackStartSector >= doneSectors);
if(tag == SectorTagType.CdSectorSubchannel &&
track != null)
{
bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw,
MmcSubchannel.Raw, sector, doneSectors, sectorsToDo, null, isrcs,
(byte)track.TrackSequence, ref mcn, tracks.ToArray(), subchannelExtents, false,
outputFormat, false, false, null, null);
if(indexesChanged)
outputOptical.SetTracks(tracks.ToList());
result = true;
}
else
result = outputFormat.WriteSectorsTag(sector, doneSectors, sectorsToDo, tag); result = outputFormat.WriteSectorsTag(sector, doneSectors, sectorsToDo, tag);
} }
@@ -1118,6 +1188,21 @@ namespace Aaru.Gui.ViewModels.Windows
Progress2Value = Progress2MaxValue; Progress2Value = Progress2MaxValue;
}); });
if(isrcs.Count > 0)
foreach(KeyValuePair<byte, string> isrc in isrcs)
outputOptical.WriteSectorTag(Encoding.UTF8.GetBytes(isrc.Value), isrc.Key,
SectorTagType.CdTrackIsrc);
if(trackFlags.Count > 0)
foreach(KeyValuePair<byte, byte> 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 else

View File

@@ -36,6 +36,7 @@ using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Xml.Serialization; using System.Xml.Serialization;
using Aaru.CommonTypes; using Aaru.CommonTypes;
using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Enums;
@@ -44,6 +45,8 @@ using Aaru.CommonTypes.Metadata;
using Aaru.CommonTypes.Structs; using Aaru.CommonTypes.Structs;
using Aaru.Console; using Aaru.Console;
using Aaru.Core; using Aaru.Core;
using Aaru.Core.Media;
using Aaru.Devices;
using Schemas; using Schemas;
using ImageInfo = Aaru.CommonTypes.Structs.ImageInfo; using ImageInfo = Aaru.CommonTypes.Structs.ImageInfo;
using MediaType = Aaru.CommonTypes.MediaType; using MediaType = Aaru.CommonTypes.MediaType;
@@ -186,6 +189,30 @@ namespace Aaru.Commands.Image
Argument = new Argument<string>(() => null), Required = false Argument = new Argument<string>(() => null), Required = false
}); });
Add(new Option(new[]
{
"--fix-subchannel-position"
}, "Store subchannel according to the sector they describe.")
{
Argument = new Argument<bool>(() => true), Required = false
});
Add(new Option(new[]
{
"--fix-subchannel"
}, "Try to fix subchannel. Implies fixing subchannel position.")
{
Argument = new Argument<bool>(() => false), Required = false
});
Add(new Option(new[]
{
"--fix-subchannel-crc"
}, "If subchannel looks OK but CRC fails, rewrite it. Implies fixing subchannel.")
{
Argument = new Argument<bool>(() => false), Required = false
});
AddArgument(new Argument<string> AddArgument(new Argument<string>
{ {
Arity = ArgumentArity.ExactlyOne, Description = "Input image path", Name = "input-path" Arity = ArgumentArity.ExactlyOne, Description = "Input image path", Name = "input-path"
@@ -204,7 +231,8 @@ namespace Aaru.Commands.Image
string driveSerialNumber, bool force, string inputPath, int lastMediaSequence, string driveSerialNumber, bool force, string inputPath, int lastMediaSequence,
string mediaBarcode, string mediaManufacturer, string mediaModel, string mediaBarcode, string mediaManufacturer, string mediaModel,
string mediaPartNumber, int mediaSequence, string mediaSerialNumber, string mediaTitle, string mediaPartNumber, int mediaSequence, string mediaSerialNumber, string mediaTitle,
string outputPath, string options, string resumeFile, string format, string geometry) string outputPath, string options, string resumeFile, string format, string geometry,
bool fixSubchannelPosition, bool fixSubchannel, bool fixSubchannelCrc)
{ {
MainClass.PrintCopyright(); MainClass.PrintCopyright();
@@ -214,6 +242,12 @@ namespace Aaru.Commands.Image
if(verbose) if(verbose)
AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(fixSubchannelCrc)
fixSubchannel = true;
if(fixSubchannel)
fixSubchannelPosition = true;
Statistics.AddCommand("convert-image"); Statistics.AddCommand("convert-image");
AaruConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", cicmXml); AaruConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", cicmXml);
@@ -241,6 +275,9 @@ namespace Aaru.Commands.Image
AaruConsole.DebugWriteLine("Analyze command", "--output={0}", outputPath); AaruConsole.DebugWriteLine("Analyze command", "--output={0}", outputPath);
AaruConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile); AaruConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile);
AaruConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose); AaruConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);
AaruConsole.DebugWriteLine("Analyze command", "--fix-subchannel-position={0}", fixSubchannelPosition);
AaruConsole.DebugWriteLine("Analyze command", "--fix-subchannel={0}", fixSubchannel);
AaruConsole.DebugWriteLine("Analyze command", "--fix-subchannel-crc={0}", fixSubchannelCrc);
Dictionary<string, string> parsedOptions = Core.Options.Parse(options); Dictionary<string, string> parsedOptions = Core.Options.Parse(options);
AaruConsole.DebugWriteLine("Analyze command", "Parsed options:"); AaruConsole.DebugWriteLine("Analyze command", "Parsed options:");
@@ -690,6 +727,48 @@ namespace Aaru.Commands.Image
AaruConsole.WriteLine(); AaruConsole.WriteLine();
Dictionary<byte, string> isrcs = new Dictionary<byte, string>();
Dictionary<byte, byte> trackFlags = new Dictionary<byte, byte>();
string mcn = null;
HashSet<int> subchannelExtents = new HashSet<int>();
Track[] tracks = inputOptical.Tracks.ToArray();
foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.
Where(t => t == SectorTagType.CdTrackIsrc).OrderBy(t => t))
{
foreach(Track track in inputOptical.Tracks)
{
byte[] isrc = inputFormat.ReadSectorTag(track.TrackSequence, tag);
if(isrc is null)
continue;
isrcs[(byte)track.TrackSequence] = 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)
{
byte[] flags = inputFormat.ReadSectorTag(track.TrackSequence, tag);
if(flags is null)
continue;
trackFlags[(byte)track.TrackSequence] = 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.OrderBy(t => t)) foreach(SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t))
{ {
if(!useLong) if(!useLong)
@@ -763,13 +842,43 @@ namespace Aaru.Commands.Image
if(sectorsToDo == 1) if(sectorsToDo == 1)
{ {
sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag); sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag);
result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector, tag);
if(tag == SectorTagType.CdSectorSubchannel)
{
bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw,
MmcSubchannel.Raw, sector, doneSectors + track.TrackStartSector, 1, null,
isrcs, (byte)track.TrackSequence, ref mcn, tracks, subchannelExtents,
fixSubchannelPosition, outputFormat, fixSubchannel, fixSubchannelCrc, null,
null);
if(indexesChanged)
outputOptical.SetTracks(tracks.ToList());
result = true;
}
else
result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector,
tag);
} }
else else
{ {
sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo, sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo,
tag); tag);
if(tag == SectorTagType.CdSectorSubchannel)
{
bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw,
MmcSubchannel.Raw, sector, doneSectors + track.TrackStartSector,
sectorsToDo, null, isrcs, (byte)track.TrackSequence, ref mcn, tracks,
subchannelExtents, fixSubchannelPosition, outputFormat, fixSubchannel,
fixSubchannelCrc, null, null);
if(indexesChanged)
outputOptical.SetTracks(tracks.ToList());
result = true;
}
else
result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector, result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector,
sectorsToDo, tag); sectorsToDo, tag);
} }
@@ -810,6 +919,21 @@ namespace Aaru.Commands.Image
AaruConsole.WriteLine(); AaruConsole.WriteLine();
} }
if(isrcs.Count > 0)
foreach(KeyValuePair<byte, string> isrc in isrcs)
outputOptical.WriteSectorTag(Encoding.UTF8.GetBytes(isrc.Value), isrc.Key,
SectorTagType.CdTrackIsrc);
if(trackFlags.Count > 0)
foreach(KeyValuePair<byte, byte> 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 else
{ {