diff --git a/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs b/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs
index 5479b8115..f988482b4 100644
--- a/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs
+++ b/DiscImageChef.Core/Devices/Dumping/CompactDisc.cs
@@ -32,18 +32,33 @@
using System;
using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml.Serialization;
+using DiscImageChef.Console;
using DiscImageChef.Core.Logging;
+using DiscImageChef.Decoders.CD;
+using DiscImageChef.Decoders.SCSI;
+using DiscImageChef.Decoders.SCSI.MMC;
using DiscImageChef.Devices;
using DiscImageChef.DiscImages;
+using DiscImageChef.Filters;
using DiscImageChef.Metadata;
+using Extents;
+using Schemas;
using MediaType = DiscImageChef.CommonTypes.MediaType;
+using PlatformID = DiscImageChef.Interop.PlatformID;
+using Session = DiscImageChef.Decoders.CD.Session;
+using TrackType = DiscImageChef.DiscImages.TrackType;
namespace DiscImageChef.Core.Devices.Dumping
{
///
/// Implement dumping Compact Discs
///
- class CompactDisc
+ // TODO: ISRC, MCN and pregaps
+ static class CompactDisc
{
///
/// Dumps a compact disc
@@ -63,6 +78,7 @@ namespace DiscImageChef.Core.Devices.Dumping
/// Try to read and dump as much Lead-in as possible
/// Path to output file
/// Formats to pass to output file plugin
+ /// Encoding to use when analyzing dump
/// If trying to dump scrambled sectors
/// If the resume file is invalid
/// If the track type is unknown (never)
@@ -71,30 +87,32 @@ namespace DiscImageChef.Core.Devices.Dumping
ref MediaType dskType,
ref
Resume resume, ref DumpLog dumpLog, bool dumpLeadIn,
- string outputPrefix,
+ Encoding encoding,
string
- outputPath, Dictionary formatOptions)
+ outputPrefix, string outputPath, Dictionary formatOptions)
{
- throw new NotImplementedException("Dumping CompactDisc is disable pending rewrite.");
+ uint subSize;
+ DateTime start;
+ DateTime end;
+ bool readcd;
+ bool sense = false;
+ const uint SECTOR_SIZE = 2352;
+ FullTOC.CDFullTOC? toc = null;
+ double totalDuration = 0;
+ double currentSpeed = 0;
+ double maxSpeed = double.MinValue;
+ double minSpeed = double.MaxValue;
+ uint blocksToRead = 64;
+ bool aborted = false;
+ System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true;
+ Dictionary mediaTags = new Dictionary();
- /*bool sense = false;
- ulong blocks;
- // TODO: Check subchannel support
- uint blockSize;
- uint subSize;
- FullTOC.CDFullTOC? toc = null;
- DateTime start;
- DateTime end;
- double totalDuration = 0;
- double totalChkDuration = 0;
- double currentSpeed = 0;
- double maxSpeed = double.MinValue;
- double minSpeed = double.MaxValue;
- Checksum dataChk;
- bool readcd;
- uint blocksToRead = 64;
- bool aborted = false;
- System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true;
+ if(dumpRaw)
+ {
+ dumpLog.WriteLine("Raw CD dumping not yet implemented");
+ DicConsole.ErrorWriteLine("Raw CD dumping not yet implemented");
+ return;
+ }
// We discarded all discs that falsify a TOC before requesting a real TOC
// No TOC, no CD (or an empty one)
@@ -105,15 +123,9 @@ namespace DiscImageChef.Core.Devices.Dumping
toc = FullTOC.Decode(cmdBuf);
if(toc.HasValue)
{
- byte[] tmpBuf = new byte[cmdBuf.Length - 2];
+ byte[] tmpBuf = new byte[cmdBuf.Length - 2];
Array.Copy(cmdBuf, 2, tmpBuf, 0, cmdBuf.Length - 2);
- sidecar.OpticalDisc[0].TOC = new DumpType
- {
- Image = outputPrefix + ".toc.bin",
- Size = tmpBuf.Length,
- Checksums = Checksum.GetChecksums(tmpBuf).ToArray()
- };
- DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].TOC.Image, tmpBuf);
+ mediaTags.Add(MediaTagType.CD_FullTOC, tmpBuf);
// ATIP exists on blank CDs
dumpLog.WriteLine("Reading ATIP");
@@ -126,15 +138,9 @@ namespace DiscImageChef.Core.Devices.Dumping
// Only CD-R and CD-RW have ATIP
dskType = atip.Value.DiscType ? MediaType.CDRW : MediaType.CDR;
- tmpBuf = new byte[cmdBuf.Length - 4];
+ tmpBuf = new byte[cmdBuf.Length - 4];
Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4);
- sidecar.OpticalDisc[0].ATIP = new DumpType
- {
- Image = outputPrefix + ".atip.bin",
- Size = tmpBuf.Length,
- Checksums = Checksum.GetChecksums(tmpBuf).ToArray()
- };
- DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].TOC.Image, tmpBuf);
+ mediaTags.Add(MediaTagType.CD_ATIP, tmpBuf);
}
}
@@ -157,7 +163,7 @@ namespace DiscImageChef.Core.Devices.Dumping
}
}
- int sessions = 1;
+ int sessions = 1;
int firstTrackLastSession = 0;
dumpLog.WriteLine("Reading Session Information");
@@ -167,17 +173,17 @@ namespace DiscImageChef.Core.Devices.Dumping
Session.CDSessionInfo? session = Session.Decode(cmdBuf);
if(session.HasValue)
{
- sessions = session.Value.LastCompleteSession;
+ sessions = session.Value.LastCompleteSession;
firstTrackLastSession = session.Value.TrackDescriptors[0].TrackNumber;
}
}
if(dskType == MediaType.CD)
{
- bool hasDataTrack = false;
- bool hasAudioTrack = false;
+ bool hasDataTrack = false;
+ bool hasAudioTrack = false;
bool allFirstSessionTracksAreAudio = true;
- bool hasVideoTrack = false;
+ bool hasVideoTrack = false;
foreach(FullTOC.TrackDataDescriptor track in toc.Value.TrackDescriptors)
{
@@ -188,7 +194,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack ||
(TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental)
{
- hasDataTrack = true;
+ hasDataTrack = true;
allFirstSessionTracksAreAudio &= track.TNO >= firstTrackLastSession;
}
else hasAudioTrack = true;
@@ -197,10 +203,10 @@ namespace DiscImageChef.Core.Devices.Dumping
}
if(hasDataTrack && hasAudioTrack && allFirstSessionTracksAreAudio && sessions == 2)
- dskType = MediaType.CDPLUS;
- if(!hasDataTrack && hasAudioTrack && sessions == 1) dskType = MediaType.CDDA;
- if(hasDataTrack && !hasAudioTrack && sessions == 1) dskType = MediaType.CDROM;
- if(hasVideoTrack && !hasDataTrack && sessions == 1) dskType = MediaType.CDV;
+ dskType = MediaType.CDPLUS;
+ if(!hasDataTrack && hasAudioTrack && sessions == 1) dskType = MediaType.CDDA;
+ if(hasDataTrack && !hasAudioTrack && sessions == 1) dskType = MediaType.CDROM;
+ if(hasVideoTrack && !hasDataTrack && sessions == 1) dskType = MediaType.CDV;
}
dumpLog.WriteLine("Reading PMA");
@@ -208,15 +214,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense)
if(PMA.Decode(cmdBuf).HasValue)
{
- tmpBuf = new byte[cmdBuf.Length - 4];
+ tmpBuf = new byte[cmdBuf.Length - 4];
Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4);
- sidecar.OpticalDisc[0].PMA = new DumpType
- {
- Image = outputPrefix + ".pma.bin",
- Size = tmpBuf.Length,
- Checksums = Checksum.GetChecksums(tmpBuf).ToArray()
- };
- DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].PMA.Image, tmpBuf);
+ mediaTags.Add(MediaTagType.CD_PMA, tmpBuf);
}
dumpLog.WriteLine("Reading CD-Text from Lead-In");
@@ -224,77 +224,132 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense)
if(CDTextOnLeadIn.Decode(cmdBuf).HasValue)
{
- tmpBuf = new byte[cmdBuf.Length - 4];
+ tmpBuf = new byte[cmdBuf.Length - 4];
Array.Copy(cmdBuf, 4, tmpBuf, 0, cmdBuf.Length - 4);
- sidecar.OpticalDisc[0].LeadInCdText = new DumpType
- {
- Image = outputPrefix + ".cdtext.bin",
- Size = tmpBuf.Length,
- Checksums = Checksum.GetChecksums(tmpBuf).ToArray()
- };
- DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].LeadInCdText.Image, tmpBuf);
+ mediaTags.Add(MediaTagType.CD_TEXT, tmpBuf);
}
}
}
- // TODO: Support variable subchannel kinds
- blockSize = 2448;
- subSize = 96;
- int sectorSize;
- if(separateSubchannel) sectorSize = (int)(blockSize - subSize);
- else sectorSize = (int)blockSize;
-
if(toc == null)
{
DicConsole.ErrorWriteLine("Error trying to decode TOC...");
return;
}
- DiscImages.Session[] sessionsForAlcohol = new DiscImages.Session[toc.Value.LastCompleteSession];
- for(int i = 0; i < sessionsForAlcohol.Length; i++)
+ MmcSubchannel supportedSubchannel = MmcSubchannel.Raw;
+ dumpLog.WriteLine("Checking if drive supports full raw subchannel reading...");
+ DicConsole.WriteLine("Checking if drive supports full raw subchannel reading...");
+ readcd = !dev.ReadCd(out byte[] readBuffer, out senseBuf, 0, SECTOR_SIZE + 96, 1, MmcSectorTypes.AllTypes,
+ false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, dev.Timeout, out _);
+ if(readcd)
{
- sessionsForAlcohol[i].SessionSequence = (ushort)(i + 1);
- sessionsForAlcohol[i].StartTrack = ushort.MaxValue;
+ dumpLog.WriteLine("Full raw subchannel reading supported...");
+ DicConsole.WriteLine("Full raw subchannel reading supported...");
+ subSize = 96;
}
- foreach(FullTOC.TrackDataDescriptor trk in
- toc.Value.TrackDescriptors.Where(trk => trk.POINT > 0 && trk.POINT < 0xA0 &&
- trk.SessionNumber <= sessionsForAlcohol.Length))
+ else
{
- if(trk.POINT < sessionsForAlcohol[trk.SessionNumber - 1].StartTrack)
- sessionsForAlcohol[trk.SessionNumber - 1].StartTrack = trk.POINT;
- if(trk.POINT > sessionsForAlcohol[trk.SessionNumber - 1].EndTrack)
- sessionsForAlcohol[trk.SessionNumber - 1].EndTrack = trk.POINT;
+ supportedSubchannel = MmcSubchannel.Q16;
+ dumpLog.WriteLine("Checking if drive supports PQ subchannel reading...");
+ readcd = !dev.ReadCd(out readBuffer, out senseBuf, 0, SECTOR_SIZE + 16, 1, MmcSectorTypes.AllTypes,
+ false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, dev.Timeout, out _);
+
+ if(readcd)
+ {
+ dumpLog.WriteLine("PQ subchannel reading supported...");
+ dumpLog.WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!");
+ DicConsole.WriteLine("PQ subchannel reading supported...");
+ DicConsole
+ .WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!");
+ subSize = 16;
+ }
+ else
+ {
+ supportedSubchannel = MmcSubchannel.None;
+ dumpLog.WriteLine("Checking if drive supports reading without subchannel...");
+ readcd = !dev.ReadCd(out readBuffer, out senseBuf, 0, SECTOR_SIZE, 1, MmcSectorTypes.AllTypes,
+ false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
+ supportedSubchannel, dev.Timeout, out _);
+
+ if(!readcd)
+ {
+ dumpLog.WriteLine("Cannot read from disc, not continuing...");
+ DicConsole.ErrorWriteLine("Cannot read from disc, not continuing...");
+ return;
+ }
+
+ dumpLog.WriteLine("Drive can only read without subchannel...");
+ dumpLog.WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!");
+ DicConsole.WriteLine("Drive can only read without subchannel...");
+ DicConsole
+ .WriteLine("WARNING: If disc says CD+G, CD+EG, CD-MIDI, CD Graphics or CD Enhanced Graphics, dump will be incorrect!");
+ subSize = 0;
+ }
}
- alcohol.AddSessions(sessionsForAlcohol);
-
- foreach(FullTOC.TrackDataDescriptor trk in toc.Value.TrackDescriptors)
- alcohol.AddTrack((byte)((trk.ADR << 4) & trk.CONTROL), trk.TNO, trk.POINT, trk.Min, trk.Sec, trk.Frame,
- trk.Zero, trk.PMIN, trk.PSEC, trk.PFRAME, trk.SessionNumber);
-
FullTOC.TrackDataDescriptor[] sortedTracks =
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
- List trackList = new List();
- long lastSector = 0;
- string lastMsf = null;
- foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR == 1 || trk.ADR == 4))
- if(trk.POINT >= 0x01 && trk.POINT <= 0x63)
- {
- TrackType track = new TrackType
+ List