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.Linq;
using System.Reactive;
using System.Text;
using System.Threading;
using System.Xml.Serialization;
using Aaru.CommonTypes;
@@ -45,6 +46,8 @@ using Aaru.CommonTypes.Metadata;
using Aaru.CommonTypes.Structs;
using Aaru.Console;
using Aaru.Core;
using Aaru.Core.Media;
using Aaru.Devices;
using Aaru.Gui.Models;
using Avalonia.Controls;
using Avalonia.Threading;
@@ -67,11 +70,9 @@ namespace Aaru.Gui.ViewModels.Windows
string _commentsText;
bool _commentsVisible;
string _creatorText;
bool _creatorVisible;
bool _destinationEnabled;
string _destinationText;
bool _destinationVisible;
string _driveFirmwareRevisionText;
bool _driveFirmwareRevisionVisible;
@@ -82,7 +83,6 @@ namespace Aaru.Gui.ViewModels.Windows
string _driveSerialNumberText;
bool _driveSerialNumberVisible;
bool _forceChecked;
bool _formatReadOnly;
double _lastMediaSequenceValue;
bool _lastMediaSequenceVisible;
@@ -152,7 +152,6 @@ namespace Aaru.Gui.ViewModels.Windows
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);
@@ -162,11 +161,8 @@ namespace Aaru.Gui.ViewModels.Windows
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);
@@ -1014,6 +1010,47 @@ namespace Aaru.Gui.ViewModels.Windows
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)
{
if(!useLong || cancel)
@@ -1076,11 +1113,44 @@ namespace Aaru.Gui.ViewModels.Windows
if(sectorsToDo == 1)
{
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);
}
else
{
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);
}
@@ -1118,6 +1188,21 @@ namespace Aaru.Gui.ViewModels.Windows
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

View File

@@ -36,6 +36,7 @@ using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Aaru.CommonTypes;
using Aaru.CommonTypes.Enums;
@@ -44,6 +45,8 @@ using Aaru.CommonTypes.Metadata;
using Aaru.CommonTypes.Structs;
using Aaru.Console;
using Aaru.Core;
using Aaru.Core.Media;
using Aaru.Devices;
using Schemas;
using ImageInfo = Aaru.CommonTypes.Structs.ImageInfo;
using MediaType = Aaru.CommonTypes.MediaType;
@@ -186,6 +189,30 @@ namespace Aaru.Commands.Image
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>
{
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 mediaBarcode, string mediaManufacturer, string mediaModel,
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();
@@ -214,6 +242,12 @@ namespace Aaru.Commands.Image
if(verbose)
AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine;
if(fixSubchannelCrc)
fixSubchannel = true;
if(fixSubchannel)
fixSubchannelPosition = true;
Statistics.AddCommand("convert-image");
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", "--resume-file={0}", resumeFile);
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);
AaruConsole.DebugWriteLine("Analyze command", "Parsed options:");
@@ -690,6 +727,48 @@ namespace Aaru.Commands.Image
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))
{
if(!useLong)
@@ -763,13 +842,43 @@ namespace Aaru.Commands.Image
if(sectorsToDo == 1)
{
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
{
sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo,
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,
sectorsToDo, tag);
}
@@ -810,6 +919,21 @@ namespace Aaru.Commands.Image
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
{