Add support for dumping ISRC and MCN.

This commit is contained in:
2018-02-04 22:43:37 +00:00
parent a14476671f
commit 4818765c5d
3 changed files with 274 additions and 159 deletions

View File

@@ -57,7 +57,7 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <summary>
/// Implement dumping Compact Discs
/// </summary>
// TODO: ISRC, MCN and pregaps
// TODO: Barcode and pregaps
static class CompactDisc
{
/// <summary>
@@ -757,6 +757,29 @@ namespace DiscImageChef.Core.Devices.Dumping
outputPlugin.WriteSectorTag(new[] {kvp.Value}, track.TrackStartSector, SectorTagType.CdTrackFlags);
}
// Set MCN
sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _);
if(!sense && mcn != null && mcn != "0000000000000")
if(outputPlugin.WriteMediaTag(Encoding.ASCII.GetBytes(mcn), MediaTagType.CD_MCN))
{
DicConsole.WriteLine("Setting disc Media Catalogue Number to {0}", mcn);
dumpLog.WriteLine("Setting disc Media Catalogue Number to {0}", mcn);
}
// Set ISRCs
foreach(Track trk in tracks)
{
sense = dev.ReadIsrc((byte)trk.TrackSequence, out string isrc, out _, out _, dev.Timeout, out _);
if(sense || isrc == null || isrc == "000000000000") continue;
if(outputPlugin.WriteSectorTag(Encoding.ASCII.GetBytes(isrc), trk.TrackStartSector,
SectorTagType.CdTrackIsrc))
{
DicConsole.WriteLine("Setting ISRC for track {0} to {1}", trk.TrackSequence, isrc);
dumpLog.WriteLine("Setting ISRC for track {0} to {1}", trk.TrackSequence, isrc);
}
}
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
double imageWriteDuration = 0;

View File

