From 9bbc70f06e8c49414704ff1c749b8642ec1b23a0 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Thu, 2 Jan 2020 18:31:49 +0000 Subject: [PATCH] Calculate track sizes and pregaps in media info. --- .../Devices/Dumping/CompactDisc/Dump.cs | 16 ++--- .../Devices/Dumping/CompactDisc/Pregap.cs | 18 ++--- .../Devices/Dumping/CompactDisc/Subchannel.cs | 47 ++++--------- .../Devices/Dumping/CompactDisc/Tracks.cs | 68 +++++++++++-------- DiscImageChef/Commands/DeviceInfo.cs | 32 +++++++++ DiscImageChef/Commands/MediaInfo.cs | 35 ++++++++++ 6 files changed, 136 insertions(+), 80 deletions(-) diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs index ad6ef743d..fec4b30d3 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Dump.cs @@ -138,8 +138,8 @@ namespace DiscImageChef.Core.Devices.Dumping } // Check subchannels support - supportsPqSubchannel = SupportsPqSubchannel(); - supportsRwSubchannel = SupportsRwSubchannel(); + supportsPqSubchannel = SupportsPqSubchannel(_dev, _dumpLog, UpdateStatus); + supportsRwSubchannel = SupportsRwSubchannel(_dev, _dumpLog, UpdateStatus); switch(_subchannel) { @@ -207,8 +207,7 @@ namespace DiscImageChef.Core.Devices.Dumping if(!_outputPlugin.SupportedSectorTags.Contains(SectorTagType.CdSectorSubchannel) && supportedSubchannel != MmcSubchannel.None) { - if(_force || - _subchannel == DumpSubchannel.None) + if(_force || _subchannel == DumpSubchannel.None) { _dumpLog.WriteLine("Output format does not support subchannels, continuing..."); UpdateStatus?.Invoke("Output format does not support subchannels, continuing..."); @@ -339,13 +338,13 @@ namespace DiscImageChef.Core.Devices.Dumping blockSize = sectorSize + subSize; - tracks = GetCdTracks(ref blockSize, dskType, out lastSector, leadOutStarts, mediaTags, out toc, trackFlags, - subType); + tracks = GetCdTracks(ref blockSize, _dev, dskType, _dumpLog, _force, out lastSector, leadOutStarts, + mediaTags, StoppingErrorMessage, subType, out toc, trackFlags, UpdateStatus); if(tracks is null) return; - SolveTrackPregaps(tracks, supportsPqSubchannel, supportsRwSubchannel); + SolveTrackPregaps(_dev, _dumpLog, UpdateStatus, tracks, supportsPqSubchannel, supportsRwSubchannel); for(int t = 1; t < tracks.Length; t++) tracks[t - 1].TrackEndSector = tracks[t].TrackStartSector - 1; @@ -872,7 +871,8 @@ namespace DiscImageChef.Core.Devices.Dumping ReadCdData(audioExtents, blocks, blockSize, ref currentSpeed, currentTry, extents, ibgLog, ref imageWriteDuration, lastSector, leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed, out newTrim, tracks[0].TrackType != TrackType.Audio, offsetBytes, read6, read10, read12, read16, - readcd, sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors, ref totalDuration, tracks); + readcd, sectorsForOffset, subSize, supportedSubchannel, supportsLongSectors, ref totalDuration, + tracks); // TODO: Enable when underlying images support lead-outs /* diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Pregap.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Pregap.cs index f0e112789..2fc2a9bf2 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Pregap.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Pregap.cs @@ -35,6 +35,7 @@ using System.Collections.Generic; using System.IO; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Structs; +using DiscImageChef.Core.Logging; using DiscImageChef.Devices; // ReSharper disable JoinDeclarationAndInitializer @@ -118,7 +119,8 @@ namespace DiscImageChef.Core.Devices.Dumping firstTrackPregapMs.Close(); } - void SolveTrackPregaps(Track[] tracks, bool supportsPqSubchannel, bool supportsRwSubchannel) + public static void SolveTrackPregaps(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus, + Track[] tracks, bool supportsPqSubchannel, bool supportsRwSubchannel) { bool sense; // Sense indicator byte[] cmdBuf; // Data buffer @@ -136,14 +138,14 @@ namespace DiscImageChef.Core.Devices.Dumping while(lba > tracks[i - 1].TrackStartSector) { if(supportsPqSubchannel) - sense = _dev.ReadCd(out cmdBuf, out _, lba, 16, 1, MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + sense = dev.ReadCd(out cmdBuf, out _, lba, 16, 1, MmcSectorTypes.AllTypes, false, false, false, + MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16, + dev.Timeout, out _); else { sense = dev.ReadCd(out cmdBuf, out _, lba, 96, 1, MmcSectorTypes.AllTypes, false, false, false, - MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Raw, + dev.Timeout, out _); if(!sense) { @@ -229,8 +231,8 @@ namespace DiscImageChef.Core.Devices.Dumping } #if DEBUG - _dumpLog.WriteLine($"Track {tracks[i].TrackSequence} pregap is {trackPregap} sectors"); - UpdateStatus?.Invoke($"Track {tracks[i].TrackSequence} pregap is {trackPregap} sectors"); + dumpLog?.WriteLine($"Track {tracks[i].TrackSequence} pregap is {trackPregap} sectors"); + updateStatus?.Invoke($"Track {tracks[i].TrackSequence} pregap is {trackPregap} sectors"); #endif tracks[i].TrackPregap = (ulong)trackPregap; diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Subchannel.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Subchannel.cs index bc242446b..61a107387 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Subchannel.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Subchannel.cs @@ -30,31 +30,8 @@ // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml.Serialization; -using DiscImageChef.CommonTypes; -using DiscImageChef.CommonTypes.Enums; -using DiscImageChef.CommonTypes.Extents; -using DiscImageChef.CommonTypes.Interfaces; -using DiscImageChef.CommonTypes.Metadata; -using DiscImageChef.CommonTypes.Structs; -using DiscImageChef.Console; using DiscImageChef.Core.Logging; -using DiscImageChef.Core.Media.Detection; -using DiscImageChef.Decoders.CD; -using DiscImageChef.Decoders.SCSI; -using DiscImageChef.Decoders.SCSI.MMC; using DiscImageChef.Devices; -using Schemas; -using CdOffset = DiscImageChef.Database.Models.CdOffset; -using MediaType = DiscImageChef.CommonTypes.MediaType; -using PlatformID = DiscImageChef.CommonTypes.Interop.PlatformID; -using Session = DiscImageChef.Decoders.CD.Session; -using TrackType = DiscImageChef.CommonTypes.Enums.TrackType; // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration @@ -64,24 +41,24 @@ namespace DiscImageChef.Core.Devices.Dumping { partial class Dump { - bool SupportsRwSubchannel() + public static bool SupportsRwSubchannel(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus) { - _dumpLog.WriteLine("Checking if drive supports full raw subchannel reading..."); - UpdateStatus?.Invoke("Checking if drive supports full raw subchannel reading..."); + dumpLog?.WriteLine("Checking if drive supports full raw subchannel reading..."); + updateStatus?.Invoke("Checking if drive supports full raw subchannel reading..."); - return!_dev.ReadCd(out _, out _, 0, 2352 + 96, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Raw, - _dev.Timeout, out _); + return!dev.ReadCd(out _, out _, 0, 2352 + 96, 1, MmcSectorTypes.AllTypes, false, false, true, + MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, + out _); } - bool SupportsPqSubchannel() + public static bool SupportsPqSubchannel(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus) { - _dumpLog.WriteLine("Checking if drive supports PQ subchannel reading..."); - UpdateStatus?.Invoke("Checking if drive supports PQ subchannel reading..."); + dumpLog?.WriteLine("Checking if drive supports PQ subchannel reading..."); + updateStatus?.Invoke("Checking if drive supports PQ subchannel reading..."); - return!_dev.ReadCd(out _, out _, 0, 2352 + 16, 1, MmcSectorTypes.AllTypes, false, false, true, - MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Q16, - _dev.Timeout, out _); + return!dev.ReadCd(out _, out _, 0, 2352 + 16, 1, MmcSectorTypes.AllTypes, false, false, true, + MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, + out _); } } } \ No newline at end of file diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Tracks.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Tracks.cs index bcb78ef44..b4be82a11 100644 --- a/DiscImageChef.Core/Devices/Dumping/CompactDisc/Tracks.cs +++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc/Tracks.cs @@ -36,7 +36,9 @@ using System.Linq; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Structs; +using DiscImageChef.Core.Logging; using DiscImageChef.Decoders.CD; +using DiscImageChef.Devices; // ReSharper disable JoinDeclarationAndInitializer // ReSharper disable InlineOutVariableDeclaration @@ -48,17 +50,25 @@ namespace DiscImageChef.Core.Devices.Dumping { /// Reads the TOC, processes it, returns the track list and last sector /// Size of the read sector in bytes + /// Device /// Disc type + /// Dump log + /// Force dump enabled /// Last sector number /// Lead-out starts /// Media tags + /// Stopping error message handler + /// Track subchannel type /// Full CD TOC /// Track flags - /// Track subchannel type + /// Update status handler /// List of tracks - Track[] GetCdTracks(ref uint blockSize, MediaType dskType, out long lastSector, - Dictionary leadOutStarts, Dictionary mediaTags, - out FullTOC.CDFullTOC? toc, Dictionary trackFlags, TrackSubchannelType subType) + public static Track[] GetCdTracks(ref uint blockSize, Device dev, MediaType dskType, DumpLog dumpLog, + bool force, out long lastSector, Dictionary leadOutStarts, + Dictionary mediaTags, + ErrorMessageHandler stoppingErrorMessage, TrackSubchannelType subType, + out FullTOC.CDFullTOC? toc, Dictionary trackFlags, + UpdateStatusHandler updateStatus) { byte[] cmdBuf = null; // Data buffer const uint sectorSize = 2352; // Full sector size @@ -71,9 +81,9 @@ namespace DiscImageChef.Core.Devices.Dumping // We discarded all discs that falsify a TOC before requesting a real TOC // No TOC, no CD (or an empty one) - _dumpLog.WriteLine("Reading full TOC"); - UpdateStatus?.Invoke("Reading full TOC"); - sense = _dev.ReadRawToc(out cmdBuf, out _, 0, _dev.Timeout, out _); + dumpLog?.WriteLine("Reading full TOC"); + updateStatus?.Invoke("Reading full TOC"); + sense = dev.ReadRawToc(out cmdBuf, out _, 0, dev.Timeout, out _); if(!sense) { @@ -83,12 +93,12 @@ namespace DiscImageChef.Core.Devices.Dumping { tmpBuf = new byte[cmdBuf.Length - 2]; Array.Copy(cmdBuf, 2, tmpBuf, 0, cmdBuf.Length - 2); - mediaTags.Add(MediaTagType.CD_FullTOC, tmpBuf); + mediaTags?.Add(MediaTagType.CD_FullTOC, tmpBuf); } } - UpdateStatus?.Invoke("Building track map..."); - _dumpLog.WriteLine("Building track map..."); + updateStatus?.Invoke("Building track map..."); + dumpLog?.WriteLine("Building track map..."); if(toc.HasValue) { @@ -113,7 +123,7 @@ namespace DiscImageChef.Core.Devices.Dumping TrackSubchannelType = subType }); - trackFlags.Add(trk.POINT, trk.CONTROL); + trackFlags?.Add(trk.POINT, trk.CONTROL); } else if(trk.POINT == 0xA2) { @@ -154,7 +164,7 @@ namespace DiscImageChef.Core.Devices.Dumping } lastSector = ((phour * 3600 * 75) + (pmin * 60 * 75) + (psec * 75) + pframe) - 150; - leadOutStarts.Add(trk.SessionNumber, lastSector + 1); + leadOutStarts?.Add(trk.SessionNumber, lastSector + 1); } else if(trk.POINT == 0xA0 && trk.ADR == 1) @@ -181,18 +191,18 @@ namespace DiscImageChef.Core.Devices.Dumping } else { - UpdateStatus?.Invoke("Cannot read RAW TOC, requesting processed one..."); - _dumpLog.WriteLine("Cannot read RAW TOC, requesting processed one..."); - sense = _dev.ReadToc(out cmdBuf, out _, false, 0, _dev.Timeout, out _); + updateStatus?.Invoke("Cannot read RAW TOC, requesting processed one..."); + dumpLog?.WriteLine("Cannot read RAW TOC, requesting processed one..."); + sense = dev.ReadToc(out cmdBuf, out _, false, 0, dev.Timeout, out _); TOC.CDTOC? oldToc = TOC.Decode(cmdBuf); if((sense || !oldToc.HasValue) && - !_force) + !force) { - _dumpLog.WriteLine("Could not read TOC, if you want to continue, use force, and will try from LBA 0 to 360000..."); + dumpLog?.WriteLine("Could not read TOC, if you want to continue, use force, and will try from LBA 0 to 360000..."); - StoppingErrorMessage?. + stoppingErrorMessage?. Invoke("Could not read TOC, if you want to continue, use force, and will try from LBA 0 to 360000..."); return null; @@ -214,7 +224,7 @@ namespace DiscImageChef.Core.Devices.Dumping TrackRawBytesPerSector = (int)sectorSize, TrackSubchannelType = subType }); - trackFlags.Add(trk.TrackNumber, trk.CONTROL); + trackFlags?.Add(trk.TrackNumber, trk.CONTROL); } else if(trk.TrackNumber == 0xAA) { @@ -229,8 +239,8 @@ namespace DiscImageChef.Core.Devices.Dumping if(trackList.Count == 0) { - UpdateStatus?.Invoke("No tracks found, adding a single track from 0 to Lead-Out"); - _dumpLog.WriteLine("No tracks found, adding a single track from 0 to Lead-Out"); + updateStatus?.Invoke("No tracks found, adding a single track from 0 to Lead-Out"); + dumpLog?.WriteLine("No tracks found, adding a single track from 0 to Lead-Out"); trackList.Add(new Track { @@ -240,12 +250,12 @@ namespace DiscImageChef.Core.Devices.Dumping TrackSubchannelType = subType }); - trackFlags.Add(1, (byte)(leadoutTrackType == TrackType.Audio ? 0 : 4)); + trackFlags?.Add(1, (byte)(leadoutTrackType == TrackType.Audio ? 0 : 4)); } if(lastSector == 0) { - sense = _dev.ReadCapacity16(out cmdBuf, out _, _dev.Timeout, out _); + sense = dev.ReadCapacity16(out cmdBuf, out _, dev.Timeout, out _); if(!sense) { @@ -258,7 +268,7 @@ namespace DiscImageChef.Core.Devices.Dumping } else { - sense = _dev.ReadCapacity(out cmdBuf, out _, _dev.Timeout, out _); + sense = dev.ReadCapacity(out cmdBuf, out _, dev.Timeout, out _); if(!sense) { @@ -269,21 +279,21 @@ namespace DiscImageChef.Core.Devices.Dumping if(lastSector <= 0) { - if(!_force) + if(!force) { - StoppingErrorMessage?. + stoppingErrorMessage?. Invoke("Could not find Lead-Out, if you want to continue use force option and will continue until 360000 sectors..."); - _dumpLog. + dumpLog?. WriteLine("Could not find Lead-Out, if you want to continue use force option and will continue until 360000 sectors..."); return null; } - UpdateStatus?. + updateStatus?. Invoke("WARNING: Could not find Lead-Out start, will try to read up to 360000 sectors, probably will fail before..."); - _dumpLog.WriteLine("WARNING: Could not find Lead-Out start, will try to read up to 360000 sectors, probably will fail before..."); + dumpLog?.WriteLine("WARNING: Could not find Lead-Out start, will try to read up to 360000 sectors, probably will fail before..."); lastSector = 360000; } } diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index 21502255d..3b4d973e8 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -33,15 +33,20 @@ using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Invocation; +using System.Linq; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.Console; using DiscImageChef.Core; +using DiscImageChef.Database; +using DiscImageChef.Database.Models; using DiscImageChef.Decoders.ATA; using DiscImageChef.Decoders.PCMCIA; using DiscImageChef.Decoders.SCSI; using DiscImageChef.Decoders.SCSI.MMC; using DiscImageChef.Decoders.SCSI.SSC; using DiscImageChef.Devices; +using Command = System.CommandLine.Command; +using Device = DiscImageChef.Devices.Device; using DeviceInfo = DiscImageChef.Core.Devices.Info.DeviceInfo; namespace DiscImageChef.Commands @@ -1066,6 +1071,33 @@ namespace DiscImageChef.Commands dev.Close(); + DicConsole.WriteLine(); + + // Open master database + var ctx = DicContext.Create(Settings.Settings.MasterDbPath); + + // Search for device in master database + Database.Models.Device dbDev = + ctx.Devices.FirstOrDefault(d => d.Manufacturer == dev.Manufacturer && d.Model == dev.Model && + d.Revision == dev.Revision); + + if(dbDev is null) + DicConsole.WriteLine("Device not in database, please create a device report and attach it to a Github issue."); + else + { + DicConsole.WriteLine($"Device in database since {dbDev.LastSynchronized}."); + + if(dbDev.OptimalMultipleSectorsRead > 0) + DicConsole.WriteLine($"Optimal multiple read is {dbDev.LastSynchronized} sectors."); + } + + // Search for read offset in master database + CdOffset cdOffset = + ctx.CdOffsets.FirstOrDefault(d => d.Manufacturer == dev.Manufacturer && d.Model == dev.Model); + + DicConsole.WriteLine(cdOffset is null ? "CD reading offset not found in database." + : $"CD reading offset is {cdOffset.Offset} samples ({cdOffset.Offset * 4} bytes)."); + return(int)ErrorNumber.NoError; } } diff --git a/DiscImageChef/Commands/MediaInfo.cs b/DiscImageChef/Commands/MediaInfo.cs index 8f67ba617..b612f031a 100644 --- a/DiscImageChef/Commands/MediaInfo.cs +++ b/DiscImageChef/Commands/MediaInfo.cs @@ -35,8 +35,10 @@ using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Invocation; using DiscImageChef.CommonTypes.Enums; +using DiscImageChef.CommonTypes.Structs; using DiscImageChef.Console; using DiscImageChef.Core; +using DiscImageChef.Core.Devices.Dumping; using DiscImageChef.Core.Media.Info; using DiscImageChef.Decoders.Bluray; using DiscImageChef.Decoders.CD; @@ -50,6 +52,7 @@ using BCA = DiscImageChef.Decoders.Bluray.BCA; using Cartridge = DiscImageChef.Decoders.DVD.Cartridge; using DDS = DiscImageChef.Decoders.DVD.DDS; using DMI = DiscImageChef.Decoders.Xbox.DMI; +using Session = DiscImageChef.Decoders.CD.Session; using Spare = DiscImageChef.Decoders.DVD.Spare; namespace DiscImageChef.Commands @@ -530,6 +533,38 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Media identified as {0}", scsiInfo.MediaType); Statistics.AddMedia(scsiInfo.MediaType, true); + if(scsiInfo.Toc != null || + scsiInfo.RawToc != null) + { + uint blockSize = 2352; + + Track[] tracks = Dump.GetCdTracks(ref blockSize, dev, scsiInfo.MediaType, null, false, + out long lastSector, null, null, null, TrackSubchannelType.None, + out _, null, null); + + if(tracks != null) + { + bool supportsPqSubchannel = Dump.SupportsPqSubchannel(dev, null, null); + bool supportsRwSubchannel = Dump.SupportsRwSubchannel(dev, null, null); + + Dump.SolveTrackPregaps(dev, null, null, tracks, supportsPqSubchannel, supportsRwSubchannel); + + for(int t = 1; t < tracks.Length; t++) + tracks[t - 1].TrackEndSector = tracks[t].TrackStartSector - 1; + + tracks[tracks.Length - 1].TrackEndSector = (ulong)lastSector; + + DicConsole.WriteLine(); + DicConsole.WriteLine("Track calculations:"); + + foreach(Track track in tracks) + DicConsole. + WriteLine("Track {0} starts at LBA {1}, ends at LBA {2}, has a pregap of {3} sectors and is of type {4}", + track.TrackSequence, track.TrackStartSector, track.TrackEndSector, + track.TrackPregap, track.TrackType); + } + } + dev.Close(); } }