@@ -31,6 +31,7 @@
// ****************************************************************************/
using System;
using System.Text;
using DiscImageChef.Console;
namespace DiscImageChef.Devices
@@ -60,11 +61,11 @@ namespace DiscImageChef.Devices
/// <param name="startingFeatureNumber">Feature number where the feature list should start from</param>
/// <param name="timeout">Timeout in seconds.</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber,
uint timeout, out double duration)
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber,
uint timeout, out double duration)
{
return GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All,
timeout, out duration);
timeout, out duration);
}
/// <summary>
@@ -77,19 +78,19 @@ namespace DiscImageChef.Devices
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
/// <param name="startingFeatureNumber">Starting Feature number.</param>
/// <param name="rt">Return type, <see cref="MmcGetConfigurationRt" />.</param>
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber,
MmcGetConfigurationRt rt, uint timeout, out double duration)
public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber,
MmcGetConfigurationRt rt, uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
buffer = new byte[8];
byte[] cdb = new byte[10];
buffer = new byte[8];
cdb[0] = (byte)ScsiCommands.GetConfiguration;
cdb[1] = (byte)((byte)rt & 0x03);
cdb[1] = (byte)((byte)rt & 0x03);
cdb[2] = (byte)((startingFeatureNumber & 0xFF00) >> 8);
cdb[3] = (byte)(startingFeatureNumber & 0xFF);
cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(buffer.Length & 0xFF);
cdb[3] = (byte)(startingFeatureNumber & 0xFF);
cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(buffer.Length & 0xFF);
cdb[9] = 0;
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
@@ -99,10 +100,10 @@ namespace DiscImageChef.Devices
if(sense) return true;
ushort confLength = (ushort)((buffer[2] << 8) + buffer[3] + 4);
buffer = new byte[confLength];
cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(buffer.Length & 0xFF);
senseBuffer = new byte[32];
buffer = new byte[confLength];
cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(buffer.Length & 0xFF);
senseBuffer = new byte[32];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense);
@@ -127,24 +128,25 @@ namespace DiscImageChef.Devices
/// <param name="agid">AGID used in medium copy protection</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType,
uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid,
uint timeout, out double duration)
uint address, byte layerNumber, MmcDiscStructureFormat format,
byte agid,
uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[12];
buffer = new byte[8];
byte[] cdb = new byte[12];
buffer = new byte[8];
cdb[0] = (byte)ScsiCommands.ReadDiscStructure;
cdb[1] = (byte)((byte)mediaType & 0x0F);
cdb[2] = (byte)((address & 0xFF000000) >> 24);
cdb[3] = (byte)((address & 0xFF0000) >> 16);
cdb[4] = (byte)((address & 0xFF00) >> 8);
cdb[5] = (byte)(address & 0xFF);
cdb[6] = layerNumber;
cdb[7] = (byte)format;
cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[9] = (byte)(buffer.Length & 0xFF);
cdb[10] = (byte)((agid & 0x03) << 6);
cdb[0] = (byte)ScsiCommands.ReadDiscStructure;
cdb[1] = (byte)((byte)mediaType & 0x0F);
cdb[2] = (byte)((address & 0xFF000000) >> 24);
cdb[3] = (byte)((address & 0xFF0000) >> 16);
cdb[4] = (byte)((address & 0xFF00) >> 8);
cdb[5] = (byte)(address & 0xFF);
cdb[6] = layerNumber;
cdb[7] = (byte)format;
cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[9] = (byte)(buffer.Length & 0xFF);
cdb[10] = (byte)((agid & 0x03) << 6);
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
@@ -153,10 +155,10 @@ namespace DiscImageChef.Devices
if(sense) return true;
ushort strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2);
buffer = new byte[strctLength];
cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[9] = (byte)(buffer.Length & 0xFF);
senseBuffer = new byte[32];
buffer = new byte[strctLength];
cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8);
cdb[9] = (byte)(buffer.Length & 0xFF);
senseBuffer = new byte[32];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out sense);
@@ -290,27 +292,27 @@ namespace DiscImageChef.Devices
/// <param name="trackSessionNumber">Track/Session number</param>
/// <param name="timeout">Timeout in seconds.</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool msf, byte format,
byte trackSessionNumber, uint timeout, out double duration)
public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool msf, byte format,
byte trackSessionNumber, uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
byte[] cdb = new byte[10];
byte[] tmpBuffer = (format & 0x0F) == 5 ? new byte[32768] : new byte[1024];
cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip;
cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip;
if(msf) cdb[1] = 0x02;
cdb[2] = (byte)(format & 0x0F);
cdb[6] = trackSessionNumber;
cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(tmpBuffer.Length & 0xFF);
cdb[2] = (byte)(format & 0x0F);
cdb[6] = trackSessionNumber;
cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(tmpBuffer.Length & 0xFF);
LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2);
buffer = new byte[strctLength];
buffer = new byte[strctLength];
if(buffer.Length <= tmpBuffer.Length)
{
@@ -341,7 +343,7 @@ namespace DiscImageChef.Devices
public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration)
{
return ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation,
timeout, out duration);
timeout, out duration);
}
/// <summary>
@@ -353,24 +355,25 @@ namespace DiscImageChef.Devices
/// <param name="dataType">Which disc information to read</param>
/// <param name="timeout">Timeout in seconds.</param>
/// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param>
public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType,
uint timeout, out double duration)
public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer,
MmcDiscInformationDataTypes dataType,
uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
byte[] tmpBuffer = new byte[804];
cdb[0] = (byte)ScsiCommands.ReadDiscInformation;
cdb[1] = (byte)dataType;
cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8);
cdb[8] = (byte)(tmpBuffer.Length & 0xFF);
cdb[8] = (byte)(tmpBuffer.Length & 0xFF);
LastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
uint strctLength = (uint)((tmpBuffer[0] << 8) + tmpBuffer[1] + 2);
buffer = new byte[strctLength];
buffer = new byte[strctLength];
Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length);
DicConsole.DebugWriteLine("SCSI Device", "READ DISC INFORMATION took {0} ms.", duration);
@@ -398,31 +401,32 @@ namespace DiscImageChef.Devices
/// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param>
/// <param name="c2Error">C2 error options.</param>
/// <param name="subchannel">Subchannel selection.</param>
public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength,
MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync,
MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout, out double duration)
public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize,
uint transferLength,
MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync,
MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout, out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[12];
byte[] cdb = new byte[12];
cdb[0] = (byte)ScsiCommands.ReadCd;
cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
if(relAddr) cdb[1] += 0x01;
cdb[2] = (byte)((lba & 0xFF000000) >> 24);
cdb[3] = (byte)((lba & 0xFF0000) >> 16);
cdb[4] = (byte)((lba & 0xFF00) >> 8);
cdb[5] = (byte)(lba & 0xFF);
cdb[6] = (byte)((transferLength & 0xFF0000) >> 16);
cdb[7] = (byte)((transferLength & 0xFF00) >> 8);
cdb[8] = (byte)(transferLength & 0xFF);
cdb[9] = (byte)((byte)c2Error << 1);
cdb[9] += (byte)((byte)headerCodes << 5);
if(sync) cdb[9] += 0x80;
cdb[0] = (byte)ScsiCommands.ReadCd;
cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
if(relAddr) cdb[1] += 0x01;
cdb[2] = (byte)((lba & 0xFF000000) >> 24);
cdb[3] = (byte)((lba & 0xFF0000) >> 16);
cdb[4] = (byte)((lba & 0xFF00) >> 8);
cdb[5] = (byte)(lba & 0xFF);
cdb[6] = (byte)((transferLength & 0xFF0000) >> 16);
cdb[7] = (byte)((transferLength & 0xFF00) >> 8);
cdb[8] = (byte)(transferLength & 0xFF);
cdb[9] = (byte)((byte)c2Error << 1);
cdb[9] += (byte)((byte)headerCodes << 5);
if(sync) cdb[9] += 0x80;
if(userData) cdb[9] += 0x10;
if(edcEcc) cdb[9] += 0x08;
cdb[10] = (byte)subchannel;
if(edcEcc) cdb[9] += 0x08;
cdb[10] = (byte)subchannel;
buffer = new byte[blockSize * transferLength];
@@ -454,29 +458,32 @@ namespace DiscImageChef.Devices
/// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param>
/// <param name="c2Error">C2 error options.</param>
/// <param name="subchannel">Subchannel selection.</param>
public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize,
MmcSectorTypes expectedSectorType, bool dap, bool sync, MmcHeaderCodes headerCodes,
bool userData, bool edcEcc, MmcErrorField c2Error, MmcSubchannel subchannel, uint timeout,
out double duration)
public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf,
uint endMsf, uint blockSize,
MmcSectorTypes expectedSectorType, bool dap, bool sync,
MmcHeaderCodes headerCodes,
bool userData, bool edcEcc, MmcErrorField c2Error,
MmcSubchannel subchannel, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[12];
byte[] cdb = new byte[12];
cdb[0] = (byte)ScsiCommands.ReadCdMsf;
cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
cdb[3] = (byte)((startMsf & 0xFF0000) >> 16);
cdb[4] = (byte)((startMsf & 0xFF00) >> 8);
cdb[5] = (byte)(startMsf & 0xFF);
cdb[6] = (byte)((endMsf & 0xFF0000) >> 16);
cdb[7] = (byte)((endMsf & 0xFF00) >> 8);
cdb[8] = (byte)(endMsf & 0xFF);
cdb[9] = (byte)((byte)c2Error << 1);
cdb[9] += (byte)((byte)headerCodes << 5);
if(sync) cdb[9] += 0x80;
cdb[0] = (byte)ScsiCommands.ReadCdMsf;
cdb[1] = (byte)((byte)expectedSectorType << 2);
if(dap) cdb[1] += 0x02;
cdb[3] = (byte)((startMsf & 0xFF0000) >> 16);
cdb[4] = (byte)((startMsf & 0xFF00) >> 8);
cdb[5] = (byte)(startMsf & 0xFF);
cdb[6] = (byte)((endMsf & 0xFF0000) >> 16);
cdb[7] = (byte)((endMsf & 0xFF00) >> 8);
cdb[8] = (byte)(endMsf & 0xFF);
cdb[9] = (byte)((byte)c2Error << 1);
cdb[9] += (byte)((byte)headerCodes << 5);
if(sync) cdb[9] += 0x80;
if(userData) cdb[9] += 0x10;
if(edcEcc) cdb[9] += 0x08;
cdb[10] = (byte)subchannel;
if(edcEcc) cdb[9] += 0x08;
cdb[10] = (byte)subchannel;
uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5]));
@@ -504,12 +511,12 @@ namespace DiscImageChef.Devices
public bool PreventAllowMediumRemoval(out byte[] senseBuffer, bool persistent, bool prevent, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[6];
senseBuffer = new byte[32];
byte[] cdb = new byte[6];
byte[] buffer = new byte[0];
cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval;
if(prevent) cdb[4] += 0x01;
cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval;
if(prevent) cdb[4] += 0x01;
if(persistent) cdb[4] += 0x02;
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
@@ -541,25 +548,27 @@ namespace DiscImageChef.Devices
return StartStopUnit(out senseBuffer, false, 0, 0, false, false, false, timeout, out duration);
}
public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions,
bool changeFormatLayer, bool loadEject, bool start, uint timeout, out double duration)
public bool StartStopUnit(out byte[] senseBuffer, bool immediate, byte formatLayer, byte powerConditions,
bool changeFormatLayer, bool loadEject, bool start, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[6];
senseBuffer = new byte[32];
byte[] cdb = new byte[6];
byte[] buffer = new byte[0];
cdb[0] = (byte)ScsiCommands.StartStopUnit;
cdb[0] = (byte)ScsiCommands.StartStopUnit;
if(immediate) cdb[1] += 0x01;
if(changeFormatLayer)
{
cdb[3] = (byte)(formatLayer & 0x03);
cdb[3] = (byte)(formatLayer & 0x03);
cdb[4] += 0x04;
}
else
{
if(loadEject) cdb[4] += 0x02;
if(start) cdb[4] += 0x01;
if(start) cdb[4] += 0x01;
}
cdb[4] += (byte)((powerConditions & 0x0F) << 4);
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration,
@@ -570,5 +579,60 @@ namespace DiscImageChef.Devices
return sense;
}
public bool ReadMcn(out string mcn, out byte[] buffer, out byte[] senseBuffer, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
mcn = null;
cdb[0] = (byte)ScsiCommands.ReadSubChannel;
cdb[1] = 0;
cdb[2] = 0x40;
cdb[3] = 0x02;
cdb[7] = (23 & 0xFF00) >> 8;
cdb[8] = 23 & 0xFF;
buffer = new byte[23];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (MCN) took {0} ms.", duration);
if(!sense && (buffer[8] & 0x80) == 0x80) mcn = Encoding.ASCII.GetString(buffer, 9, 13);
return sense;
}
public bool ReadIsrc(byte trackNumber, out string isrc, out byte[] buffer, out byte[] senseBuffer, uint timeout,
out double duration)
{
senseBuffer = new byte[32];
byte[] cdb = new byte[10];
isrc = null;
cdb[0] = (byte)ScsiCommands.ReadSubChannel;
cdb[1] = 0;
cdb[2] = 0x40;
cdb[3] = 0x03;
cdb[6] = trackNumber;
cdb[7] = (23 & 0xFF00) >> 8;
cdb[8] = 23 & 0xFF;
buffer = new byte[23];
LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration,
out bool sense);
Error = LastError != 0;
DicConsole.DebugWriteLine("SCSI Device", "READ READ SUB-CHANNEL (ISRC) took {0} ms.", duration);
if(!sense && (buffer[8] & 0x80) == 0x80) isrc = Encoding.ASCII.GetString(buffer, 9, 12);
return sense;
}
}
}

View File

@@ -56,9 +56,9 @@ namespace DiscImageChef.Commands
{
internal static void DoMediaInfo(MediaInfoOptions options)
{
DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug);
DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose);
DicConsole.DebugWriteLine("Media-Info command", "--device={0}", options.DevicePath);
DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", options.Debug);
DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", options.Verbose);
DicConsole.DebugWriteLine("Media-Info command", "--device={0}", options.DevicePath);
DicConsole.DebugWriteLine("Media-Info command", "--output-prefix={0}", options.OutputPrefix);
if(options.DevicePath.Length == 2 && options.DevicePath[1] == ':' && options.DevicePath[0] != '/' &&
@@ -114,13 +114,13 @@ namespace DiscImageChef.Commands
static void DoScsiMediaInfo(string outputPrefix, Device dev)
{
byte[] cmdBuf;
byte[] senseBuf;
bool sense;
MediaType dskType = MediaType.Unknown;
ulong blocks = 0;
uint blockSize = 0;
int resets = 0;
byte[] cmdBuf;
byte[] senseBuf;
bool sense;
MediaType dskType = MediaType.Unknown;
ulong blocks = 0;
uint blockSize = 0;
int resets = 0;
if(dev.IsRemovable)
{
@@ -192,7 +192,7 @@ namespace DiscImageChef.Commands
}
}
Modes.DecodedMode? decMode = null;
Modes.DecodedMode? decMode = null;
PeripheralDeviceTypes devType = dev.ScsiType;
sense = dev.ModeSense10(out byte[] modeBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current,
@@ -218,8 +218,8 @@ namespace DiscImageChef.Commands
if(!sense)
DataFile.WriteTo("Media-Info command", outputPrefix, "_scsi_modesense.bin", "SCSI MODE SENSE", modeBuf);
byte scsiMediumType = 0;
byte scsiDensityCode = 0;
byte scsiMediumType = 0;
byte scsiDensityCode = 0;
bool containsFloppyPage = false;
if(decMode.HasValue)
@@ -246,15 +246,15 @@ namespace DiscImageChef.Commands
{
DataFile.WriteTo("Media-Info command", outputPrefix, "_readcapacity.bin", "SCSI READ CAPACITY",
cmdBuf);
blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]);
blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + cmdBuf[7]);
blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]);
blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + cmdBuf[7]);
}
if(sense || blocks == 0xFFFFFFFF)
{
sense = dev.ReadCapacity16(out cmdBuf, out senseBuf, dev.Timeout, out _);
if(sense && blocks == 0)
if(sense && blocks == 0)
if(dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice)
{
DicConsole.ErrorWriteLine("Unable to get media capacity");
@@ -269,7 +269,7 @@ namespace DiscImageChef.Commands
Array.Copy(cmdBuf, 0, temp, 0, 8);
Array.Reverse(temp);
blocks = BitConverter.ToUInt64(temp, 0);
blocks = BitConverter.ToUInt64(temp, 0);
blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + cmdBuf[7]);
}
}
@@ -280,6 +280,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)",
blocks, blockSize, blocks * blockSize);
}
break;
case PeripheralDeviceTypes.SequentialAccess:
byte[] medBuf;
@@ -318,6 +319,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Medium types currently inserted in device:");
DicConsole.WriteLine(DensitySupport.PrettifyMediumType(meds));
}
DicConsole.WriteLine(DensitySupport.PrettifyMediumType(seqBuf));
}
}
@@ -472,12 +474,12 @@ namespace DiscImageChef.Commands
*/
#region All DVD and HD DVD types
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL ||
dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL || dskType == MediaType.DVDR ||
dskType == MediaType.DVDRAM || dskType == MediaType.DVDRDL || dskType == MediaType.DVDROM ||
dskType == MediaType.DVDRW || dskType == MediaType.DVDRWDL || dskType == MediaType.HDDVDR ||
dskType == MediaType.HDDVDRAM || dskType == MediaType.HDDVDRDL || dskType == MediaType.HDDVDROM ||
dskType == MediaType.HDDVDRW || dskType == MediaType.HDDVDRWDL)
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL ||
dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL || dskType == MediaType.DVDR ||
dskType == MediaType.DVDRAM || dskType == MediaType.DVDRDL || dskType == MediaType.DVDROM ||
dskType == MediaType.DVDRW || dskType == MediaType.DVDRWDL || dskType == MediaType.HDDVDR ||
dskType == MediaType.HDDVDRAM || dskType == MediaType.HDDVDRDL || dskType == MediaType.HDDVDROM ||
dskType == MediaType.HDDVDRW || dskType == MediaType.HDDVDRWDL)
{
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out _);
@@ -566,9 +568,9 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Xbox 360 DMI:\n{0}", DMI.PrettifyXbox360(cmdBuf));
// All XGD3 all have the same number of blocks
if(blocks == 25063 || // Locked (or non compatible drive)
if(blocks == 25063 || // Locked (or non compatible drive)
blocks == 4229664 || // Xtreme unlock
blocks == 4246304) // Wxripper unlock
blocks == 4246304) // Wxripper unlock
dskType = MediaType.XGD3;
}
}
@@ -628,6 +630,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Disc Definition Structure:\n{0}", DDS.Prettify(cmdBuf));
}
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.DvdramMediumStatus, 0, dev.Timeout, out _);
if(sense)
@@ -639,6 +642,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Medium Status:\n{0}", Cartridge.Prettify(cmdBuf));
}
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.DvdramSpareAreaInformation, 0, dev.Timeout,
out _);
@@ -651,6 +655,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Spare Area Information:\n{0}", Spare.Prettify(cmdBuf));
}
break;
case MediaType.DVDR:
case MediaType.HDDVDR:
@@ -914,6 +919,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Disc Information:\n{0}", DI.Prettify(cmdBuf));
}
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.Pac, 0, dev.Timeout, out _);
if(sense)
@@ -941,6 +947,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Burst Cutting Area:\n{0}", BCA.Prettify(cmdBuf));
}
break;
#endregion BD-ROM only
@@ -961,6 +968,7 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Blu-ray Disc Definition Structure:\n{0}",
Decoders.Bluray.DDS.Prettify(cmdBuf));
}
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.CartridgeStatus, 0, dev.Timeout, out _);
if(sense)
@@ -973,6 +981,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Cartridge Status:\n{0}", DI.Prettify(cmdBuf));
}
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.BdSpareAreaInformation, 0, dev.Timeout,
out _);
@@ -986,6 +995,7 @@ namespace DiscImageChef.Commands
"SCSI READ DISC STRUCTURE", cmdBuf);
DicConsole.WriteLine("Blu-ray Spare Area Information:\n{0}", DI.Prettify(cmdBuf));
}
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Bd, 0, 0,
MmcDiscStructureFormat.RawDfl, 0, dev.Timeout, out _);
if(sense)
@@ -1005,6 +1015,7 @@ namespace DiscImageChef.Commands
DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_001b.bin",
"SCSI READ DISC INFORMATION", cmdBuf);
}
sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf,
MmcDiscInformationDataTypes.PowResources, dev.Timeout, out _);
if(sense)
@@ -1016,6 +1027,7 @@ namespace DiscImageChef.Commands
DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_010b.bin",
"SCSI READ DISC INFORMATION", cmdBuf);
}
break;
#endregion Writable Blu-ray only
@@ -1096,7 +1108,7 @@ namespace DiscImageChef.Commands
}
}
int sessions = 1;
int sessions = 1;
int firstTrackLastSession = 0;
sense = dev.ReadSessionInfo(out cmdBuf, out senseBuf, dev.Timeout, out _);
@@ -1111,30 +1123,32 @@ namespace DiscImageChef.Commands
DicConsole.WriteLine("Session information:\n{0}", Session.Prettify(session));
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;
if(toc.HasValue)
foreach(TOC.CDTOCTrackDataDescriptor track in toc.Value.TrackDescriptors)
{
if(track.TrackNumber == 1 &&
((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack ||
(TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental))
if(track.TrackNumber == 1 &&
((TocControl)(track.CONTROL & 0x0D) ==
TocControl.DataTrack ||
(TocControl)(track.CONTROL & 0x0D) ==
TocControl.DataTrackIncremental))
allFirstSessionTracksAreAudio &= firstTrackLastSession != 1;
if((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack ||
(TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental)
{
hasDataTrack = true;
hasDataTrack = true;
allFirstSessionTracksAreAudio &= track.TrackNumber >= firstTrackLastSession;
}
else hasAudioTrack = true;
@@ -1143,10 +1157,10 @@ namespace DiscImageChef.Commands
}
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;
}
sense = dev.ReadRawToc(out cmdBuf, out senseBuf, 1, dev.Timeout, out _);
@@ -1163,9 +1177,9 @@ namespace DiscImageChef.Commands
if(fullToc.HasValue)
{
FullTOC.TrackDataDescriptor a0Track =
fullToc.Value.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1);
if(a0Track.POINT == 0xA0)
{
fullToc.Value.TrackDescriptors
.FirstOrDefault(t => t.POINT == 0xA0 && t.ADR == 1);
if(a0Track.POINT == 0xA0)
switch(a0Track.PSEC)
{
case 0x10:
@@ -1175,9 +1189,9 @@ namespace DiscImageChef.Commands
dskType = MediaType.CDROMXA;
break;
}
}
}
}
sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out _);
if(sense)
DicConsole.DebugWriteLine("Media-Info command", "READ TOC/PMA/ATIP: PMA\n{0}",
@@ -1200,6 +1214,16 @@ namespace DiscImageChef.Commands
if(CDTextOnLeadIn.Decode(cmdBuf).HasValue)
DicConsole.WriteLine("CD-TEXT on Lead-In:\n{0}", CDTextOnLeadIn.Prettify(cmdBuf));
}
sense = dev.ReadMcn(out string mcn, out _, out _, dev.Timeout, out _);
if(!sense && mcn != null && mcn != "0000000000000") DicConsole.WriteLine("MCN: {0}", mcn);
for(byte i = toc.Value.FirstTrack; i <= toc.Value.LastTrack; i++)
{
sense = dev.ReadIsrc(i, out string isrc, out _, out _, dev.Timeout, out _);
if(!sense && isrc != null && isrc != "000000000000")
DicConsole.WriteLine("Track's {0} ISRC: {1}", i, isrc);
}
}
break;
@@ -1223,7 +1247,7 @@ namespace DiscImageChef.Commands
{
DicConsole.WriteLine("PFI:\n{0}", PFI.Prettify(cmdBuf));
if(nintendoPfi.Value.DiskCategory == DiskCategory.Nintendo &&
nintendoPfi.Value.PartVersion == 15)
nintendoPfi.Value.PartVersion == 15)
switch(nintendoPfi.Value.DiscSize)
{
case DVDSize.Eighty:
@@ -1294,8 +1318,9 @@ namespace DiscImageChef.Commands
}
totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]);
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _);
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd,
0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _);
if(sense)
{
DicConsole.ErrorWriteLine("Cannot get PFI.");
@@ -1304,9 +1329,9 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors",
totalSize);
l0Video = PFI.Decode(cmdBuf).Value.Layer0EndPSN -
l0Video = PFI.Decode(cmdBuf).Value.Layer0EndPSN -
PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1;
l1Video = totalSize - l0Video + 1;
l1Video = totalSize - l0Video + 1;
// Get game partition size
DicConsole.DebugWriteLine("Dump-media command", "Getting game partition size");
@@ -1346,8 +1371,9 @@ namespace DiscImageChef.Commands
}
totalSize = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + cmdBuf[3]);
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _);
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.Dvd,
0, 0,
MmcDiscStructureFormat.PhysicalInformation, 0, 0, out _);
if(sense)
{
DicConsole.ErrorWriteLine("Cannot get PFI.");
@@ -1357,18 +1383,20 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors",
totalSize);
middleZone =
totalSize - (PFI.Decode(cmdBuf).Value.Layer0EndPSN -
PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1) - gameSize + 1;
totalSize -
(PFI.Decode(cmdBuf).Value.Layer0EndPSN -
PFI.Decode(cmdBuf).Value.DataAreaStartPSN + 1) -
gameSize + 1;
totalSize = l0Video + l1Video + middleZone * 2 + gameSize;
layerBreak = l0Video + middleZone + gameSize / 2;
totalSize = l0Video + l1Video + middleZone * 2 + gameSize;
layerBreak = l0Video + middleZone + gameSize / 2;
DicConsole.WriteLine("Video layer 0 size: {0} sectors", l0Video);
DicConsole.WriteLine("Video layer 1 size: {0} sectors", l1Video);
DicConsole.WriteLine("Middle zone size: {0} sectors", middleZone);
DicConsole.WriteLine("Game data size: {0} sectors", gameSize);
DicConsole.WriteLine("Total size: {0} sectors", totalSize);
DicConsole.WriteLine("Real layer break: {0}", layerBreak);
DicConsole.WriteLine("Middle zone size: {0} sectors", middleZone);
DicConsole.WriteLine("Game data size: {0} sectors", gameSize);
DicConsole.WriteLine("Total size: {0} sectors", totalSize);
DicConsole.WriteLine("Real layer break: {0}", layerBreak);
DicConsole.WriteLine();
}
}